mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Timer funktioniert nicht 16-Bit CTC


Autor: Flo S. (tuxianer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hi,
ich probiere gerade einen Timer für ein anderes Projekt zum laufen zu 
bringen. Ich verwende einen Atmega162 mit 7372800 Hz. Nur der Code 
springt nicht in die Interrupt Routine. Hier mal die relevanten stellen:
int ms;
uint8_t s;
uint8_t min;

//Timer1 Compare Match Interrupt
ISR(TIMER1_COMPA_vect)
{
  //Milli Sekunden um 1 erhöhen
  ms++;
  //sind 1000 ms um?
  if (ms==1000) {
    //ms zurücksetzen und Sekunden erhöhen
    ms=0;
    s++;
    //sind 60 Sekunden um?
    if (s==60) {
      //Sekunden zurück setzen und Minuten erhöhen
      s=0;
      min++;
    }    
  }
}

.
.
.

//In main():
  //CTC Modus & Vorteiler 8
  TCCR1B |= (1<<CS11)|(1<<WGM12);
  //Interrupt bei Compare Match
  TIMSK = (1<<OCIE1A);
  //Compare Wert setzen
  OCR1A = 9216-1;


der Timer soll jeder ms nen Interrupt auslösen, und die Variable ms 
hochzählen.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wo ist sei(); ?

MFG
Falk

Autor: Flo S. (tuxianer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
sorry hab ich hier nicht gepostet, ist aber drin!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hast du interrupt.h includet?
Woher weist du eigentlich, das der Interrupt nicht
angesprungen wird?
Warum sind s und min nicht volatile? Die werden ja doch wahrscheinlich
von der Hauptschleife her ausgelesen?
usw. usw.

Poste doch bitte das komplette Programm!
Dann  brauchen wir nicht jedes Fitzelchen Code nachzufragen.
Nimm einfach dein *.c und hänge es als Attachment an.
Das ist erstens für dich viel einfacher und zweitens kann
dann keine Information fehlen.

Autor: Flo S. (tuxianer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
der Code ist hier drin:
http://www.mikrocontroller.net/attachment/highlight/30489

Ich habe den Code auch mal auf einem Mega32 getestet mit 16 Mhz:
int main(void) {
  
  //CTC Modus & Vorteiler 8
  TCCR1B |= (1<<CS11)|(1<<WGM12);
  //Interrupt bei Compare Match
  TIMSK = (1<<OCIE1A);
  //Compare Wert setzen
  OCR1A = 20000-1;
  
  sei();

und eine Sekunde ist nach ca. 8 Sekunden um. Also es funktioniert doch. 
Nur zu langsam.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dann läuft Dein Controller vermutlich nicht mit 7,... MHz sondern mit 1 
MHz. Dann musst Du vermutlich die Fusebits entsprechend ändern, dass 
der Controller auch weiß, dass er mit dem Quarz laufen soll und nicht 
mit dem internen RC-Oszillator.

Autor: Flo S. (tuxianer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also der Mega162 läuft ganz sicher mit Ext. Oszi! Beim Mega32 bin ich 
mir auch ziemlich sicher! (Alle CKSEL gesetzt)!

Autor: Flo S. (tuxianer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
oder habe ich mich nur verrechnet?

Beim 16 Mhz:

160000/16000000=0.01
   |
160000/8=20000

Autor: Jörg X. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Warum lässt du nicht den Compiler rechnen - der kann das ja ganz gut ;) 
:
OCR1A = F_CPU /8 /1000;
/*                ^- 1ms -> 1kHz
               ^- Prescaler
        ^- Takt 
ODER (exakt dasselbe):
OCR1A = F_CPU / 8 * 0.001 // [Hz] / [1] *[s]...
*/
//...

hth. Jörg

ps.: ja, du hast dich verrechnet, 1 Millisekunde ist 0.001s

Autor: Flo S. (tuxianer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sind ne ms nicht 10^-3 Sekunden?

Autor: Marian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nein, ne Millisekunde sind 10e-4 Sekunden, also 1/1000. 1e-3 ist auch 
eine Millisekunde^^ :)

Autor: Flo S. (tuxianer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stimmt ihr habt natürlich recht blöder Fehler vielen Dank!

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Marian wrote:
> Nein, ne Millisekunde sind 10e-4 Sekunden, also 1/1000. 1e-3 ist auch
> eine Millisekunde^^ :)
Doch, eine Millisekunde sind 10^-3 Sekunden, und das sind 0,001 
(Grundschule: Man nehme eine 1 und schiebe das Komma um 3 Stellen nach 
links...). 10^-4 (oder 1e-4 wie manche es lieber schreiben) sind 
logischerweise 0,1 ms...

EDIT: OK, 10e-4 sind natürlich 1e-3... Das ist natürlich ein völliges 
Durcheinander.

Autor: Flo S. (tuxianer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
daraus resultiert aber ein neues Problem!...ich komme für eine ms nicht
mehr auf einen ganzzahligen ctc wert.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Florentin S. wrote:
> daraus resultiert aber ein neues Problem!...ich komme für eine ms nicht
> mehr auf einen ganzzahligen ctc wert.

Jetzt bist du reif für das hier:
http://www.mikrocontroller.net/articles/AVR_-_Die_...

Autor: Flo S. (tuxianer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
könnte ich es auch nicht so machen:

7372800/1000/64=115.2

Also sind es alle 5ms eine zuenig...also zähle ich alle 5 eine dazu.

Autor: Flo S. (tuxianer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ne es ist eine zu viel

Autor: AVRFan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eine Möglichkeit wäre, den Timer ohne Prescaler laufen zu lassen, und 
den Compare-Match-Wert auf 36864 zu setzen.  Das liefert genau 5 
Interrupts pro ms.  Um von den 0.2 ms zu den ganzen Millisekunden zu 
kommen, schachtelst Du den Code im Interupthandler einfach in einen 
1:5-Software-Frequenzteiler ein, so wie Du es schon bei den ms und s 
praktiziert hast.

Während 0.2 ms kann Dein Controller immer noch soviele Instruktionen 
abarbeiten (ihm stehen ja 36864 Zyklen zur Verfügung), dass Du keine 
Überforderung befürchten musst.

Autor: Flo S. (tuxianer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
bei den 36864 sind da die -1 schon inbegriffen?

Autor: AVRFan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab mich mit den Zahlenwerten verhaspelt. Sorry!

Richtig ist:

7372800 Hz / 36864 = 200 Hz --> 5 ms Interruptintervall.

Das ist das kleinstmögliche dezimalsystemkompatible Intervall. Auf 1 ms 
kommst Du nicht (lies: nicht ohne "Tricks"), weil 36864 nicht durch 5 
teilbar ist.  Für 1 ms Compare-Match-Interrupt-Intervall hat Dein Quarz 
mit 7.372800 MHz einen zu krummen Wert.

OCR1A musst Du tatsächlich mit 36863 laden, wenn Du alle 36864 Zyklen 
einen Überlauf wünschst (gilt nur bei Prescaler = 1).

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gibt es überhaupt einen triftigen Grund für die Verwendung eines 
Baudratenquarzes? Das beschriebene Problem ist nämlich der gewaltige 
Nachteil von solchen Quarzen. Die haben nunmal Frequenzen, die ein 
Vielfaches von 300 Hz sind. Und alles mit ner "3" drin ist in solchen 
Fällen etwas problematisch. Wenn es irgendwie geht, nimm lieber nen 
Standardquarz (z.B. 8 MHz, damit lassen sich sehr schön ms-Takte 
erzeugen).

Autor: Flo S. (tuxianer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Naja ist halt ne rein serielle Anwendung.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Florentin S. wrote:
> Naja ist halt ne rein serielle Anwendung.
Das sagt erstmal gar nichts. Viele übliche Baudraten lassen sich auch 
mit Standardquarzen mit ausreichender bis sehr guter Genauigkeit 
erzeugen. Baudratenquarze brauchts eigentlich nur dann, wenn man 
entweder auf irgendeine bestimmte Baudrate festgelegt ist, die mit 
Standardquarzen nicht generierbar ist oder wenn man flexibel zwischen 
allen üblichen Baudraten wählen können will. Teilnehmer A und Teilnehmer 
B müssen sich nur auf eine Baudrate einigen. Und wenn beide Teilnehmer 
µCs sind, dann braucht man sich nicht mal an die Standard-Baudraten (mit 
300Hz * 2^n) zu halten...

Autor: AVRFan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Naja ist halt ne rein serielle Anwendung.

Auch wenn eine Echtzeituhr drin ist? Scherzkeks! :-)

Autor: Flo S. (tuxianer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
na die Echtzeit Uhr ist für einen Timeout zuständig und ersetzt die 
Softwarewaits, so das Programm nebenbei noch andere Dinge tun kann.

Autor: AVRFan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sehr vernünftig.  Aber wenn Du wirklich 9 oder 23 oder 161 ms 
quarzpräzise abzählen können willst, darfst Du halt keinen 
Baudratenquarz verwenden.  Ansonsten musst Du entweder eine kleine 
Ungenauigkeit in Kauf nehmen (mit 7373 für den Compare Match [*] 
bekommst Du 7373 / 7372800 Hz = 1.0000271 ms), oder den Fehler 
softwaremäßig korrigieren (Compare Match Wert jedes n-te Mal auf 7372 
herabsetzen, n passend wählen; genaueres in der Codesammlung unter "Die 
genaue Sekunde"), oder Dich mit dem minimal möglichen exakten Zeitraster 
von 5 ms begnügen.

[*] OCR1A dann mit 7372 laden.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.