www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik [Assembler] Simulation in AVRStudio geht, in anderem Programm nicht


Autor: Sven J. (locutussum)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich versuche gerade, ein kleines Programm für den attiny11 zu schreiben 
(hab von dem noch ein, zwei rumfliegen und das, was ich machen will ist 
nicht wirklich umfangreich!).
Ziel soll im Endeffekt ein Einlesen von Tastern und aufgrund von 
Tastendrücken ein Dekrementieren bzw. Inkrementieren von einem 
Ausgabewert auf 3 Pins (also im endeffekt BCD-Code mit 3 stellen als 
Ausgabe) sein.
Dazu dann natürlich noch eine Entprellung und ein "automatisch alle 1s 
eins weiter schalten"-funktion bei gedrücktem Knopf.

Fertig geschrieben sieht das ganze bei mir so aus:
.include "tn11def.inc"
.org 0x0000
  rjmp main                  ; Reset Handler
.org OVF0addr
  rjmp timer0_overflow       ; Timer Overflow Handler


timer0_overflow:
  sbrs r18, 0                 ; wenn Entprellhandler nicht gesetzt
  rjmp output                ; Eingänge überprüfen
  subi r19, 1                 ; Timercounter dekrementieren
  cpi r19, 0
  breq action                  ; und wenn auf 0
  rjmp loop

action: 
  ldi r18, 0               ; Entprellhandler ausschalten
  rjmp loop

output:
  ldi r18, 1                ; Entprellhandler setzen
  ldi r19, 10               ; 10 Interrupts bis nächste Ausführung Ausgabe
  sbis PINB, 3
  add r17, r20              ; Eingänge einlesen
  sbis PINB, 4
  sub r17, r20
  SBRC r17, 5               ; Wenn über "7"
  ldi r17, 0b00011000       ; zurück auf "0"
  SBRS r17, 3               ; Wenn unter "0"
  ldi r17, 0b00011111       ; zurück auf "7"
  out PORTB, r17            ; Ausgeben
  rjmp loop
 
main: 
  ldi r20, 1             ; eine  EINS
  ldi r19, 0                ; Timercounter
  ldi r18, 0                ; Entprellhandler
  ldi r17, 0b00011000      ; BCD-Basis-System
  ldi r16, 0b00000111      ; IO-Aufbau
  out DDRB, r16
  out PORTB, r17
  ldi r16, (1<<CS02)       ; CS02 setzen: Teiler 256
  out TCCR0, r16
  ldi r16, (1<<TOIE0)      ; TOIE0: Interrupt bei Timer Overflow
  out TIMSK, r16
  ldi r16, (1<<7)
  rjmp loop

loop:
    out SREG, r16
  rjmp loop           ; Warteschleife


(ich hoffe mal, die kommentare machen das einigermaßen verständlich)

jetzt mein Problem: wenn ich das ganze in AVR-Studio simuliere, dann 
läuft das erst mal ganz gut - bis auf den Fehler "HW Stack Overflow" 
oder so, welcher mir angezeigt wird, welchen ich aber auch nur so 
ausmerzen könnte, dass ich dabei gleichzeitig im SREG das interrupt-Flag 
nicht regelmäßig neu setzen würde. (und dann würde das ganze nicht mehr 
funktionieren, da sich das flag nach jedem interrupt löscht? o.O)
Im handbetrieb initialisiert sich der Timer nicht richtig und arbeitet 
auch sonst nur bedingt: eigentlich sollte der prescaler auf 256 stehen, 
lasse ich das ganze aber "laufen", so wird der Prescaler immer auf "kein 
teiler" gestellt. ist das ein Fehler im programm? oder absicht?
wenn ich im angehaltenen Zustand die Pins verändere, welche eben später 
fürs Input verantwortlich sind, dann funktioniert das im "laufen lassen" 
auch ganz gut, ich bekomme den bcd-code raus und der schaltet sich auch 
schön durch.

