wie o.g. suche ich eine Lösung für dieses Projekt. Schlau gemacht habe ich mich im Tutorial "Entprellen" und den vielen Threads. Es läuft immer wieder auf internes Interrupt hinaus. Da ich das realisieren könnte, habe ich den vielen Profis im Forum zu verdanken. Das ist nicht das Problem! Aber...ich wollte eigentlich eine ISR für eine andere Anwendung im gleichen Quellcode verwenden. Ist es denn möglich, 2 Interrupts zu realisieren? Oder gäbe es evtl. ein Befehl wie "Wait" in Bascom um eine Zeitverzögerung einzubauen? Grüße Rolf
Gast
#2488440
Hi >Es läuft immer wieder auf internes Interrupt hinaus. Nein. http://www.mikrocontroller.net/articles/AVR-Tutorial:_Tasten MfG Spess
Rolf Hegewald schrieb: > Aber...ich wollte eigentlich eine ISR für eine andere Anwendung > im gleichen Quellcode verwenden. > Ist es denn möglich, 2 Interrupts zu realisieren? Niemand schreibt vor, dass eine Timer-Interrupt Routine nur eine Aufgabe erfüllen darf. Entprellen ist insofern anspruchslos, als es nicht besonders zeitkritisch ist. Ob der Entprellcode alle 4 oder alle 40ms ausgeführt wird, spielt keine wirklich große Rolle. D.h. beim Timing, wie oft bzw. in welchen Zeitabständen die ISR aufgerufen wird, orientierst du dich erst mal an deiner anderen Anwendung. Und dann rechnest du dir aus, nach dem wievielten Mal des ISR-Aufrufs dann auch wieder die Portpins zum Entprellen abgefragt werden, damit du so ungefähr in das benötigte Zeitfenster zum Entprellen kommst. Dieses Zeitfenster ist groß genug, dass man es praktisch immer ohne Probleme schafft, da rein zukommen.
Taster-Entprellung am Tiny13 in Assembler Hier müsstest Du ein Beispiel in verschiedenen Varianten finden, das auf PeDas Entprellalgorithmus basiert. Es ist zwar für den Tiny15 geschrieben, da es den Tiny13 damals noch nicht gab. Die Tastenentprellung läuft auch auf em Tiny13, das ganze Programm allerdings nicht. http://www.hanneslux.de/avr/divers/melody/melody01.html ...
oh..weia! hatte nicht mit so viel Aufwand gerechnet. zu spess: wieso schreibst Du "nein" ist ja doch mit Interrupt. Aber es schadet nicht neue Befehle wie mov und andere kennen zulernen. Ich weiß nur aus der Franziszeit mit Bascom, daß die Leute eine simple einfache Routiene mit ihren Wait20 Befehl realisierten. Erst mal ein Dankeschön Rolf
he Leute,
bin mit meiner Entprellerei schon weiter gekommen.
Stehe aber jetzt vor einer Routiene, bei der mir das
Tutorial oder Datenblatt nicht weiter helfen kann.
Also, wenn ich vorgebe:
pause: ldi r17,0b11110000
warte: dec r17
sbrc r17
rjmp warte
ret
kommt error: Wrong number of operands (falsche Anzahl v. Operanden).
Der Operand ist doch 3xr17 und warte.
gebe ich vor
pause: ldi r17,0b11110000
warte: dec r17
tst r17
brne warte
ret
ist die Welt in Ordnung
mh... wo steckt bei mir der Überlegungsfehler.
Dachte schon dieses 3xr17 hintereinander verträgt sich nicht,
aber kann doch nicht sein!
Dieses Wrong xxxx habe ich nun schon oft erlebt!
Grüße
Rolf
Gast
#2492603
Hi >Der Operand ist doch 3xr17 und warte. SBRC (Skip if Bit in Register is Cleared) braucht 2 Argumente: Das Register und die Bitnummer -> sbrc r17,3 . >warte: dec r17 > tst r17 > brne warte Das tst r17 kannst du dir sparen da das Z-Flag schon durch dec r17 gesetzt wird. MfG Spess
> Ich weiß nur aus der Franziszeit mit Bascom, daß die Leute > eine simple einfache Routiene mit ihren Wait20 Befehl realisierten. Und genau so hat die dann auch funktioniert: simpel und einfach und im Extremfall gar nicht. > hatte nicht mit so viel Aufwand gerechnet. Alles eine Frage der Sichtweise. Für das Gebotene finde ich den Aufwand sogar erstaunlich gering.
danke für Eure Antworten! Spess...werde ich heute noch austesten! Hast Recht..Karl Heinz, deshalb habe ich das Bascom schnellstens wieder verlassen. Jahre liegt es zurück, als ich mit den Pics rumgefummelt habe und einen guten Lehrherr zur Seite hatte...ich meine, er hieß Thomas Ehlers und da lief auch alles in Assembler. Grüße Rolf
Rolf Hegewald schrieb: > Aber...ich wollte eigentlich eine ISR für eine andere Anwendung > im gleichen Quellcode verwenden. Was soll es den überhaupt mal werden? Ich frage deshalb, weil man viele Dinge, die eine Zeitbasis benötigen, ganz gut mit der PeDa-Tastenentprellung kombinieren kann. ...
Hallo Hannes, da ich viele Ideen mit einer Modelleisenbahn (H0) habe, interessiert mich das Thema. Hier werden oft Taster-Umschaltungen, z.B. für Weichen, Signale usw. benötigt. Aber was ist denn "PeDa-Tastenentprellung" noch nie gehört. Aber bitte keine Basic-Befehle...nur in Assembler! Grüße Rolf
Rolf Hegewald schrieb: > Hallo Hannes, > da ich viele Ideen mit einer Modelleisenbahn (H0) habe, > interessiert mich das Thema. > Hier werden oft Taster-Umschaltungen, z.B. für Weichen, Signale usw. > benötigt. > Aber was ist denn "PeDa-Tastenentprellung" noch nie gehört. PeDa steh für "Peter Dannegger". Er hat diese Entprellung vor Jahren hier gepostet und sie hat sich zur Standardlösung entwickelt, wenn man Tasten behandeln möchte. Sie braucht fast keine Resourcen und funktioniert erstklassig. Wenn nur mehr Profis in den Firmen da draussen diese Entprellung benutzen würden, die Welt wäre eine bessere und man müsste sich nicht mehr mit nicht oder nur halb funktionierenden Tasten auf diversen Fernsteuerungen, Liftaufzügen, Automaten etc. rumärgern. > Aber bitte keine Basic-Befehle...nur in Assembler! Du hast sie beim Hannes im Code gesehen? Im Kern besteht sie aus einem Teil, der in eine Timer-Interrupt Routine hineinkommt. In welchen Zeitabständen diese Interrupt Routine aufgerufen wird ist ziemlich unkritisch. Von ca 4ms bis ca 40ms ist alles möglich. Hier ist dieser Kern in dem von Hannes verlinkten Code
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
dieser Code wird vom Timer Interrupt alle paar Millisekunden abgearbeitet und erledigt das Einlesen und Entprellen von bis zu 8 Tastern an einem Eingangsport. Der Timer muss dazu natürlich initialisiert werden, so dass er die entsprechenden Interrupts auslöst. Dazu muss man noch wissen, wie man dann die Tasten tatsächlich abfrägt, die dieser Code als gedrückt identifiziert. Und das geht so (wieder aus dem Code von Hannes)
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
also alles in allem eine sehr einfache Sache. Mach dir um den Code in der ISR keine Gedanken. Der ist trickreich und nicht leicht zu verstehen. Macht aber nichts, den kannst du einfach so übernehmen. Du musst nur die Konstanten entsprechend anpassen.
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
und für die benutzten Register Assignments machen
1 | |
2 | |
3 | |
4 | |
(und das was jetzt noch alles fehlt, findet sich ebenfalls in Hannes Code) Und das Original findet sich hier Entprellung
Karl Heinz Buchegger schrieb: > ;Definition der Bits, die die 4 Taster repräsentieren: > .equ t1=pb0 ;Taster 1 > .equ t2=pb2 ;Taster 1 > .equ t3=pb3 ;Taster 1 > .equ t4=pb4 ;Taster 1 Aua, muss man das erst zitiert bekommen, damit man sowas merkt??? Das sollte natürlich nicht alles Taster 1 sein... Karl Heinz Buchegger schrieb: > Und das Original findet sich hier > Entprellung Zu der Zeit, als ich das Bimmel-Programm schrieb, allerdings noch nicht. Ich hatte die Infos von hier: Beitrag "Tasten entprellen - Bulletproof" Rolf Hegewald schrieb: > Hier werden oft Taster-Umschaltungen, z.B. für Weichen, Signale usw. > benötigt. Naja, ich frug nach, um Dir evtl. ein Programm für den Tiny13 zu schreiben, das Zeitbasis und Tastenentprellung enthält und das Du als "Rohling" für eigene Versuche und Implementierungen verwenden kannst. Rolf Hegewald schrieb: > da ich viele Ideen mit einer Modelleisenbahn (H0) habe, > interessiert mich das Thema. Da hänge ich Dir doch gleich mal eine drei Jahre alte Spielerei mit dem Mega8 an. Es realisiert eine Schranke der DR aus Erichs Zeiten. Auch da ist Peters Tastenentprellung drin, allerdings etwas modifiziert. Der DCC-Decoder war mal geplant wurde aber bisher noch nicht implementiert. ...
Hier mal noch ein kleines Progrämmchen für den Tiny13. Es hat allerdings keine Tastenentprellung, sondern steuert anhand eines Logikpegels ein Modellbauservo. Je nachdem ob H oder L anliegt, wird das Servo in eine der beiden per Poti einstellbaren Positionen gefahren. Es dient zum Steuern des Entkupplerservos von akkubetriebenen Gartenbahn-Lokomoteufelchen. ...
Hallo Hannes, zu meiner Schande muß ich gestehen, daß ich nach PeDa gefragt habe, und seit dem 6. Januar daran arbeite bzw. es zu verstehen versuche. Ich hatte an dem Tag die Qelldatei gleich runter gezogen. Die vielen .def, .equ, und die Schaufelei in der ISR haben mich erst mal umgehauen. Versuchte auch zu ergründen, warum in der ISR get8key: steht. Nehme es erst mal so hin. Hab das ganze auf den Tiny13 gebusselt und hänge noch an error: Wrong number of operands. Aber Spess hatte mir schon Tips gegeben, das kriege ich raus. Ein Mega8 bedient hier einen Schwenkkran der Fa. Märklin der ca. 20 Jahre alt ist. Das ganze noch mit Bascom geschrieben. Ein Atari MEGA1 aus dem Jahre 1983 bedient seit 1993 die Eisenbahnanlage. Linksseitig verfügt er über eine Schnittstelle, auf dessen Leitungen im Multiplexverfahren die Adresse bzw. die Daten liegen. Die Auswertung über von mir erstelltes Interface war die Wahnsinnsarbeit. Alle Signale, Weichen, Schranke, Drehscheibe Fahrstufen werden mit Hilfe von erstellten Proceduren über das alte GFA-Basic erzeugt. Über manche "IF/ELSE/ENDIF" Schleife habe ich graue Haare bekommen. So, das wars erst mal, der Tag könnte 48 Stunden haben. Grüße Rolf
Gast
#2494088
Hi
>Aber Spess hatte mir schon Tips gegeben, das kriege ich raus.
Der Tip war aber nur auf den Syntax des Befehls bezogen. Für eine
Warteschleife ist SBRC ungeeignet bzw. nur sehr bedingt geeignet.
MfG Spess
Rolf Hegewald schrieb: > Hallo Hannes, > zu meiner Schande muß ich gestehen, daß ich nach PeDa gefragt habe, > und seit dem 6. Januar daran arbeite bzw. es zu verstehen versuche. > Ich hatte an dem Tag die Qelldatei gleich runter gezogen. > Die vielen .def, .equ, Das sind doch nur Alias-Namen, die den Code übersichtlicher und verständlicher machen (sollen). Mit .def tauft man egister, mit .equ kreiert man Konstanten. > und die Schaufelei in der ISR haben mich Welche Schaufelei?? Da werden einfach nur 8 Zweibit-Zähler (als Entprell-Zähler für jede der 8 Tasten separat) gleichzeitig und unabhängig voneinander behandelt. Dies dient dazu, einen Pegelwechsel erst dann "durchzulassen", wenn er 4 mal hintereinander erkannt wurde. Damit wird sowohl das Betätigen, als auch das Loslassen der Tasten nur dann akzeptiert, wenn der neue Pegel (Zustand) 4 Runden hintereinander identisch war. > erst mal umgehauen. > Versuchte auch zu ergründen, warum in der ISR > get8key: > steht. Nehme es erst mal so hin. Das ist ein Label. Also ein Name für die Adresse, an der der Code steht. Das ermöglicht dem Programmierer, die Routine mit ihrem Namen aufzurufen, ohne die genaue Adresse zu kennen. Der Befehl "RJMP get8key" setzt den Programmcounter dann auf die Adresse, an der das Label steht. Oftmals vergibt man auch Labels, die gar nicht als Sprungziel gebraucht werden, Hintergrund ist die Erhöhung der Lesbarkeit. > Hab das ganze auf den Tiny13 gebusselt und hänge noch an > error: Wrong number of operands. Nunja, Du wolltest einen Skip-Befehl zum Rechnen missbrauchen. Und der wehrt sich nun. Der Skip-Befehl überspringt den nächsten Befehl, wenn die Bedingung wahr ist, also im Byte xy das Bit z den richtigen Wert hat. Dies braucht 2 Parameter. Du wolltest aber damit subtrahieren oder vermindern und hast nur einen Parameter (r17) angegeben. Das wird also nix. Ich empfehle Dir, Dir aus dem Datenblatt die Tabelle "Instruction Set Summary" auszudrucken und diese als Arbeitsblatt zu benutzen. Gleiches gilt für die Tabelle mit den I/O-Adressen und deren Namen für die Bytes und Bits. Das ist für den Einstieg eine sehr gute Hilfe und schützt vor Schreibfehlern. > Aber Spess hatte mir schon Tips gegeben, das kriege ich raus. Ja klar... Noch'n Tip: In AVR-Studio mal die F1-Taste drücken, wenn der Cursor auf einem ASM-Befehl steht. > Ein Mega8 bedient hier einen Schwenkkran der Fa. Märklin > der ca. 20 Jahre alt ist. > Das ganze noch mit Bascom geschrieben. Ja warum nicht? > Ein Atari MEGA1 aus dem Jahre 1983 bedient seit 1993 > die Eisenbahnanlage. Einem Commodore Plus/4 aus derselben Epoche habe ich 1991 mal beigebracht, die Fräsmaschine eines Feinmechanikers und Großuhrmachers (Turmuhren) zu steuern. > Linksseitig verfügt er über eine Schnittstelle, > auf dessen Leitungen im Multiplexverfahren die Adresse bzw. > die Daten liegen. Die Auswertung über von mir erstelltes Interface > war die Wahnsinnsarbeit. Ich habe sowas ähnliches mal für Pauls PC gemacht: http://www.hanneslux.de/mobast/index.html Ist aber schon etwas neuer... > Alle Signale, Weichen, Schranke, Drehscheibe Fahrstufen werden > mit Hilfe von erstellten Proceduren über das alte GFA-Basic erzeugt. > Über manche "IF/ELSE/ENDIF" Schleife habe ich graue Haare bekommen. Ich bekomme graue Haare, wenn man "If/Else/Elseif/Endif" als Schleife bezeichnet, das ist nämlich keine Schleife, sondern eine Verzweigung. :-)) > > So, das wars erst mal, der Tag könnte 48 Stunden haben. Und dann müsste man auch noch Frühstück und Mittag durchmachen... > > Grüße > > Rolf ...
> Hab das ganze auf den Tiny13 gebusselt und hänge noch > an error: Wrong number of operands. Was. Etwa immer noch? Dazu brauchst du in erster Linie keinen Tip, sondern einen Druck auf F1, wenn der Cursor im AVR-Studio auf dem angemeckerten Befehl steht. Dann kommt die Hilfe hoch, praktischerweise genau zu dem Befehl über dem der Cursor steht (und der die Fehlermeldung ausgelöst hat), und dann sieht man in der Hilfe: sbrc benötigt 2 Argumente. Ist ja auch irgendwie logisch. Der Befehl heißt in Longform "Skip if Bit in Register is Cleared", also in etwa "Überspringe (den nächsten Befehl) wenn ein bestimmtes Bit in einem bestimmten Register den Wert 0 hat". Was also wird der Befehl für Angaben benötigen? Einfach: welches Bit in welchem Register. Bei dir steht sbrc r17 die Frage "welches Register" ist damit beantwortet: r17. Aber welches Bit soll denn getestet werden? Diese Angabe fehlt. Und genau darüber meckert die Fehlermeldung "Wrong number of Arguments" - "Falsche Anzahl an Argumenten". Für SBRC sind 2 Angaben notwendig, du hast nur 1. Jetzt gibt es 2 Möglichkeiten * entweder der SBRC ist überhaupt schon mal der falsche Befehl dazu muss man sich die Logik an der Stelle ansehen und entscheiden was an dieser Stelle eigentlich höchst wahrscheinlich passieren sollte. Dann kann man entscheiden ob der SBRC zb einfach nur ein Tippfehler war und eigentlich ein ganz anderer Befehl hätte sein sollen * oder der SBRC ist grundsätzlich schon richtig, nur ist eben eine der notwendigen Angaben nicht gemacht worden.
Rolf Hegewald schrieb: > da ich viele Ideen mit einer Modelleisenbahn (H0) habe, > interessiert mich das Thema. > Hier werden oft Taster-Umschaltungen, z.B. für Weichen, Signale usw. > benötigt. > ... > Aber bitte keine Basic-Befehle...nur in Assembler! Ja, nur Assembler, ist mir auch lieber als Basic, zumindest auf dem AVR und besonders dann, wenn es zeitkritisch wird und Interrupts im Spiel sind. Ich habe Dir mal PeDas Tastenentprellung in ein Tiny13-Programm eingebaut. Da Du keine konkrete Anwendung genannt hast, habe ich die Servosteuerung drin gelassen. Das Servo wird jetzt durch zwei Taster hin und her bewegt, wobei beide Positionen per Poti einstellbar sind. Das Programm soll Dir erstmal zur Analyse dienen und bei der Einarbeitung in AVR-ASM helfen. ...
Hallo Hannes,
ich habe mich erst mal auf eine Taste am Tiny13 konzentriert.
D.h. erst mal einfach anfangen.
Das ganze sieht so aus:
; Projekttiny13
; Datei: debbug02.asm ;Datum: 12.01.2012
; PORTB,Pb0: Ausgang PINB,PB0
; PORTB,Pb3: Eingang
;AVR: Tiny 13
.INCLUDE "tn13def.inc" ; Deklarationen für Tiny13
.EQU takt = 1000000 ; Systemtakt 1 MHz
.DEF akku = r16 ; r16 in akku benannt
rjmp start ; Reset-Einsprung
.ORG OVF0addr ;Interrupt-Vektor
rjmp TIM0_OVF ;Sprung zur ISR
start: ldi akku,LOW(RAMEND); Stapel anlegen
out SPL,akku ;
ldi akku,0b00000001 ; Bitmuster 0000 0001
out DDRB,akku ; PortB,PB0 ist Ausgang
ldi akku,0b11111110 ; PB1-PB7 = PULLUP
out PORTB,akku
;Timer0 initialis.
ldi akku,1<<CS01|1<<CS00 ;Timer mit Vorteiler 64
out TCCR0B,akku
ldi akku,1<<TOIE0 ;Timer Overflow Interrupt
out TIMSK0,akku
sei ; und los gehts: Timer frei
loop: nop
ein: sbic PINB,3 ;sbic, springe wenn PINB,B3=LOW
rjmp ein
ldi akku,1 ; Bitmuster 0000 0001
out PORTB,akku ; PB0 = HIGH
rcall pause
aus: sbic PINB,3
rjmp aus
ldi akku,0
out PORTB,akku ; PB0 = LOW
rcall pause
rjmp loop
pause: ldi r17,0b00111111
warte: tst r17
brne warte ;springe zu warte,wenn r17 kein Null
ret
;Interrupt_ISR
TIM0_OVF: push r16 ; Timer0 Overflow
in r16,SREG
push r16
dec r17
pop r16
out SREG,r16
pop r16
reti
Nun kommt etwas eigenartiges.
Nach anstecken der Vcc wartet der Tiny
in der Abfrage
sbic PINB,3 die LED an PB0 bleibt dunkel.
Drücke ich die Taste, leuchtet die LED und fängt an zu blinken.
Vcc wieder entfernt und PB3 extern mit 10K gegen Vcc belegt,
mh.. dann ist die Welt in Ordnung.
D.h. die LED läßt sich über die Taste sauber EIN/AUSschalten.
Ich habe das Tutorial über Pullup-Widerstand studiert.
Da ging man natürlich von PORTB und PORTD aus, was der Tiny13 nun
mal nicht hat.
Ich kann mir das mit meiner Pullup Konfiguration nicht erklären.
Wo liegt bei mir der Denkfehler?
Grüße
Rolf
Rolf Hegewald schrieb: > Hallo Hannes, Hallo Rolf... > ich habe mich erst mal auf eine Taste am Tiny13 konzentriert. Ob eine Taste oder bis zu 8 Tasten, das ist beim Entprellen kein Unterschied. Ein Byte hat 8 Bit, somit können 8 Tasten gleichzeitig behandelt werden wenn man es richtig macht. > D.h. erst mal einfach anfangen. > Das ganze sieht so aus: > > ; Projekttiny13 > > ; Datei: debbug02.asm ;Datum: 12.01.2012 > > ; PORTB,Pb0: Ausgang PINB,PB0 > ; PORTB,Pb3: Eingang > > > ;AVR: Tiny 13 > > .INCLUDE "tn13def.inc" ; Deklarationen für Tiny13 > .EQU takt = 1000000 ; Systemtakt 1 MHz Der Tiny13 kann nicht mit 1 MHz laufen, schau mal ins Datenblatt unter Clock Sources. Ab Werk läuft sein Oszillator mit 9,6 MHz, der Systemtakt-Vorteiler (CLKPR) ist durch die aktive CLKDIV8-Fuse auf 1 zu 8 voreingestellt, wodurch ein neuer Tiny13 mit 1,2 MHz arbeitet. > .DEF akku = r16 ; r16 in akku benannt Ich bin eigentlich froh, dass die AVRs 32 Register haben und möchte daher ungern an Akku, X und Y erinnert werden... ;-)) > > > rjmp start ; Reset-Einsprung > .ORG OVF0addr ;Interrupt-Vektor > rjmp TIM0_OVF ;Sprung zur ISR Ich mag diese Darstellung nicht, ich halte das Kopieren der kompletten Interrupt-Sprungtabelle für übersichtlicher. Das ist aber Geschmacksache. > > > > start: ldi akku,LOW(RAMEND); Stapel anlegen > out SPL,akku ; Das macht der Tiny13 beim Reset selbst, siehe Datenblatt oder meinen Beispiel. > ldi akku,0b00000001 ; Bitmuster 0000 0001 > out DDRB,akku ; PortB,PB0 ist Ausgang > ldi akku,0b11111110 ; PB1-PB7 = PULLUP > out PORTB,akku > > ;Timer0 initialis. > ldi akku,1<<CS01|1<<CS00 ;Timer mit Vorteiler 64 > out TCCR0B,akku > ldi akku,1<<TOIE0 ;Timer Overflow Interrupt > out TIMSK0,akku > sei ; und los gehts: Timer frei Jou stimmt... > > loop: nop Warum NOP?? > ein: sbic PINB,3 ;sbic, springe wenn PINB,B3=LOW > rjmp ein > ldi akku,1 ; Bitmuster 0000 0001 > out PORTB,akku ; PB0 = HIGH Und schon sind alle PullUp-Widerstände aus, weil Du Nullen reingeschrieben hast... > rcall pause > > aus: sbic PINB,3 > rjmp aus > ldi akku,0 > out PORTB,akku ; PB0 = LOW Und hier werden die PullUps auch deaktiviert. > rcall pause > rjmp loop > > pause: ldi r17,0b00111111 Worin liegt der Sinn, den Vorladewert eines Timeout-Zählers binär anzugeben? Mit dezimaler Eingabe sähe es zwar nicht so wissenschaftlich aus, wäre aber viel besser lesbar und viel verständlicher. > warte: tst r17 > brne warte ;springe zu warte,wenn r17 kein Null > ret Kann man machen, ist aber nicht der Sinn des Timers beim Entprellen von Tasten. > > ;Interrupt_ISR > TIM0_OVF: push r16 ; Timer0 Overflow > in r16,SREG > push r16 > dec r17 > pop r16 > out SREG,r16 > pop r16 > reti Warum machst Du das so? Der AVR hat 32 Register, da kann man es sich leisten, die Register, die in der Mainloop verwenet werden, in Ruhe zu lassen. Selbst zum Sichern des SREG kann man ein Exklusivregister vereinbaren. Die ganze Push-Pop-Orgie ist hier (in diesem Zusammenhang) Unsinn. > Nun kommt etwas eigenartiges. > Nach anstecken der Vcc wartet der Tiny > in der Abfrage > sbic PINB,3 die LED an PB0 bleibt dunkel. > Drücke ich die Taste, leuchtet die LED und fängt an zu blinken. > > Vcc wieder entfernt und PB3 extern mit 10K gegen Vcc belegt, > mh.. dann ist die Welt in Ordnung. Ha sicher, das hast Du doch auch so programmiert. Wenn Du den internen PullUp abschaltest, dann kann er halt nur ein mal wirken... Der AVR hat wunderbare Befehle zum Setzen und Löschen einzelner Bits in einem Teil des I/O-Bereiches (in dem auch die Ports liegen). SBI und CBI sind Deine Freunde. Das bringt Dir aber nicht viel, denn Dein Konzept ist sehr gewöhnungsbedürftig und alles Andere als optimal. Ich gehe mal davon aus, dass Du mein Beispiel der Tastenentprellung mit Tiny13 nicht gelesen hast. Naja, schade um die Arbeit bzw. Zeit. > D.h. die LED läßt sich über die Taste sauber EIN/AUSschalten. > Ich habe das Tutorial über Pullup-Widerstand studiert. > Da ging man natürlich von PORTB und PORTD aus, was der Tiny13 nun > mal nicht hat. > Ich kann mir das mit meiner Pullup Konfiguration nicht erklären. > Wo liegt bei mir der Denkfehler? Vermutlich im Übersehen der Doppelfunktion des Port-Registers. Ist der Portpin Eingang, dann wirkt PORTB auf die PullUp-Widerstände (1 eingeschaltet, 0 ausgeschaltet). Ist der Port Ausgang (mit DDRB eingestellt), dann wirkt PORTB auf den Ausgangspegel. Und willst Du den von außen angelegten Zustand der Portpins erfassen, dann musst Du PINB einlesen. Jeder Port hat also 3 Register, DDRx, PORTx und PINx... > > Grüße > > Rolf ...
Hannes Lux schrieb: > Ich mag diese Darstellung nicht, ich halte das Kopieren der kompletten > Interrupt-Sprungtabelle für übersichtlicher. Das ist aber > Geschmacksache. Dann sollte man aber auch einen bad-isr-handler aufsetzen, der zeigt, daß ein Interrupt ohne Handler aufgerufen wird. Und dann sollte man trotzdem jedesmal ein .org machen, damit die Adresse stimmt. Peter
Peter Dannegger schrieb: > Dann sollte man aber auch einen bad-isr-handler aufsetzen, der zeigt, > daß ein Interrupt ohne Handler aufgerufen wird. Mach' ich doch auch schon geraume Zeit, zumindest als definierten Punkt wo sich das Programm aufhängen soll. Während des Debuggens wird da bei Problemen auch mal eine LED eingeschaltet. Die Zeit der RETIs in der Sprungtabelle ist schon lange vorbei. > Und dann sollte man trotzdem jedesmal ein .org machen, damit die Adresse > stimmt. Da bin ich kein Freund von, denn die Gefahr, die reservierten Namen falsch zu schreiben ist (bei mir!!) größer als die komplette Tabelle fehlerhaft zu kopieren. Ich kopiere die Tabelle für jeden benutzten Typ einmalig aus dem Datenblatt, passe sie an und speichere sie zur Wiederverwendung in einer Textdatei. Aber ich muss ja nicht für einen Arbeitgeber programmieren, sondern nur für eigene kleine Basteleien. Daher muss ich nicht unbedingt alles nachmachen, was Profis für sinnvoll halten oder was ihnen vorgeschrieben wird. Profis programmieren auch in C, und da komme ich nun gar nicht ran... Gruß nach Bln. ...
Hallo Hannes, für Deine vielen Hinweise erst mal meinen Dank. Es fiel mir wie Schuppen von den Augen, als ich erkannte, was ich mit den PortB anstelle. Stimmt nicht, wenn Du schreibst, ich hätte das mit den 8 Tasten nicht durchgelesen "Schade um die Zeit"! Habe es ausgedruckt, es liegt hier vor mir und versuche es Stück für Stück zu verarbeiten, bzw. es an einen Tiny2313 anzupassen. Aber da sind ja auch jede Menge Registerbezeichnungen drinnen (für r1-r5, r16,r17) ...ich denke, Du magst das nicht, oder habe ich was falsch gelesen? Ich bin immer noch Anfänger, bedenke das, mein Alter möchte ich garnicht erwähnen. So, ich komme drauf zurück, in einer Stunde will ich zum Hubschrauberfliegen in einer Turnhalle. Grüße Rolf Vor mir liegen BL-Regler (wenn Dir das was sagt) mit zwei AVR drauf, von den ich 15 Stück mit SMD1206 bzw. 0805 erstellt habe. Die Atmel waren natürlich von einen Österreicher programmiert worden. Will mich nicht mit fremden Federn schmücken.
Rolf Hegewald schrieb: > Hallo Hannes, > für Deine vielen Hinweise erst mal meinen Dank. > Es fiel mir wie Schuppen von den Augen, als ich erkannte, > was ich mit den PortB anstelle. Gut. > Stimmt nicht, wenn Du schreibst, ich hätte das mit den 8 Tasten > nicht durchgelesen "Schade um die Zeit"! > Habe es ausgedruckt, es liegt hier vor mir und versuche es Stück > für Stück zu verarbeiten, bzw. es an einen Tiny2313 anzupassen. Tastenentprellung frei nach PeDa auf dem Tiny2313 ist im Anhang. Natürlich ist die Entprellung kein Selbstzweck, das Programm macht natürlich noch ein paar andere Dinge. Die Entprellung wird also nur so nebenbei mit erledigt. > Aber da sind ja auch jede Menge Registerbezeichnungen drinnen > (für r1-r5, r16,r17) ...ich denke, Du magst das nicht, oder habe > ich was falsch gelesen? Da verwechselst Du was. Spess mag die Registertaufe nicht. ;-)) Bei kleineren überschaubaren Programmen, wo ich einen großen Teil der Variablen in (den 32 verfügbaren) Registern halten kann, benutze ich schon recht gern Exklusivregister. Und diese bekommen dann auch ihre Namen. Das Umbenennen der Register in "Akku", "Temp1" bis "Temp4" mach' ich persönlich aber nicht. Da hat eben jeder seine Vorlieben. Das Umbenennen in "Akku" suggeriert mir, dass Derjenige damit im Stil des 6502 arbeiten will, der nur Akku und zwei Indexregister (X, Y) hatte, und damit auf die Vorzüge der 32 Register der (meisten) AVRs verzichtet. Was ich persönlich nicht so mag, sind die Bezeichner für die Interruptvektoren. Das hat aber andere Ursachen. > Ich bin immer noch Anfänger, bedenke das, mein Alter möchte ich > garnicht erwähnen. Na etwa eine halbe Generation älter als ich... > So, ich komme drauf zurück, in einer Stunde will ich zum > Hubschrauberfliegen in einer Turnhalle. Viel Spaß... > > Grüße > > Rolf > Vor mir liegen BL-Regler (wenn Dir das was sagt) mit zwei AVR > drauf, von den ich 15 Stück mit SMD1206 bzw. 0805 erstellt habe. > Die Atmel waren natürlich von einen Österreicher programmiert > worden. Will mich nicht mit fremden Federn schmücken. Da kann ich nicht mitreden, ich bin nich so der Nachbauer. Ich backe zwar kleine Brötchen, aber meine eigenen... ...
Hallo Hannes,
die Tastenentprellung (nur erst mal für eine Taste) funzt
einmalig am Tiny13.
Habe heute Morgen Dein Vorschlag mit den Befehl "sbi bzw. cbi"
gescheckt; das ist ja ne tolle Sache, zumal hier die Inhalte der
anderen Pins nicht beinflußt werden und man nicht jedesmal ein
Register für eine Pinänderung benötigt.
Interessant war auch zu testen, ab wann sich die Umschaltung bei
Tastendruck verheddert.
in der Subroutiene pause: steht
pause: ldi r17,0b00001111 ;also 15
warte: tst r17 ;Spess meinte, das kann weg,aber dann kommen Probleme!
brne warte
ret
in der ISR steht
TIM0_OVF: push r16 ;habe den Begriff akku entfernt
in r16,SREG
push r16
dec r17
pop r16
out SREG,r16
pop r16
reti
mh... diesen Ablauf habe ich von Spess übernommen, habe es
aus einem anderen Thread extra ausgedruckt.
Wie K. H. Buchegger immer wieder schreibt "nicht einfach abschreiben
und übernehmen, erst mal damit beschäftigen"!
Nach meiner Hochrechnung sieht das Ganze bei 1,2 MHz und Prescale
von 64 so aus:
0,833yS x 64 = 53,33yS x 256 = 13,65mS =1Tick x 15 Runden = 204,75mS
(aufgerundet)
Wenn ich jetzt pause: ldi r17, auf 0b00000111 verkleinere,
habe ich einen sog. Zufallsgenerator, d. h. dann wäre die Zeit
kleiner als 204,75mS..kann man vielleicht auch mal gebrauchen.
Das wars erst mal,
Grüße
Rolf
Gast
#2504987
Hi Das >warte: dec r17 > tst r17 > brne warte und das (Decrement im Interrupt) >pause: ldi r17,0b00001111 ;also 15 >warte: tst r17 ;Spess meinte, das kann weg,aber dann kommen Probleme! > brne warte > ret sind aber zwei Paar Schuhe. Bei letzterem wird durch Sichern von SREG im Interrupt das Z-Flag im Hauptprogramm nicht beeinflusst. Da musst du das durch 'tst r17' setzen. Im ersten Code wird das durch 'dec r17' gesetzt. >in der ISR steht >TIM0_OVF: push r16 ;habe den Begriff akku entfernt > in r16,SREG > push r16 <<<<<<<< > dec r17 > pop r16 <<<<<<<< > out SREG,r16 > pop r16 > reti >mh... diesen Ablauf habe ich von Spess übernommen,.... In dem Fall sind die mit '<<<<<<<' gekennzeichneten Zeilen nicht notwendig, da r16 nicht weiter verwendet wird. MfG Spess
doch...doch r16 als akku benannt, wird schon weiter benutzt. Blättere mal zurück zur Quelldatei, oder evtl. doch nicht? Ich muß ehrlich zugeben, daß ich mich mit den PUSH und POP noch nicht intensiv beschäftigt habe..man hat eben zu viel um die Ohren. Besser aber so als Langeweile! Grüße Rolf
Gast
#2505208
Hi >doch...doch r16 als akku benannt, wird schon weiter benutzt. >Blättere mal zurück zur Quelldatei, oder evtl. doch nicht? Aber doch nicht in der Interruptroutine. Mit dem ersten 'push r16' ist das Register gesichert. Mit dem zweiten 'push r16' schiebst du nur das zuvor eingelese SREG auf den Stack. Der Inhalt von r16 ist aber weiter der Inhalt von SREG. >Ich muß ehrlich zugeben, daß ich mich mit den PUSH und POP >noch nicht intensiv beschäftigt habe.. Dann wird es aber Zeit. MfG Spess
mh...jetzt hab ich das nochmal heraus gesucht.
Wenn du einen Motor eine bestimmte Zeit in eine Richtung fahren lassen
willst geht das einfach so:
ldi r16,2
out PORTB,r16 ; Motor einschalten
ldi r17,10 ; Zeit laden
loop: test r17 ; Zeit abgelaufen?
brne loop
ldi r16,0
out PORTB,r16 ; Motor ausschalten
....
TIMER0_OVF:
push r16 ; Timer0 Overflow
in r16,SREG
push r16
dec r17
pop r16
out SREG,r16
pop r16
reti
MfG Spess
aber hier wird r16 doch auch nicht anderweitig verwendet,
so richtig blicke ich noch nicht durch.
Gast
#2505272
Hi Stimmt. Dort ist es auch überflüssig. Kann sein, das ich den Code vom Interrupt damals teilweise automatisch generiert hatte. Das Augenmerk lag auch mehr auf der Warteschleife. Im Prinzip stört es auch nicht. Der Interrupt ist nur etwas länger. Werde versuchen in Zukunft besser aufzupassen. MfG Spess
Rolf Hegewald schrieb: > aber hier wird r16 doch auch nicht anderweitig verwendet, > so richtig blicke ich noch nicht durch. Das scheint mir auch so. Und dabei kann man es sich doch wirklich einfacher machen. Der AVR hat 32 Register, da kommt man bei kleinen Programmen sogar ohne RAM aus. Da kann man es sich leisten, ein unteres (dummes) Register exklusiv für die SREG-Sicherung im Interrupt zu verwenden. Da dieses Register nirgendwoanders benutzt wird (es dient ja exklusiv der SREG-Sicherung) braucht man es auch nicht auf Stack sichern. Man kann sich auch leisten, für Hauptschleife und Interrupt-Handler separate Register zu nutzen, denn dann brauchen auch die in der ISR benutzten Register nicht auf Stack gesichert werden, sie sind halt exklusiv für diesen Zweck reserviert. Push-Pop-Orgien sind erst nötig, wenn die Register knapp werden. Das ist bei Dir aber noch lange nicht der Fall. Du hast es also nicht nötig, r16 zum Akku zu erklären und nach 6502-Manier alles mit dem Akku und dem Stack zu machen. Für unbenutzte Register gibt es kein Geld zurück. Rolf Hegewald schrieb: > "sbi bzw. cbi" gescheckt; Bitte drucke Dir die Liste "Instruction Set Summary" aus dem Datenblatt aus und lege sie als eine Art Arbeitsblatt bzw. Referenz neben Deinen Computer... ...
Hallo Hannes,
nun habe ich mich einmal intensiv mit den PUSH und POP
beschäftigt, und muß feststellen, daß ich da irgendwelchen
Quatsch fabriziere.
als Beispiel eine Qelldatei von mir, bei der die ISR
so aussieht (Tiny13)
TIM0_OVF: push r16 ;kopiere Inhalt von r16 auf die von Stapelzeiger SP
;adressierte SRAM Speicherstelle, danach SP-1
in r16,SREG ;Inhalt vom Statusregister nach r16 laden
dec r17 ;Zeitablauf im Hauptprogramm
pop r16 ;erst SP+1, danach lade r16 mit dem
;adressierten SRAM-Byte
out SREG,r16 ;Inhalt von r16 in SREG laden
reti
Ich meine, ich hätte irgendwo gelesen, daß nur die I/O Register
in der ISR gerettet werden sollen, die in ihr auch auftauchen, oder?
Ich verwende r16 häufig im Hauptprogramm..r17 auch.
In der ISR wird aber doch nur r17 verwendet, also muß es doch
so ablaufen:
push r17
in r17,SREG
dec r17
pop r17
out SREG,r17
Liege ich hier falsch oder richtig!
Danke für Deine Antwort.
Grüße
Rolf
Gast
#2519836
1 | |
2 | |
3 | |
4 | |
5 | |
Rolf Hegewald schrieb: > TIM0_OVF: push r16 ;kopiere Inhalt von r16 auf die von Stapelzeiger SP > ;adressierte SRAM Speicherstelle, danach SP-1 > > in r16,SREG ;Inhalt vom Statusregister nach r16 laden > dec r17 ;Zeitablauf im Hauptprogramm > pop r16 ;erst SP+1, danach lade r16 mit dem > ;adressierten SRAM-Byte > out SREG,r16 ;Inhalt von r16 in SREG laden > reti Lass uns das doch mal ganz konkret durchspielen Das seien deine CPU Register, kurz bevor deine ISR betreten wird (die aktuellen Zahlen an sich spielen keine Rolle, ich hab sie jetzt frei erfunden) SREG r16 r17 Stack +-------+ +--------+ +--------+ +----------+ | 0x35 | | 0x12 | | 0x89 | | | <--- +-------+ +--------+ +--------+ +----------+ | | +----------+ | | +----------+ | | .... Ziel der ISR ist es, r17 runterzuzählen. Das und NUR DAS soll die ISR machen. Etwas anderes darf nicht verändert werden! Schaun wir mal push r16 Aha. Den Inhalt von r16 auf den Stack schieben. SREG r16 r17 Stack +-------+ +--------+ +--------+ +----------+ | 0x35 | | 0x12 | | 0x89 | | 0x12 | +-------+ +--------+ +--------+ +----------+ | | <--- +----------+ | | +----------+ | | .... in r16,SREG Den Inhalt von SREG nach r16 kopieren SREG r16 r17 Stack +-------+ +--------+ +--------+ +----------+ | 0x35 | | 0x35 | | 0x89 | | 0x12 | +-------+ +--------+ +--------+ +----------+ | | <---- +----------+ | | +----------+ | | .... dec r17 r17 um 1 erniedrigen. SChau in der Befehlsreferenz nach, das verändert auch das Statusregister SREG r16 r17 Stack +-------+ +--------+ +--------+ +----------+ | 0xAB | | 0x35 | | 0x88 | | 0x12 | +-------+ +--------+ +--------+ +----------+ | | <--- +----------+ | | +----------+ | | .... pop r16 den letzten Wert vom Stack holen und in r16 speichern SREG r16 r17 Stack +-------+ +--------+ +--------+ +----------+ | 0xAB | | 0x12 | | 0x88 | | | <--- +-------+ +--------+ +--------+ +----------+ | | +----------+ | | +----------+ | | .... out SREG,r16 ; den INhalt von r16 nach SREG kopieren SREG r16 r17 Stack +-------+ +--------+ +--------+ +----------+ | 0x12 | | 0x12 | | 0x88 | | | <--- +-------+ +--------+ +--------+ +----------+ | | +----------+ | | +----------+ | | .... reti Das wars. Die ISR ist fertig. Und jetzt vergleich mal, in welchem Zustand die Register waren, als die ISR betreteb wurden und wie sie jetzt sind. Welche dürfen verändert werden (r17) und welche nicht (alle anderen). Und wie ist die Situation tatsächlich und wie ist es dazu gekommen? So war die Situation vor dem Betreten der ISR
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
und so ist sie danach
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
r17 wurde korrekt um 1 erniedrigt, was ja auch der Sinn der ISR war. r16 hat wieder denselben Wert, der Stackpointer zeigt auch auf das gleiche Element wie am Anfang. Aber SREG hat NICHT denselben Wert! -> Fehler
Gast
#2519846
Hi >Liege ich hier falsch oder richtig! Falsch. >push r17 -> r17 auf den Stack >in r17,SREG -> r17 = SREG >dec r17 -> r17 = SREG-1 >pop r17 -> r17 = Wert bei Interrupteinsprung >out SREG,r17 -> SREG = Wert von r17 bei Interrupteinsprung Merkst du etwas? >Ich verwende r16 häufig im Hauptprogramm..r17 auch. >In der ISR wird aber doch nur r17 verwendet, also muß es doch >so ablaufen: Nein. Du willst doch das r17 verändert wird. Es werden dir Register gesichert, die in der Interruptroutine benutzt und nicht verändert werden dürfen. >als Beispiel eine Qelldatei von mir, bei der die ISR >so aussieht (Tiny13) Dai ist auch ein Fehler drin (<<<<<) >TIM0_OVF: push r16 > in r16,SREG > dec r17 > pop r16 <<<<<<< Falsche > out SREG,r16 <<<<<<< Reihenfolge > reti Richtig ist: >push r16 -> r16 auf den Stack >in r16,SREG -> r16 = SREG >dec r17 -> r17 = r17-1 >out SREG,r16 -> SREG = r16 >pop r16 -> r16 = Wert bei Interrupteinsprung MfG Spess
Rolf Hegewald schrieb: > Hallo Hannes, Hallo Rolf, eigentlich wurde schon alles gesagt (geschrieben), doch da Du mich direkt ansprachst, werde ich auch noch antworten... > nun habe ich mich einmal intensiv mit den PUSH und POP > beschäftigt, und muß feststellen, daß ich da irgendwelchen > Quatsch fabriziere. Jou, ein Stack ist ein Stapel, Du kannst nur das herunternehmen, was Du zuletzt draufgelegt hast. Wühlen ist nicht, dann wäre es kein Stack. Zum Vergleich bzw. der Abgrenzung: - Random-Zugriff (völlig wahlfrei adressierbarer Speicher), - FiFo (First In First Out, Ringspeicher), - LiFo (Last In First Out, Stack). > > als Beispiel eine Qelldatei von mir, bei der die ISR > so aussieht (Tiny13) > > TIM0_OVF: push r16 ;kopiere Inhalt von r16 auf die von Stapelzeiger SP > ;adressierte SRAM Speicherstelle, danach SP-1 > > in r16,SREG ;Inhalt vom Statusregister nach r16 laden > dec r17 ;Zeitablauf im Hauptprogramm > pop r16 ;erst SP+1, danach lade r16 mit dem > ;adressierten SRAM-Byte > out SREG,r16 ;Inhalt von r16 in SREG laden > reti Die Reihenfolge am Ende ist falsch, aber das schrieb man Dir ja bereits. Dein Konzept zu umständlich, für die Sicherung des SREGs lohnt sich der Einsatz eines Exklusivregisters. Da dabei keine Konstantenzugriffe erfolgen, reicht ein unteres Register aus. Ich bevorzuge r2 oder r3, da ich r0 und r1 aus Gewohnheit frei lasse, da sie gelegentlich auch für Sonderfunktionen gebraucht werden. Beispiele findest Du in meinen Quelltexten, die Du vielleicht doch mal analysieren solltest. > Ich meine, ich hätte irgendwo gelesen, daß nur die I/O Register > in der ISR gerettet werden sollen, die in ihr auch auftauchen, oder? Gar keine I/O-Register, sondern nur Arbeitsregister (falls man keine Exklusivregister in der ISR benutzt) und das Statusregister (siehe sehr ausführliche Erklärung von Karl-Heinz). > Ich verwende r16 häufig im Hauptprogramm..r17 auch. Ja, der AVR hat aber noch 30 weitere Register. Und für nicht verwendete Register gibt es kein Geld zurück. Solange genug Register verfügbar sind, darf man sie ruhig (exklusiv) zweckgebunden verwenden. Natürlich braucht man ein oder zwei Register für temporäre Zwecke, bei mir sind das wl und wh (r24, r25). Die verwende ich aber nur bei der Initialisierung, in der Mainloop und in Jobs der Mainloop. Und auch nur für Zwecke, wo mich der Inhalt einige Programmzeilen später nicht mehr interessiert. In der ISR benutze ich sie aber nicht, um mir das Sichern und Wiederherstellen zu sparen. Deshalb benenne (und benutze) ich für die ISR eigene Tempregister. Diese werden dann nur in den ISRs temporär verwendet. Man muss sie also nicht sichern und nicht wiederherstellen. Push und Pop gibt es bei mir in den ISRs nur, wenn ich Register mit Spezialfunktionen brauche, die auch woanders gebraucht werden, wie z.B. Pointer (X Y, Z). > In der ISR wird aber doch nur r17 verwendet, also muß es doch > so ablaufen: > > push r17 > in r17,SREG > dec r17 > pop r17 > out SREG,r17 > > Liege ich hier falsch oder richtig! Völlig falsch, aber das hat man Dir ja bereits ausführlich erklärt. > > Danke für Deine Antwort. [Dummer Spruch] Nix zu danken, Kundendienst... ;-) [/Dummer Spruch] > > Grüße > > Rolf Deinen Problemen nach zu urteilen, solltest Du Dein Projekt zurückstellen und das Tutorial nochmal von vorn beginnen. Da sind etliche Basics, die Dir noch fehlen, weshalb Du Dich an allen Ecken und Kanten vera..lbern lässt. Uns dann solltest Du wirklich mal meine Quelltexte analysieren, ich habe sie nämlich nicht umsonst reingestellt. Sie sind relativ einfach gehalten, übersichtlich strukturiert und üppig kommentiert, also ziemlich einsteigerfreundlich. Wenn Du dazu Detail-Fragen hast (warum so, und nicht wie im Tutorial), werde ich sie Dir gern beantworten. Nochmal zum Konzept. All diesen Aufwand betreibst Du, um dann in der Mailoop (bzw. einem UP davon) zu warten , bis der Timeout abgelaufen ist. Diese Vorgehensweise lernt man ausschließlich aus didaktischen Gründen, nämlich um bei der ersten ernsthaften Anwendung zu erkennen, dass das Quatsch ist, weil nämlich die CPU während des Wartens keine andere Arbeit ausführen kann. Richtig ist es, wenn man statt "auf der Stelle zu treten" zur Mainloop zurück kehrt und weitere Arbeiten erledigt, solange der Timeout noch nicht abgelaufen ist. Mit Deinem Konzept benutzt Du zwar einen Timer, wirfst seine Vorzüge aber in den Müll. Da kannst Du auch bei Warteschleifen bleiben, da braucht es keinen Timer... ...
Hallo Karl Heinz und Spess, habe alles erstmal ausgedruckt und werde es Morgen früh verarbeiten. So langsam gehen mir die Augen auf über das Ganze. Der "Fehler" am Ende von Karl Heinz zeigt doch, daß hier im unteren Bereich eine Verdrehung vorliegt, wie das Spess ganz klar erklärte. Na ich spiele das alles morgen nochmal durch Das würde doch bedeuten, wenn ich im Hauptprogramm r16, r17, r18 verwende, muß ich auch in der ISR push r16 push r17 push r18 pop r18 pop r17 pop r16 einrichten, oder? Grüße Rolf und ein Dankeschön für die Hilfe
Rolf Hegewald schrieb: > Das würde doch bedeuten, wenn ich im Hauptprogramm r16, r17, r18 > verwende, muß ich auch in der ISR > > push r16 > push r17 > push r18 > > pop r18 > pop r17 > pop r16 > > einrichten, oder? Im Prinzip: ja. Aber was Hannes dir schon die ganze Zeit zu erklären versucht: verwende halt einfach r16, r17 und r18 nicht in der ISR. Gut r17 musst du verwenden, weil es die Aufgabe der ISR ist, r17 zu verändern. Aber r16 und r18 nicht. Du hast noch haufenweise andere Register, die du zu Arbeitszwecken innerhalb der ISR benutzen kannst. Muss ja nicht ausgerechnet r16 und r18 sein. Veränderst du die Register in der ISR nicht, brauchst du sie auch nicht sichern. Manchmal kann die Welt so einfach sein. Aber: SREG musst du immer und auf jeden Fall in der ISR sichern und wiederherstellen.
Gast
#2520516
Hi >Das würde doch bedeuten, wenn ich im Hauptprogramm r16, r17, r18 >verwende, muß ich auch in der ISR... Nur wenn sie 1. durch die Interruptroutine verändert werden. 2. durch die Interruptroutine nicht verändert werden dürfen. Ich habe jetzt bewusst 'verändert' geschrieben. Es gibt auch Befehle die ein Register verwenden, aber es nicht beeinflussen. Z.B. add r16,r17 Hier wird nur r16 beeinflusst, r17 bleibt unverändert. MfG Spess
Gast
#2521032
Hi Rolf Hegewald schrieb: > Das würde doch bedeuten, wenn ich im Hauptprogramm r16, r17, r18 > verwende, muß ich auch in der ISR > > push r16 > push r17 > push r18 > > pop r18 > pop r17 > pop r16 > > einrichten, oder? Egal, ob die Register erforderlich sind oder nicht, so ist es schon richtig, aber..... der Fehler steckt auch hier: > In der ISR wird aber doch nur r17 verwendet, also muß es doch > so ablaufen: > > push r17 > in r17,SREG > dec r17 > pop r17 > out SREG,r17 > > Liege ich hier falsch oder richtig! R17 retten ist ok. SReg nach r17 laden auch ok Dec kann man machen, aber, dann holst du dir den alten r17 Wert vom Stack und packst ihn in das Statusregister. Was bitteschön erwartest du nun für Statusbits ? R17 hat vor dem Pushen einen Wert zwischen 0 und 255. Da es ein Interrupt ist, kannst du nicht erwarten, diesen Wert zu kennen. Und genau den haust du in das Statusregister.... Bingo... Volltreffer. aus 145 wird 0b10010001, also Statusbits. Richtig ist:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
Aber dazu sind auch schon eine Menge Antworten erfolgt. Vielleicht waren sie einfach zu ausführlich, das der Kern des Fehlers untergegangen ist. Gruß oldmax
zu Karl Heinz
nochmal von vorne:
TIM0_OVF: push r2 ;kopiere Inhalt von r2 auf die von Stapelzeiger SP
;adressierte SRAM Speicherstelle, danach SP-1
in r2,SREG ;Inhalt vom Statusregister nach r2 laden
dec r17 ;Zeitablauf im Hauptprogramm
out SREG,r2 ;Inhalt von r2 in SREG laden
pop r2 ;erst SP+1, danach lade r2 mit dem
;adressierten SRAM-Byte
reti
So sieht der Anfang aus:
SREG r2 r17 Stack
+-------+ +--------+ +--------+ +----------+
| 0x35 | | 0x12 | | 0x89 | | | <---
+-------+ +--------+ +--------+ +----------+
| |
+----------+
| |
+----------+
| |
....
;den Dreher korrigiert:
out SREG,r2
den INhalt von r2 nach SREG kopieren
SREG r2 r17 Stack
+-------+ +--------+ +--------+ +----------+
| 0x35 | | 0x35 | | 0x88 | | | <---
+-------+ +--------+ +--------+ +----------+
| |
+----------+
| |
+----------+
| |
....
pop r2
den letzten Wert vom Stack holen und in r2 speichern
SREG r2 r17 Stack
+-------+ +--------+ +--------+ +----------+
| 0x35 | | 0x12 | | 0x88 | | | <---
+-------+ +--------+ +--------+ +----------+
;die Endwerte entsprechen denen vom Anfang
reti
Lese ich auch das von Hannes, dann dient in meinen Beispiel das
Arbeitsregister r2 nur dazu, den Inhalt vom Statusregister SREG
zu retten. Ich werde mir nochmals die Quelldateien von Hannes
ansehen und besonders mein Augenmerk auf seine ISR legen.
Grüße
Rolf
Rolf Hegewald schrieb: > Das würde doch bedeuten, wenn ich im Hauptprogramm r16, r17, r18 > verwende, muß ich auch in der ISR > > push r16 > push r17 > push r18 > > pop r18 > pop r17 > pop r16 > > einrichten, oder? In Assembler hat man viele Optimierungsmöglichkeiten: Wenn Du keine Schweinereien in Interrupts mach willst, also jeder wird zuende abgearbeitet, dann kannst Du ein Register fürs SREG Sichern reservieren. Auch kannst Du von den 32 Registern einige als Interruptarbeitsregister reservieren. Vorzugsweise auch den Y-Pointer, im Main kommt man gut mit nur 2 Pointern zurecht. So kann man dann Interrupts oft ganz ohne PUSH/POP schreiben. Und auch fürs Main reserviert man einige Register als zerstörbar, dann müssen Unterfunktionen keine Arien an PUSH/POP machen. Oftmals übergibt man ja Werte an Unterfunktionen, die danach garnicht mehr gebraucht werden. Peter
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.
