Forum: Mikrocontroller und Digitale Elektronik Verständnisproblem zu Zeitangaben im Quellcode


von Dominik K. (zergi)


Angehängte Dateien:

Lesenswert?

Hallo, ich hab ein Verständnisproblem zu Zeitangaben im C Code.

Ich programmiere mit AVR-Studio und beschreibe den µC auf dem STK500.
Hab etwa ein halbes dutzend ATTiny13, 23 & 25 ausprobiert.
Gemessen habe ich mit einem USB-Speicheroskar und Analogoskar, in beiden 
fällen identische Ergebnise.


Im Quellcode steht:
#define send1()    leds_on();    _delay_us(13.15);    leds_off(); 
_delay_us(13.15);

Das sollte eine Frequenz von 38khz ergeben.


Was das Osziloskop anzeigt findet man im Anhang.
Positive für 107us.
Negative für 112us.
Frequenz 4,6khz.

Nun versteh ich nicht wo der Fehler ist! Muss ich den Takt 
berücksichtigen und die Zeitangaben per hand Korrigieren? Wäre sowas 
nicht Aufgabe des Kompilors? So kenne ich das zumindestens von anderen 
Programmiersprachen.
Hab schon mal die Optimierungseinstellungen von AVR Studio 
durchprobiert, das hat den Wert zwar minimal (Nachkommastelle) 
verändernt, brachte aber keine Verbesserung.

Oder liegt diese Ungenauigkeit an Laufzeiten?
Oder hab ich mich einfach verrechnet?


Was ich auch nicht verstehe ist dass das negative Signal länger als das 
Positive ist, und das sogar wenn ich die beiden Signale tausche.
Das spricht ja eigentlich dafür das es nicht an der Laufzeit liegt.


mfg
Zergi

von holger (Gast)


Lesenswert?

CKDIV8 Fuse ausschalten.

von spess53 (Gast)


Lesenswert?

Hi

Hast du die CKDIV8-Fuse deaktiviert?

MfG Spess

von Dominik K. (zergi)


Lesenswert?

Ne, die war nicht deaktiviert.
Bis gerade hatte ich angenommen dass das setzen von F_CPU 
ausschlaggebend wäre.

Hatte daher auch den CPU Takt auf 8MHZ gesetzt und hatte 8x schnellere 
Zeitwerte.




Das verstehe ich jetzt aber gar nicht.

Warum habe ich unterschliedliche Zeiten wenn ich den Takt selber auf 
8MHZ setze, als wenn CKDIV8 (durch Deaktivierung) es macht?


Edit: Die Frequenz liegt dann bei 28,8khz.

von spess53 (Gast)


Lesenswert?

Hi

>Bis gerade hatte ich angenommen dass das setzen von F_CPU
>ausschlaggebend wäre.

Das interessiert nur den Compiler. Den Controller musst du schon selbst 
auf die richtige Frequenz stellen.

MfG Spess

von Dominik K. (zergi)


Lesenswert?

Huhu,


also angenommen der Kompilor denkt der µC rechnet richtig und übergibt 
irgendeine Zahl an den µC.
Der rechnet aber nur mit 1/8 Leistung. Müsste die Frequenz dann nicht 8x 
höher sein?

Das wäre ja dann (ungefähr) das was mit das Osziloskop anzeigt wenn ich 
keinen F_CPU Wert angebe.

Aber wenn ich einen Takt angebe liegt die Frequenz ca. 25% unter dem 
Wert den der µc überhaupt nicht kennt.



F_CPU: NIX
Frequenz soll: 38khz
Frequenz ist: 4,5khz

F_CPU: 8kk
Frequenz soll: 38khz
Frequenz ist: 28khz


Ist zwar schön das ich jetzt weiß wie ich den Fehler wegbekomme, aber 
rein rechnerisch versteh ich es nicht.


mfg
Dominik

von Rolf Magnus (Gast)


Lesenswert?

Dominik K. schrieb:

> also angenommen der Kompilor denkt der µC rechnet richtig und übergibt
> irgendeine Zahl an den µC.
> Der rechnet aber nur mit 1/8 Leistung. Müsste die Frequenz dann nicht 8x
> höher sein?

Wenn der Prozessor seine Warteschleifen nur mit 1/8 der erwarteten 
Geschwindigkeit dreht, warum sollte das dadurch erzeugte Signal dann das 
8-fache der erwarteten Geschwindigkeit haben?

> Das wäre ja dann (ungefähr) das was mit das Osziloskop anzeigt wenn ich
> keinen F_CPU Wert angebe.

Wenn du keine F_CPU angibst, müßte der Compiler eigentlich mit einem 
Fehler abbrechen.

> Aber wenn ich einen Takt angebe liegt die Frequenz ca. 25% unter dem
> Wert den der µc überhaupt nicht kennt.

Verstehe nicht, was du meinst. Was für ein "Wert den der µC überhaupt 
nicht kennt"?

> F_CPU: NIX
> Frequenz soll: 38khz
> Frequenz ist: 4,5khz

Das ist etwas mehr als Faktor 8.

> F_CPU: 8kk
> Frequenz soll: 38khz
> Frequenz ist: 28khz
>
>
> Ist zwar schön das ich jetzt weiß wie ich den Fehler wegbekomme, aber
> rein rechnerisch versteh ich es nicht.

Deine Funktionen leds_on() und leds_off() brauchen auch Zeit.

von Peter D. (peda)


Lesenswert?

Lies Dir doch erstmal im Datenblatt "6. System Clock and Clock Options" 
durch.
Dann weißt Du, wie Du welchen Takt Du einstellen kannst (Fuse Bits 
setzen).
Und den mußt Du dann natürlich auch Deinem Compiler bekannt geben.

