Hi, ich möchte ein IR-Signal gem. Anhang erzeugen, wobei die Trägerfrequenz 40 kHz betragen soll. D. h. für die im Anhang angegebenen Zeiten soll der Träger eben entsprechen an- bzw. ausgeschaltet werden. Das ganze möchte ich mit einem ATmega8 (8 MHz) erzeugen und mein bisheriger Ansatz ist, dass ich Timer 2 genommen habe, um die 40 kHz zu erzeugen => kein Problem. Ferner möchte ich nun noch Timer 1 benutzen, um die Zeiten für die Schaltdauer zu generieren. Und genau da ist mein Problem, ich kriege es einfach nicht hin. Wollte einfach mal generell fragen, ob das so der geeignete Ansatz ist. Denn erschwerend kommt noch dazu, dass es möglichst universell sein soll. D. h. es wäre wünschenswert, dass die Zeiten z. B. in Vielfachen von 10µs in einem Array liegen, dass ich dann einfach durchlaufen kann. Oder gibt es bessere Ideen? Gruß Thomas
Also du könntest das so machen: (Pseudocode!)
1 | i = 0 |
2 | while(true) { |
3 | a = lade pulsdauer_high[i] |
4 | PIN = HIGH |
5 | while (a >=0) { |
6 | WARTE bis 10µS vorbei |
7 | a = a - 1 |
8 | } |
9 | a = lade pulsdauer_low[i] |
10 | while(a >=0) { |
11 | WARTE bis 10µS vorbei |
12 | a = a - 1 |
13 | } |
14 | i = i + 1 |
15 | if (i > maximale_pulse) { |
16 | i = 0 |
17 | } |
18 | } |
Dein Ansatz sollte also brauchbar sein ;)
Alle Deine Verzögerungen passen in das 16-Bit-Raster des Timer1. Lass Timer1 mit 1MHz klappern und nutze einen Compare-Interrupt. In dessen ISR - holst Du das nächste Intervall aus dem Array und addierst es auf den aktuellen Compare-Wert auf (OCR1A einlesen, Intervall dazu addieren, Ergebnis in OCR1A zurückschreiben), um den Termin für den nächsten Int zu setzen, - erhöhst Du einen Zähler, um anhand seines Bit 0 festzustellen, ob jetzt Signal oder Pause ausgegeben wird. Bei Signal koppelst Du den OCR-Pin von Timer2 an Timer2 an (40kHz wird ausgegeben), bei Pause schaltest Du den OCR-Pin als normalen Ausgang, der auf L liegt. Das alles findet in der ISR statt und verbraucht weniger als 1% Rechenleistung. Dein Mega8 kann also noch viele andere Dinge nebenher erledigen... ...
Hallo Hannes, vielen Dank für deine Antwort, ich komme der Sache langsam näher :) Mein Fehler war, dass ich den CTC-Mode benutzt habe, welcher ja den Zählerstand bei jedem Match wieder nullt. Außerdem bin ich nicht auf die einfach Sache gekommen, einfach aufzuaddieren. Hier mal auszugsweise mein Code:
1 | #define PRESCALE1 2
|
2 | #define PRESCALE2 1
|
3 | |
4 | // nur als Beispiel mal 4 Werte
|
5 | unsigned int timer[4] = {8000,8000,8000,8000}; |
6 | |
7 | SIGNAL(SIG_OUTPUT_COMPARE1A) |
8 | {
|
9 | static unsigned char cnt = 0; |
10 | |
11 | OCR1A += timer[cnt++]; |
12 | if(cnt==4) cnt = 0; |
13 | |
14 | PORTB ^= 1; |
15 | }
|
16 | |
17 | int main(void) |
18 | {
|
19 | // configure timer 1
|
20 | // Zeitbasis
|
21 | TCCR1A = (0<<COM1A1)|(0<<COM1A0)|(0<<COM1B1)|(0<<COM1B0)| |
22 | (0<<FOC1A)|(0<<FOC1B)|(0<<WGM11)|(0<<WGM10); |
23 | TCCR1B = (0<<ICNC1)|(0<<ICES1)|(0<<WGM13)|(0<<WGM12)|PRESCALE1; |
24 | |
25 | // configure timer 2
|
26 | // erzeugt 40kHz
|
27 | TCCR2 = (0<<FOC2)|(1<<WGM21)|(0<<WGM20)|(0<<COM21)| |
28 | (1<<COM20)|PRESCALE2; |
29 | OCR2 = IRVAL; |
30 | |
31 | // init
|
32 | OCR1A = timer[0]; |
33 | TCNT1 = 0; |
34 | |
35 | TIMSK |= (1<<OCIE1A); |
36 | |
37 | sei(); |
38 | |
39 | return 0; |
40 | }
|
Nochmal die Rahmenbedingungen: AVR läuft mit 8MHz, Prescaler für Timer1 ist /8, der für Timer2 /1. Ich lasse mir bei jedem Compare-Interrupt PB0 toggeln. Warum messe ich eine Frequenz von 500Hz an PB0? Bei jedem Interrupt addiere ich doch 8000 dazu, wegen des Prescalers kommt der nächste Interrup dann quasi 8*8000=64000 Take später, ein toggeln müsste doch so alle (1/8MHz)*64000=8ms erfolgen, oder nicht? Thomas
Ja und noch was, wenn ich den Prescaler verstelle, ändert sich NICHTS. ???
> Nochmal die Rahmenbedingungen: AVR läuft mit 8MHz, Prescaler für Timer1 > ist /8, Das ist gut, der Timer1 läuft daher mit 1 MHz. > der für Timer2 /1. Der spielt jetzt noch keine Rolle, da Du ja erstmal nur PB0 toggelst. > Ich lasse mir bei jedem Compare-Interrupt PB0 > toggeln. Richtig, zum Test... > Warum messe ich eine Frequenz von 500Hz an PB0? Bei jedem Interrupt > addiere ich doch 8000 dazu, wegen des Prescalers kommt der nächste > Interrup dann quasi 8*8000=64000 Take später, ein toggeln müsste doch so > alle (1/8MHz)*64000=8ms erfolgen, oder nicht? 8 MHz und Vorteiler 8 kürzen sich raus, man kann mit 1 MHz Timerztakt rechnen, ein Timerwert entspricht also einer Mikrosekunde. Demnach toggelst Du alle 8 Millisekunden, bekommst eine Periode von 16 ms, das entspricht einer Frequenz von 62,5 Hz. Wenn Du etwas Anderes misst, dann macht Dein Code nicht das, was Du von ihm erwartest. Da kann ich Dir aber nicht helfen, C ist nicht mein Ding, ich werkele in Assembler. ...
Hi, >wenn Du etwas Anderes misst, dann macht Dein Code nicht das, was Du >von ihm erwartest. Du hast Recht, lag aber an meiner Dummheit. Ich hatte noch eine Zeile zum stoppen von Timer 2 drin, und die hat ein Bit von Timer 1 verändert, daher das verhalten. Jetzt funktioniert alles. Vielen Dank, Hannes! Thomas
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.