Go Down

Topic: 8/16bit timer Konfiguration ? (Read 610 times) previous topic - next topic

hoboPowa

Nov 20, 2012, 09:00 pm Last Edit: Nov 21, 2012, 04:49 pm by hoboPowa Reason: 1
hy,
hab die Tage wieder einmal den arduino (mit ATmega328P) in die Hand genommen und wollte ein paar Timer durch Bit-Manipulation konfigurieren, so dass diese 1s abzählen. Ausgabe durch umschalten (an <=> aus) von angeschlossenen LED's. Ich hatte jedoch nicht sehr viel Erfolg; allgemeines C-Beispiel zB 8bit timer (1s Zählzeit)  
=> mein Arduino schaltet erst nach ca 2sek. anstatt nach einer...
Arduino spezifisch hab ich bisher nicht wirklich etwas hilfreiches gefunden  :~
Von daher schaut bitte über meine Programme und erklärt was falsch ist. Wahrscheinlich hab ich irgendwelche grundlegenden, arduino-spezifischen Einstellungen/Regeln/Größen nicht beachtet.
die 3 Timer:
Code: [Select]

//---------------- 8bit-Timer, abzählen einer Sekunde ---------------- //
int counter = 0;

void setup(){
  DDRD = 0xFF;
  PORTD = 0x00;
  DDRB = 0x3F;
  PORTB = 0x00;
  // Ausgänge, alle auf 0
  TCCR2A  = (1 << WGM21);
  // CTC- Mode; Clear Timer on Compare Match
  TCCR2B |= ((1 << CS22) | (1 << CS21) | (1 << CS20));
  // prescaler: in diesem Fall clockspeed von 16MHz / 1024 = 15625Hz für den timer
  OCR2A = 125;
  // 15625 / 125 = 125 => nach 125 durchläufen ist eine Sekunde vorbei
  TIMSK2 = (1 << OCIE2A);
  //Compare A Match Interrupt Enable für timer2/counter2
  // Vergleichswert = 125, Interrupt wird ausgelöst wenn TCNT2 = OCR2A
  SREG = (1 << 7);             
  // interrupts enabled
}

void loop(){
  while(1){
    delay(1000); // überprüfen des Timers
    PORTB = ~PORTB;  //leds werden an bzw aus geschaltet (an <=> aus)
  }
}

ISR(TIMER2_COMPA_vect){
  if(counter <= 125){
    counter++;
  }
  else{
    counter = 0;
    PORTD = ~PORTD;
  }
}
   
// Ergebniss: ca 1s , aber nach 10s schon abweichung von +0,5s => da bei jedem durchlauf ISR zusätzlich Takte "hinzufügt" ?


//-----------------------------------------------------------//
//-----------8bit-Timer, abzählen einer Sekunde -------------//

int counter = 0;
void setup(){
  DDRD = 0xFF;
  PORTD = 0x00;
  DDRB = 0x3F;
  PORTB = 0x00;
  // Ausgänge, alle auf 0
  TCCR2B |= ((1 << CS22) | (1 << CS21) | (1 << CS20));
  // prescaler: in diesem Fall clockspeed von 16MHz / 1024 = 15625Hz für den timer
  TIMSK2 = (1 << TOIE2);
  //overflow Interrupt Enable für timer2/counter2
  SREG = (1 << 7);             
  // interrupts enabled
}

void loop(){
  while(1){
    delay(1000);     
    PORTB = ~PORTB; 
    // überprüfung, ob Timer stimmt
  }
}

// Takt = 15625Hz geteilt durch 256 = 61,04 => nach rund 61 durchläufen ist eine Sekunde vorbei ?!
ISR(TIMER2_OVF_vect){ 
  if(counter <= 61){
    counter++;
  }
  else{
    counter = 0;
    PORTD = ~PORTD;
  }
}
   
// Ergebniss : ungefähr 2s sind die LED's and, 2s aus usw Warum?


//-----------------------------------------------------------//
//-------------- 16bit Timer, abzählen einer Sekunde --------//
int counter = 0;

void setup(){
  DDRD = 0xFF;
  PORTD = 0x00;
  DDRB = 0x3F;
  PORTB = 0x00;
  // Ausgänge, alle auf 0
  SREG = (1 << 7);             
  // global interrupts enabled
  TCCR1B  |= ((1 << CS12) | (1 << WGM12));
  //prescaler: in diesem Fall 16MHz /256 = 62500Hz für den timer // CTC- Mode => zählen bis vergleichswert, automatisch zurückgesetzt
  TCNT1 = 0;
  OCR1A = 0b1111010000100100;
  // Vergleichswert = 62500 , Interrupt wird ausgelöst wenn TCNT1 = OCR1A
  //62500 Takte werden gezählt mit Frequenz von 62500Hz => eine sekunde vorbei(?), durch interrupt werden leds an (für 1s) bzw ausgeschaltet (für 1s) => theoretisch
  TIMSK1 = (1 << OCIE1A);  //Output Compare A Match Interrupt Enable setzten
  // spielt die Reihenfolge der Bit-Manipulation eine Rolle ?
}

void loop(){
  while(1){
    delay(1000);
    PORTB = ~PORTB;
    //zum vergleich, ob der timer 1s abzählt
  }
}

ISR(TIMER1_COMPA_vect){ 
  PORTD = ~PORTD;  // schaltet LEDS ein und aus
}

/* => ERGEBNIS : LED's bleiben dauerhaft aus
                 Fehler ?
      mit prescaler /64 sind die leds dauerhaft an (zu schnelles schalten für menschliches Auge ?!)
*/ 

habe versucht alle Schritte gut zu erklären.
Daten-Blatt: atmega328P

Vielen Dank für eure Hilfe

pylon

Soll die Arduino-Umgebung weiterhin funktionieren? Dann darfst Du Timer0 nicht verwenden, der ist für millis() und delay() verantwortlich.

Dein C-Beispiel ist für einen mit 4 MHz getakteten ATmega geschrieben, läuft auf dem Timer0 und verändert den Prescaler. Willst Du das wirklich?

pylon

Wenn's Timer1 sein kann, dann könnte Dich der folgende Code glücklich machen:

Code: [Select]

void setup() {
  TCCR1B = 0x0D; // CTC1 | Prescaler 1024
  OCR1AH = 15625 >> 8;
  OCR1AL = 15625 & 0xFF;
  TIMSK1 |= OCIE1A;
}

void loop() {
}

ISR(TIMER1_COMPA_vect) {
  // executes every second
  // attention: interrupt context
}

Go Up