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


von technikus (Gast)


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
1
// 100kHz Timer 0 Overflow ISR
2
ISR(TIMER0_OVF_vect)
3
{
4
  TCNT0=preload;       //Preload
5
6
  counter++;      //increment counter    
7
8
  //limit counter for 12,5kHz
9
  if (counter==8)
10
    counter=0;
11
  
12
  if (counter<=1)
13
    PORTC|=(1<<PC0);
14
  
15
  if (counter>1)
16
    PORTC&=~(1<<PC0);      
17
}

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

von (prx) A. K. (prx)


Lesenswert?

Stichwort PWM in der Doku des Controllers.

von Karl H. (kbuchegg)


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)

von Karl H. (kbuchegg)


Lesenswert?

1
  //limit counter for 12,5kHz
2
  if (counter==8)
3
    counter=0;
4
  
5
  if (counter<=1)
6
    PORTC|=(1<<PC0);
7
  
8
  if (counter>1)
9
    PORTC&=~(1<<PC0);


Beim Programmieren ist es oft auch hilfreich, sich nicht nur auf 
Intuition zu verlassen, sondern sich auch eine Zeichnung zu machen
1
  //limit counter for 12,5kHz
2
  if (counter==8)
3
    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
1
  if (counter<=1)
2
    PORTC|=(1<<PC0);
3
  
4
  if (counter>1)
5
    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
1
  if (counter<=1)
2
    PORTC|=(1<<PC0);
3
  
4
  if (counter>1)    // na was soll er denn sonst sein?
5
                    // wenn counter NICHT kleiner gleich 1 ist, dann
6
                    // muss er größer als 1 sein
7
    PORTC&=~(1<<PC0);

->
1
  if (counter < 1)
2
    PORTC|=(1<<PC0);
3
  else  
4
    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.

von technikus (Gast)


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

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.