Forum: Mikrocontroller und Digitale Elektronik Timer Läuft im Sim - Aber nicht in real?


von Oliver W. (oliver_w49)


Angehängte Dateien:

Lesenswert?

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 :)

: Bearbeitet durch User
von Jobst M. (jobstens-de)


Lesenswert?

Oliver W. schrieb:
> TCCR1B = 0x1D; //CTC Mode und Prescaler 1024

TCCR1B = 0x15; //CTC Mode und Prescaler 1024
TCCR1A = 0


Gruß

Jobst

von Thomas E. (thomase)


Lesenswert?

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.

: Bearbeitet durch User
von Jobst M. (jobstens-de)


Lesenswert?

Thomas Eckmann schrieb:
> Leider völlig falsch. Das andere ist nur ein bisschen falsch.

Komisch. Läuft bei mir so.

von Mike (Gast)


Lesenswert?

Oliver W. schrieb:
> Hardware: ... 16Mhz Quarz
Fuse auch?

von Thomas E. (thomase)


Lesenswert?

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.

: Bearbeitet durch User
von Jobst M. (jobstens-de)


Lesenswert?

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

: Bearbeitet durch User
von Thomas E. (thomase)


Lesenswert?

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.

von Axel S. (a-za-z0-9)


Lesenswert?

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

von aerbabrt (Gast)


Lesenswert?

Dann könnte man sich aber auch nicht stundenlang mit den Timern
beschäftigen :-)

von Эраст Петрович Фандорин (Gast)


Lesenswert?

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

von TriHexagon (Gast)


Lesenswert?

Das Problem hatte ich auch erst kürzlich. Bin mir aber nicht sicher, ob 
es an einem fehlenden sei() gelegen hat oder nicht.

von Oliver W. (oliver_w49)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

Oliver W. schrieb:

> für das OCR1A ist aber nun
>
1
> OCR1AH = 0x06;
2
> OCR1AL = 0x19;
3
>
>
> gleichbedeutend mit
>
>
1
> OCR1A = 0x0619;
2
>

Und das wiederrum ist gleichbedeutend mit
1
  OCR1A = 1563;

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.

: Bearbeitet durch User
von fgqzh35z (Gast)


Lesenswert?

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.

von Oliver W. (oliver_w49)


Lesenswert?

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.

von fgqzh35z (Gast)


Lesenswert?

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?

von Oliver W. (oliver_w49)


Lesenswert?

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 :)

von fgqzh35z (Gast)


Lesenswert?

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...

von Leo C. (rapid)


Lesenswert?

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.
1
leo@cb:/tmp$ cat test16.c
2
#include <avr/io.h>
3
4
int main(void)
5
{
6
  OCR1AH = 0x06;
7
  OCR1AL = 0x19;
8
  
9
  OCR1A = 0x0619;
10
11
  return 0;
12
}
13
14
leo@cb:/tmp$ avr-gcc -mmcu=atmega8 -O2 -S test16.c -o -
15
  .file  "test16.c"
16
__SP_H__ = 0x3e
17
__SP_L__ = 0x3d
18
__SREG__ = 0x3f
19
__tmp_reg__ = 0
20
__zero_reg__ = 1
21
  .section  .text.startup,"ax",@progbits
22
.global  main
23
  .type  main, @function
24
main:
25
/* prologue: function */
26
/* frame size = 0 */
27
/* stack size = 0 */
28
.L__stack_usage = 0
29
  ldi r24,lo8(6)
30
  out 0x2b,r24
31
  ldi r24,lo8(25)
32
  out 0x2a,r24
33
  ldi r24,lo8(25)
34
  ldi r25,lo8(6)
35
  out 0x2a+1,r25
36
  out 0x2a,r24
37
  ldi r24,0
38
  ldi r25,0
39
  ret
40
  .size  main, .-main
41
  .ident  "GCC: (GNU) 4.8.1"
42
leo@cb:/tmp$

von San L. (zwillingsfreunde)


Lesenswert?

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.

von fgqzh35z (Gast)


Lesenswert?

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.

von Jobst M. (jobstens-de)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von c-hater (Gast)


Lesenswert?

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...

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.