So, hab jetzt noch mal ein konkretes Problem mit dem externen Interrupt.
Und zwar funktioniert der irgendwie nur jedes zweite Mal korrekt. Bzw. wenn ich den benutze um den AVR wieder aufzuwecken geht das nur einmal. Beim zweiten Mal schläft er dann für immer.
Woran kann das jetzt liegen?
Hier mal mein dazugehöriger Code. Das ganze soll mal ne Eieruhr werden
Code:
/*
* Folgender Code ist für eine Eieruhr basierend auf einem
* Atmega tiny2313. Der Code darf frei weitergegeben verändert
* zerstückelt oder sonst wie von jedem verwendet werden.
* Über eine kurz Email (jsemail@gmx.de) würde ich mich freuen.
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <stdint.h>
#define F_CPU 1000000 // Clock in Hz
#include <util/delay.h>
#define TIMER1_END_VALUE 1 //Values for Timer Compare Match
#define TIMER0_END_VALUE 5
#define TIME_TILL_PWR_DOWN 10 //Time in blinks till going to Power Down Mode
//*** global variables ***
//global state
uint8_t volatile current_time = 1;
uint8_t volatile time_set = 1;
enum global_state {STATE_SLEEP, STATE_SET, STATE_RUN};
enum global_state volatile current_state = STATE_SET;
enum global_state volatile new_state = STATE_SET;
//function prototypes
void init(void);
void change_state(void);
int main(void)
{
init();
//Haupt(endlos)schleife
while (1)
{
if(new_state != current_state)
{
change_state();
}
sleep_mode(); //einschlafen
}
return 0;
}
ISR(TIMER0_COMPA_vect)
{
static uint8_t debounced_button_state; // Debounced state of the switches
static uint8_t button_plus_state; // for button debouncing
static uint8_t button_minus_state;
static uint8_t button_start_state;
uint8_t debounced_button_state_old;
uint8_t button_press; // bit 1 on rising edge (button down)
static uint8_t set_led_active_count;
static uint8_t pwr_down_count;
//read button states
button_plus_state = (button_plus_state<<1) | ((PINB & (1<<PINB2))>>2);
button_minus_state = (button_minus_state<<1) | ((PINB & (1<<PINB3))>>2);
button_start_state = (button_start_state<<1) | ((PINB & (1<<PINB4))>>2);
//run debounce algorithm and check for rising edge
debounced_button_state_old = debounced_button_state;
debounced_button_state = ((button_plus_state && 0x0F)<<PINB2) | ((button_minus_state && 0x0F)<<PINB3) | ((button_start_state && 0x0F)<<PINB4);
button_press = (debounced_button_state ^ debounced_button_state_old) & debounced_button_state;
if(debounced_button_state == ((1<<PINB2) | (1<<PINB3)))
{
time_set = 1;
}
set_led_active_count++;
if(set_led_active_count == 50)
{
PORTD = time_set;
}
else
{
if(set_led_active_count >= 80)
{
PORTD = 0x00;
set_led_active_count = 0;
pwr_down_count++;
if(pwr_down_count == TIME_TILL_PWR_DOWN)
{
pwr_down_count = 0;
new_state = STATE_SLEEP;
return;
}
}
}
if(button_press)
{
pwr_down_count = 0;
switch(button_press)
{
case(1<<PINB2) :
if(time_set > 1)
{
time_set--;
}
break;
case(1<<PINB3) :
if(time_set < 60)
{
time_set++;
}
break;
case(1<<PINB4) :
current_time = time_set;
PORTD = 0x00;
new_state = STATE_RUN;
break;
default :
break;
}
}
return;
}
ISR(TIMER1_COMPA_vect)
{
static uint16_t run_led_active_count = 0;
static uint16_t run_beep_count;
if(current_time == 0)
{
run_beep_count++;
if(run_beep_count <= 50)
{
PORTB ^= (1<<PINB0);
}
if(run_beep_count == 100)
{
run_beep_count = 0;
}
return;
}
run_led_active_count++;
if(run_led_active_count == 900)
{
PORTD = current_time;
}
if(run_led_active_count >= 1000)
{
run_led_active_count = 0;
PORTD = 0x00;
current_time--;
if(GIMSK ^ (1 << PCIE))
{
PCMSK |= (1 << PCINT4); //externe Interrupts auf Taster 4 (ACHTUNG: nicht sauber es hier zu machen statt in change_state()...)
GIMSK |= (1 << PCIE); //externe Interrupts erst hier aktivieren
}
}
return;
}
ISR(PCINT_vect)
{
GIMSK &= ~(1<<PCIE); //externe Interrupts deaktivieren
_delay_ms(200);
new_state = STATE_SET;
}
void init()
{
//Datenrichtung für die Ausgänge
DDRD = (1 << DDD0) | (1 << DDD1) | (1 << DDD2) | (1 << DDD3) | (1 << DDD4) | (1 << DDD5) | (1 << DDD6);
DDRB = (1 << DDB0);
//Setup Timer 1
OCR1A = TIMER1_END_VALUE; //Compare Value
TCCR1B = (1<<WGM12); //CTC Mode
TIMSK |= (1<<OCIE1A); //Output Compare A Match Interrupt Enable
//Setup Timer 0
OCR0A = TIMER0_END_VALUE; //Compare Value
TCCR0A = (1<<WGM01); //CTC Mode
TCCR0B |= (1<<CS02) | (1<<CS00); //Teiler
TIMSK |= (1<<OCIE0A); //Enable Interrupt Output Compare
current_time = 1;
sei();
return;
}
void change_state()
{
cli();
switch(new_state)
{
case(STATE_SLEEP) :
set_sleep_mode(SLEEP_MODE_PWR_DOWN); //Sleep Mode auf Power Down setzen
TCCR1B &= ~((1<<CS12) | (1<<CS11) | (1<<CS10)); //alle Timer deaktivieren
TCCR0B &= ~((1<<CS02) | (1<<CS01) | (1<<CS00));
PCMSK |= (1 << PCINT2) | (1 << PCINT3) | (1 << PCINT4); //externe Interrupts aktivieren zum Aufwecken
GIMSK |= (1 << PCIE);
break;
case(STATE_SET) :
set_sleep_mode(SLEEP_MODE_IDLE); //Sleep Mode auf Idle setzen
GIMSK &= ~(1<<PCIE); //externe Interrupts deaktivieren
PCMSK &= ~((1 << PCINT2) | (1 << PCINT3) | (1 << PCINT4)); //externe Interrupts aktivieren zum Aufwecken
TCCR1B &= ~((1<<CS12) | (1<<CS11) | (1<<CS10)); //Timer1 deaktivieren
TCCR0B |= (1<<CS02) | (1<<CS00); //Timer0 aktivieren
break;
case(STATE_RUN) :
set_sleep_mode(SLEEP_MODE_IDLE); //Sleep Mode auf Idle setzen
TCCR0B &= ~((1<<CS02) | (1<<CS01) | (1<<CS00)); //Timer0 deaktivieren
TCCR1B |= (1<<CS12) | (1<<CS10); //Timer1 aktivieren
break;
default :
break;
}
current_state = new_state;
sei();
return;
}
Lesezeichen