aber jetzt mein größeres Problem: da ich z.Z. keinen Programmer habe, 
welcher auch den tiny11 programmieren kann, kann ich das programm noch 
nicht in der Schaltung testen. wohl aber in Prospice simulieren. und bei 
der simulation scheint auch wieder einiges schiefzulaufen: nach dem 
starten und initialisieren kommt an den ausgängen überall "low" (soweit 
ja richtig) und die input-pins werden beide "high" (soweit ja auch 
richtig, sind ja die pullups!). wenn ich aber über eine Taste einen der 
Input-Pins auf "low" ziehe, so ändert sich an den ausgängen rein 
garnichts. und ich weis wirklich nicht wieso. (mit dem debugger in 
prospice konnte ich zumindenst feststellen, dass der timer vernünftig 
läuft und regelmäßig ein interrupt aufwirft! aber Aktionen am PortB hat 
er komischerweise überhaupt nicht, auch wenn ich an dem Port ne taste 
drücke!)

hat da wer ne idee, woran das liegt? hab ich da evtl. noch irgendetwas 
falsch gemacht in meinem code?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
timer0_overflow:
  sbrs r18, 0                 ; wenn Entprellhandler nicht gesetzt
  rjmp output                ; Eingänge überprüfen
  subi r19, 1                 ; Timercounter dekrementieren
  cpi r19, 0
  breq action                  ; und wenn auf 0
  rjmp loop

  rjmp loop  ?

Bist du des Wahnsinns fette Beute?
Aus einer ISR steigt man mit reti aus und sonst mit nichts anderem. Das 
ist konzeptionell ein Unterprogrammaufruf! So richtig mit: Returnadresse 
wird auf den Stack geschrieben und so.

Wenn man schon anders raus muss, dann korrigiert man zumindest den 
Stackpointer. Aber eigentlich sollte man solche Querausstiege nicht 
machen, eben weil man dabei gerne zuviele Dinge übersieht.

Dann kannst du auch das SREG in der Hauptschleife in Ruhe lassen.

Autor: MWS (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Willst Du das als Schadcode bei den Borg einspielen ? :D

Schon mal was von RETI gehört ? Das ist ein völliger 
Durcheinandergespringe, kein Wunder, daß der Stack überläuft, das geht 
so grundsätzlich nicht.

Autor: Spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>timer0_overflow:
>  sbrs r18, 0                 ; wenn Entprellhandler nicht gesetzt
....
>  rjmp loop

Was soll denn das? Eine Interruptroutine wird mit 'reti' beendet. Kein 
Wunder das du einen Stack-Overflow bekommst.

MfG Spess

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Selbiges nach
action:
und
output:

Autor: Grrrr (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sven J. schrieb:
> (ich hoffe mal, die kommentare machen das einigermaßen verständlich)

Leider nicht wirklich.

> welchen ich aber auch nur so
> ausmerzen könnte

Man kann auch den Stackpointer selbst initialisieren falls man nicht 
glauben will oder kann das eine höhere Macht das schon tun wird. :-)

Autor: Spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>Man kann auch den Stackpointer selbst initialisieren falls man nicht
>glauben will oder kann das eine höhere Macht das schon tun wird. :-)

Der ATTiny11 hat einen Hardwarestack. Also keine Initialisierung nötig.

MfG Spess

Autor: Grrrr (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Grrrr schrieb:
> Man kann auch den Stackpointer selbst initialisieren falls man nicht
> glauben will oder kann das eine höhere Macht das schon tun wird. :-)

Ach Mist. Ist ja ein Tiny11. Vergiss es.

