mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik "genaue" Frequenz mit Timer ISR erzeugen


Autor: technikus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich möchte ein frequenzgenaues Rechtecksignal mit einem Timer (AVR 
ATMega) erzeugen. Programmiersprache ist C. Das Rechtecksignal soll eine 
Einschaltdauer zu Ausschaltdauer von 1:7 haben.

Jetzt erzeuge ich eine ISR Mit einer Frequenz von z.B. 100kHz
// 100kHz Timer 0 Overflow ISR
ISR(TIMER0_OVF_vect)
{
  TCNT0=preload;       //Preload

  counter++;      //increment counter    

  //limit counter for 12,5kHz
  if (counter==8)
    counter=0;
  
  if (counter<=1)
    PORTC|=(1<<PC0);
  
  if (counter>1)
    PORTC&=~(1<<PC0);      
}

Das Ausgangssignal an PC0 müsste ja jetzt 12,5kHz sein. Wie erwähnt, 
möchte ich diese Frequenz sehr genau realisieren. Assemblerkenntnisse 
habe ich leider keine :-(
Laut AVR Studio Simulation passt die Frequenz nicht. Könnt ihr mir hier 
Tipps geben, wie ich auf eine genauere Frequenz komme?

Für Eure Hilfe danke ich schon jetzt!

Güße
Markus

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stichwort PWM in der Doku des Controllers.

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

Bewertung
0 lesenswert
nicht lesenswert
Das hängt davon ab, wie du den Timer taktest.

Ist doch einfach:
Dein Systemtakt (zb durch einen Quarz realisiert) sei zb 4Mhz.
Diese 4Mhz werden in einen Vorteiler für den Timer gesteckt. Welchen 
kannst du einstellen und welche es für den von dir benutzten Timer gibt, 
steht im Datenblatt deines µC.
Aber nehmen wir einmal an, du hättest einen Vorteiler von 8 ausgewählt. 
Das bedeutet, dass der Timer nur jeden 8-ten Systemtakt um 1 
weiterzählt. Der Timer zählt also nicht mit 4Mhz hoch, sondern mit 
4000000 / 8 = 500000, also 500kHz.

Aber achtung: Das ist die Frequenz, mit der der Timer zählt. Also 0, 1, 
2, 3, 4, 5, ...

Jetzt hast du zb einen 8-Bit Timer. Das wiederrum bedeutet, dass der 
Timer nur bis 255 zählen kann, danach fängt er wieder bei 0 an. Wann 
immer das passiert kannst du dir einen Overflow-Interrupt generieren 
lassen. Wie oft kommt daher dieser Overflow.
Nun wenn der Timer in 1 Sekunde bis 500000 zählen könnte (wenn er soweit 
zählen könnte), dann schafft er es offensichtlich in 1 Sekunde 1953.125 
mal von 0 bis 255 zu zählen (500000 / 256 = 1953.125)

Es liegt jetzt an dir, dir eine Systemfrequenz bzw. einen Vorteiler 
rauszusuchen, so dass die von dir gewünschte Frequenz in den Overflow 
Interrupts entsteht.

Du siehst auch schon, dass Overflows in der Beziehung nicht sehr 
flexibel sind, da man nur in relativ großen Sprungen die Aufruffrequenz 
einer ISR einstellen kann. Mit dem CTC Modus geht das besser. Das 
Prinzip ist fast dasselbe, nur dass du dem Timer vorgeben kannst, wie 
weit er zählen soll anstelle der fest vorgegebenen 255 (die sich durch 
die Bitbreite des Timers ergibt)

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

Bewertung
0 lesenswert
nicht lesenswert
  //limit counter for 12,5kHz
  if (counter==8)
    counter=0;
  
  if (counter<=1)
    PORTC|=(1<<PC0);
  
  if (counter>1)
    PORTC&=~(1<<PC0);      


Beim Programmieren ist es oft auch hilfreich, sich nicht nur auf 
Intuition zu verlassen, sondern sich auch eine Zeichnung zu machen
  //limit counter for 12,5kHz
  if (counter==8)
    counter=0;

Der Counter zählt also ständig 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4

In welchen Perioden davon schaltest du den Ausgang auf 1 und wann auf 0
  if (counter<=1)
    PORTC|=(1<<PC0);
  
  if (counter>1)
    PORTC&=~(1<<PC0);      

Mal sehen

Conter    0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1,
Ausgang   1  1  0  0  0  0  0  0  1  1  0  0  0  0  0  0  1  1

Zähl nach. Das ist ein 2:6 Verhältnis und kein 1:7

Und dann noch
  if (counter<=1)
    PORTC|=(1<<PC0);
  
  if (counter>1)    // na was soll er denn sonst sein?
                    // wenn counter NICHT kleiner gleich 1 ist, dann
                    // muss er größer als 1 sein
    PORTC&=~(1<<PC0);      

->
  if (counter < 1)
    PORTC|=(1<<PC0);
  else  
    PORTC&=~(1<<PC0);      

Das geht erstens schneller und verhindert zweitens einen Fehler, wenn du 
das Länge des Highpulses anpasst. Der Highpuls wird nur noch an 1 Stelle 
eingestellt und nicht an 2, was die Gefahr eines Fehlers bei einer 
Änderung drastisch verringert.

Autor: technikus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Karl Heinz:


Ich habe den Timer jetzt im CTC Mode laufen. Das verkürzt mir die ISR um 
die Zeile mit dem Laden des TCNT0 Registers. Deine Tipps habe ich soweit 
eingebaut. Ich möchte mich für deine immer sehr lehrreichen 
hervorragenden Beiträge bedanken!!!

Grüße
Markus

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.