Timer1 hadcore konfigurieren ;-)

Grüß euch,
Ich versuche gerade den Timer 1 zu konfigurieren.
Die Aufgabenstellung:

Auf einer Welle sitzt ein Hallgeber, und ich bekomme je Umdrehung einen Impuls am
(PCINT0/CLKO/ICP1) PB0 auf dem Pin möchte ich auch noise Canceler enablen

Bei jedem Impuls soll der Timer die ISR(TIMER1_CAPT_vect) anspringen dort lese ich den Counter aus und berechene ..
und setze die Compare Register OCR1A und OCR1B

Wenn OCR1A oder OCR1B gleich TCNT1 soll die jeweilige ISR angsprungen werden.

ISR(TIMER1_COMPA_vect)
ISR(TIMER1_COMPB_vect)

und wenn ein Timer1 Overflow passiert, soll natürlich ISR(TIMER1_OVF_vect) ausgelöst werden.

Ich kenn mich ned gut aus, und habe viele Beiträge im I-Net durchsucht und das ATMEL-Datasheet gewälzt, aber mir sagt das zu wenig um wirklich Code rauslesen zu können.

Wenn einer von euch da fitt ist und nur mal drüberschauen könnte ob ich was wichtiges vergessen habe, oder ob ich Blödsinn geschrieben habe, wäre ich sehr dankbar!!

Ich hab das in einer anderen Sprach schon mal geschrieben, aber da sind das 3 Zeilen, und man hat keine Ahnung was sich im Hintergrund tut. Ich würde das gerne nach Arduino übertragen.

So und nun mein Code :slight_smile:

/*
 Test mit Timer 1
*/


// the setup function runs once when you press reset or power the board

// avr.clock 20000000 = 20MHz

void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);


// Initialisieren Timer1 16Bit
noInterrupts();           // Alle Interrupts temporär abschalten
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;            // Timer auf 0 Setzen
TCCR1B |= (1 << CS10)|(1 << CS11); // 64 als Prescale-Wert spezifizieren
TCCR1B |= (1<<ICES1);  // PB0 - reagiert bei steigender Flanke
TIMSK1 |= (1 << TOIE1)| (1 << ICIE1);   // Timer Overflow Interrupt aktivieren (1 << TOIE1) , PB0 als externer Interrupt (1 << ICIE1) Interrupt bei Signal an ICP1
TIFR1 |= (1<<ICF1);     // Enable noise Canceler
// Compare Interrupt erlauben
  TIMSK1 |= (1<<OCIE1A)|(1<<OCIE1B); // Interrupt für Timer1 freischalten  gilt das damit für OCR1A und OCR1B ??

 

interrupts();             // alle Interrupts scharf schalten
}

// the loop function runs over and over again forever
void loop() {
  /*
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);                       // wait for a second
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);                       // wait for a second
  */
}



// für den Timer Overflow
ISR(TIMER1_OVF_vect)  
{
  
  // Aktion ...........
  TCNT1 = 0;             // Zähler erneut vorbelegen -- TCNT1 (Timer/Counter Register): d.h. der eigentliche Zähler.
  digitalWrite(LED_BUILTIN, digitalRead(LED_BUILTIN) ^ 1); // LED ein und aus
}

// für den Timer Capture Event - Hallsensor
ISR(TIMER1_CAPT_vect)  
{
  // TCNT1 = Variable mit dem Wert mit dem gerechnet wird. 
  // Setzen der Compare Register
OCR1A = 21250;;           // Output Compare Register vorbelegen  --  OCR1 (Output Compare Register): Ist der Zähler in TCNT1 gleich dem Inhalt des OCR1, erfolgt ein Timer Compare Interrupt.
OCR1B = 45000;;           // Output Compare Register vorbelegen  --  OCR1 (Output Compare Register): Ist der Zähler in TCNT1 gleich dem Inhalt des OCR1, erfolgt ein Timer Compare Interrupt.
 // Das Zählen beginnt von neuem
  TCNT1 = 0 // löschen des Zählers damit er von 0 wiede beginnt.
 
}


// für den Timer CompareA Interrupt
ISR(TIMER1_COMPA_vect)        
{
  digitalWrite(LED_BUILTIN, digitalRead(LED_BUILTIN) ^ 1); // LED ein und aus
}

