Pages: [1]   Go Down
Author Topic: Problem mit Timer (Interrupt)  (Read 2218 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 42
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallo,

ich habe ein Problem mit Timer Interrupts auf einem Duemilanove (Atmega 328). Folgendes Programm:
Code:
#include <Servo.h>
#include <LiquidCrystal.h>

unsigned int tcnt2;
int int_counter = 0;

int minute = 59;
int sekunde = 60;

Servo myservo;
LiquidCrystal lcd(12, 6, 5, 4, 3, 2);

int p1 = 0;
int p2 = 0;
int p3 = 0;
int p4 = 0;
boolean kiste = false;
 
void setup()
{
  /* First disable the timer overflow interrupt while we're configuring */  
  TIMSK2 &= ~(1<<TOIE2);  
  
  /* Configure timer2 in normal mode (pure counting, no PWM etc.) */  
  TCCR2A &= ~((1<<WGM21) | (1<<WGM20));  
  TCCR2B &= ~(1<<WGM22);  
  
  /* Select clock source: internal I/O clock */  
  ASSR &= ~(1<<AS2);  
  
  /* Disable Compare Match A interrupt enable (only want overflow) */  
  TIMSK2 &= ~(1<<OCIE2A);  
  
  /* Now configure the prescaler to CPU clock divided by 128 */  
  TCCR2B |= (1<<CS22)  | (1<<CS20); // Set bits  
  TCCR2B &= ~(1<<CS21);             // Clear bit  
  
  /* We need to calculate a proper value to load the timer counter.
   * The following loads the value 131 into the Timer 2 counter register
   * The math behind this is:
   * (CPU frequency) / (prescaler value) = 125000 Hz = 8us.
   * (desired period) / 8us = 125.
   * MAX(uint8) + 1 - 125 = 131;
   */  
  /* Save value globally for later reload in ISR */  
  tcnt2 = 131;    

  myservo.attach(9);  // attaches the servo on pin 9 to the servo object
  kisteZu();
  lcd.begin(16, 2);
  anzeige("Hallo!", 0);
  delay(2000);
  anzeige("Herzlichen", 1);
  delay(2000);
  anzeige("Glueckwunsch!", 1);
  delay(2000);
  lcd.clear();
  anzeige("Findet den Code", 0);
  anzeige("und oeffnet die", 1);
  delay(3000);
  lcd.clear();
  anzeige("Kiste. Ihr habt", 0);
  anzeige("aber nur eine", 1);
  delay(3000);
  lcd.clear();
  anzeige("Stunde Zeit.", 0);
  anzeige("Also beeilt Euch", 1);
  delay(3000);
  
  lcd.clear();
  /* Finally load end enable the timer */  
  TCNT2 = tcnt2;  
  TIMSK2 |= (1<<TOIE2);  
}

 
void loop()
{
  if (!kiste) {
    p1 = lesePoti(0);
    p2 = lesePoti(1);
    p3 = lesePoti(2);
    p4 = lesePoti(3);

    lcd.setCursor(0,0);
    lcd.print("Code: ");
    lcd.print(p1, DEC);
    lcd.print(":");
    lcd.print(p2, DEC);
    lcd.print(":");
    lcd.print(p3, DEC);
    lcd.print(":");
    lcd.print(p4, DEC);
    if (p1 == 1 && p2 ==2 && p3 == 3 && p4 == 4) {
      kisteAuf();
    }
    delay(100);
  } else {
    anzeige("Geschafft!", 0);

    delay(10000);
  }
}

void kisteAuf()
{
  // disable timer
  TIMSK2 &= ~(1<<TOIE2);
  lcd.clear();  
  kiste = true;
  lcd.setCursor(0,1);
  lcd.print("Kiste ist: auf");
  myservo.write(0);
  delay(2000);
}

void kisteZu()
{
  lcd.setCursor(0,1);
  lcd.print("Kiste ist: zu ");
  myservo.write(45);
}

int lesePoti(int nr)
{
  int val = analogRead(nr);
  delay(10);
  return map(val, 0, 1023, 0, 9);
}

void anzeige(char* s, byte zeile)
{
  lcd.setCursor(0,zeile);
  lcd.print(s);
}

ISR(TIMER2_OVF_vect) {  
   /* Reload the timer */  
   TCNT2 = tcnt2;  
   int_counter += 1;
   if (int_counter == 1000) {
     int_counter = 0;
     sekunde--;
     if (sekunde == 0) {
       minute--;
       sekunde = 59;
     }
     lcd.setCursor(0,1);
     lcd.print("Zeit:");
     lcd.setCursor(11,1);
     if (minute < 10) {
       lcd.print(0);
     }
     lcd.print(minute);
     lcd.print(":");
     if (sekunde < 10) {
       lcd.print(0);
     }
     lcd.print(sekunde);
   }
}
Ist der Timer aus läuft alles wunderbar. In der ersten Zeile auf dem LCD-Display wird der Wert von 4 Potis angezeigt, in der zweiten Zeile läuft eine Uhr rückwärts.
Ist der Interrupt aktiv läuft das Programm auch ordentlich an, aber nach ca. 10-60 Sekunden (unbestimmte Zeit) wird auf dem LCD nur noch Schrott angezeigt (komische Zeichen, blinkender Cursor usw.):

Offenbar gibt es einen Konflikt zwischen dem Timer und irgendeiner anderen Arduino-Funktion. Aber wo? Und wie kann ich das Problem lösen?
Danke für jede Hilfe, das ganze muss in 4 Tagen laufen (Geburtstagsgeschenk).
« Last Edit: January 16, 2011, 04:45:03 pm by hammerhaiv » Logged

"The old Europe"
Offline Offline
Edison Member
*
Karma: 1
Posts: 2005
Bootloaders suck!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Ich wuerde mal schaetzen, dass dein overflow interrupt einen zugriff auf das LCD in der loop() zerhackt.

Wenn du des englischen maechtig bist, dann empfehle ich die info zu "ATOMIC BLOCK" in der avr libc docu.

Evtl. langt es auch schon jeden lcd zugriff folgender weise zu verpacken:

Code:
byte _sreg = SREG; // interrupt flags speichern
cli(); // alle interrupts aus
lcd.irgendwas(); // wird so nicht durch irgendwelche interrupts unterbrochen
SREG = _sreg; // interrupt flags wiederherstellen

Allerdings wuerde ich empfehlen, in ISRs keinerlei konflikttraechtigen aktionen auszufuehren. Es ist ja nicht ohne weiteres vorauszusehen, was gerade unterbrochen wird. Nur flags setzen und die dann im hauptprogramm auswerten.
Logged

• Upload doesn't work? Do a loop-back test.
• There's absolutely NO excuse for not having an ISP!
• Your AVR needs a brain surgery? Use the online FUSE calculator.
My projects: RGB LED matrix, RGB LED ring, various ATtiny gadgets...
• Microsoft is not the answer. It is the question, and the answer is NO!

0
Offline Offline
Newbie
*
Karma: 0
Posts: 42
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ich hab's gestern abend noch alleine lösen können. Irgendwo hatte ich mal gelesen, dass man in einer ISR so wenig wie möglich machen soll, also hab ich den ganzen Anzeige-Kram da raus genommen und zähle in der ISR nur noch Sekunden und Minuten, der Rest ist im Main-Loop. Jetzt läuft es.
Logged

Pages: [1]   Go Up
Jump to: