This C code, Atmel Studio, is supposed to check pins 2 and 3 on PORTD which is connected to a 4 direction tilt sensor (Up, down, left, right) then lights up 4 different LEDs for each direction. LEDs are connected on PORTB.
code:
#include <avr/io.h>
#include <util/delay.h>
#ifndef F_CPU
#define F_CPU 16000000UL
#endif
//// define input sensor on PORT D
//
//#define tilt_S1 (PIND&(1<<2))
//#define tilt_S2 (PIND&(1<<3))
//
////define output LEDs on PORT B
//
//#define LED_U (PINB&(1<<0))
//#define LED_D (PINB&(1<<1))
//#define LED_L (PINB&(1<<2))
//#define LED_R (PINB&(1<<3))
int main(void)
{
DDRD =0x00; //port d as input
DDRB =0xFF; //port b as out
while (1)
{
//int pos = GetTiltPos(); //get current sensor position
if ( ( (PIND & (1<<2))==0 ) && ((PIND & (1<<3))==0 ) ) //Up (North) [S1=0, S2=0]
{
PORTB |= 1<<PINB0; //up turn on TOP led only
PORTB &= ~(1<<PINB1); //down
PORTB &= ~(1<<PINB2); //left
PORTB &= ~(1<<PINB3); //right
}
else if (((PIND & (1<<2))==1 ) && ((PIND & (1<<3))==0 )) //Left (West) [
{
PORTB &= ~(1<<PINB0); //up
PORTB &= ~(1<<PINB1); //down
PORTB |= 1<<PINB2; //left turn on LEFT led only
PORTB &= ~(1<<PINB3); //right
}
else if (((PIND & (1<<2))==0) && ((PIND & (1<<3))==1)) //Right (East)
{
PORTB &= (~(1<<PINB0)); //up
PORTB &= (~(1<<PINB1)); //down
PORTB &= (~(1<<PINB2)); //left
PORTB |= (1<<PINB3); //right turn on RIGHT led only
}
else if ( ((PIND & (1<<2))==1 ) && ((PIND & (1<<3))==1 ) ) //Down (South)
{
PORTB &= ~(1<<PINB0); //up
PORTB |= 1<<PINB1; //down turn on BOTTOM led only
PORTB &= ~(1<<PINB2); //left
PORTB &= ~(1<<PINB3); //right
}
}
}
//int GetTiltPos() //function to determine position of sensor
//{
//int S1 = 1<<PIND2;
//int S2 = 1<<PIND3;
//int R = ((S1<<1)| S2) ;
//return R;
//
//}
i tried defining the LEDs and sensors first, but that didn't work so i tried reading from the pin directly But that wont work either and I don't understand why. This code results in the upper LED to be always ON.
the sensor used is the 4 direction tilt sensor RPI-1031
The expression (PIND & (1<<2))==1 will never be true. The result of (PIND & (1<<2)) will either be 0 or 4 (1<<2). An easy way to avoid this issue is to always check for equal or not equal to zero, such as (PIND & (1<<2)) != 0.
You read from PINB instead of PIND (example: (PINB & (1<<2))) - i should be (PIND & (1<<2))
You do not set the port D as input as |= does not not work the way you think
DDRD |=0x00; //port d as input
This line does nothing. If you want to zero the register you need to:
DDRD = 0;
or if you only need to zero some of the bits on the register (for example bit 1,3 & 5)
DDRD &= ~((1 << 1) || (1 << 3) | (1 << 5));
Related
In the following code I am trying to create 4 scenarios
I) Red Led blinks at the specified rate when button 1 is pressed
II) Green Led blinks at the specified rate when button 2 is pressed
III) Both Led blinks at the specified rate when button 3 is pressed
IV) when more than 1 button is pressed Do nothing.
Scenario I,II,III works but I am having trouble for IV
#include <avr/io.h>
#include <util/delay.h>
#define DURATION 40
int main(void){
DDRD = 1<<DDD7|1<<DDD6;// D7 as output; other pins input
PORTD = 1<<PORTD4|1<<PORTD2|1<<PORTD5; // Set internal pullup resistor on D4
while(1){
if ((PIND & (1<<PIND2)) == 0){ // PIND4=0 when pressed
PORTD ^= (1<<PORTD6);
_delay_ms(DURATION);}
else{
PORTD &= ~(1<<PORTD6);
}
if ((PIND & (1<<PIND4)) == 0){ // PIND4=0 when pressed
PORTD ^= (1<<PORTD7);
_delay_ms(DURATION);}
else {
PORTD &= ~(1<<PORTD7);}// When button isn't pressed
if ((PIND & (1<<PIND5)) == 0){
_delay_ms(DURATION);
PORTD ^= (1<<PORTD6);
_delay_ms(DURATION);
PORTD ^= (1<<PORTD7);
_delay_ms(DURATION);
}
else {
PORTD &= ~(1<<PORTD6)|~(1<<PORTD7);
}
if((PIND & (1<<PIND5)|(1<<PIND2)|(1<<PIND4)) == 0){
PORTD &= ~(1<<PORTD6)|~(1<<PORTD7);
}
}
return(0);
}
change PORTD &= ~(1<<PORTD6)|~(1<<PORTD7); to PORTD &= ~((1<<PORTD6)|(1<<PORTD7)); because result of first expression is 0xFF
I'm testing some things on a Attiny85 and thought about the best way to handle the interrupt rutine. I know it is bad to have a lot of code in the interrupt handler, but I'm uncertain of any other ways to do this. I want my main program to sleep and wake on PCINT, the PCINT comes from multiple pins (rotary encoder A, b & switch and a receiving UART) so I was thinking just having a lot of code in the handler.
The code to determining which pin caused the interrupt, would look like this
#include <avr/io.h>
#include <stdint.h> // has to be added to use uint8_t
#include <avr/interrupt.h> // Needed to use interrupts
volatile uint8_t portbhistory = 0xFF; // default is high because the pull-up
int main(void)
{
DDRB &= ~((1 << DDB0) | (1 << DDB1) | (1 << DDB2)); // Clear the PB0, PB1, PB2 pin
// PB0,PB1,PB2 (PCINT0, PCINT1, PCINT2 pin) are now inputs
PORTB |= ((1 << PORTB0) | (1 << PORTB1) | (1 << PORTB2)); // turn On the Pull-up
// PB0, PB1 and PB2 are now inputs with pull-up enabled
PCICR |= (1 << PCIE0); // set PCIE0 to enable PCMSK0 scan
PCMSK0 |= (1 << PCINT0); // set PCINT0 to trigger an interrupt on state change
sei(); // turn on interrupts
while(1)
{
/*main program loop here */
}
}
ISR (PCINT0_vect)
{
uint8_t changedbits;
changedbits = PINB ^ portbhistory;
portbhistory = PINB;
if(changedbits & (1 << PB0))
{
/* PCINT0 changed */
}
if(changedbits & (1 << PB1))
{
/* PCINT1 changed */
}
if(changedbits & (1 << PB2))
{
/* PCINT2 changed */
}
}
And then ofc inside each of the if-statements in the interrupt handler, there would be code handling something, like this code, turning on the Timer0
TCNT0 = 0; // Set counter to 0
OCR0A = SERIAL_BIT_TIME; // Call timer interrupt in middle of first bit
position = 0; // Reset position and data
TIMSK |= 1 << OCIE0A; // Enable interrupt for compare register A (timer interrupt)
TIFR |= 1 << OCF0A; // Clear timer interrupt flag to prevent it jumping directly there
PCMSK &= ~(1 << SERIAL_RECEIVE); // Disable pin change interrupt
or with the switch input, the code inside the if-statement would be
if (lightState)
{
dali.transmit(ADDRESS, OFF);
lightState = 0;
}
else
{
dali.transmit(ADDRESS, ON);
lightState = 1;
}
Would this be a dumb solution?
volatile uint8_t flag;
int main(void)
{
DDRB &= ~((1 << DDB0) | (1 << DDB1) | (1 << DDB2)); // Clear the PB0, PB1, PB2 pin
// PB0,PB1,PB2 (PCINT0, PCINT1, PCINT2 pin) are now inputs
PORTB |= ((1 << PORTB0) | (1 << PORTB1) | (1 << PORTB2)); // turn On the Pull-up
// PB0, PB1 and PB2 are now inputs with pull-up enabled
PCICR |= (1 << PCIE0); // set PCIE0 to enable PCMSK0 scan
PCMSK0 |= (1 << PCINT0); // set PCINT0 to trigger an interrupt on state change
sei(); // turn on interrupts
while(1)
{
gotosleep();
do
{
switch(flag)
{
case 1:
dosomething1();
break;
case 2:
dosomething2();
break;
case 3:
dosomething3();
break;
}
cli();
flag = 0;
sei();
}while(flag);
}
}
ISR (PCINT0_vect)
{
uint8_t changedbits;
changedbits = PINB ^ portbhistory;
portbhistory = PINB;
if(changedbits & (1 << PB0))
{
flag = 1;
}
if(changedbits & (1 << PB1))
{
flag = 2;
}
if(changedbits & (1 << PB2))
{
flag = 3;
}
}
I am trying to build a drum machine using an Atmega644. The drum machine will have 16 LED's which will show which 16th of the beat it is at. The user should be able to set the BPM and therefore the updating of the LED will be different for different BPM.
I have a 16 MHz Crystal set at XTAL1 and XTAL2. I used a FUSE calculator to write the FUSE bits to a "Full Swing Oscillator" and remove the internal clock divide 8. I then set up the TIMER0 to perform this task
#define F_CPU 16000000UL // 1MHz internal clock
unsigned int tempo = 250; // Default BPM of 120.
volatile unsigned int seq_timer = 0;
//set-up timer for 0.5 ms update
TIMSK0 = (1<<OCIE0A);
TCCR0A = (1 << WGM01) |(1<<WGM00);
TCCR0B = (0 << WGM02) | (0<< CS02) | (1 << CS01) | (1 << CS00); //divide by 64
OCR0A = 125;
ISR (TIMER0_COMPA_vect) {
if (seq_timer>0) {seq_timer--;}
}
//Update which 16th note we are at.
void step(void){
update_led();
step_number = step_number < 15 ? step_number +1 : 0;
}
//Shift the LED such that the LED corresponding to step_number is lit up.
void update_led(void) {
for (int j = 16; j>=0; j--)
{
if ((((1 << step_number))>>j) & 0x01) {
PORTD |= (1 << PD5); //Serial Input
}
else {
PORTD &= ~(1 << PD5);
}
PORTD |= (1 << PD4); //Read clock
PORTD &= ~(1<< PD4);
}
PORTD |= (1 << PD3); //Shift clock
_delay_ms(40);
PORTD &= ~(1 << PD3);
}
while (1)
{
if ((seq_timer == 0)) {
seq_timer = tempo;
step();
}
Step functions calls a "update_led()" function which light up the LED corresponding to the step_number. This should according to my calculations occur (16e6 / (64*250*125)) = 8 updates/sec. But instead it does 4 updates/sec.
Am I missing something crucial?
I'm designing a click counter for a microcontroller and I'm using C for developing the code.
What happens here is when I click first button it will count the number of button presses. Then I have to press the second button to display the count in binary lighting up the LEDs. For example, if I press first button 10 times, it will light up second LED and fourth LED.
Since there are 8 LEDs I'm using 2 different ports.( 6 bits from PORTB and 2 bits from PORTD).
For that I have developed a code using if/else.But I want to implement this operation without multiple if/else operations because this method doesn't seem like much efficient.
while(PIND & 0b00100000){ //while PD5 switch is not pressed
if(clickCount>=128){ //if click count>=128
PORTB = PORTB | 0b00100000; //set PB5 HIGH
clickCount-=128; //deduct 128 from clickCount
}else if(clickCount>=64){
PORTB = PORTB | 0b00010000;
clickCount-=64;
}else if(clickCount>=32){
PORTB = PORTB | 0b00001000;
clickCount-=32;
}else if(clickCount>=16){
PORTB = PORTB | 0b00000100;
clickCount-=16;
}else if(clickCount>=8){
PORTB = PORTB | 0b00000010;
clickCount-=8;
}else if(clickCount>=4){
PORTB = PORTB | 0b00000001;
clickCount-=4;
}else if(clickCount>=2){
PORTD = PORTD | 0b10000000;
clickCount-=2;
}else if(clickCount==1){
PORTD = PORTD | 0b01000000;
clickCount = 0;
}
}
And I want to make this code in less number of bytes. So is there any way to develop this code segment using a for loop or any other method?
I don't know if this reduces the binary size, and not tested. You can still do something like this:
unsigned char mask[] = {
0b01000000, 0b10000000, 0b00000001, 0b00000010,
0b00000100, 0b00001000, 0b00010000, 0b00100000};
while(PIND & 0b00100000) {
for (int i = 7, v = 128; i > -1; --i, v /= 2) {
if (clickCount >= v && clickCount > 0) {
if (clickCount >= 4) {
PORTB = PORTB | mask[i];
} else {
PORTD = PORTD | mask[i];
}
clickCount -= v;
break;
}
}
}
Or you can use a single loop:
int v = 128, i = 7;
while (v > 0 && (PIND & 0b00100000)) {
if (clickCount >= v) {
if (clickCount >= 4) {
PORTB = PORTB | mask[i];
} else {
PORTD = PORTD | mask[i];
}
clickCount -= v;
} else {
--i;
v /= 2;
}
}
This could be done by just assigning values to PORTB and PORTD seperately since you have the number of clicks stored in a variable-clickCounter.
PORTB = PORTB | (clickCount & 0b00111111);
PORTD = PORTD | (clickCount & 0b11000000);
To handle the output, I would do something like:
clickCount %= 256; /* because the output is 8-bit */
PORTB = clickCount;
To make the output exactly 1 instruction long:
unsigned char clickCount = 0;
... /* do things, handle increment, handle 2nd button */
PORTB = clickCount; /* modulo 256 no longer needed, ClickCount cannot be more than 8 bits anyway */
I see no reason for doing it bit by bit.
I am trying to control three LEDs on an Arduino Uno board. These
LEDs are connected to the pin 3,4,5 of the port D as the outputs.
The pin 2 of the port D is connected to a push button, and it is configured
as the input.
The whole circuit has bee tested with the default Arduino code and was fully functional. However, with the code given below (without arduino libraries), the input pin (pin 2 on port D) always reads HIGH, regardless the state of the push button.
Any help will be greatly appreciated.
#include <avr/io.h>
#include <util/delay.h>
#define IS_LOW(reg, pin) ((reg) & (1 << (pin)) == 0)
#define SET_BIT(reg, pin) do{(reg) |= 1 << (pin);} while(0)
#define CLEAR_BIT(reg, pin) do{(reg) &= ~(1 << (pin));} while(0)
int main (void)
{
DDRD &= ~(1 << DDD2); //pin 2 on port D as INPUT
DDRD |= 1 << DDD3; //pin 3 on port D as OUTPUT
DDRD |= 1 << DDD4; //pin 4 on port D as OUTPUT
DDRD |= 1 << DDD5; //pin 5 on port D as OUTPUT
while(1)
{
if (IS_LOW(PIND, PD2))
{
SET_BIT(PORTD, PD3);
CLEAR_BIT(PORTD, PD4);
CLEAR_BIT(PORTD, PD5);
}
else
{
CLEAR_BIT(PORTD, PD3);
CLEAR_BIT(PORTD, PD4);
SET_BIT(PORTD, PD5);
_delay_ms(250);
SET_BIT(PORTD, PD4);
CLEAR_BIT(PORTD, PD5);
_delay_ms(250);
}
}
}
Unfortunately, the priority of & operator is lower than one of == operator.
You should define the IS_LOW macro like this:
#define IS_LOW(reg, pin) (((reg) & (1 << (pin))) == 0)