mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik AVR Timing genau einhalten in C


Autor: Stefan Schulte (st_schulte)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

Ich versuche den NEC-Code als Fernbedienungs-Ersatz per
Mega48 und C (ICC AVR 6.31 Demo) zu senden.
Irgendwie passen die Timings noch nicht.
Kann man im AVR Studio (4.12.460) die Stopuhr (Stop Watch) des 
Prozessor-Fensters zum messen des Zeitverbrauchs einsetzen (dann habe 
ich ein heftiges Problem :-) oder wie kann man in C eine High-Low 
Sequenz am besten Zeitgenau hinkriegen?

cu

Stef@n

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Stefan Schulte (st_schulte)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi!

War zwar superschnell, aber "Die Timer/Counter des AVR" bringts nicht.
Ich muß 560us pulsen (das natürlich mit Timer), 1690us pausen für eine 0
und 560us pulsen und 565us pause für eine 1, das ganze 32bit in Reihe
ohne Pause. Da dauert ja das Timer setzen schon zu lange :-)

Autor: antworter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>560us pulsen

@16MHz:

1 clockcycle = 1 / 16MHz = 62.5 ns

> Da dauert ja das Timer setzen schon zu lange

Benötigt das Timer setzen bei Dir 9000 Takte ?

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Betreibe den Timer im CTC-Modus mit Portpin toggeln bei Compare. Dann 
hast Du nach einem Umschalten des Portpins jeweils mindestens 560 µs 
Zeit, den Compare-Wert zu ändern. Das sollte überhaupt kein Problem 
sein. Wie man das jetzt genau macht, steht allerdings im Tutorial bzw. 
Datenblatt...

Autor: Rahul, der Trollige (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Da dauert ja das Timer setzen schon zu lange :-)

Selbst bei 1MHz würde der Controller erst sehr langsam ins Schwitzen 
kommen.

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

Bewertung
0 lesenswert
nicht lesenswert
Stefan Schulte wrote:
> Hi!
>
> War zwar superschnell, aber "Die Timer/Counter des AVR" bringts nicht.
> Ich muß 560us pulsen (das natürlich mit Timer), 1690us pausen für eine 0
> und 560us pulsen und 565us pause für eine 1, das ganze 32bit in Reihe
> ohne Pause. Da dauert ja das Timer setzen schon zu lange :-)

Allerdings.

Bei diesen Zeiten musst du schon kräftig aufpassen, dass dir
der AVR vor Langeweile nicht einschläft. Wenn der erst mal
vor sich hinschnarcht, kriegt man den so schnell nicht
mehr wach :-)

Autor: Stefan Schulte (st_schulte)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
johnny.m wrote:
> Betreibe den Timer im CTC-Modus mit Portpin toggeln bei Compare. Dann
> hast Du nach einem Umschalten des Portpins jeweils mindestens 560 µs
> Zeit, den Compare-Wert zu ändern. Das sollte überhaupt kein Problem
> sein. Wie man das jetzt genau macht, steht allerdings im Tutorial bzw.
> Datenblatt...

Nun, das geht eben nicht, da der Portpin ja bereits mit 38kHz toggelt.
Ich schalte nur das DDRx im Taktverhältnis um (pulsen, nicht pulsen).

Mein Problem ist irgenwie das Umsetzen der Timer in C (denn das war auch 
meine erste Idee), da ich nicht genau weiß wie lange der C-Code für das
umschalten, starten, DDRx ändern, ... benötigt.
Das Oszi sieht jedenfalls nicht gut aus.
Die Idee das mit AVR Studio zu testen war dann durch das Port-Toggeln 
auch dahin.
Deshalb die Frage nach der Stop Watch. (verläßliche Simulationszeit?)

Autor: Rahul, der Trollige (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie wäre es, wenn du deinen Code mal posten würdest?

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn Du ne PWM drauf hast, dann geht das doch im Prinzip genau so! Du 
musst nur den Compare-Wert ändern. Und dafür hast Du reichlich Zeit...

Autor: Stefan Schulte (st_schulte)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rahul, der Trollige wrote:
> Wie wäre es, wenn du deinen Code mal posten würdest?

Ein paar Spaghetti:

#pragma global_register DelayL:21
unsigned char DelayL;

#pragma global_register DelayH:22
unsigned char DelayH;

void NECLogic0(void)
/* Sendet eine "0" */
{
  DDRB |= (1<<PB2);    // OC1B = PB2 auf Ausgang
  DelayH = 4;        // 500us
  loop125u();
  DelayL = 60;      // +60 = 560us
  loop();
  DDRB &= ~(1<<PB2);    // OC1B = PB2 Ausschalten
  DelayH = 4;        // 500us
  loop125u();
  DelayL = 65;      // +65 = 565us
  loop();
}

void NECLogic1(void)
/* Sendet eine "1" */
{
  DDRB |= (1<<PB2);    // OC1B = PB2 auf Ausgang
  DelayH = 4;        // 500us
  loop125u();
  DelayL = 60;      // +60 = 560us
  loop();
  DDRB &= ~(1<<PB2);    // OC1B = PB2 Ausschalten
  DelayH = 13;      // 500us
  loop125u();
  DelayL = 65;      // +65 = 1690us
  loop();
}

void loop(void)
/* Schleife mit DelayL Verzoegerung */
{
  asm ("_loop1:: dec %DelayL\n"
          "nop\n"
          "nop\n"
          "nop\n"
          "nop\n"
          "nop\n"
              "brne _loop1");
}

void loop125u(void)
/* Schleife mit 125us*DelayH Verzoegerung */
{
  asm ("_looph:: ldi R30,250\n"
     "_loopl:: dec R30\n"
           "nop\n"
          "brne _loopl\n"
          "dec %DelayH\n"
          "brne _looph");
}

in main habe ich dann mal ein paar "0"en und "1"en fürs Oszi ausgegeben.
Nur das Ergebnis sieht nicht sehr "richtig" aus :-)

