Hallo zusammen,
ich habe gerade irgendwie ein kleines komisches Problem:
Hardware: ATMega8, 16Mhz Quarz
Timer 0 läuft ohne Probleme wie errechnet.
Timer 1 allerdings läuft nicht (obwohl er im Debug-Simulator von
AVR-Studio 4 läuft?)
Ich finde meinen Fehler nicht so ganz :(
setup():
1
TCCR1B = 0x1D; //CTC Mode und Prescaler 1024
2
//Interrupt alle 100ms -> alle 1563 = 0x061B Schritte
3
OCR1AH = 0x06;
4
OCR1AL = 0x19;
5
TIMSK |= 0x10; //Interrupt an
ISR:
1
ISR(TIMER1_COMPA_vect)
2
{
3
PORTC++;
4
//time++;
5
}
"Entwickelt" nach Datenblatt :/
Fakt ist:
Im Simulator schaff ich wie gewünscht ca alle 1500000 Schritte einen
Interrupt.
Auf dem AVR allerdings erreicht er die ISR nur ein mal (PC0 wird HIGH),
aber dann passiert nichts mehr (der AVR läuft aber weiter).
Danke für jede Hilfe :)
Jobst M. schrieb:> Oliver W. schrieb:>> TCCR1B = 0x1D; //CTC Mode und Prescaler 1024>> TCCR1B = 0x15; //CTC Mode und Prescaler 1024> TCCR1A = 0
Leider völlig falsch. Das andere ist nur ein bisschen falsch.
Aber wer hat schon Lust, sich die Bits nach Datenblatt zusammen und
auseinander zu klabüstern.
> TCCR1B = 0x1D; //CTC Mode und Prescaler 1024> //Interrupt alle 100ms -> alle 1563 = 0x061B Schritte> OCR1AH = 0x06;> OCR1AL = 0x19;> TIMSK |= 0x10; //Interrupt an
Wurde hier schliesslich oft und lange genug gepredigt, wie man das
richtig macht.
mfg.
Jobst M. schrieb:> Thomas Eckmann schrieb:>> Leider völlig falsch. Das andere ist nur ein bisschen falsch.>> Komisch. Läuft bei mir so.
Deine Einstellung ist Mode 8 "PWM, Phase and Frequency Correct".
Da gibt es natürlich zwischendurch einen Compare Mach. Aber dann läuft
der Timer bis ICP, das bei dir wahrscheinlich gesetzt ist, weiter. Aber
das ist kein CTC-Mode. Ist es beim TO aber, Mode12. Nur bei seiner
Einstellung braucht er ICR1 statt OCR1A. Aber das erzähl ich ihm nicht
wegen seiner Bitfriemel-Schreibweise. Also das bleibt jetzt unter uns.
mfg.
Thomas Eckmann schrieb:> Deine Einstellung ist Mode 8 "PWM, Phase and Frequency Correct".
Stimmt - das andere Bit ist bei mir gelöscht! Sorry.
Dann ist es TCCR1B = 0x0D was ich meinte. (Mode 4)
Thomas Eckmann schrieb:> Bitfriemel-Schreibweise.
Die ich allerdings auch schon seit 20 Jahren bevorzuge ...
Gruß
Jobst
Jobst M. schrieb:> Thomas Eckmann schrieb:>> Deine Einstellung ist Mode 8 "PWM, Phase and Frequency Correct".>> Stimmt - das andere Bit ist bei mir gelöscht! Sorry.>> Dann ist es TCCR1B = 0x0D was ich meinte. (Mode 4)
Genau.
>> Thomas Eckmann schrieb:>> Bitfriemel-Schreibweise.>> Die ich allerdings auch schon seit 20 Jahren bevorzuge ...
Ja. Aber wahrscheinlich findest du deine Fehler auch selber.
Bei den Ports ist das ja auch vollkommen egal. Naja, sagen wir fast
egal.
Aber gerade bei den Timern ist es eine Zumutung für jemand anderes,
jedesmal im Datenblatt die Bits zusammenzufriemeln. Weil gerade die
Timer-Bits bei den AVRs andauernd anders verteilt sind.
mfg.
Ist es eigentlich echt so schwer, die vordefinierten Bitnamen zu
benutzen? Würde das den Code vielleicht zu lesbar oder womöglich gar
noch portabel machen?
Also z.B.
1
TIMSK|=(1<<OCIE1A);
statt
1
TIMSK|=0x10;
Und warum in Hergottsnamen setzt du OCR1AH und OCR1AL separat, wo dir
der Compiler doch frei Haus den Luxus bietet, direkt 16 Bit in OCR1A zu
schreiben? Und warum stimmen die Kommentare so offensichtlich nicht
mit dem Code überein?
XL
Oliver schrieb:
>Timer 1 allerdings läuft nicht (obwohl er im Debug-Simulator von>AVR-Studio 4 läuft?)
Das ist das Schöne an einem Simulator, daß das Resultat nicht der
Wirklichkeit entspricht.
Erast Fandorin
Na aber hallo Axel, danke für die netten Worte o.O ich mag das Forum
hier und ich lese hier gerne und viel mit. Unglaublicherweise kommen
aber manche hier aus anderen Welten als AVR, ich zum Beispiel hab in der
Hochschule zumeist mit 8051-Varianten zu tun und da kann ich weder
diesen direkten 16-Bit Zugriff nutzen, noch gibt es das Shiften der Bits
für die von dir bevorzugte Einzel-Bit-Schreibwese (sondern oft - nicht
immer - Bitweisen Zugriff).
Wenn du da so viel Wert drauf legst bzw das generell hier der Fall ist
nehme ich diesen Hinweis gerne an, allerdings finde ich diesen Tonfall
recht arrogant.
Der Fehler das es offensichtlich bei Reload-Wert nicht stimmt nehme ich
auf meine Kappe, da hatte ich die Refresh-Rate noch ein bisschen
angepasst um auf einen "glatteren" Wert zu kommen.
Also, ich versuch da jetzt nochmal für mich auseinander zu klamüsern was
ihr hier schreibt:
Timer Mode 4 will ich nutzten (wie vorher auch), hatte allerdings vorher
WGM13 gesetzt -> Mode 12 wurde genutzt und daher als Reload-Wert ICR1
statt OCR1A.
Folglich wäre für das TCCR1B:
1
TCCR1B = (1<<WGM12) | (1<<CS12) | (1<<CS10)
für das OCR1A ist aber nun
1
OCR1AH = 0x06;
2
OCR1AL = 0x19;
gleichbedeutend mit
1
OCR1A = 0x0619;
Nur damit ich das mit den 16Bit Registern verstehe:
Die Option das in einem Schritt zu machen ist also ein Compiler-Makro,
dh im Flash landet es wieder in der 1., geteilten Variante? Ich hab also
keinen Geschwindigkeitsvorteil daraus? (Dann würde ich weiterhin die
erste Variante nutzen, um nicht jedesmal umdenken zu müssen zwischen 2
Architekturen).
Ich bin zZ auf Arbeit, kanns also erst am Nachmittag testen und
berichten.
Nochmal danke an alle die sich die Zeit nehmen und helfen, sowohl an
Thomas und Jobst als auch an Axel, danke für jede Hilfe, trotzdem finde
ich den Tonfall (nicht nur hier und bei dir, auch generell bei anderen)
etwas... unangemessen.
Ich verstehe deinen Einwand bezüglich der Nachvollziehbarkeit und werde
mir wahrscheinlich einfach ein kleines Tastaturmakro anlegen, aber
vielleicht kann man das ganze auch ein wenig anderes Schreiben, siehe
Thomas Eckmann schrieb:> Nur bei seiner> Einstellung braucht er ICR1 statt OCR1A. Aber das erzähl ich ihm nicht> wegen seiner Bitfriemel-Schreibweise.
Kann man vielleicht auch "Lehrerhafter" schreiben:
"Schreib uns das ganze doch noch mal nach
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Ver.C3.A4ndern_von_Registerinhalten
auf, dann kann man das besser nachvollziehen", so klingt das ganze nach
"Wir sind hier eine Elitäre Gruppe und wollen keine "Neulinge", und wenn
doch, dann musst du von Anfang an wissen wie wir es haben wollen sonst
kriegst du hier keine Hilfe *grimmiger-alter-Mann-Gesicht*"
Gruß von einem Lern und Anpassungsbereiten Studenten, der heute Abend
von seinen Erfolgen berichten wird.
wobei man da jetzt wieder recht schnell sieht, dass das eigentlich
falsch ist. Denn zusammen mit dem Kommentar darüber sollte das
eigentlich
1
//Interrupt alle 100ms -> alle 1563 Schritte
2
OCR1A=1562;
lauten. Denn auch der Rücksetzschritt vom OCR1A Wert auf 0 ist ein
Schritt.
Will man das dann noch ein wenig komfortabler, dann lässt man sogar den
Compiler den Zahlenwert aus F_CPU und der gewünschten Zeitdauer
ausrechnen.
aber: warum einfach, wenns auch umständlich geht.
Oliver W. schrieb:> (Dann würde ich weiterhin die> erste Variante nutzen, um nicht jedesmal umdenken zu müssen zwischen 2> Architekturen).
Darf ich auch mal arrogant sagen:
Oh oh.
Irgendwann mal eine µC-Architektur kennengelernt und dann mit diesem
Wissen stehen bleiben und irgendwann sterben.
Karl Heinz schrieb:> wobei man da jetzt wieder recht schnell sieht, dass das eigentlich> falsch ist.> Denn auch der Rücksetzschritt vom OCR1A Wert auf 0 ist ein Schritt.
Danke! Ich glaub das war meine Ungenauigkeit.
> Will man das dann noch ein wenig komfortabler, dann lässt man sogar den> Compiler den Zahlenwert aus F_CPU und der gewünschten Zeitdauer> ausrechnen.>> aber: warum einfach, wenns auch umständlich geht.
Hab so Makros schon mal gesehen und werden auch irgendwann bestimmt mal
eingesetzt ;)
fgqzh35z schrieb:> Darf ich auch mal arrogant sagen:
Darfst du ;)
> Oh oh.
Nein - Doch - Oh!
> Irgendwann mal eine µC-Architektur kennengelernt und dann mit diesem> Wissen stehen bleiben und irgendwann sterben.
So sollte das nicht rüberkommen, umdenken muss man natürlich immer.
Darum ja die Frage:
Macht der Compiler aus dem 16Bit-Aufruf 2 8-Bit aufrufe oder unterstützt
der AVR eine 16Bit-Ladefunktion (afaik nein)? Weil wenn 1. der Fall ist,
ist meine Lösung vielleicht nicht die kürzeste, aber doch genau so
Richtig und Schnell.
Oliver W. schrieb:> Macht der Compiler aus dem 16Bit-Aufruf 2 8-Bit aufrufe oder unterstützt> der AVR eine 16Bit-Ladefunktion (afaik nein)?
Weißt Du, wie unwichtig das an dieser Stelle ist?
Du durchläufst diese Init-Routinen ein mal.
Hier geht es einzig und alleine darum, dass man den Code
als Mensch besser lesen und verstehen kann.
Was der Compiler daraus später macht ist sowas von egal.
Oder hast Du hier ganz spezielle Anforderungen?
Nein nein, ich verstehe eure Argumentation schon.
Mir ging es nur für mich um den Lern Faktor, Unterschied ja nein.
Das es für euch praktischer ist berücksichtige ich heute Abend gerne :)
Karl Heinz schrieb:>> für das OCR1A ist aber nun>>> OCR1AH = 0x06;>> OCR1AL = 0x19;>> >>> gleichbedeutend mit>>>>> OCR1A = 0x0619;>>> Und das wiederrum ist gleichbedeutend mit OCR1A = 1563;
Würde ich persönlich auch immer in dieser Situation so
schreiben, also kein Hex-Wert.
Ich bin ein Mensch :-) und rechne im 10er-System.
Wenn Konfigurationsregister gesetzt werden, mag die Hex-Schreibweise
ja irgendwie noch Sinn machen.
0x32 => 0011 (3) 0010 (2)
Leider hat es eine Binär-Darstellung noch nicht in den C-Standard
geschafft (oder doch). Sowas o.ä. würde ich mir wünschen:
00110010b
Bei bitadressierbaren µCs kann min in der Regel auch die einzelnen
Bits von Konfigurationsregistern symbolisch ansprechen (z.B. beim
C166-Core). Dann kann man das auch im Sourcecode noch irgendwie
lesen. Mit einem ergänzenden Kommentar.
In den Coding-Guidelines vieler Firmen ist auch eine Zuweisung
wie oben ("OCR1A = 1563;") nicht erlaubt (Magic Number),
sondern nur über Defines. Und dem obligatischen Kommentar
warum genau 1563 und nicht 1564 bzw. was es mit diesem Wert
denn überhaupt auf sich hat.
Aber ich schweife vom Thread-Thema ab...
Oliver W. schrieb:> Darum ja die Frage:> Macht der Compiler aus dem 16Bit-Aufruf 2 8-Bit aufrufe oder unterstützt> der AVR eine 16Bit-Ladefunktion (afaik nein)? Weil wenn 1. der Fall ist,
Ausprobieren geht bei sowas schneller als zu fragen, und auf mehr oder
weniger geistreiche Antworten zu warten.
fgqzh35z schrieb:> Ich bin ein Mensch :-) und rechne im 10er-System.
Wenn du Regelmässig Programmierst und dir das schreiben der HEX Zahlen
angewöhnst, ist das nichtmehr sonderlich schwer zu erkennen, welche Bits
nun 1 oder 0 sind. Doof ist halt nur, dass es meist nichts bringt zu
wissen, dass beispielsweise Bis 2 nun auf 1 ist, wenn man keine Ahnung
hat wofür das Bit im Register überhaupt steht.
San Lue schrieb:> Wenn du Regelmässig Programmierst und dir das schreiben der HEX Zahlen> angewöhnst, ist das nichtmehr sonderlich schwer zu erkennen, welche Bits> nun 1 oder 0 sind. Doof ist halt nur, dass es meist nichts bringt zu> wissen, dass beispielsweise Bis 2 nun auf 1 ist, wenn man keine Ahnung> hat wofür das Bit im Register überhaupt steht.
Wie gesagt, ein Konfigurationsregister mit "25" zu initialisieren
macht wohl leserlich wenig Sinn.
Aber einen Zähler mit einem Hex-Wert zu setzen schon, das hat da
nämlich erst mal nichts mit Bits(erkennung) zu tun.
Oliver W. schrieb:> Macht der Compiler aus dem 16Bit-Aufruf 2 8-Bit aufrufe oder unterstützt> der AVR eine 16Bit-Ladefunktion (afaik nein)? Weil wenn 1. der Fall ist,> ist meine Lösung vielleicht nicht die kürzeste, aber doch genau so> Richtig und Schnell.
Ich weiß nicht warum man über die Frage diskutieren muss.
Korrekt ist: Der Controller versteht nur die beiden 8-Bit Zuweisungen
und in Assembler ist man auch dazu gezwungen dies dann so zu machen, wie
Du es gemacht hast. Falsch ist Deine Lösung also nicht
Hintergrundwissen ist immer gut, sonst muss man antworten: Das brauchst
Du nicht zu wissen. ;-)
Gruß
Jobst
Oliver W. schrieb:> ist meine Lösung vielleicht nicht die kürzeste, aber doch genau so> Richtig und Schnell.
Darum gehts überhaupt nicht.
Du hattest 2 Fehler in 2 Anweisungen.
Beide mit der richtigen Schreibweise leicht vermeidbar.
Darum gehts.
Es geht nicht darum, was am µC am schnellsten abläuft. Es geht darum,
wie du dir selbst bei der Programmierung ein Bein stellst und wie man
das vermeiden kann.
Jobst M. schrieb:> Korrekt ist: Der Controller versteht nur die beiden 8-Bit Zuweisungen> und in Assembler ist man auch dazu gezwungen dies dann so zu machen, wie> Du es gemacht hast. Falsch ist Deine Lösung also nicht
Falsch ist sie natürlich nicht, aber trotzdem dumm. Und zwar in Asm
genauso wie in C. Das Problem ist nämlich, daß beim Zugriff auf diese
Pseudo-16Bit-Register oft auch die korrekte Reihenfolge der Zugriffe auf
L- und H-Teil eine Rolle spielt. Deswegen ist es schlau, Makros zu
verwenden, die diese korrekte Reihenfolge der Zugriffe implementieren.
Und zwar in C ganz genauso wie in Asm!
Dazu kommt noch, daß man solche nichtatomaren Zugriffe spätestens dann
atomar gestalten muß, wenn auch ISRs auf diese Register zugreifen. Im
Falle der AVRs ist es sogar noch schlimmer, denn da geraten wegen des
geshareten Hilfsregisters Zugriffe auf jegliche Pseudo-16Bit-Register
eines konkreten Timers in Konflikt. Man ist also nicht auf der sicheren
Seite, wenn die Hauptschleife z.B. nur auf OCR1BH/L zugreift, die ISR
nur auf OCR1AH/L. Die können sich TROTZDEM in's Gehege kommen.
In dieser Gegend des gehobenen Programmierens hilft allerdings der
primitive eingebaute Scheiß der avrlib von C auch nicht weiter. Da muß
man genauso wie in Asm selbst tätig werden und etwas intelligentere
Makros entwerfen und anwenden.
Der Vorteil von Asm ist dann: die Syntax bleibt unverändert, man muß ich
also nicht umgewöhnen. Bei C mit nachgerüsteter Eigenintelligenz muß man
sich hingegen von dieser ach so schicken einfachen Zuweisungssyntax
verabschieden...
> Hintergrundwissen ist immer gut
Jepp. Deswegen ist Asm der bessere Weg. Wenn man weiß, was man tut, kann
man dann ja trotzdem in C programmieren...
Eine eigene Frage?
Dieser Thread ist über 12 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.