Timer zählt falsch

Guten Morgen^^,

Ich habe einen Arduino bzw. Genuino Mega mit einem Atmega 2560.

Ich möchte für die Uni eine Interrupt-Funktion schreiben die alle paar Mirkosekunden einen Analogen Wert schreibt. Im Endeffekt soll damit eine PWM realisiert werden.
Nun wollte ich klein anfangen und die integrierte LED auf Pin 13 jede Sekunde togglen lassen.

Dazu habe ich mich ein wenig belesen und vorherige Kenntnisse angewendet und bin zu folgendem Sketch gekommen.

#include <avr/io.h>
#include <avr/interrupt.h>


int toogle_LED =0;
void setup() {
  Serial.begin(9600);
  pinMode(13,OUTPUT);
  
  // put your setup code here, to run once:
  noInterrupts(); // Disable Interrupts
  // set Timer 3 on 1Hz
  TCCR3A = 0; // TCCR3A register set to 0
  TCCR3B = 0; // same with register B
  TCNT3  = 0; // counter value to 0
  //Compare match registre for 1hz
  OCR3A = 15624; // 16.000.000 / 1*1024(prescaler)-1
  //CTC enable
  TCCR3A |=(1<<WGM12);
  // set prescaler to 1024
  TCCR3B |=(1<<CS12)|(1<<CS10);
  // enable timer compare interrupt
  TIMSK3 |=(1<<OCIE3A);

  interrupts();// enable again interrupts

}

//INterrupt funktion

ISR(TIMER3_COMPA_vect){
  if(toogle_LED==0){
    digitalWrite(13,HIGH);
    toogle_LED=1;  
  }
  else{
    digitalWrite(13,LOW);
    toogle_LED=0;  
  }
}


void loop() {
  digitalRead(10);
  analogRead(10);
}

Dabei musste ich allerdings feststellen, dass meine LED nun nicht jede Sekunde sondern ca. alle 4 Sekunden Toogelt.
Habe mir mehrere Foren durchgelesen und bin auf keine Lösung gestoßen.

Die Interrupts sind kurz geschrieben, Im Loop passiert nicht viel und der Timer dürfte richtig konfiguriert sein.
Ich habe mehrere Timer ausprobiert und nur der Timer 3 Hat es geschafft die LED überhaupt zum leuchten zubringen.
Alle anderen Timer versagen leider.

Ich habe bereits mal gelesen, dass die Timer von Arduino selber PWM verwenden und solange diese aktiv sind wohl die Zeit Ergebnisse nicht stimmen bzw. ungenau werden. Leider habe ich nichts weiter drüber gefunden.

Vielen Dank für Eure Hilfe

Hi willkommen hier!

Warum verwendest du nicht das Verfahren aus:
BlinkWithoutDelay

int toogle_LED =0;

Dieses solltest als volatile deklarieren

void loop() {

digitalRead(10);
 analogRead(10);
}

Das ist ja nun völlig Sinn befreit.

Habe mir mehrere Foren durchgelesen und bin auf keine Lösung gestoßen.

Tipp:
Orientiere dich am Datenblatt des Prozessors.
In Foren findest du eher halbgares.

Hey,

Ich habe die Variable als volatile definiert und die Anweisungen im Loop entfernt. (Da sollte später noch Code folgen).

Unsere Aufgabe ist es mit den Interrupts zu arbeiten, weshalb ich nicht mit millis() oder delay() arbeite.

Ich habe mich am Datenblatt orientiert und laut diesem müsste halt die LED jede Sekunde Tooglen aber sie tut es einfach weiterhin nicht.

Ah, ja, eine Hausaufgabe!
(habe mir schon sowas gedacht)

Bei mir würde das so aussehen, auch wenn dir das jetzt nicht helfen wird:

#include <INTERVAL.h>    

void setup()
{  
  pinMode(LED_BUILTIN,OUTPUT);
}
      
void loop()
{ 
  INTERVAL(1000)
  {
     digitalWrite(LED_BUILTIN,!digitalRead(LED_BUILTIN));
  }
}

Ich habe mich am Datenblatt orientiert

Ja???

TCCR3A hat kein Bit namens: WGM12
TCCR3B hat keine Bits namens: CS12 oder CS10

Ein bisschen mehr am Datenblatt orientieren, würde nicht schaden…
:smiling_imp: :smiling_imp: :smiling_imp:

Hallo,

das mit den falschen Bits wollte ich auch gerade schreiben. Und ich würde vorher auch das TIMSK3 Register reseten oder das Bit nicht mit ODER verknüpft setzen. Du weißt ja nicht welche Einstellung es vorher hatte.

Edit:
Du möchtest Timer Mode 4 CTC nutzen?
Dann ist das Compare Match Register ist auch falsch gesetzt, weil du mit der falschen Formel rechnest.
Du willst vielleicht PWM machen, aber solange du den CTC Mode nutzt, kann man ja machen, gelten auch die Vorgaben vom CTC Mode und nicht vom PWM Mode.

