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
Hi Hast du die CKDIV8-Fuse deaktiviert? MfG Spess
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.
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
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
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.
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
Frequenz Erzeugung über Warteschleifen funktioniert NIEMALS genau. Dafür gibt es in jedem µC hardware TIMER.
Peter Dannegger schrieb: > Die AVR-GCC Lib nimmt bei fehlender Angabe 1MHz an Wozu soll das denn gut sein? Zur Verwirrung?
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"?
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.
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.
Stefan B. schrieb: > PINB = (1<<PINB1); // 1 schreiben toggelt PORTB1 auf modernen AVR Was, wie??
1 | PORTB ^= (1<<PB1); |
Das suchst du.
> 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
Danke für die Aufklärung! Klingt fast wie ein Maskenfehler, der als Feature verkauft wird.
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.
Tabellator schrieb: > PORTB ^= ... > braucht mehrere Takte, lesen von PortB, XOR, schreiben von PortB. Und Nö, ist ein Befehl aus dem Instruktionssatz.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.