Sehr geehrtes Forum,
ich will mit Assembler auf einem Atmega88 einen Timer verwenden,
um ca jede Sekunde eine LED zum Blinken zu bringen.
Getreut dieses Beitrages:
Beitrag "Timer, aber ohne Interrupt"
Habe ich das ganze in Assembler umgesetzt, in der Praxis sieht das
allerdings so aus, dass die grüne LED permanent leuchtet, ohne dass sich
etwas tut.
Ich habe keinen externen Quarz angeschlossen, und das Fuse "Divide Clock
By 8" ist ja standardmäßig so eingestellt, weswegen der MC einen Takt 1
MHz haben sollte. Ich verwende einen Prescaler für den Timer 0 von 1024.
1
.include "m88def.inc"
2
3
4
/*
5
6
1 LED angeschlossen
7
8
Die Verwendung des Timers soll bewirken, eine LED im 1s Takt zu blinken.
9
10
Taktfrequenz des MC: 1 MHz
11
*/
12
13
.CSEG
14
15
// Richtung der IO Ports definieren
16
LDI R16, 0b11111111 // 1=Output, 0=Input
17
OUT DDRB, R16
18
OUT DDRC, R16
19
OUT DDRD, R16
20
21
// Stackpointer initialisieren
22
LDI R16, low(RAMEND)
23
OUT SPL, R16
24
LDI R16, high(RAMEND)
25
OUT SPH, R16
26
27
// Timer Einstellung initialisieren
28
SBR R16, (1<<CS00) | (1<<CS02) // Prescaler von 1024 einstellen
29
STS TCCR0B, R16
30
31
// Main Methode
32
LDI R17, 0xFF
33
34
MAIN:
35
SBI PORTD, PD0 // LED einschalten
36
// Warten bis 1 Sekunde vergangen
37
RCALL WAIT_A_SECOND
38
39
40
CBI PORTD, PD0 // LED ausschalten
41
// Warten bis 1 Sekunde vergangen
42
RCALL WAIT_A_SECOND
43
RJMP MAIN
44
45
WAIT_A_SECOND:
46
LDI R18, 4
47
LOOP_1_1:
48
STS TCNT0, R17 // Counter resetten
49
LOOP_1: // Warten bis Counter abgelaufen
50
LDS R16, TCNT0
51
CPI R16, 255
52
BRLO LOOP_1
53
DEC R18
54
CPI R18, 0
55
BRNE LOOP_1_1
56
57
// Dauer von 4*(255*1024+4) = 1.044.496 Takten vergangen = 1,04s
58
RET
Kann mir jemand einen Tipp geben, woran es liegt?
Danke für eure Hilfe,
m.f.G.: Developer_X
K. R. schrieb:> LDI R16, high(RAMEND)> OUT SPH, R16>> // Timer Einstellung initialisieren> SBR R16, (1<<CS00) | (1<<CS02) // Prescaler von 1024 einstellen
Da steht bestimmt noch was in r16.
K. R. schrieb:> um ca jede Sekunde eine LED zum Blinken zu bringen.
Soll die LED fortlaufend für eine Sekunde eingeschaltet und für eine
Sekunde ausgeschaltet werden oder
soll sie eine halbe Sekunde ein- und für eine halbe Sekunde
ausgeschaltet werden (und damit jede Sekunde eingeschaltet werden) oder
soll sie jede Sekunde eingeschaltet werden und dann blinken in einer
noch zu bestimmenden Frequenz und Zeit oder ...
> Da steht bestimmt noch was in r16.
Ja, nämlich high(RAMEND), also $04, was dem (1<<CS02) entspricht, es
passt also zufälligerweise.
Das Verfahren in WAIT_A_SECOND taugt nicht. Sie laden TCNT0 mit $FF, und
da bleibt er für bis zu 1024 Takte (je nach Stand des Vorteilers), d.h.
die nachfolgende Abfrage brlo ist fast nie erfüllt.
Von einem Timer sehe ich zwar etwas, aber nichts von einem timer-int
Mach mal ein einfacheres Programm:
;am passenden Platz der int-Einstegsadressen (int-Vektoren) rjmp
timerint angeben.
;initalisierung wie gehabt
;timer int freigeben und sei
main ;main läuft sozusagen leer
rjmp main
timerint: ;diese Routine läuft bei timerint ab.
inc r17
brne timerend ;doppelt geschachtelte Schleife, mit r17 und r18 zur
Verlangsamumg
inc r18
out portd,r18
timerend:
reti
;an port d toggeln dann bei richtig ablaufendem int die bits mit binär
;gestaffelter Stufung und können im Steckaufbau (steckboard) gut
;kontrolliert werden.
Wenn dann der int richtig abläuft, können wir über den zeitmaßstab
reden.
Im übrigen ist es Zeit sich endlich mal mit dem SImulator vertraut zu
machen.
Solche Dinge kann und soll man mit der Simulation debuggen.
Das Programm in Einzelschritten durchgehen und sich in der I/O View die
einzelnen Register ansehen.
Hilfreich ist es dazu, wenn man magische Zahlen dazu erst mal etwas
kleiner macht. Bei einem Vorteiler von 1024 tippt man sich sonst nämlich
einen Ast ab, bis der Timer um 1 weiterzählt. D.h. zum Debuggen im
Simulator wird man da erst mal mit einem Vorteiler von zb 8 reingehen.
(1 ist schlecht, sonst ist es unwahrscheinlich, dass du den Timer
ausgerechnet dann in der Abfrage erwischt, wenn er auf 255 steht)
Aber da musst du durch.
Gerade in der Assembler Programmierung ist der Simulator dein Freund um
rauszufinden, wo du dir wieder mal selbst ein Bein gestellt hast.
Karl H. schrieb:> Hilfreich ist es dazu, wenn man magische Zahlen dazu erst mal etwas> kleiner macht. Bei einem Vorteiler von 1024 tippt man sich sonst nämlich> einen Ast ab, bis der Timer um 1 weiterzählt. D.h. zum Debuggen im> Simulator wird man da erst mal mit einem Vorteiler von zb 8 reingehen.> (1 ist schlecht, sonst ist es unwahrscheinlich, dass du den Timer> ausgerechnet dann in der Abfrage erwischt, wenn er auf 255 steht)
Wobei:
in deinem konkreten Fall ist das sogar ziemlich egal.
Denn 255 (oder eben 0xFF) ist nun mal nicht kleiner als 255
Sowas könnte man im Simulator wunderbar sehen.
S. Landolt schrieb:> Ja, nämlich high(RAMEND),
Aaah, ich war von 0x3FF ausgegangen. Aber der RAM geht ja erst bei 0x100
los.
Ist aber trotzdem ein Befehl, mit dem man sich prima ins Knie schießen
kann. Für's Bitsetzen lieber das 'Original' ORI nehmen (find ich
verständlicher). Bzw. in diesem Fall LDI. Besonders, wenn sich der TO
mit den Hinweisen von Karl Heinz anfreunden kann, dann bleibt die 4
nämlich stehen.
Hi
>die Register von Timer0 sollten mit IN/OUT Befehlen angesprochen werden>und nicht mit LDS/STS Befehlen.
Auch wenn sie, bis auf TIFR1, im erweitertem IO-Bereich liegen?
MfG Spess
Hallo,
Auszug ATMega88 datasheet Seite 21
When using the I/O specific commands IN and
OUT, the I/O addresses 0x00 - 0x3F must be used. When addressing I/O
Registers as data
space using LD and ST instructions, 0x20 must be added to these
addresses.
Auszug ATMega88 datasheet Seite 345 siehe REG.png
Auszug m88def.inc
.equ GPIOR1 = 0x2a
.equ OCR0B = 0x28
.equ OCR0A = 0x27
.equ TCNT0 = 0x26
.equ TCCR0B = 0x25
.equ TCCR0A = 0x24
.equ GTCCR = 0x23
Gemäss Auszug ATMega88 datasheet Seite 21 muss für z.B. TCNT0 = 0x46
benutzt werden, wenn LD oder ST Befehle benutzt werden.
Gruß
gatsby
gatsby schrieb:> die Register von Timer0 sollten mit IN/OUT Befehlen angesprochen werden> und nicht mit LDS/STS Befehlen.
Offensichtlich, denn im Simulator läuft der Zähler nur los, wenn TCCR0B
mit OUT beschrieben wird.
Hallo liebes Forum,
vielen Dank für eure vielen Antworten!
1. Den Debugger habe ich auch schon genutzt, und hab mich immer
gewundert, warum der Timer nicht läuft
2. Genau da lag das Problem, man muss für manche Register IN und OUT
verwenden, und für andere, weil diese außerhalb des Bereichs liegen, LDS
und STS.
Jetzt funktioniert alles bestens :).
1
.include "m88def.inc"
2
3
.CSEG
4
5
// Richtung der IO Ports definieren
6
LDI R16, 0b11111111 // 1=Output, 0=Input
7
OUT DDRB, R16
8
OUT DDRC, R16
9
OUT DDRD, R16
10
11
// Stackpointer initialisieren
12
LDI R16, low(RAMEND)
13
OUT SPL, R16
14
LDI R16, high(RAMEND)
15
OUT SPH, R16
16
17
// Timer Einstellung initialisieren
18
IN R16, TCCR0B
19
SBR R16, (1<<CS00) | (1<<CS02) // Prescaler von 1024 einstellen
20
OUT TCCR0B, R16
21
22
// Main Methode
23
LDI R17, 0x00
24
25
MAIN:
26
SBI PORTD, PD0 // LED einschalten
27
// Warten bis 1 Sekunde vergangen
28
RCALL WAIT_A_SECOND
29
30
31
CBI PORTD, PD0 // LED ausschalten
32
// Warten bis 1 Sekunde vergangen
33
RCALL WAIT_A_SECOND
34
RJMP MAIN
35
36
WAIT_A_SECOND:
37
LDI R18, 4
38
LOOP_1_1:
39
OUT TCNT0, R17 // Counter resetten
40
LOOP_1: // Warten bis Counter abgelaufen
41
IN R16, TCNT0
42
CPI R16, 254
43
BRLO LOOP_1
44
DEC R18
45
CPI R18, 0
46
BRNE LOOP_1_1
47
48
// Dauer von 4*(255*1024+4) = 1.044.496 Takten vergangen = 1,04s
K. R. schrieb:> Hallo liebes Forum,> vielen Dank für eure vielen Antworten!>> 1. Den Debugger habe ich auch schon genutzt, und hab mich immer> gewundert, warum der Timer nicht läuft
Dann hättst du als nächstes im Simulator kontrollieren sollen, ob nach
der Instruktion in den Konfigurationsregistern die von dir für den
Vorteiler angedachten Bits gesetzt sind oder nicht.
Der Simulator mag zwar so manchen Fehler haben, indem das Verhalten von
Subsystemen manchmal nicht ganz dem dokumentierten entspricht, aber das
setzen von Bits in Registern gehört da nicht dazu. Das macht der
zuverlässig.
Na ja.
Jetzt kennst du ja das Fehlerbild und weisst worauf du achten musst.
Wenn ein Timer nicht läuft, dann hat er keinen gesetzten Vorteiler. Beim
nächsten mal kannst du dir dann schon selber helfen
(dein ADC Problem, war im Prinzip von der gleichen Sorte. Eine
Instruktion hat nicht das gemacht was du denkst, dass sie tun sollte.
Draufgekommen wärst du auf genau die gleiche Art und Weise: indem du im
Simulator dir die relevanten Register ansiehst und beim Durchsteppen
kontrollierst, ob alle Bits in der Simulation auch ganz genau so gesetzt
werden, wie du das erwartest. Derartige 'Probleme' werden dich noch
öfter plagen. Also musst du dir selbst beibringen, wie du derartige
Dinge erkennst und nachvllziehst. Auch das gehört zu einem Software
Entwickler. Ich würde sogar soweit gehen und sagen, dass das ein
wesentlicher Punkt ist, von dem sich SW-Entwickler vom Rest der
Menschheit abheben: systematische Problemlösungskompetenz)
Hallo,
nur ein kleiner Schönheitsfehler bei
DEC R18
CPI R18, 0
BRNE LOOP_1_1
Der CPI Befehl ist überflüssig, da der DEC Befehl automatisch das Zero
Flag setzt, wenn die Null erreicht wurde.
Gruß
gatsby
K. R. schrieb:> 2. Genau da lag das Problem, man muss für manche Register IN und OUT> verwenden, und für andere, weil diese außerhalb des Bereichs liegen, LDS> und STS.
Das ist so nur zum Teil richtig. Richtig ist das diese Aussage auf
bestimmte Fälle zutrifft. Auf das TCCR0B Register trifft es nicht zu.
Dein Problem ist es, das Du von dem was Du machst nicht viel verstehst.
Das soll Keine persönliche Diffamierung sein. Denn das ist nicht ein
Problem von dir alleine. Eine typische Krankheit der Internet
Generation. Es ist bequemer sich durch Fragen so gerade eben von einer
Problemlösung zur nächsten zu hangeln.
Ich empfehle einmal ein gutes Buch über die Programmierung von Micro
Controllern an der AVR Reihe in Assembler von Anfang bis Ende zu lesen.
Besonders zu empfehlen das Buch von geschätzten Kollegen Prof. Dr.
Günter Schmitt. Wenn es am Geld mangelt dieses freie Lehrbuch:
http://www.weigu.lu/a/index.html
Zu der Sache mit dem TCCR0B:
Dieses liegt in einem Bereich in dem man sich aussuchen kann mit welchen
Befehlen es sich beschreiben lässt. In der Deffinitionsdatei die Du
verwendest ohne genau zu wissen was dort alles wie definiert wird wird
die Adresse des Registers ohne den ($20) Offset definiert. Dein Code
funktioniert mit
1
IN R16, TCCR0B
2
SBR R16, (1<<CS00) | (1<<CS02) // Prescaler von 1024 einstellen
3
STS (TCCR0B+0x20), R16
ebenso gut wie mit dem out Befehl.
Wenn Du mal ein gutes Buch liest, ohne dich gleich an den PC zu setzen
und los zu programmieren verstehst Du auch was dahinter steckt. Die
Industrie braucht später einmal Leute die ohne Internet und Andere die
einem helfen verstehen was Sie da eigentlich machen
Abgesehen von deinem konkreten Problem würde ich dieses Beispiel das
vermutlich der Übung dient ganz schnell vergessen, denn eine
delay-function die 1000ms nichts anders macht als sich mit sich selbst
zu beschäftigen hat in keinem Programm etwas zu suchen, nicht mal wenn
man seinen Kindern demonstrieren will wie so Computer funktionieren. Und
wenn man schon so einen Mist meint machen zu müssen, dann geht das auch
genau so präzise ohne auch noch einen Timer zu "vergewaltigen". Ausser
um einmalig externe hardware zu initialisieren sind Delay's im Ein-,
oder 2-Stelligen ms Bereich erlaubt. Ansonsten nie. Man brauch sie
nicht, auch nicht um eine LED im Sekundentakt blinken zu lassen.
Thomas H. schrieb:> Dein Problem ist es, das Du von dem was Du machst nicht viel verstehst.> Das soll Keine persönliche Diffamierung sein. Denn das ist nicht ein> Problem von dir alleine. Eine typische Krankheit der Internet> Generation. Es ist bequemer sich durch Fragen so gerade eben von einer> Problemlösung zur nächsten zu hangeln.
Nicht so aggro, jeder hat mal klein angefangen. Daß jemand über die
Problematik STS/LDS bzw IN/OUT stolpert, ist nicht unbedingt ein
Anfängerproblem.
Immerhin hat er sich Mühe gegeben, seinen Code übersichtlich,
vollständig und gut kommentiert zu posten und eine konkrete Frage zu
stellen. Dies zeugt von einer gewissen Lernbereitschaft, die man hier
nicht soo oft findet. Mehr als ein "Geht nicht. Warum?" kommt sonst
selten, also "two thumbs up" von mir dafür.
> abgesehen von deinem konkreten Problem würde ich dieses Beispiel das> vermutlich der Übung dient ganz schnell vergessen, denn eine> delay-function die 1000ms nichts anders macht als sich mit sich selbst> zu beschäftigen hat in keinem Programm etwas zu suchen
Mein Gott, daß ist eine reine Newbie-Übung, die nunmal keinen sinnvollen
Zweck erfüllt, außer auf ganz einfache Weise irgendeine Funktion
rückzumelden, damit der Anfänger ein Erfolgserlebnis hat. Das muß man
nicht so eng sehen, er steht ganz am Anfang und will die Schaltung doch
nicht verkaufen.
A.B. schrieb:
> Register IN und OUT verwenden...
Wenn ich mir nicht ganz sicher bin, schreibe ich erstmal in bzw.
out, ggf. meckert dann der Assembler, und ich korrigiere zu lds
resp. sts. Mag etwas umständlich sein, ist aber sicher.
Ralf G. schrieb:
> Für's Bitsetzen lieber das 'Original' ORI nehmen (find ich> verständlicher).
Das geht mir genauso, sbr bzw. cbr hatte ich mir sehr schnell
abgewöhnt zugunsten von ori resp. andi.
Icke ®. schrieb:> Nicht so aggro, jeder hat mal klein angefangen. Daß jemand über die> Problematik STS/LDS bzw IN/OUT stolpert, ist nicht unbedingt ein> Anfängerproblem.
Was an der sachlichen und ausgesprochenen "nicht diffamierenden"
Aufzählung von Tatsachen aggressiv sin soll, will mir nicht einleuchten.
Ich gehe davon aus das Sie mit dem Ausdruck "aggro" aggressiv meinen.
> Immerhin hat er sich Mühe gegeben, seinen Code übersichtlich,> vollständig und gut kommentiert zu posten und eine konkrete Frage zu> stellen.
Das hat niemand, auch ich nicht in Abrede gestellt.
> Dies zeugt von einer gewissen Lernbereitschaft, die man hier> nicht soo oft findet.> Mehr als ein "Geht nicht. Warum?" kommt sonst> selten, also "two thumbs up" von mir dafür.
Auch eine gewisse Lernbereitschaft habe ich niemandem in Abrede
gestellt. Ihr "Daumen hoch" ist sicher eine nette Geste. Sie sind sicher
ein netter Mansch. Deutschland ist voll davon. Ich gehöre nicht dazu.
Ich bin aber auch nicht aggressiv.
> Mein Gott, daß ist eine reine Newbie-Übung,
Auch wenn ich ihnen nicht zutraue anhand von geschriebenen Text "Gott"
zu erkennen, ohne das er sich ihnen explizit offenbart, so kann ich
trotzdem nicht verhehlen das mich Ihre Anrede in gewisser Weise
schmeichelt.
> die nunmal keinen sinnvollen> Zweck erfüllt,
Das bedarf nun kaum einer Erwähnung!
> außer auf ganz einfache Weise irgendeine Funktion> rückzumelden, damit der Anfänger ein Erfolgserlebnis hat. Das muß man> nicht so eng sehen, er steht ganz am Anfang und will die Schaltung doch> nicht verkaufen.
Nun genau..., eben weil er Anfänger ist und offensichtlich Ihrer
eigenen Feststellung nach über eine.... Zitat: "gewisse
Lernbereitschaft" verfügt mache ich ihn auf die Unsinnigkeit der
Verwendung solcher Delayfunktionen aufmerksam. Vielleicht verhindere
ich, neben der Tatsache jemanden vielleicht zum Nachdenken angeregt zu
haben dadurch eine erneute Frage hier warum denn das neue Projekt
irgendwie seltsam langsam ist...
Für mich ist an dieser Stelle die Diskussion zu diesem Thema beendet.
Thomas H. schrieb:> Nun genau..., eben weil er Anfänger ist und offensichtlich Ihrer> eigenen Feststellung nach über eine.... Zitat: "gewisse> Lernbereitschaft" verfügt mache ich ihn auf die Unsinnigkeit der> Verwendung solcher Delayfunktionen aufmerksam.
Das Problem ist, dass die Alternative noch weit jenseits seines
Kentnisstandes ist. Lass ihn erst mal die ersten Dinge sicher
beherrschen. Dann kann man ihn immer noch zum Timer führen. Irgendwann
kommt das Thema erfahrungsgemäss sowieso auf.
..ich will ja niemanden hindern, ich wollte ihn nur zum nachdenken
Anregen... in der Form "warum schreibt der so was"
Blinken, nicht auf die ms genau und ohne blocken des Programms geht
doch auch ohne Timer in der Form:
1
variable counter = soviel_muss_ich_zaehlen
2
3
MAINLOOP....
4
5
if(!counter)
6
{
7
tue was mit LED
8
counter = soviel_muss_ich_zaehlen
9
}
10
11
decrementiere counter
12
13
tue irgendwas anderes vernuenftiges
14
15
goto ....MAINLOOP
das geht sogar mit 10 LED's in unterschiedlichen Frequenzen simultan,
das mache mal einer mir _delay's ;-)
Und das Vorgehen gibt ein viel besseres Gefühl dafür wie eine
vernünftige Strategie beim Programmieren aussehen sollte...
Thomas H. schrieb:> Was an der sachlichen und ausgesprochenen "nicht diffamierenden"> Aufzählung von Tatsachen aggressiv sin soll, will mir nicht einleuchten.
Nun, diese Aussage...
Thomas H. schrieb:> Eine typische Krankheit der Internet> Generation. Es ist bequemer sich durch Fragen so gerade eben von einer> Problemlösung zur nächsten zu hangeln.
...wirkt schon ein wenig herablassend. Ohne Zweifel gibr es jede Menge
dieser Spezies und genauso viele Threads, wo die Leute nur Code aus
Tutorials kopieren, ohne sich die Mühe des Verstehenwollens zu machen
und dann für jede Programmzeile eine Frage stellen. Aber in diesem
konkreten Fall sehe ich keinen Grund zur Kritik.
> Nun genau..., eben weil er Anfänger ist und offensichtlich Ihrer> eigenen Feststellung nach über eine.... Zitat: "gewisse> Lernbereitschaft" verfügt mache ich ihn auf die Unsinnigkeit der> Verwendung solcher Delayfunktionen aufmerksam.
Im Prinzip schon richtig, aber:
Karl H. schrieb:> Das Problem ist, dass die Alternative noch weit jenseits seines> Kentnisstandes ist.
Wie oft kommen hier Anfänger und wollen sofort Quadrokoptersteuerungen
o.ä. programmieren? Da lautet der Rat: "Laß zunächst eine LED blinken."
Genau dies tut der TE richtigerweise.
...es mag sein, das es sich nicht sehr freundlich anhörte was ich
schrieb. Ich bin aber auch absolut kein freundlicher Mensch. Das muss
man wissen, dann ist es nur halb so schlimm..
Thomas H. schrieb:> ...es mag sein, das es sich nicht sehr freundlich anhörte was ich> schrieb. Ich bin aber auch absolut kein freundlicher Mensch. Das muss> man wissen, dann ist es nur halb so schlimm..
Das schreit nach einem Forumstreffen...
Icke ®. schrieb:> btw, wo ist eigentlich unser Assembler-Hero Moby, wenn er mal gebraucht> wird... =8Pg wollt ich auch schon fragen, hab mich aber net getraut.
Vom Umfang her würds ja passen ;-)