Hallo,
Ich habe mal wieder ein Problem, was ich scheinbar nicht selbst gelöst
kriege. Ich bin dabei mir die Drehzahl eines Drehtellers zu ermitteln
(Attiny2313 mit 12mhz-quarz). Der Drehteller hat eine
Schwarz/Weiss-Teilung, welche ich mittels Fototransistor/LED abtaste
(INT0). Während dessen Zähle ich die Abstände der
Impulse(TIMER0-Overflow). Ich benutze ASM und habe das Problem, das die
REGISTER, meinetwegen r19 oder r24, nach einem Interrupt Aufruf, ihre
Werte ändern. Ich kann sie also nicht als Umgebungsvariablen nutzen.
Wenn ich alles mittels sts/lds im SRAM erledige, geht es "soweit" in
Ordnung. Aber ich vermiese mir das ganze Wochenende mit Fehlersuche und
dann finde ich keine Erklärung.
Das Programm ist ursprünglich komplexer und ich musste es, der
Fehlersuchehalber, soweit herunterkürzen. Ein Schrittmotor sollte mir
das tachomäßig anzeigen. Es geht mir hauptsächlich um den Fakt, das sich
die Register ändern. Schon mal Danke für diejenigen die sich das
durchlesen...Muss jetzt zur Arbeit..
Hallo,
wenn Du die Register in einer Interruptroutine benutzt werden sie
natürlich ihren Wert entsprechend ändern.
Wenn sie im Hauptprogramm auch genutzt werden, mußt sie eben in der ISR
mit push / pop sichern.
PS: ich wünsche Dir viel Vergnügen, falls Du in 2 Jahren nochmal in Dein
Programm schaust: keine Kommentare, keine sinnvollen Namen per
Register-Defines usw. usw.
Das geht auch alles in ASM.
Gruß aus Berlin
Michael
Robert V. schrieb:> Ich benutze ASM und habe das Problem, das die> REGISTER, meinetwegen r19 oder r24, nach einem Interrupt Aufruf, ihre> Werte ändern.
Wenn du im Interrupt-Handler R19 veränderst, dann könnte es tatsächlich
vorkommen, dass sich R19 wirklich ändert. ;-)
Robert V. schrieb:> das die> REGISTER, meinetwegen r19 oder r24, nach einem Interrupt Aufruf, ihre> Werte ändern.
Wenn Du im Interrupt Register benutzt und nicht sicherst, sollte klar
sein, daß im Main Unsinn passiert.
In Assembler muß man sich eben um jeden Pipfax selber kümmern.
Nur eine Programmiersprache sichert benutzte Register automatisch.
Peter D. schrieb:> In Assembler muß man sich eben um jeden Pipfax selber kümmern.> Nur eine Programmiersprache sichert benutzte Register automatisch.
Nicht nur benutzte Register, sondern auch unbenutzte, da eine
Prog-sprache meist nicht Überblick eines Assembler-Programmierer hat.
Zwar können Willensstarke auch einem C-Compiler ihren Willen aufzwingen,
aber das ist dann auch wieder "Pipfax um den man sich selbst kümmern
muss, damit es perfekt passt".
Bitwurschtler schrieb:> Nicht nur benutzte Register, sondern auch unbenutzte, da eine> Prog-sprache meist nicht Überblick eines Assembler-Programmierer hat.
Eine Programmiersprache behält immer den Überblick, wo ihn der
Assembler-Frickler schon längst verloren hat. Ich möchte jedenfalls
keine 64kB in Assembler schreiben.
Bitwurschtler schrieb:> Zwar können Willensstarke auch einem C-Compiler ihren Willen aufzwingen
Willensstärke ist völlig unnötig, einfach Unterfunktionen, die in
Interrupts aufgerufen werden, als Inline definieren.
Es gibt bei einigen Compilern aber auch globale Optimierung, d.h. sie
merken sich die Registernutzung von Unterfunktionen und nutzen
Register-Renaming.
Peter D. schrieb:> Bitwurschtler schrieb:>> Nicht nur benutzte Register, sondern auch unbenutzte, da eine>> Prog-sprache meist nicht Überblick eines Assembler-Programmierer hat.>> Eine Programmiersprache behält immer den Überblick, wo ihn der> Assembler-Frickler schon längst verloren hat.
Assembler ist aber auch eine Programmiersprache. Es ist nicht so sehr
die Sprache die den Überblick behält, sondern der Programmierer. Und der
kann das in Assembler genau so gut oder schlecht, wie in jeder beliebige
andere Programmiersprache auch.
OK, der Programmiercode den ich gelistet habe scheint zu undurchsichtig.
So habe ich das Programm noch etwas gekürzt und kommentiert. Und
Assembler sieht, meiner Meinung nach, einfach besser aus. So
funktioniert das Prog schon ein wenig in die Richtung in die ich wollte.
Ich glaube eines meiner Problem liegt auch an der mangelnden
Flankensteilheit.
Die Register besitzen immer nur eine Bedeutung! Sie sollen als
Umgebungsvariablen dienen, was leider nicht funktioniert.
1
.include "2313.inc"
2
rjmp START
3
.org INT0addr
4
rjmp IMPULS
5
6
.org OVF0addr
7
rjmp TIMER
8
reti
9
10
11
12
.cseg
13
SCHRITTE: ;Hier ist die Bitfolge, welche der schrittmotor benötigt
Dir ist bekannt, was ein Status-Register ist, was beispielsweise das
"Zero" Flag ist? Deine Hauptschleife ist von dessen Zustand abhängig,
die darin aufgerufene Anzeigeroutine auch. Deine Interrupt-Handler
verändern jedoch dieses Flag, ohne das Statusregister mit dem Z Flag
darin zu sichern. Das geht in die Hose.
Robert V. schrieb:> OK, der Programmiercode den ich gelistet habe scheint zu undurchsichtig.> So habe ich das Programm noch etwas gekürzt und kommentiert. Und> Assembler sieht, meiner Meinung nach, einfach besser aus. So> funktioniert das Prog schon ein wenig in die Richtung in die ich wollte.> Ich glaube eines meiner Problem liegt auch an der mangelnden> Flankensteilheit.> Die Register besitzen immer nur eine Bedeutung! Sie sollen als> Umgebungsvariablen dienen, was leider nicht funktioniert.
Tun sie NICHT,
R19 benutzt du in beiden Int-Routinen, da brauchst du dich nicht wundern
das sich der Zustand ändert
R22 verwendest du auch in WARTY
Und wie schon erwäht du kannst den Registern ruhig Namen geben - dann
weiß man wenigstens für was die da sind.
Sascha
Robert V. schrieb:> Die Register besitzen immer nur eine Bedeutung! Sie sollen als> Umgebungsvariablen dienen, was leider nicht funktioniert.
Vermutlich liegt hier der wichtige Punkt in Deinem Verständnis.
Ich weiss ja nicht, zu welchem System Du da die Analogie herstellst,
aber es ist vielleicht hilfreich, zumindest vorerst, Register nicht
als Umgebungsvariablen zu betrachten.
Wenn Du an irgendeiner Stelle im Code, ein Register (R0-R31) mit einem
bestimmten Wert lädst, dann behält dieses Register, egal was geschieht
diesen Wert, solange bis sein Inhalt wieder geändert wird.
"Egal was geschieht" gilt insbesondere auch für Interrupt-Routinen. Das
ist hier sinngemäß schon einige Male gesagt worden, aber vielleicht
nicht deutlich genug erklärt.
Betrachte das mal einen Moment lang als nützlich: Wenn Du in einer
Interrupt-Routine ein Register mit einem Wert lädst, z.B. mit dem
zuletzt vom UART empfangenen Byte aus UDR, dann bleibt der da, auch wenn
die ISR verlassen wurde (mit IRET). Das Hauptprogramm kann also dieses
empfangende Byte aus dem Register lesen, weil es immer noch darin ist
. Gut, oder?
Umgekehrt geht das natürlich auch; vom Hauptprogramm zur ISR.
ABER: Wenn Du im Hauptprogramm in dem Register einen wichtigen Wert
hast, der erhalten werden soll UND Du in der ISR, das selbe Register
anderweitig benutzt, dann MUSST Du das Register am Anfang der ISR mit
push auf den Stack sichern (mit STI oder so im RAM speichern geht
prinzipiell auch) und es vor dem verlassen der ISR mit pop wieder
herstellen.
Daran führt kein Weg vorbei.
Vor allem führt auch kein Weg daran vorbei, das Statusregister zu
sichern, wenn im Hauptprogramm damit eine Entscheidung getroffen wird.
Wurde ja auch schon erwähnt.
Gruß
Jobst
danke habe die Register+Statusregister der Interruptroutinen gesichert,
habe diesen Fakt wirklich nicht bedacht.
Ich habe DDRD jetzt mit 0b11111011 gesetzt (das ist mir megapeinlich),
was keinen Unterschied macht..... Schrittmotor welcher an PD0,PD1,..PD3
und PD4 liegt funktionierte vorher auch.
Jetzt scheint alles zu funktionieren.
Jetzt kann ich den Prescaler verringern um die Genauigkeit zu erhöhen
und einen durchschnitt zu bilden.
Des weiteren ist meine Flanke nicht steil genug. Es handelt sich um ein
Zahnkranz, wobei die Stirnflächen der Zähne mit weißer Farbe markiert
worden. Ich beleuchte sie mit einer Weißen LED nebenan der
Fototransistor an Int0. Das krieg ich schon hin.
1000 Dank an euch
> was keinen Unterschied macht...
Es wurden vorher mit 'out PORT...' die internen pull-up-Widerstände ein-
bzw. ausgeschaltet. Wenn das dem Schrittmotortreiber reicht, okay.
Robert V. schrieb:> Des weiteren ist meine Flanke nicht steil genug.
Dafür hat der Tiny2313 den analogen Komparator, dafür solltest du
allerdings PB0 und PB1 nicht anderweitig benutzen.
Danke Leute ihr habt mir viele Arbeitsstunden erspart. Und mit dem
analogen Komperator muss ich mich erstmal auseinander setzten. Kaum zu
glauben, das ich seit 4...5 Jahren AVR's für meine Bastelprojekte
benutze.
MfG
Da Du definitiv sowohl im Hauptprogramm am Status-Register
herumfummelst, als auch in den Unterbrechungsroutinen, kann ein
"Missverständnis" als sicher angenommen werden.
Natürlich bleibt, wie immer, die Frage offen: Wann?
Robert V. schrieb:> Kaum zu> glauben, das ich seit 4...5 Jahren AVR's für meine Bastelprojekte> benutze.
Und Du hast bisher noch nie Interrupts benutzt?
Das saugt man doch schon fast mit der Muttermilch auf, daß alles, was
man im Interrupt zerstört, auch gesichert werden muß.
Es gibt natürlich auch die Möglichkeit, sich einige der 32 Register
exklusiv für Interrupts zu reservieren, d.h. die sind dann für das Main
strengstens tabu. Man sollte dann aber den Registern Namen geben, damit
man nicht den Überblick verliert.
Robert V. schrieb:> Danke Leute ihr habt mir viele Arbeitsstunden erspart. Und mit dem> analogen Komperator muss ich mich erstmal auseinander setzten. Kaum zu> glauben, das ich seit 4...5 Jahren AVR's für meine Bastelprojekte> benutze.
Komperator --> Komparator
AVR's ---> AVRs (www.deppenapostroph.info)
Robert V. schrieb:> Ich werde das gleich *korregieren*
korregieren --> korrigieren