Guten Tag. Habe ein "kleines" Progrämmchen geschrieben b.z.w. bin noch dabei. Leider ist das Programm jetzt bereits so groß das ich obwohl ich es möglichst übersichtlich gehalten habe nicht mit 100%iger Sicherheit überprüfen kann ob ich auch alles richtig gemacht habe (Kein überfluten des Stack, Sicherung aller benötigten Register und richtige Rücksicherung ...) Wie schon gesagt, Überprüfung ist freiwillig.
Was die Kommentare angeht: sehr gut, aber data_kill solltest du auch besser kommentieren. Bei Assemblerprogrammen sollte man fast jeden Befehl kommentieren, damit man auch später (und ev. andere) nachvollziehen kann, warum man das so gemacht hat. Nur meine bescheidene Meinung.
Gewöhn Dir sowas garnicht erst an. Aus nem Interrupt raus gibt es nur das RETI und nichts weiter! Ins Main zurück springen ist ne Zeitbombe, die Dir irgendwann explodiert, wenn das Progrämmchen auch nur ein Pfitzelchen größer wird. Und warten im Interrupt ist auch Pfui-Bäh. Sei nicht so sparsam mit Kommentaren. Peter
Data_kill bin ich gerade bei ... (wird gerade kommentiert) ... und hier ist es auch schon:
1 | ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
2 | ; |
3 | ; Daten ignorieren |
4 | |
5 | Data_kill: |
6 | push temp |
7 | in temp, sreg |
8 | push temp ; Register sichern |
9 | push temp4 |
10 | ldi temp4, 10 ; 11 bits müssen ignoriert werden |
11 | ldi ZL, LOW(kill) ; beim nächsten Interrupt auf Kill springen |
12 | ldi ZH, HIGH(kill) |
13 | ldi Wait1, $FF ; Wartezeit um im Wait den Interrupt zu empfangen |
14 | sei ; - und temp4 nicht sichern zu müssen |
15 | rcall Wait |
16 | ldi ZL, LOW(Data_Recieve) ; sollt kein Interrupt aufgetreten sein (Daten abgerissen) |
17 | ldi ZH, HIGH(Data_Recieve) ; - geht der nächste Interupt wieder in die Empfangsroutine |
18 | pop temp4 |
19 | pop temp ; Register zurücksichern |
20 | out sreg, temp |
21 | pop temp |
22 | reti ; Zurück ins Programm |
23 | killing: |
24 | pop temp |
25 | pop temp |
26 | pop temp ; rcall und Interuptadressen aus Stack löschen |
27 | pop temp |
28 | dec temp4 ; zu ignorierende Bit verringern |
29 | breq killed ; wenn alle gekilled bei killed weiter machen |
30 | ldi Wait1, $FF |
31 | sei ; wenn nicht in Warteschleife auf weitere Warten |
32 | rcall Wait |
33 | killed: |
34 | cli |
35 | pop temp4 ; Interupts deaktiveren um Fehler zu verhindern |
36 | pop temp |
37 | ou sreg, temp ; Register wieder herstellen |
38 | pop temp |
39 | ldi ZL, LOW(Data_Recieve) ; Beim nächsten Interrupt wieder normal Daten empfangen |
40 | ldi ZH, HIGH(Data_Recieve) |
41 | reti ; Zurück ins Programm |
Hi
>Und warten im Interrupt ist auch Pfui-Bäh.
LCD auch.
Aus langjähriger Assemblererfahrung: Mit dem Ansatz wirst du nicht froh.
Was soll das genau machen? PC-Tastetur einlesen?
MfG Spess
Peter Dannegger schrieb: > Gewöhn Dir sowas garnicht erst an. Aus nem Interrupt raus gibt es nur > > das RETI und nichts weiter! Wie meinen? (Weil ich teilweise mit: sei -> reti rausgegangen war?) Sonst bin ich doch immer mit Reti rausgegangen ... > Ins Main zurück springen ist ne Zeitbombe, die Dir irgendwann > > explodiert, wenn das Progrämmchen auch nur ein Pfitzelchen größer wird. Springe doch nur einmal ins Main (Loop) nach der Initialisierung und der Sprung nach 0x00 ist zur Fehlerbehebung (eingrenzung das ich n Reset habe weil ich an den Pin nicht rankomme). > Und warten im Interrupt ist auch Pfui-Bäh. Im Interrupt nutze ich massig Register, welche ich sonst immer sichern müsste und wieder neu auslesen. Oder kennen sie da eine bessere Möglichkeit? > Sei nicht so sparsam mit Kommentaren. Dachte das Reicht ... weiß nicht was ich da sonst noch hinschreiben sollte ... Trotzdem vielen Dank für die Anmerkungen
spess53 schrieb: > Hi > > > >>Und warten im Interrupt ist auch Pfui-Bäh. > > > > LCD auch. > > > > Aus langjähriger Assemblererfahrung: Mit dem Ansatz wirst du nicht froh. > > > > Was soll das genau machen? PC-Tastetur einlesen? > > > > MfG Spess Beim Warten im Interrupt geht es mir darum das diese Arbeit nicht unterbrochen werden darf/soll. Was ist an meinem Ansatz falsch? Was würden sie empfehlen? Am Mikrocontroller sind eine Tastatur und ein LCD angeschlossen. Die Tasten der Tastatur werden auf dem Display dargestellt. Es soll am Ende möglich sein auf dem Display nicht anders als auf dem PC damit zu schrieben.
Michael Dierken schrieb: > Sonst bin ich doch immer mit Reti rausgegangen ... Aus jeder Unterroutine darf es nur 1 Ausgang geben. Mehrfache Ausgänge (und zudem, wenn sie so verteilt sind) brechen dir garantiert das Genick... Klar kostet das einen Sprung mehr, aber dafür ist das Leben wesentlich einfacher und der Stack besser unter Kontrolle! Michael Dierken schrieb: > Was ist an meinem Ansatz falsch? Was würden sie empfehlen? Dort hinein gehört die ganze Arbeit:
1 | ; Hauptprogramm |
2 | |
3 | Loop: |
4 | sbis PINB, 2 ; Noch bei Low PINB2 Reset |
5 | rjmp 0x00 |
6 | rjmp Loop ; Rücksprung Loop da noch leer |
In Interrupts wird nur gemacht, was das Hauptprogramm unterbricht (so
sind die Interrupts auch zu ihrem Namen gekommen).
> rjmp 0x00
Achtung: ein Sprung nach Adresse 0 ist KEIN RESET!
Hi >Was ist an meinem Ansatz falsch? Was würden sie empfehlen? Ich gehe jetzt mal von einer PC-Tastatur aus. Dort gibt es einen Takt, bei dem eine Flanke anzeigt wenn die Daten gültig sind. Bei ATmel gibt es einen AppNote dazu: http://www.atmel.com/dyn/resources/prod_documents/doc1235.pdf http://www.atmel.com/dyn/resources/prod_documents/AVR313.zip Siehe S.3 The Algorithm MfG Spess
Michael Dierken schrieb: >> Sei nicht so sparsam mit Kommentaren. > > Dachte das Reicht ... weiß nicht was ich da sonst noch hinschreiben > sollte ... Sorry. Ich nehm alles zurück. Ich war in Gedanken bei nem anderen Thread. Vergiß also, was ich gesagt habe. Peter
Hi Ok, Interrupt heißt, auf kleinste Ereignisse zu reagieren. Z.B. es kommt ein Nadelimpuls, dann eine kleine Weile nix. Den Nadelimpuls kannst du nur sicher mit einem Interrupt erfassen, also kommt in die ISR ein flag, was dieses Ereignis der Programmschleife übergibt. Das Programm prüft irgendwann das Flag, bearbeitet das Ereignis und setzt das Flag zurück. Unterschätze nicht die Geschwindigkeit deines Controllers. Bedenke, bei 1 MHz und 2 Taktzyklen pro Befehl dauert die Befehlsbearbeitung mal grade zwei µSek. Wenn deine Programmschleife 1000 befehle ababeitet,ist die Zykluszeit zwei mSek. Ich glaube nicht, das du so schnell schreiben kannst, das selbst bei 1/10 Tastendruck (Puls-Pause) der Controller die Zeichen nicht erfassen kann. Gruß oldmax
Hi Hab noch was vergessen... Du setzt einen Interrupt ein, um schnell reagieren zu können und dann programmierst du in die ISR eine Wartezeit. Meinst du nicht auch bei ein wenig Überlegung, das diese Vorgehensweise nicht wirklich richtig sein kann. ISR - schnell. Also, Ereignis erfassen, zuordnen und wieder raus. Und nicht stundenlang überlegen, mach ich was oder nicht.... so, jetzt sollte es gut sein. Gruß oldmax
Das Programm arbeitet so das es bei Beginn eines Zeichens (Fallende Flank Clock) einen Interrupt auslöst welcher das Startbit abfragt. Ist dies da so fährt er vor und wartet auf 8 Datenbits ... Sollte das Startbit fehlerhaft sein (z.B. High) oder er die 8Bit + Parität + Stop empfangen habe sowie Parität geprüft und Zeichen ans Display ausgegeben so geht er wieder zurück ins Hauptprogramm. Die Erkennung des nächsten Zeichens läuft immer über den interrupt sodass ich nicht dauernt den Pin abfragen muss.
Ja aber ... wenn ich im Programm auf den nächsten Interrupt warte muss ich die Register immer im SRAM sichern und nachher wieder zurücksichern und ich müsste einen Timer setzen um ein abbrechen der Daten zu erkennen.
Hi Versuchst du eine Soft - UART zu programmieren ? Es ist ja ok, wenn man schnelle Signale per ISR erfasst, aber innerhalb einer ISR warten macht keinen Sinn. Stell dir vor, du erkennst in der ISR einen Flankenwechsel. Wie lange dauert es, bis der nächst eintrifft ? Hast du genug zeit, so setze dit in der ISR ein Flag und verlasse diese. Es braucht nur die Push und Pop's für die verwendeten Register sowie für's Statusregister. Das Haupprogramm hat nun die Aufgabe, die Signalauswertung zu übernehmen. Da braucht aber nix gepusht und gepoppt zu werden. Bspl. einer beliebigen ISR
1 | X_ISR: |
2 | Push Temp |
3 | In Temp, SReg |
4 | Push Temp |
5 | LDS Temp, Flags |
6 | Or Temp, 0b00000001 |
7 | STS Flags, Temp |
8 | POP Temp |
9 | Out SREG, Temp |
10 | POP Temp |
11 | RETI |
Wie du siehst, wird nur ein Bit un eine Variable "Flags" geschrieben.... Im Hauptprogramm kannst du nun dieses Bit abfragen und in ein Unterprogramm verzweigen:
1 | Main: |
2 | .... |
3 | LDS Temp, Flags |
4 | Andi Temp, 0b00000001 |
5 | BREQ Next |
6 | RCALL Meine_Reaktion_Auf_ISR |
7 | Next: |
8 | .... |
9 | RJmp Main |
10 | |
11 | Meine_Reaktion_auf_ISR: |
12 | .... |
13 | .... |
14 | RET |
Vielleicht hilft dir dieses kleine Beispiel. Gruß oldmax
ich verstehe leider nicht wie du das meinst. Die Zeit zwischen den Flankenwechsel ist unterschiedlich lang und ich muss zeitweise mit 3 Werten "gleichzeitig" arbeiten. Mit UART hat das erstmal noch garnichts zu tun (habe den nur zur Fehlersuche mit konfiguriert). Ansonsten läuft das Programm ja so das es in den Interrupt geht und dann das Unterprogramm startet wo es Programm dann weiter läuft.
Ich kann gerne wie ihr meint so machen das ich nach jedem Empfangenen Bit wieder in das Hauptprogramm springe, müsste dann aber wissen wie ich einen Abbruch des Datenstranges (z.B. bei Abziehen der Tastatur) erkennen kann.
Michael Dierken schrieb: > ich verstehe leider nicht wie du das meinst. wenn wir das richtig sehen liefert deine Tastatur (PS2??) ein serielles Datenpaket. Du kannst dazu den UART deines AVR nutzen (in der syncronen Betriebsart). Sascha
Den UART brauche ich noch um Daten an den PC zu senden, werde ich mir aber mal anschauen.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.