Es ist weniger eine Hausaufgabe als mehr ein Studienprojekt. Bin Student im 5. Semester.
Und unsere Aufgabe ist es eine über eine Dreieck-Sinus-Modulation eine PWM für einen Asynchronmotor herzustellen.

Das ganze drum herum ist ja momentan nicht wichtig, ich will ja nur diese LED mittels Interrupts ansteuern.
Da später der Interrupt bei 50 Hz getaktet wird um die Modulation zu steuern.
Aber wenn mein Interrupt anstatt 50Hz mit 10 Hz funktioniert geht mir im Worst-Case der Motor kaputt.
Deswegen probiere ich mich langsam dem Gewünschten anzunähern.

Aus diesen gründen muss ein zuverlässiger Interrupt erfolgen. Und ein Interrupt erfolgt ja auch momentan bei dem Quellcode jedoch nicht wie aus dem Datenblatt errechneten 1 Hz.

Okay,

Ich habe die Bits richtig verändert.
War ein Überbleibsel aus den Versuchen mit den Anderen Timern.

  TCCR3A |=(1<<WGM32);
  // set prescaler to 1024
  TCCR3B |=(1<<CS32)|(1<<CS30);
  // enable timer compare interrupt
  TIMSK3  = 0;
  TIMSK3 |=(1<<OCIE3A);

Die LED tooglelt immer noch nicht wir gewünscht.

jerry134:
Ich habe einen Arduino bzw. Genuino Mega mit einem Atmega 2560.

Ich möchte für die Uni eine Interrupt-Funktion schreiben die alle paar Mirkosekunden einen Analogen Wert schreibt.

Das ist unmöglich mit deiner Hardware.

@Whandall

Entschuldige, ich habe mich verschrieben.
Alle paar Millisekunden.
Die dürften möglich sein.

@Doc_Arduino

Wieso ist das Compare match Register falsch gesetzt??
Es berechnet sich doch aus Mikroprozessorgeschwindigkeit (16MHZ) durch die gewünschte Taktfrequenz sowie durch den prescaler und alles -1 aufgrund des 0 setztens.

Hallo,

wie gesagt, du nimmst die falsche Formel. Wenn du den CTC Mode nimmst, mußte auch die Formel für diesen verwenden. Guck mal im Datenblatt bei Timer und dann beim CTC Mode was da für eine Formel steht.

Okay,
Ich war im Datenblatt unterwegs und habe folgendes gefunden.
Verwende ich den CTC Mode Zählt mein Timer von 0 Bis zum OCRnA Wert mit entsprechendem prescaler.
Daraufhin wird im ORCFnA ein Interrupt erzeugt.
Allerdings kann ich auch das OCnA Register tooglen lassen wann immer der der Zählerwert TCNT den Compare match Register OCRnA erreicht.
Dazu gibt es eine Formel mit der ich dann auf eine Frequenz von einem halbem Herz kommen würde.

Das ist die einzige Formel die da steht.

Hallo,

na was steht denn da für eine Formel? Schreib die doch mal hier hin.
Auf welcher Seite, welches Kapitel liest du denn dafür?

Die Register Settings stimmen auch nicht. Haste ganz schön die Bits verhauen.
Schaue unbedingt nochmal das Datenblatt an welche Bits in welchen Registern liegen.
Die WGM und CS Bits sind über 2 Register verteilt!

Hey,

Ich beziehe mich auf folgendes Datenblatt:
Datenblatt Atmega 2560
Die Formal die ich gefunden habe steht auf Seite 146 und lautet:

fOCnA=fclk_I/O /[2N(1+OCRnA)], dabei steht N für den prescaler. Und der Rest dürfte dir was sagen.
Ich habe die Formel im Kapitel 17.9 “Modes of Operations” für 16-bit Timer/Counter, wobei dies Timer 1,3,4 und 5 sind.

Für die Bestimmung der Register habe ich mich auf Kapitel 17.11 bezogen. Dabei ist für das Setting des prescalers folgendes gegeben:

Um ein prescaler vom Wert 1024 zubekommen müssen CSn2 und CSn0 auf 1 gesetzt sein, welches ich im Code mit folgender Zeile erreiche:

TCCR3B |=(1<<CS32)|(1<<CS30);

Alle Anderen Bits des Registers belasse ich bei 0.

Und um den CTC Modus zu aktivieren setze ich das WGM32 Bit auf eins.
Während des Schreibens ist mir aufgefallen das dies nicht wie ursprünglich angenommen im TCCR3A Register sondern im TCCR3B Register liegt. Sprich das Bit setzte ich mit folgendem Code:

TCCR3B |=(1<<WGM32);

Ich habe den Sketch erneut hochgeladen und es Funktioniert nun, so wie es soll:)

Vielen Dank für den energische Datenblatt Hinweis.

Hallo,

das TCCR3B Register stimmt jetzt.
Die Formel stimmt jetzt auch endlich.
Nur wenn du damit immer noch auf auf ein Compare Match Wert von obigen 15624 kommst, dann rechnest du immer noch falsch und der Takt stimmt nicht. Auf was kommste denn aktuell? Oder zeig nochmal den gesamten Sketch.

Hey hey,
Hier mein Code.

