Atmega 328 Code Issue | I am trying to create 4 scenarios - c

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

Related

What can i change in this code to make it work?

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));

Best way to handle multiple PCINT in AVR

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;
}
}

Toggle LED in C code with CMSIS not working

I am trying to toggle a LED with C code and CMSIS. However, what happens is that it doesn't toggle the LED, it just turns it on and that's it. It needs to toggle when the button is pressed.
this is my button configuration:
//Configure Port C pin 13 (Button)
RCC->AHBENR |= 0x80000;
GPIOC->MODER &= ~(00 << 26);
GPIOC->PUPDR &= ~(01 << 26);
this is my Led configuration:
RCC->AHBENR |= 0x20000;
GPIOA->MODER |= 0x400;
GPIOA->OTYPER |= 0x00;
GPIOA->PUPDR &= ~(00 << 10);
and this is the code that i have this far:
//Read pin state of Port C pin 13
if((GPIOC->IDR & (1<<13)) == 0)
{
if(!button_down)
{
GPIOA->ODR = 0b0100000;
}
button_down = 1;
}
else
{
button_down = 0;
}

attiny13 pwm led complete on off

Sorry for my english. I have some issues on attiny13 with pwm. pwm works perfectly on adjustment. However while OCR0B value is going to zero or max, led not complete off or on. I tried use " PORTB &= ~ (1<<); " while OCROX was zero, but it doesnt work. afterwards I find that I must add " ISR(TIM0_COMPA_vect)" for interrupt. I have recently begun work on tiny ,so its too hard especially avr side for me and pls ignore my illiteracy. This is code, ı used.
#define F_CPU 1200000
#define LED PB1
#include <avr/io.h>
const int buttonPin = 4; // the pin that the pushbutton is attached to
int buttonPushCounter = 0; // counter for the number of button presses
int buttonState = 0; // current state of the button
int lastButtonState = 1;
int model; // previous state of the button
void setup() {
// initialize the button pin as a input:
pinMode(buttonPin, INPUT);
// initialize the LED as an output:
}
void adc_setup (void)
{
// Set the ADC input to PB2/ADC1
ADMUX |= (1 << MUX0);
ADMUX |= (1 << ADLAR);
// Set the prescaler to clock/128 & enable ADC
// At 9.6 MHz this is 75 kHz.
// See ATtiny13 datasheet, Table 14.4.
ADCSRA |= (1 << ADPS1) | (1 << ADPS0) | (1 << ADEN);
}
void pwm_setup (void)
{
// Set Timer 0 prescaler to clock/8.
// At 9.6 MHz this is 1.2 MHz.
// See ATtiny13 datasheet, Table 11.9.
TCCR0B |= (1 << CS01);
// Set to 'Fast PWM' mode
TCCR0A |= (1 << WGM01) | (1 << WGM00);
// Clear OC0B output on compare match, upwards counting.
TCCR0A |= (1 << COM0B1);
}
void pwm_write (int val)
{
OCR0B = val;
}
void button()
{
buttonState = digitalRead(buttonPin);
// compare the buttonState to its previous state
if (buttonState != lastButtonState) {
// if the state has changed, increment the counter
if (buttonState == HIGH) {
// if the current state is HIGH then the button went from off to on:
buttonPushCounter++;
model = buttonPushCounter % 5 ;
} else {
// if the current state is LOW then the button went from on to off:
}
// Delay a little bit to avoid bouncing
delay(250);
}
lastButtonState = buttonState;
}
int main (void)
{
int adc_in;
// LED is an output.
DDRB |= (1 << LED);
adc_setup();
pwm_setup();
while (1) {
// Get the ADC value
button();
//adc_in = adc_read();
// Now write it to the PWM counter
switch(model)
{
case 0:
pwm_write(0);
//PORTB &= ~ (1<<PB3);
break;
case 1:
pwm_write(50);
break;
case 2:
pwm_write(100);
break;
case 3:
pwm_write(150);
break;
case 4:
pwm_write(255);
//PORTB |= (1<<PB3);
break;
}
}
}
I find another code successfully turn on, off and adjust led via using interrupt with two button, but I dont understand how code write values on OCR0X. Could somebody can explain me the connection between OCR0X and duty(count, pwm value) at the second code . Because ı need write constant values in those OCR0X.
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define PWM_PIN PB0
#define KEY_UP_PIN PB1
#define KEY_DOWN_PIN PB2
#define PWM_DUTY_MIN (0)
#define PWM_DUTY_MAX (100)
#define PWM_DUTY_STEP (1)
#define KEY_UP (1 << 1)
#define KEY_DOWN (1 << 2)
static volatile uint8_t duty = 0;
static uint8_t counter = 0;
static void process(void);
static uint8_t read_keys(void);
ISR(TIM0_COMPA_vect)
{
if (duty > PWM_DUTY_MIN && duty < PWM_DUTY_MAX) {
if (counter == 0) {
PORTB |= _BV(PWM_PIN);
} else if (counter == duty) {
PORTB &= ~_BV(PWM_PIN);
}
if (++counter == PWM_DUTY_MAX) {
counter = 0;
}
}
}
int
main(void)
{
/* setup */
DDRB |= _BV(PWM_PIN); // set PWM pin as OUTPUT
PORTB |= _BV(KEY_UP_PIN)|_BV(KEY_DOWN_PIN);
TCCR0A |= _BV(WGM01); // set timer counter mode to CTC
TCCR0B |= _BV(CS00); // set prescaler
OCR0A = 95; // set Timer's counter max value (96 - 1)
TIMSK0 |= _BV(OCIE0A); // enable Timer CTC interrupt
sei(); // enable global interrupts
_delay_ms(100); // time of debounce
/* loop */
while (1) {
process();
_delay_ms(8);
}
}
void
process(void)
{
uint8_t keys;
if (!(keys = read_keys())) {
return;
}
if ((keys & KEY_UP) && duty < PWM_DUTY_MAX) {
duty += PWM_DUTY_STEP;
}
if ((keys & KEY_DOWN) && duty > PWM_DUTY_MIN) {
duty -= PWM_DUTY_STEP;
}
if (duty == PWM_DUTY_MIN) {
PORTB &= ~_BV(PWM_PIN);
} else if (duty == PWM_DUTY_MAX) {
PORTB |= _BV(PWM_PIN);
}
}
static uint8_t
read_keys(void)
{
uint8_t result = 0;
if ((PINB & _BV(KEY_UP_PIN)) == 0) {
result |= KEY_UP;
}
if ((PINB & _BV(KEY_DOWN_PIN)) == 0) {
result |= KEY_DOWN;
}
return result;
}

Why is my Atmega644 TIMER0 running at half the speed of the expected clock speed?

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?

Resources