// für den Timer CompareB Interrupt
ISR(TIMER1_COMPB_vect) 
{
  digitalWrite(LED_BUILTIN, digitalRead(LED_BUILTIN) ^ 1); // LED ein und aus
}

Du bringst Capture und Compare Modus durcheinander. Im Capture Modus misst man die Breite von Impulsen. Der Timer arbeitet als Counter und wenn eine Flanke kommt wird das Counter Register in das Capture Register kopiert. Und ein Interrupt ausgelöst wo man dann die Impulse-Länge berechnen kann (aus dem Timer Takt, dem Inhalt des Counter Registers und den Überlaufen).
Wenn man High- und Low-Zeit getrennt messen will schaltet man die Flanke um auf die getriggert wird.

Der Output Compare Modus ist um die Anzahl der Impulse zu zählen. Der Timer kann statt intern über einen externen Pin getaktet werden und bei einer bestimmten Anzahl von Impulsen wird ein Interrupt ausgelöst.

Es macht nicht viel Sinn das beides zu kombinieren

Um Frequenzen zu messen geht im Prinzip beides. Für hohe Frequenzen misst man am besten die Anzahl der Impulse in einer gewissen Torzeit. z.B. die Impulse innerhalb von 250ms mal 4 ergibt direkt die Frequenz in Hertz.
Bei niedrigen Frequenzen hat das den Nachteil dass die Torzeit sehr hoch sein muss, wodurch die Reaktionszeit schlecht ist. Da ist es besser man misst die Impulslänge

Servus, ich will ja keine Frequenzen messen, ich baue damit eine Zündung.
Das gibt es selbstverständlich alles von der Stange, aber wo bleibt da der drang Wissen zu erwerben :wink:
in LunaAvr (www.myluna.de) habe ich den Timer so konfiguriert. und möchte das in die Arduino IDE übertragen. Da ich sowas nur sporadisch mache ist mir Arduino lieber, da findet man eher Lösungen bei Fragen, ausser halt bei den Timern, da bin ich bis jetzt gescheitert, und versuche mir halt jetzt den Code zusammen zu suchen :wink:

' Timer einstellen
'-------------------------------------------------------

timer1.isr = SIG_OVERFLOW    ' Serviceroutine zuweisen
timer1.clock = Prescaler         ' Prescaler einstellen
timer1.enable                       ' Timer1 einschalten
timer1.capt.clock = rising       ' Timer1 triggern einschalten,auf steigende Flanke
timer1.capt.isr   = SIG_Hallgeber   ' Capture-Serviceroutine zuweisen, Signal vom Hallgeber
timer1.capt.denoise.enable          ' Capture-Rauschunterdrückung einschalten
timer1.capt.enable               ' Capture aktivieren

timer1.cmpa.isr  = Zuendspule_EIN         ' Service-Routine für Endstufe EIN
timer1.cmpb.isr  = Zuenden_Spule_AUS   ' Service-Routine für Endstufe AUS (Zünden)
'----------------------------------------------------------
'---------------------------------------------------------
'##############################################################################
' Timer Overflow
'##############################################################################
isr SIG_OVERFLOW fastauto
Zaeler_standabschaltung = Zaeler_standabschaltung + 1
ticks = 0
rpm = 0
rpm_old_0   = 0
rpm_old_1   = 0
rpm_old_2   = 0
Unterdruckdose = 0

' Timer-Compares abschalten
timer1.cmpa.disable
timer1.cmpb.disable

If Zaeler_standabschaltung > standabschaltung Then
Zuendspule = 0                                 ' Zündspule AUS (Zünden)
Zuendspule1 = 0                                 ' Zündspule AUS (Zünden)
end if
endisr

Signal vom Hallgeber auswerten

'##############################################################################
' Signal Hallgeber / Timer auswerten
'##############################################################################

isr SIG_Hallgeber fastauto