#include <avr/io.h>
#include <avr/interrupt.h>


volatile int toogle_LED =0;
void setup() {
  Serial.begin(9600);
  pinMode(13,OUTPUT);
  
  // put your setup code here, to run once:
  noInterrupts(); // Disable Interrupts
  // set Timer one 2kHz
  TCCR3A = 0; // TCCR0A register set to 0
  TCCR3B = 0; // same with registreb B
  TCNT3  = 0; // counter value to 0
  //Compare match registre for 2khz
  OCR3A = 15624; // 16.000.000 / 1*1024(prescaler)-1
  //CTC enable
  TCCR3B |=(1<<WGM32);
  // set prescaler to 1024
  TCCR3B |=(1<<CS32)|(1<<CS30);
  // enable timer compare interrupt
  TIMSK3  = 0;
  TIMSK3 |=(1<<OCIE3A);

  // set timer 1 HZ

  interrupts();// enable interrupts

}

//INterrupt funktion

ISR(TIMER3_COMPA_vect){
  if(toogle_LED==0){
    digitalWrite(13,HIGH);
    toogle_LED=1;  
  }
  else{
    digitalWrite(13,LOW);
    toogle_LED=0;  
  }
}


void loop() {

}

Momentan habe ich noch einen Wert von 15624 zustehen.
Aber mit der Formel müsste ich einen Wert von 7811,5 nehmen um auf eine Freqeunz von 1 Hz zu bekommen. Also denke ich mal nehm ich einene Wert für den prescaler 7812?

EDit: Nein doch nicht wenn ich einene wert von 7812 nehme, wird toogelt der OCnA mit einer Frequnz von 1 Hz aber das bedeutet, dass in dieser Zeit 2 Mal der Wert vom OCRnA vom Timer erreicht wurde. Sprich ich bräuchte wiederum das Doppelte, also doch 15624.?!

Hallo,

was soll ich dir jetzt sagen um das Ergebnis nicht vorwegzunehmen. Ich möchte noch das du selbst darauf kommst.
Ein Wert ist falsch und der andere richtig. Soviel kann ich sagen.
Wegen dem 1Hz.
Was ist denn 1Hz?
Wie sieht die Periodendauer aus? Also deren Verlauf.
An welchen Punkten muß der Compare Match zuschlagen um auf diese Periodendauer zu kommen?
Wie lang ist denn die Periodendauer für 1Hz?
Und was ist das entscheidende während der Periode damit man überhaupt von Takt reden kann?
Mal dir das mal auf.

Edit 1:
Für einen Elektrotechnikstudenten, nehme ich an, erwarte ich jetzt konkrete richtige Zahlen usw.
Das mit Frequenzen ist nämlich Schulwissen. Nur mal so zur Info. :slight_smile:

Edit 2:
meinetwegen kannste die Formel auch umstellen um auf die ISR Zeit zu kommen.

Guten Morgen,

1Hz ist eine Frequenz und bedeutet das die Periodendauer 1ne Sekunde beträgt. Mein gewünschter Periodenverlauf am Ausgang der LED muss lauten 1s Off und 1s On.
Sprich der OCRnA muss jede Sekunde Erreicht werden. Folglich, und hier ist glaube mein Denkfehler drin gewesen, muss die Frequenz vom OCnA, also die Flag, einen halben Herz betragen. Damit OCnA eine Periodendauer von 2 Sekunden hat, in der die LED beide Zustände durchlaufen hat. Dadurch wird der Zählerstand vom OCRnA jede Sekunde erreicht. So wie ich mir das Ursprünglich gedacht habe.

Folglich habe ich die Formel nach dem Compare Match Register umgestellt und einen Wert von 15624 erhalten.
Diesen habe ich Programmiert und die LED blinkt(soweit ich den Vergleich mit der Windows Uhr und der LED ziehen kann) mit einer Frequenz vom 1Hz sprich, 1 Sekunde an und dann 1 Sekunde aus.

Jedoch bin ich dann damit wieder am alten Punkt angelangt.

jerry134:
1Hz ist eine Frequenz und bedeutet das die Periodendauer 1ne Sekunde beträgt. Mein gewünschter Periodenverlauf am Ausgang der LED muss lauten 1s Off und 1s On.

Nein. Du beschreibst eine Frequenz von 1/2 Hz.

Ich hätte vllt. einen Absatz machen sollen.

Die Aussage das 1 Hz eine Periodendauer von 1 Sekunde hat, ist unabhängig von meinem gewünschten Periodenverlauf und war nur eine Antwort auf die Frage " Was ist denn 1 Hz?"
Ich weiß jetzt das meine gewünschte Frequenz ein halber Hertz sind, weshalb ich auch schrieb:
"Folglich, und hier ist glaube mein Denkfehler drin gewesen, muss die Frequenz vom OCnA, also die Flag, einen halben Herz betragen"

Nein, da kannst du dich nicht rausreden.

jerry134:
mit einer Frequenz vom 1Hz sprich, 1 Sekunde an und dann 1 Sekunde aus.

Das ist eben nicht so. Dieser Ablauf hat eine Frequenz von 1/2 Hz.