Archiv verlassen und diese Seite im Standarddesign anzeigen : Testroutine für Zählerüberlauf
Hallo,
die Sache sieht so aus: Ein Zähler wird in einer Schleife um den Wert einer Variablen bei jedem Durchlauf verringert. Sobald der Zähler überläuft, muss ich das wissen. Gibts da ein Befehl? ATMega8
Bin ein Anfänger.
SprinterSB
11.01.2007, 21:00
Bei einem Underflow (Unterlauf) wird das Carry gesetzt. Also sollte BCS gehen.
Den Befehl finde ich in der Dokumentation nicht. Wie benutze ich ihn?
SprinterSB
11.01.2007, 23:45
branch on carry set
Der Befehl sollte BRCS heissen.
Eine andere durchaus übliche Art und Weise ist übrigens rückwärts bis Null zu zählen. Der Befehl um das zu prüfen ist ein simples BREQ direkt nach der Subtraktion.
Grüße,
Hanni
Eine andere durchaus übliche Art und Weise ist übrigens rückwärts bis Null zu zählen. Der Befehl um das zu prüfen ist ein simples BREQ direkt nach der Subtraktion.i
Aber wenn das Ergebnis nach der Subtraktion nicht 0 sondern 255 ist? Ich ziehe ja nicht immer 1 ab ...
Ich will die Sache jetzt mit einem Timer lösen. Die Timer in ATMega8 bieten dafür sogar schon Lösungen. Den Tipp habe ich in einem anderen Forum bekommen. Aber ich weiß leider nicht, wie man die Timer konfiguriert. Hier auf roboternetz.de gibts ein Artikel über Timer, doch leider steht nichts drin, wie man das in Assembler löst.
Aber ich weiß leider nicht, wie man die Timer konfiguriert
Schau mal hier (http://www.izaseba.roboterbastler.de/index.php?popup=Tutorial§ion=Lektion10) nach, ich hab da einen Artikel über Timer geschrieben.
Gruß Sebastian
gibts ein Artikel über Timer, doch leider steht nichts drin, wie man das in Assembler löst.
1. im Datenblatt das Kapitel über die Timer raussuchen.
2. die Bits für den gewünschen Modi notieren
3. die entsprechenden Register setzen.
4. fertig ....
Aber ich weiß leider nicht, wie man die Timer konfiguriert
Schau mal hier (http://www.izaseba.roboterbastler.de/index.php?popup=Tutorial§ion=Lektion10) nach, ich hab da einen Artikel über Timer geschrieben.
Gruß Sebastian
Kaum zu glauben, aber ich hatte schon vor, dir eine Mail zu schreiben, dass du eine Tut über Timer machst. =D>
Kaum zu glauben, aber ich hatte schon vor, dir eine Mail zu schreiben, dass du eine Tut über Timer machst.
Tja, geplannt waren Timer sowieso, ich wäre auch gerne weiter damit, aber man hat nicht immer Zeit und Lust weiterzuschreiben....
Ich hoffe, daß Du damit was anfangen kannst, sonst lohnt es sich hin und wieder mal vorbeizuschauen, ob was neues dazugekommen ist :-)
Gruß Sebastian
Irgendwie finde ich im Datenblatt vom ATMega8 kein Interrupr füt Match on Compare vom Timer0. Sagt jetzt bloß nicht, das Timer0 das nicht unterstützt.
Sagt jetzt bloß nicht, das Timer0 das nicht unterstützt.
Tja was soll ich sagen...
Nimm den Timer 2....
Gruß Sebastian
Also das mit dem Match on Compare lasse ich erstmal sein. Ich komme nämlich bei einem kleine Programm nicht weiter. Die LED leuchtet nicht. ;-)
Wo ist da der Fehler?
.include "m8def.inc"
.def temp = r16
.org 0x000
rjmp main
.org 0x009
rjmp timer
main:
ldi temp, LOW(RAMEND)
out SPL, temp
ldi temp, HIGH(RAMEND)
out SPH, temp
sbi DDRD, PD5
sei
loop:
rjmp loop
timer:
sbi PORTD, PD5
reti
Ich wette, dass da irgend ein Flag nicht gesetzt wurde.
.org 0x009
Schreib besser
.org OVF0addr
Ist doch besser zu lesen, oder ?
Ich wette, dass da irgend ein Flag nicht gesetzt wurde.
Damit hättest Du die Wette gewonnen, schau mal im Dattenblatt nach :
TCCR0 ->Prescaller
TIMSK -> Interrupt beim Überlauf freischalten
eventuell
TCNT ->um den Timerwert vorzugeben...
ldi temp, LOW(RAMEND)
out SPL, temp
ldi temp, HIGH(RAMEND)
out SPH, temp
Mach es andersrum, zuerst High und dann LOW schreiben, es gibt da Registerpaare, wo das nicht egal ist!!
Gruß Sebastian
Ich wollte mit SBI TCCR0, CS02 ein Bit in den Register setzen, aber der Compiler meldet: "Out of range".
Mit LDI temp, 0b00000100 und dann OUT TCCR0, temp hat es dann geklappt. Aber jetzt frage ich mich, wie ich einzelne Bits in dem Register manipulieren kann, ohne andere zu beeinflussen?
Noch was:
Ne ganz komische Sache. Beim ersten Überlauf wird der Interrupt aktiviert, alles ok. Der TOV0 Flag wird auch (automatisch) zurückgesetzt und die LED geht an. Beim zweiten Überlauf kommt das Programm aber nicht mehr aus der loop-Schleife und der TOV1 Flag wird zwar gesetzt, aber nicht mehr gelöscht. Auch die Befehle ldi temp, (1<<TOV0) und out TIFR, temp haben da nicht gebracht. Woran liegt das?
Hier der Quellcode:
.include "m8def.inc"
.def temp = r16
.org 0x000
rjmp main ; Reset Handler
.org OVF0addr
rjmp timer ; Timer0 Handler
main:
ldi temp, HIGH(RAMEND)
out SPH, temp
ldi temp, LOW(RAMEND)
out SPL, temp
sbi DDRD, PD5
cbi DDRD, PD2
ldi temp, 0b00000001
out TCCR0, temp
ldi temp, 0b00000001
out TIMSK, temp
sei
loop:
rjmp loop
timer:
sbis PORTD, PD5
rjmp setLED
sbic PORTD, PD5
rjmp clrLED
setLED:
sbi PORTD, PD5
ldi temp, (1<<TOV0)
out TIFR, temp
rjmp loop
clrLED:
cbi PORTD, PD5
ldi temp, (1<<TOV0)
out TIFR, temp
rjmp loop
Ich wollte mit SBI TCCR0, CS02 ein Bit in den Register setzen, aber der Compiler meldet: "Out of range".
Wenn du nur das eine Bit ändern möchtest kannst du es auch so versuchen:
in r16, TCCR0
ori r16, (1<<CS02)
out TCCR0, r16
Noch was:
Ne ganz komische Sache. Beim ersten Überlauf wird der Interrupt aktiviert, alles ok. Der TOV0 Flag wird auch (automatisch) zurückgesetzt und die LED geht an. Beim zweiten Überlauf kommt das Programm aber nicht mehr aus der loop-Schleife und der TOV1 Flag wird zwar gesetzt, aber nicht mehr gelöscht. Auch die Befehle ldi temp, (1<<TOV0) und out TIFR, temp haben da nicht gebracht. Woran liegt das?
Das liegt dadran, das mein eine ISR (und timer ist eine) nicht mit rjmp #label sondern mit reti verlassen wird.
Grüße,
Hanni.
Danke, dann schreib' ich das Programm um.
edit: Habe Schwierigkeiten, das zu realisieren. Bin eben noch sehr unerfahren, was den Stack angeht.
Also ein Flowchart habe ich schonmal angefertigt. Mit dem Quellcode klappt das alleridngs noch nicht.
http://www.cipoint.homepage.t-online.de/roboternetz/blink.jpg
Der uC befindet sich zunächst in einer Endlosschleife. Im Interrupthandler vom Timer0 (Label timer) wird dann mit sbic abgefragt, ob die LED an ist. Wenn nicht, springt der uC zum Label LEDon. Dort wird die LED angemacht. Danach kehrt der uC ja aber wieder zurück zum Label timer. Dort steht leider der Befehl sbis, nach welchem der Sprung zu LEDoff steht.
Wie verhindere ich also, dass der uC nicht nach LEDoff springt, wenn er im selben Durchlauf schon in LEDon war?
edit²: Habe das jetzt so gelöst.
include "m8def.inc"
.def temp = r16
.def oldStatus = r17
.org 0x000
rjmp main ; Reset Handler
.org OVF0addr
rjmp timer ; Timer0 Handler
main:
ldi temp, HIGH(RAMEND)
out SPH, temp
ldi temp, LOW(RAMEND)
out SPL, temp
sbi DDRD, PD5
cbi DDRD, PD2
ldi temp, 0b00000001
out TCCR0, temp
ldi temp, 0b00000001
out TIMSK, temp
sei
cbi PORTD, PD5
loop:
rjmp loop
timer:
sbic PORTD, PD5
rjmp LEDoff
sbi PORTD, PD5
reti
LEDoff:
cbi PORTD, PD5
reti
Ist das programmiertechnisch und stilistisch richtig?
Ist das programmiertechnisch und stilistisch richtig?
Programmiertechnisch schon, über den Stil und die Lesbarkeit kann man sicher streiten.
Anstatt:
ldi temp, 0b00000001
out TCCR0, temp
ldi temp, 0b00000001
out TIMSK, temp
würde ich in dem Teil das folgende schreiben:
ldi temp, (1<<CS00)
out TCCR0, temp
ldi temp, (1<<TOIE0)
out TIMSK, temp
Das ganze ist meiner Ansicht nach vor allem besser lesbar.
Im übrigen sollte man in Interupt Routinen prinzipiell das Status Register SREG sichern. dieses kann z.B. wie folgt erfolgen:
timer:
push temp
in temp, SREG
push temp
sbic PORTD, PD5
rjmp LEDoff
sbi PORTD, PD5
rjmp timer_exit
LEDoff:
cbi PORTD, PD5
timer_exit:
pop temp
out SREG, temp
pop temp
reti
Dieses ist insbesondere dann wichtig, wenn in deinem Loop und in der ISR Operationen durchgeführt werden, bei denen Flags im SREG verändert werden können.
In deinem Programmablaufplan würde ich die Timer Interupt Routine komplett entkoppelt zeichnen. Zum einen, weil der µC nach dem Interupt exakt dort weitermacht, wo er aufgehört hat und zum anderen, weil es später weniger verwirrend wirkt.
Grüße,
Hanni
Ist das programmiertechnisch und stilistisch richtig?
Anstatt:
ldi temp, 0b00000001
out TCCR0, temp
ldi temp, 0b00000001
out TIMSK, temp
würde ich in dem Teil das folgende schreiben:
ldi temp, (1<<CS00)
out TCCR0, temp
ldi temp, (1<<TOIE0)
out TIMSK, temp
Das ganze ist meiner Ansicht nach vor allem besser lesbar.
Aber wenn ich CS00, CS01 und CS02 manipulieren will, und zwar getrennt voneinander? Bleibt mir da nur die Möglichkeit, den kompletten Register auszulesen, mit OR oder AND zu bearbeiten und zurückzuschreiben?
Für I/O Register gibt es ja sbi und sbi. Und für "normale" Register?
Aber wenn ich CS00, CS01 und CS02 manipulieren will
z.B.: ldi temp, (1<<CS00) | (1<<CS01)
zum setzen von 2 Bits.
@izaseba: Zu deinem TutorialII: Ich habe zwar rausbekommen, dass das Programm immer prüft, ob die Register für LedX gleich 0 sind und dementsprechend die Bits in tmp1 für die Ausgänge gesetzt werden. Aber was es mit den Operationen in #setze und #setze1 auf sich hat, bleibt mir ein Rätsel.
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.