www.mikrocontroller.net

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


Autor: Thomas (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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

Autor: Läubi .. (laeubi) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also du könntest das so machen: (Pseudocode!)
i = 0
while(true) {
 a = lade pulsdauer_high[i]
 PIN = HIGH
 while (a >=0) {
  WARTE bis 10µS vorbei
  a = a - 1
 }
 a = lade pulsdauer_low[i]
 while(a >=0) {
  WARTE bis 10µS vorbei
  a = a - 1
 }
 i = i + 1
 if (i > maximale_pulse) {
  i = 0
 }
}

Dein Ansatz sollte also brauchbar sein ;)

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht 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...

...

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
#define PRESCALE1 2
#define PRESCALE2 1

// nur als Beispiel mal 4 Werte
unsigned int timer[4] = {8000,8000,8000,8000};

SIGNAL(SIG_OUTPUT_COMPARE1A)
{  
  static unsigned char cnt = 0;
  
  OCR1A += timer[cnt++];
  if(cnt==4) cnt = 0;
  
  PORTB ^= 1;
}

int main(void)
{     
   // configure timer 1
   // Zeitbasis
   TCCR1A = (0<<COM1A1)|(0<<COM1A0)|(0<<COM1B1)|(0<<COM1B0)|
            (0<<FOC1A)|(0<<FOC1B)|(0<<WGM11)|(0<<WGM10);
   TCCR1B = (0<<ICNC1)|(0<<ICES1)|(0<<WGM13)|(0<<WGM12)|PRESCALE1;
   
   // configure timer 2
   // erzeugt 40kHz
   TCCR2 = (0<<FOC2)|(1<<WGM21)|(0<<WGM20)|(0<<COM21)|
           (1<<COM20)|PRESCALE2;
   OCR2 = IRVAL;
  
   // init    
   OCR1A = timer[0];
   TCNT1 = 0;
   
   TIMSK |= (1<<OCIE1A); 

   sei();
         
   return 0;
}

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

Autor: Thomas (Gast)
Datum:

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

Autor: Thomas Glass (taximan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
wäre eine data-Tabelle evtl eine gute Idee?

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht 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.

...

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

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.