Hey, ich brauch Hilfe von Profis, ich spiel zurzeit ein wenig mit Attiny25-20PU herum und bin total verwirrt von dem Datenblatt und dem Verhalten. Mir ist irgendwie nicht klar welche internen Oszillator Frequenz dieser besitzt. Ich hab leider kein Oszi und hab deswegen eine LED blinken lassen im ca. 1Hz Takt und wenn ich das einmal als grob Schätzung annehme müsste der interne Clock 2 MHz sein. Das macht aber keinen richtigen Sinn wenn ich das Datenblatt richtig verstehe. Kann mir jemand sagen was die maximale interne Frequenz ist? Und wie ich diese mit den Fusebits im AVR-Studio 4 einstelle? Schon mal vielen Dank, Matthias
Warum ist dir die MAXIMALE Frequenz so wichtig? Da sie nicht exakt reproduzierbar ist, MUSS man bei Benutzung des internen Oszillators mit seinem Mittelwert "rechnen". Mit dem FUSE-Bit CKDIV8 stellst du ein, ob der µC mit den vollen (UNGEFÄHR!) 8 MHz des internen Oszillators arbeitet, oder mit 1/8 davon (1 MHz). Bei Auslieferung ist das FUSE-Bit auf 1/8 eingestellt. Abgleichen kann man die Frequenz des internen Oszillators mit dem OSCCAL-Register auf etwa 4...16 MHz. Ohne Änderung des FUSE-Bits bekommt man 0,5...2 MHz.
Beim Attiny25 ist standardmäßig der interne Oszillator mit 8 MHz aktiviert, das ist auch gleichzeitig die maximale intern erzeugbare Frequenz. Allerdings wird der Attiny auch mit gesetzter CKDIV8-Fuse geliefert, d.h. der Oszillator-Takt wird durch acht geteilt, so dass der effektive Takt 1 MHz ist. Zusätzlich gibt es dann noch ein Register, über welches man andere Prescaler für den Takt einstellen kann, das muss aber in der Firmware geschehen.
Übrigens ist dieser interne Oszillator nach meiner Erfahrung erstaunlich genau (viel besser, als +/- 10%). Wenn du "rückwärts gerechnet" auf 2 MHz kommst, würde ich erst mal auf einen Programmierfehler tippen. Wahrscheinliche Werte sind 0,9...1,1 MHz ohne Veränderung des Fuse-Bits, oder 7,2...8,8 MHz mit Änderung.
Matthias schrieb: > LED blinken lassen im ca. 1Hz Takt Zeig mal dein Programm und deine Berechnung. Ich wette du hast in deiner Berechnung einen Fehler mit Faktor 2 eingebaut, weil du nicht bedacht hast, dass eine LED die 1 Sekunde hell, 1 Sekunde dunkel ist, mit einer Frequenz von 0.5Hz blinkt und nicht mit 1Hz. Sprich: wenn du in einer Timer ISR den Ausgang toggelst, dann halbierst du damit die Aufruffrequenz der ISR am Ausgang.
Bernie schrieb: > Übrigens ist dieser interne Oszillator nach meiner > Erfahrung erstaunlich genau (viel besser, als +/- 10%). > > Wenn du "rückwärts gerechnet" auf 2 MHz kommst, würde > ich erst mal auf einen Programmierfehler tippen. > Wahrscheinliche Werte sind 0,9...1,1 MHz ohne Veränderung > des Fuse-Bits, oder 7,2...8,8 MHz mit Änderung. ... oder Schwankungen in der Versorungsspannung? Weiß ja nicht wie die Schaltung aussieht, aber auf dem Steckbrett kann das schon mal zum fehlerhaften Blinken führen (hatte ich gerade erst beim Tiny13). 100nF direkt am µC und auf einmal war das merkwürdige Verhalten weg.
Hi, > Zeig mal dein Programm und deine Berechnung. Das Programm besteht nur aus einer variablen die mit dem Systemtakt hochzählt, ist dieser Wert eine Million toggelt die LED. An und Aus dauern ca. 1 Sekunde, ist ziemlich ungenau aber es ist definitiv kein 1 MHz takt und auch kein 8 MHz Takt. Das Fuse Bit zum achteln der Frequenz ist aus. Außerdem kann man ja die CLK source umstellen von "PLL CLK" auf "int. CLK mit 8 MHz", welche nimmt man ich habe gerade das erste einsgestellt. > Abgleichen kann man die Frequenz des internen Oszillators > mit dem OSCCAL-Register auf etwa 4...16 MHz. > Ohne Änderung des FUSE-Bits bekommt man 0,5...2 MHz. Hab dieses Register wie im Datenblatt steht auf 0xFF für 200% Highest Frequency gestellt und es verdoppelt auch die Frequenz. Aber ich bin immer noch nicht bei 8 MHz geschweige denn bei 16 MHz. Hab ich irgendwas vergessen oder mache ich was falsch? Wegen der Spannungsversorgung ich habe einen IC Sockel der einen 100 nF Kondensator integriert hat. Viele Grüße, Matthias
Wie schon gesagt, zeig mal dein Programm und deinen Aufbau. Wir haben es hier oft genug, dass Fragen gestellt werden, weil etwas nicht klappt, aber der Code angeblich korrekt wäre. Am Ende ist der Code dann doch nicht korrekt und es liegt daran. Mit welcher Optimierung compilierst du dein Programm? Und wild an den Clock-Einstellungen rumzuspielen würde ich lassen, denn damit kann man sich ganz schnell komplett aussperren, und dann wird es kompliziert den AVR wieder ans Laufen zu kriegen.
also ich hab jetzt einmal meinen Code eingefügt, mit der Variante des eigestellten OSCCAL Register auf 200%, jetzt blinkt die LED wieder in einem Herz Takt, also an und aus ca. 1 sek. => aktuell eine Frequenz von 4 MHz (ca.)
1 | int main () |
2 | {
|
3 | DDRB |= (1<<DDB1)|(1<<DDB3)|(1<<DDB4); // LEDs als Ausgang |
4 | |
5 | OSCCAL = 0xFF; |
6 | CLKPR = 0x00; |
7 | while(1) |
8 | {
|
9 | y++; |
10 | if (y >= 2000000) |
11 | {
|
12 | PORTB ^= (1<<red); |
13 | y = 0; |
14 | }
|
15 | }
|
16 | return 0; |
17 | }
|
Das ist aber nicht das vollständige Programm, lässt sich bei mir nicht kompilieren, "y" und "red" sind nicht definiert.
Hi >>also ich hab jetzt einmal meinen Code eingefügt, mit der Variante des >eigestellten OSCCAL Register auf 200%, jetzt blinkt die LED wieder in >einem Herz Takt, also an und aus ca. 1 sek. => aktuell eine Frequenz von >4 MHz (ca.) Eine Aussage kannst du nur mit dem Assemblercode machen, der der Compiler erstellt. Mit deinem C-Code kann man das nur ahnen. MfG Spess
Matthias schrieb: > Hi, > >> Zeig mal dein Programm und deine Berechnung. > > Das Programm besteht nur aus einer variablen die mit dem Systemtakt > hochzählt, ist dieser Wert eine Million toggelt die LED. Sorry. Aber das ist Blödsinn! Daraus kannst du überhaupt nichts über das Zeitverhalten ableiten. Je nach Optimierungseinstellung deines Compilers kommen da Hausnummern raus, gegen die der Wasserstand in der Donau ein Präzissionsinstrument ist. Du musst das schon nach den Regeln machen! Wenn du ungefähr eine realistische Zeitablesung machen willst, dann geht das so
1 | // Testprogramm für CPU Takt
|
2 | // Hier die vermeintliche Taktrate des µC eintragen
|
3 | // Im Beispiel hier: 1Mhz
|
4 | |
5 | #define F_CPU 1000000
|
6 | |
7 | #include <avr/io.h> |
8 | #include <util/delay.h> |
9 | |
10 | // Hier die tatsächlich verwendeten Parameter angeben
|
11 | |
12 | #define LED_PORT PORTB
|
13 | #define LED_DDR DDRB
|
14 | #define LED_PIN PB1
|
15 | |
16 | int main() |
17 | {
|
18 | LED_DDR |= 1 << LED_PIN; |
19 | |
20 | while (1) |
21 | {
|
22 | LED_PORT ^= 1 << LED_PIN; |
23 | _delay_ms(1000); |
24 | }
|
25 | |
26 | return 0; |
27 | }
|
Wenn dein µC mit 1 Mhz läuft, dann ist die LED 1 Sekunde ein und 1 Sekunde aus. Läuft der µC mit 8Mhz dann ist das enstprechend nur 1/8 Sekunde, es sei denn du trägst bei F_CPU die 8000000 ein. Dann ist es wieder 1 Sekunde. Das ganze beruht darauf, dass dir der Compiler nur dann die notwendigen Werte für _delay_ms korrekt errechnen kann, wenn der F_CPU Wert mit der Realität des tatsächlichen Taktes übereinstimmt. Nur dann benötigt ein _delay_ms(1000) auch tatsächlich 1000 Millisekunden (also 1 Sekunde). Alles was du mit selbstgebauten Warteschleifen machst, beruht immer auf irgendwelchen windigen Annahmen, wie der Compiler deinen Code übersetzt und ist daher eine ausgesprochen schlechte Idee. WICHTIG: Bei obigem Code muss der Optimizer auf -Os stehen. Nur dann stimmen die Zeiten, die _delay_ms wartet!
Nimm lieber so etwas wir __delay_cycles oder wie auch immer es heissen mag.
Matthias schrieb: > also ich hab jetzt einmal meinen Code eingefügt, mit der Variante des > eigestellten OSCCAL Register auf 200%, jetzt blinkt die LED wieder in > einem Herz Takt, also an und aus ca. 1 sek. => aktuell eine Frequenz von > 4 MHz (ca.) > > int main () > { > DDRB |= (1<<DDB1)|(1<<DDB3)|(1<<DDB4); // LEDs als Ausgang > > OSCCAL = 0xFF; > CLKPR = 0x00; > while(1) > { > y++; > if (y >= 2000000) Aha. Und diese Operationen macht dein µC in 0-Zeit, oder wie? Folgt man deiner Argumentation, dann benötigt (laut dir) dein µC für das Durcharbeiten eines Schleifendurchlaufs nur 1 Taktzyklus. Das ist 'ein klein wenig' zu optimistisch :-)
Ich habe mir mal "y" und "red" selbst definiert und das Ganze im Simulator laufen lassen. Mit Optimierung -O1 lande ich nach etwa 12.000.000 Takten in der if-Abfrage. Macht also bei 8 MHz knapp 1,5 Sekunden. Eine zuverlässige Zeitmessung macht man auch nicht so, wie du sie programmiert hast. Du hast allein schon einen großen Denkfehler. Du sagst, du erhöhst pro Takt den Zähler um eins. In Wirklichkeit werden hier schon mehrere Takte benötigt, da du, um einen Wert von 2.000.000 feststellen zu können eine 32 Bit Variable benötigt, der AVR jedoch eine 8 Bit-Architektur hat und daher jedes Byte einzeln berechnen muss. Zudem brauchst du noch einige Takte um zu prüfen, ob der richtige Wert erreicht wurde, so dass die schlussendlich vergangene Zeit erheblich abweicht. Nutz für sowas besser einen Timer mit ISR oder die zumindest entsprechenden delay-Funktionen.
Super vielen Dank an alle, das nächste mal werde ich gleich meinen Code posten das würde vieles Abkürzen.
Noch ein Nachtrag, so wie du es programmiert hast ist die Abweichung sogar noch größer, denn wenn du auf 2.000.000 prüft (angenommen pro Inkrementierung vergeht ein Takt) müsste die LED bei 8 MHz nur 1/4s an bzw. aus sein. Damit ist das Ganze um den Faktor 6 langsamer als gewünscht ;)
Daniel H. schrieb: > Beim Attiny25 ist standardmäßig der interne Oszillator mit 8 MHz > aktiviert, das ist auch gleichzeitig die maximale intern erzeugbare > Frequenz. Ich entschuldige mich gleich vorab, weil mein Einwurf mit dem Thread-Thema wenig zu tun hat, aber trotzdem, zur Ehrenrettung des ATtiny25: Die maximale nutzbare reguläre Frequenz des internen Oszillators ist 16 MHz. Die Serie ATtiny25/45/85 besitzt einen Frequenzvervielfacher (8-fach), der für den Timer1 genutzt wird. Aus diesem kann die CPU getaktet werden (nach einem Teiler durch 4). Dadurch kann die CPU mit der doppelten regulären RC-Oszillator-Frequenz laufen. OSCCAL arbeitet unabhängig davon und kann zusätzlich genutzt werden, um die Frequenz weiter zu erhöhen. Allerdings ist bei ca. 21 MHz Schluss, weil der Frequenzvervielfacher (PLL) nicht schneller als etwa 85 MHz schwingt. Steht jedenfalls im Datenblatt – ausgereizt habe ich das noch nicht.
Das Problem ist hier, dass der Wert des clock prescalers nicht gesetzt wird. Man kann den Wert nicht einfach in das Register CLKPR schreiben, sondern muss erstmal das höchste Bit setzen und dann in einem weiteren Zugriff innerhalb von 4 Taktzyklen des gewünschten Wert einstellen. Das Problem wird im Beitrag "AVR clock prescaler (CLKPR) und gcc-Codeoptimierung" genauer beleuchtet.
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.