Die AVR-GCC Lib nimmt bei fehlender Angabe 1MHz an (gibt zwar ne Warnung 
aus, daß sie das tut) und das ist eben oftmals falsch.

Besonders beim ATtiny13, der ist default auf 1,2MHz.

Und der interen RC-Oszillator ist natürlich nicht quarzstabil.


Peter

von Ralph (Gast)


Lesenswert?

Frequenz Erzeugung über Warteschleifen funktioniert NIEMALS genau.

Dafür gibt es in jedem µC hardware TIMER.

von Rolf Magnus (Gast)


Lesenswert?

Peter Dannegger schrieb:
> Die AVR-GCC Lib nimmt bei fehlender Angabe 1MHz an

Wozu soll das denn gut sein? Zur Verwirrung?

von Dominik K. (zergi)


Lesenswert?

Muss der µC aber nicht, wenn er mit 1 MHZ rechnet obwohl der Compiler 
von 8MHZ ausgeht um das 8fache daneben liegen?
Das ist das was ich nicht verstehe.


38khz und 28khz ist aber nicht wirklich Faktor 8.
Oder zählt diese Abweichung jetzt schon unter "ungenau"?

von Rolf Magnus (Gast)


Lesenswert?

Dominik K. schrieb:
> Muss der µC aber nicht, wenn er mit 1 MHZ rechnet obwohl der Compiler
> von 8MHZ ausgeht um das 8fache daneben liegen?

Ja.

> Das ist das was ich nicht verstehe.

Wie und wo hast du das F_CPU denn angegeben?

> 38khz und 28khz ist aber nicht wirklich Faktor 8.

Allerdings.

> Oder zählt diese Abweichung jetzt schon unter "ungenau"?

Für einen Faktor von 1 wäre diese Abweichung plausibel.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Du hast doch sicher noch eine Schleife drin und das Send steht in der 
Schleife. Damit kommen bei 1 MHz mind. 4 us pro Schleife für den 
Rücksprung hinzu (einfaches RJMP). Diese Zeit addiert sich zu dem Delay 
dazu.

Deine ersten Messungen sind ziemlich gut 107 us => 112 us sind fast die 
4 us. Und ich denke dein AVR lief am Anfang mit 1 Mhz Werkseinstellung.

Nach der Umstellung auf 8 MHz musst du an den Rücksprung und an den Code 
innerhalb der led_on/led_off Funktionen denken. Die knapsen auch 
Laufzeit ab.

Um das zu justieren, könntest du mal ein Toggeln versuchen

DDRB = (1<<PINB1);
while(1)
{
   PINB = (1<<PINB1); // 1 schreiben toggelt PORTB1 auf modernen AVR
                      // Anzahl Takte nachsehen
   _delay_us(12.65);  // - Feintuning für Rücksprung,,, - s.o.
}

Das ist aber müßig. Setze eine PWM auf, die kann per Hardware einen Pin 
(OC1A oder OC1B...) locker mit 38 kHz toggeln. Das gibt dir die 
Trägerfrequenz der LED. Dann schaltest du die LED plus Vorwiderstand 
zwischen diesen Pin und einen anderen O-Pin als geschaltete Stromsenke. 
HIGH an diesem Pin: LED aus, LOW an diesem PIN: LED an. Das moduliert 
das Datentelegramm auf die Trägerfrequenz.

von Michael H. (michael_h45)


Lesenswert?

Stefan B. schrieb:
>    PINB = (1<<PINB1); // 1 schreiben toggelt PORTB1 auf modernen AVR
Was, wie??

1
PORTB ^= (1<<PB1);
Das suchst du.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

> Was, wie??

"Bei den neueren AVR (wie z. B. ATtiny13, ATtiny2313, ATtiny24/44/84, 
ATtiny25/45/85, ATmega48/88/168, usw.) kann man als Ausgang 
konfigurierte Pins toggeln (PORTx zwischen 0 und 1 „umschalten“), indem 
man eine 1 an die entsprechende Bit Position des PINx Register 
schreibt."
http://www.mikrocontroller.net/articles/AVR-Tutorial:_IO-Grundlagen#Zusammenfassung_der_Portregister

von Michael H. (michael_h45)


Lesenswert?

Danke für die Aufklärung!
Klingt fast wie ein Maskenfehler, der als Feature verkauft wird.

von Tabellator (Gast)


Lesenswert?

Michael H. schrieb:
> Klingt fast wie ein Maskenfehler, der als Feature verkauft wird.

Aber ein sinnvolles Feature.

PORTB ^= ...

braucht mehrere Takte, lesen von PortB, XOR, schreiben von PortB. Und 
kann dummerweise von einem IRQ unterbrochen werden. Wenn der IRQ jetzt 
auch was an PORTB verändern wollte, geht seine Änderung gleich nach dem 
RETI wieder verloren.
Beim Togglen über den den PINB write kann das nicht passieren.

von Michael H. (michael_h45)


Lesenswert?

Tabellator schrieb:
> PORTB ^= ...
> braucht mehrere Takte, lesen von PortB, XOR, schreiben von PortB. Und
Nö, ist ein Befehl aus dem Instruktionssatz.

von Karl H. (kbuchegg)


Lesenswert?

Michael H. schrieb:
> Tabellator schrieb:
>> PORTB ^= ...
>> braucht mehrere Takte, lesen von PortB, XOR, schreiben von PortB. Und
> Nö, ist ein Befehl aus dem Instruktionssatz.

Toggeln?

Bit Setzen und Löschen sind drinn, aber toggeln IMHO nicht.

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.