Autor: Grrrr (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Spess53 schrieb:
> Der ATTiny11 hat einen Hardwarestack. Also keine Initialisierung nötig.

Richtig.

Autor: Sven J. (locutussum)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
sorry, aber ist schon was her, dass ich das letzte mal was in assembler 
machen musste und ich hab inzwischen auch alle befehle weitestgehend 
vergessen (und die, die ich noch wusste, wie adi, die gehen nicht mal 
bei avr. :( ), so dass ich mir die befehle erst selbst wieder zusammen 
suchen musste.
ansonsten simulierts sich jetzt auch wundervoll in ISIS, wenn ich knopf 
drücke, zählt die bcd-anzeige schön hoch, anderer knopf zählt runter 
(und reset macht natürlich reset), sodass ich jetzt davon ausgehen kann, 
dass der code so wie er jetzt ist auch wirklich funktioniert. (muss wohl 
wirklich einzig und alleine am reti gelegen haben, wo mir der befehl 
doch so schön entfallen war. ^^) also danke an alle, die mich auf das 
RETI hingewiesen haben.

und wie sieht das mit dem I-Bit in SREG aus? kann ich das nicht irgendwo 
einfacher (und weniger ... ìdiotisch?) dazu zwingen, das flag gesetzt zu 
halten?

Autor: Spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>und wie sieht das mit dem I-Bit in SREG aus? kann ich das nicht irgendwo
>einfacher (und weniger ... ìdiotisch?) dazu zwingen, das flag gesetzt zu
>halten?

Normalerweise wird das I-Flag mit sei gesetzt und mit cli gelöscht. Und 
von allein ändert es sich nicht.

MfG Spess

Autor: Kluchscheißernder Nixwisser (kluchscheisser)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Spess53 schrieb:
> Hi
>
>>und wie sieht das mit dem I-Bit in SREG aus? kann ich das nicht irgendwo
>>einfacher (und weniger ... ìdiotisch?) dazu zwingen, das flag gesetzt zu
>>halten?
>
> Normalerweise wird das I-Flag mit sei gesetzt und mit cli gelöscht. Und
> von allein ändert es sich nicht.

Hmmm, ääähhhh, und was ist mit Interrupts?

Das I-Flag wird (beim AVR) beim Auslösen eines Interrupts per Hardware 
gelöscht und beim verlassen der ISR per RETI wieder gesetzt. Dies 
verhindert, dass während der Abarbeitung eines Interrupts ein weiterer 
Interrupt abgearbeitet wird.

Dies nur als Ergänzung, ansonsten kannst Du Spess53 schon vertrauen. ^^

>
> MfG Spess

MfG, Kluchscheißer

Autor: Spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>Hmmm, ääähhhh, und was ist mit Interrupts?

OK. Kleine Unterlassungssünde. Aber das von Problem von Sven sollte sich 
mit dem richtigen Einsatz von 'reti' erledigt haben.

MfG Spess

Autor: Sven J. (locutussum)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
stimmt. das sei funktioniert einwandfrei! (ich hatte das vorher schon 
mal probiert, da hat es aber nicht so richtig funktioniert, wird wohl an 
den sprüngen gelegen haben!)

jetzt sieht der code so aus:
.include "tn11def.inc"
.org 0x0000
  rjmp main                  ; Reset Handler
.org OVF0addr
  rjmp timer0_overflow       ; Timer Overflow Handler


timer0_overflow:
  sbrs r18, 0                 ; wenn Entprellhandler nicht gesetzt
  rjmp readin                ; Eingänge überprüfen
  subi r19, 1                 ; Timercounter dekrementieren
  cpi r19, 0
  breq action                  ; und wenn auf 0
  reti

action: 
  ldi r18, 0               ; Entprellhandler ausschalten
  reti

readin:
  mov r21, r17
  ldi r19, 10               ; 10 Interrupts bis nächste Ausführung Ausgabe
  sbis PINB, 3
  add r17, r20              ; Eingänge einlesen
  sbis PINB, 4
  sub r17, r20
  SBRC r17, 5               ; Wenn über "7"
  ldi r17, 0b00011000       ; zurück auf "0"
  SBRS r17, 3               ; Wenn unter "0"
  ldi r17, 0b00011111       ; zurück auf "7"
  cp r17, r21
  brne output
  reti

output:
  ldi r18, 1                ; Entprellhandler setzen
  out PORTB, r17            ; Ausgeben
  reti
 
main: 
  ldi r20, 1             ; eine  EINS
  ldi r19, 0                ; Timercounter
  ldi r18, 0                ; Entprellhandler
  ldi r17, 0b00011000      ; BCD-Basis-System
  ldi r16, 0b00000111      ; IO-Aufbau
  out DDRB, r16
  out PORTB, r17
  mov r21, r17
  ldi r16, (1<<CS02)       ; CS02 setzen: Teiler 256
  out TCCR0, r16
  ldi r16, (1<<TOIE0)      ; TOIE0: Interrupt bei Timer Overflow
  out TIMSK, r16
  sei
  rjmp loop

loop:
  rjmp loop           ; Warteschleife

lässt sich auch wunderbar überall simulieren, funktioniert also 
anscheinend einwandfrei. ^^
also danke noch mal.

eine frage stellt sich mir da aber natürlich trotzdem noch: ist das so 
vom stil her in ordnung? oder könnte/sollte/müsste man das evtl. noch 
ein wenig verändern, damit es irgendwo zuverlässiger läuft? (zeit ist 
bei dieser sache ja kein ding, beim tastendruck wird praktisch sofort 
umgesetzt, danach alle sekunde eines weitergeschaltet, also scheint mir 
soweit gut zu funktionieren!)

Autor: Kluchscheißernder Nixwisser (kluchscheisser)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sven J. schrieb:
> stimmt. das sei funktioniert einwandfrei!

Tipp: Bei www.atmel.com kann man das Datenblatt zum Controller 
(kostenfrei) herunterladen. Darin findet man neben der Liste der 
I/O-Register auch die Befehlsliste. Weiterführende Informationen zu den 
ASM-Befehlen findet man in der Online-Hilfe des AVR-Studios.

> (ich hatte das vorher schon
> mal probiert,

Das "Ausprobieren" der Instruktionen ist daher überflüssig.

> da hat es aber nicht so richtig funktioniert, wird wohl an
> den sprüngen gelegen haben!)

> ...

>
> eine frage stellt sich mir da aber natürlich trotzdem noch: ist das so
> vom stil her in ordnung? oder könnte/sollte/müsste man das evtl. noch
> ein wenig verändern, damit es irgendwo zuverlässiger läuft?

Ja, kann man.

Schau Dir mal die Bulletproof-Tastenentprellung von Peter Dannegger an. 
Sie entprellt (durch Vierfachabfrage im Timer-Interrupt) das Drücken und 
das Loslassen, selektiert die Flanke beim Drücken und ermöglicht auch 
eine sehr saubere Repeat-Funktionalität. Und da sie den Timer nicht 
stoppt oder anderswie manipuliert, kann der Timer nebenher auch noch für 
andere Dinge genutzt werden. Durch die Vierfachentprellung von Drücken 
und Loslassen können Störimpulse keinen versehentlichen Tastendruck 
auslösen, was derzeit in Deinem Programm der Fall ist.

Überdenke nochmal Deine Zählumfangsbegrenzung. Du sparst Dir die 
Abfragen, wenn Du den Zählerstand permanent mit 7 verANDest und die 
beiden starren Bits (interne Ziehwiderstände) dazu ORst.

> (zeit ist
> bei dieser sache ja kein ding, beim tastendruck wird praktisch sofort
> umgesetzt,

Und das ist das Problem, denn jeder Störimpuls ist in der Lage, einen 
Zählvorgang auszulösen. Deine "Entprellung" entprellt ja den ersten 
Tastendruck nicht, sondern wirkt nur als Repeat-Verzögerer.

> danach alle sekunde eines weitergeschaltet, also scheint mir
> soweit gut zu funktionieren!)

Der Schein trügt, im Simulator mag das funktionieren, in der Realität 
zählt es jeden Störimpuls.

Schau Dir das mal an:
Beitrag "Tasten entprellen - Bulletproof"
http://www.mikrocontroller.net/attachment/1925/Get8keyb.asm

MfG

Autor: Kluchscheißernder Nixwisser (kluchscheisser)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich sehe gerade, das die Forensoftware den ersten Link verändert hat. 
Ich hatte den Link auf die Bulletproof-Entprellung eingefügt:
Beitrag "Tasten entprellen - Bulletproof"
und meine den ersten Beitrag des Threads.

MfG

Autor: test (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kluchscheißender Consulter schrieb:
> Tipp: Bei www.atmel.com kann man das Datenblatt zum Controller
> (kostenfrei) herunterladen. Darin findet man neben der Liste der
> I/O-Register auch die Befehlsliste. Weiterführende Informationen zu den
> ASM-Befehlen findet man in der Online-Hilfe des AVR-Studios.

Und wem das nicht reicht (oder wer kein AVR Studio, zwecks Hilfe nutzt), 
für den hat Atmel sogar noch was besseres:

http://atmel.com/dyn/resources/prod_documents/doc0856.pdf

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.