Autor: Rahul, der Trollige (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn man nicht mehr als diese Funktion haben will, kann man auch 
problemlos 2 Timer benutzen: Der eine erzeugt 38kHz und der andere die 
Pulse und Pausen. Das kann man dann entweder einer ISR verunden oder 
extern.

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

Bewertung
0 lesenswert
nicht lesenswert
Ich würd alles mit einem Timer machen.
Der löst regelmässig einen Interrupt aus.
Im Interrupt wird dann mitgezählt:

  einmal die notwendigen Interruptaufrufe um auf
  die 32 kHz zu kommen und bei richtigem Zählerstand
  den Output Pin zu toggeln

  und zum zweiten zählt er noch das Puls/Pause
  Verhältnis mit. Ist er im Puls wird der vorher
  ermittelte Trägerwellenzustand an den Portpin
  gegeben. Ist er in der Pause, wird der Portpin
  auf 0 (oder 1, je nachdem wie die LED angeschlossen ist)
  eingefroren.

Die einzige Herausforderung ist es einen Vorteiler zu wählen,
so dass sich das komplette Timing (32 kHz + die Puls/Pausen
Zeiten für 0 und 1) sauber ausgeht.

Ohne jetzt das Timing durchgerechnet zu haben, so
ungefähr:

ISR (was_weis_ich_wahrscheinlich_ein_CTC_am_Timer_1)
{
  Takt++;

  if( Takt == was_auch_immer_notwendig_für_32_khz_ist ) {
    Takt = 0;
    Neuer_Port_Zustand = 1 - Alter_Port_Zustand;
  }

  if( SchickePuls ) {
    Pulsdauer--;
    if( Pulsdauer == 0 ) {     // der Puls ist vorbei
      SchickePuls = 0;
      Pausendauer = was_auch_immer_notwendig_ist_bei_dem Vorteiler;
    }
  }
  else {
    Neuer_Port_Zustand = 0;
    Pausendauer--;
    if( Pausendauer == 0 ) {
      if( nächstes_Bit == 0 )
        Pulsdauer = was_auch_immer_notwendig_ist_um die_Zeit
                    für_einen_1_Puls_zu kriegen
      else
        Pulsdauer = was_auch_immer_notwendig_ist_um die_Zeit
                    für_einen_0_Puls_zu kriegen
      SchickePuls = 1;
    }
  }

  PORTx = Neuer_Port_Zustand;
  Aler_Port_Zustand = Neuer_Port_Zustand;
}

Das ist jetzt mal so schnell als Skizze hingeschrieben.
Aber so ungefähr würde ich das versuchen.

Jetzt heist es natürlich mal ein bischen rechnen, so dass
sich beim gewählten Vorteiler und dem CTC-Wert (*) schöne
Zahlen für die "was_weis_ich...." Zählerstände ergeben.

(*) Ev. gehts auch mit Overflows aber ich denke mal
mit dem CTC gehts einfacher die Zeiten Taktgenau
einzustellen.

Autor: Rahul, der Trollige (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>die 32 kHz zu kommen

Es sind 38kHz, wenn ich mich nicht verlesen habe...

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

Bewertung
0 lesenswert
nicht lesenswert
Rahul, der Trollige wrote:
>>die 32 kHz zu kommen
>
> Es sind 38kHz, wenn ich mich nicht verlesen habe...

Auch gut.
Wo hab ich jetzt die 32 kHz her?


Was hältst du von der Skizze. Würde das so in etwa
gehen?

Autor: Rahul, der Trollige (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Was hältst du von der Skizze. Würde das so in etwa gehen?
Ja, warum auch nicht?

>Wo hab ich jetzt die 32 kHz her?
"Karl Heinz, der magische"...

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

Bewertung
0 lesenswert
nicht lesenswert
Rahul, der Trollige wrote:
>>Was hältst du von der Skizze. Würde das so in etwa gehen?
> Ja, warum auch nicht?
>
>>Wo hab ich jetzt die 32 kHz her?
> "Karl Heinz, der magische"...

Ommmmmmmmmmmmmm

Autor: Winne (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
 so wie k.h.
würde ich das auch machen.

und wenns wirklich mal schneller gehen muss lassen sich asm-routinen 
einbinden was hier nicht nötig werden dürfte.

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.