Zaeler_standabschaltung = 0
Zuendspule = 0                   ' Zündspule AUS (Zünden)
Zuendspule1 = 0                  ' Zündspule AUS (Zünden)
ticks = Timer1.capt.Value         'Capture-Zählerwert des Timers auslesen
Timer1.Value=0                    'Zählerwert des Timers auf 0 setzen
toggle LedSignal                  ' Signal-LED togglen
tick_Grad = FIX (ticks/360)       ' In Abhängigkeit der Drehzahl die Ticks je Grad


if rpm > minrpm_zzp then
call schnelle_Mittelwertbildung()     ' schnelle Berechnung ;-)
else
call genauere_Mittelwertbildung()    ' bei niedrigerer Drehzah bessere Mittelwertbildung, das wirkt sich beim ankicken und bei niedriger Leerlaufdrehzahl positiv aus
endif


call Zyndzeitpunkt_errechnen() ' Anspringen der Subroutine
timer1.cmpa.value = ticks_zsw      ' ersten Vergleichswert laden Zündstufe EIN
timer1.cmpb.value = ticks_zzp      ' zweiten Vergleichswert laden Zündstufe AUS (Zünden)
' Timer-Compares aktiviren falls deaktiviert
timer1.cmpa.enable
timer1.cmpb.enable
endif

endisr

Zündspule ein oder aus

'##############################################################################
'Laden der Zündspule
'##############################################################################
isr  Zuendspule_EIN fastauto
' Prüfen ob plausibler Compare-Vergleich, beim Setzen von verschiedenen Werten
' können Zwischeninterrupts ausgelöst werden. Wir prüfen daher ob der Zählerstand
' Zündungsrelevant plausibel ist.
if Timer1.Value>100 then
Zuendspule = 1                                 ' Zündspule EIN
Zuendspule1 = 1                                 ' Zündspule EIN
'LedZZP = 0                                     ' Kontrollanzeige
end if
endisr

'##############################################################################
' Zündfunke Zündendstufe
'##############################################################################
isr Zuenden_Spule_AUS fastauto
' Prüfen ob plausibler Compare-Vergleich, beim Setzen von verschiedenen Werten
' können Zwischeninterrupts ausgelöst werden. Wir prüfen daher ob der Zählerstand
' Zündungsrelevant plausibel ist.
if Timer1.Value>100 then
Zuendspule = 0                                 ' Zündspule AUS (Zünden)
Zuendspule1 = 0                                 ' Zündspule AUS (Zünden)
'LedZZP = 1                                    ' Kontrollanzeige
end if
endisr

Serenifly:
Du bringst Capture und Compare Modus durcheinander. Im Capture Modus misst man die Breite von Impulsen. Der Timer arbeitet als Counter und wenn eine Flanke kommt wird das Counter Register in das Capture Register kopiert. Und ein Interrupt ausgelöst wo man dann die Impulse-Länge berechnen kann (aus dem Timer Takt, dem Inhalt des Counter Registers und den Überlaufen).
Wenn man High- und Low-Zeit getrennt messen will schaltet man die Flanke um auf die getriggert wird.

Der Output Compare Modus ist um die Anzahl der Impulse zu zählen. Der Timer kann statt intern über einen externen Pin getaktet werden und bei einer bestimmten Anzahl von Impulsen wird ein Interrupt ausgelöst.

Es macht nicht viel Sinn das beides zu kombinieren

Um Frequenzen zu messen geht im Prinzip beides. Für hohe Frequenzen misst man am besten die Anzahl der Impulse in einer gewissen Torzeit. z.B. die Impulse innerhalb von 250ms mal 4 ergibt direkt die Frequenz in Hertz.
Bei niedrigen Frequenzen hat das den Nachteil dass die Torzeit sehr hoch sein muss, wodurch die Reaktionszeit schlecht ist. Da ist es besser man misst die Impulslänge

Danke für die super Erklärung!
Das ist für mich auch ein Grund hier oft (nur) mitzulsesen.

100% vergleichen kann ich es nicht, aber auf den ersten Blick sieht es in Ordnung aus

Wichtig ist was du gemacht hast erst mal die Register auf 0 setzten (oder statt dem ersten Oder eine Zuweisung machen). Vor allem die TCCR1n Register. Die werden von der IDE für PWM vorbesetzt und sind daher nicht 0

Danke, wenn ich auf einen grünen Zweig komme, poste ich den Code.

lg
Andi