Forum: Mikrocontroller und Digitale Elektronik [AVR] Wie Impulsfolge erzeugen?


von Thomas (Gast)


Angehängte Dateien:

Lesenswert?

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

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

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 ;)

von Hannes L. (hannes)


Lesenswert?

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...

...

von Thomas (Gast)


Lesenswert?

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

von Thomas (Gast)


Lesenswert?

Ja und noch was, wenn ich den Prescaler verstelle, ändert sich NICHTS. 
???

von Thomas G. (Firma: Frickelhauptquartier) (taximan)


Lesenswert?

wäre eine data-Tabelle evtl eine gute Idee?

von Hannes L. (hannes)


Lesenswert?

> 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.

...

von Thomas (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.