Forum: Mikrocontroller und Digitale Elektronik Assembler Programm funktioniert im Simulator aber nicht in der Praxis


von Bernd (Gast)


Lesenswert?

Hallo alle zusammen,
ich bin seid einiger Zeit ein stiller Mitleser und konnte bisher kleine 
Assemblerprogramme mit euer Hilfe und des Tutorials fehlerfrei 
schreiben.
Jetzt bin ich mit meinem Latein am Ende.

Ich möchte mit einem kleinen Taster eine Kreislauf starten.
Wenn der Taster S1 (PB2) betätig wird, soll eine grüne LED (PB4) kurz 
aufleuchten, um zu zeigen, dass der Kontakt vom Taster (PB2) erkannt 
wurde. Dabei soll das Programm kurzzeitig stehen bleiben (Delay) und 
dann weiter arbeiten. Als nächstes soll die rote LED (PB0) eingeschaltet 
werden und gleichzeitig geht die grüne LED aus (wenn kein Kontakt über 
den Taster erkannt wurde).
Die rote LED bleibt so lange eingeschaltet, bis ein weiterer Impuls über 
den Taster eingegangen ist.
Dann beginnt der Zyklus von vorn.

Ich verwende einen ATtiny13 und ein kleines Board aus einem Lernpaket.

Mein Problem, wenn ich das Programm im AmtelStudio 6 durchlaufen lasse, 
läuft es ohne Probleme. Sobald ich es in den uC lade leuchtet die grüne 
LED nach ein paar Impulsen dauerhaft und nach ein paar weiteren, 
schaltet der uC auf die rote LED um und das wars. Nix funktioniert mehr.

Über eure Hilfe bin ich sehr dankbar :-)
1
    .include "tn13def.inc"
2
    rjmp anf
3
anf:
4
    .def zustand =r17
5
    ldi r16, (1<<PB2)       ; PB2 an PinB aktivieren
6
    out portb, r16                 ; der Port auf Eingang gestellt ist.
7
8
9
ledgruen:
10
     clr r16
11
     in r16, pinb       ; an Port b anliegende Werte (Taster) nach r16 einlesen
12
     cpi r16, 0x00    ;0 = kein Signal liegt an
13
     breq ledgruen
14
     cpi r16, 0x10    ; Signal von LED - Grün - möglicher Zustand laut Simulator
15
     breq ledgruen
16
     cpi r16, 0x11   ; Signal von LED - Rot und LED - Grün - möglicher Zustand laut Simulator
17
     breq ledgruen    
18
     rjmp noteq
19
20
         rjmp ledgruen     ;  zu "loop:" -> Endlosschleife
21
noteq:
22
    ldi r16, (1<<PB4)
23
    ldi r18, (1<<DDB4)
24
    out ddrb, r16    ; PB4 Ausgang low
25
    out portb, r18    ; PB4 Ausgang high = LED Grün Ein
26
    clr r16
27
    rcall DLY1      ; Verhinderung einer Signalüberschneidung durch den Taster
28
    rjmp zt_kontrolle
29
    rjmp ledgruen
30
31
zt_kontrolle:
32
    cpi zustand,0    ;Vergleiche den Gespeicherten Zustand mit 1(=EIN)
33
    brne LEDrotAus    ;Wenn Zustand = 1, dann springe zu LEDrotAus
34
    ldi zustand,1    ;Wenn Zustand ungleich 1 ist, dann lade in Zustand den Wert 1
35
    ldi r16, (1<<PB0)|(0<<PB4)
36
    ldi r18, (1<<DDB0)|(0<<DDB0)
37
    out ddrb, r16    ;PB0 als Ausgang setzen (Low)      PB4 wird als Eingang gesetzt
38
    out portb, r18    ;Rote LED ein (High)          PB4 - Tri State
39
    rjmp ledgruen
40
LEDrotAus:
41
    clr zustand      ;Zustand löschen (=0)
42
    ldi r16, (0<<PB0)|(0<<PB4)
43
    ldi r18, (0<<DDB0)|(0<<DDB4)
44
    out ddrb, r16    ;PB0 als Ausgang löschen
45
    out portb, r18    ;Rote LED aus -  Tri - State
46
    rjmp ledgruen
47
48
DLY1:        ; Warteschleife ca. 0,5 - 1 sec
49
  ldi r16, 250
50
DLY2:
51
  ldi r17, 250
52
DLY3:
53
  ldi r18, 5
54
DLY4:
55
  dec  r18
56
  brne DLY4
57
  dec  r17
58
  brne DLY3
59
  dec r16
60
  brne DLY2
61
  ret

Oder
1
ledgruen:
2
     in r16, pinb       ; an Port b anliegende Werte (Taster) nach r16 einlesen
3
     cpi r16, 0x04    ; Wert bei Eingang vom Taster
4
     breq noteq
5
     cpi r16, 0x15    ; Wert bei Eingang vom Taster und den LED's
6
     breq noteq
7
     rjmp ledgruen     ;  zu "loop:" -> Endlosschleife

Vielen Dank schon mal im Vorraus

von Stefan E. (sternst)


Lesenswert?

Zwei (von vielleicht mehr) Punkten:

1) Den Pull-Up an PB2 schaltest du im Verlauf des Programms wieder aus.

2) Du vergleichst immer den kompletten Port-Inhalt, obwohl dich doch nur 
eine einzelnes Bit interessiert.

Ganz allgemein ist für dich jetzt also der Zeitpunkt gekommen, wo du 
dich ganz dringend damit beschäftigen musst, wie man Aktionen auf nur 
einzelne Bits beschränkt, sowohl beim Output (Punkt 1), als auch beim 
Input (Punkt 2).

von der alte Hanns (Gast)


Lesenswert?

Der Zustand (r17) wird in DLY immer 0 gesetzt.

von Bernd_Stein (Gast)


Lesenswert?

Bernd schrieb:
> ldi r16, (1<<PB2)       ; PB2 an PinB aktivieren
>     out portb, r16                 ; der Port auf Eingang gestellt ist.

Ich verstehe Deine Kommentare nicht so ganz.

Nach einem Reset werden ja alle " Special Functions Register " ( SFR ), 
mit einem bestimmten Wert vorinitialsiert. Beim Data Direction Register 
PortB ( DDRB ) geschieht dies mit einem Nullbyte, also alle Bits = 0.

Das bedeutet mit den beiden oberen Befehlszeilen aktivierst Du den 
Portpin B2, als Eingang mit internen Pullup. Bzw. als Eingang werden sie 
ja schon durch die Reset-Initialisierung eingestellt. Du schaltetst mit 
den beiden Befehlen nun den Pullup an den Eingangspin PB2. Dies wolltest 
Du sicherlich auch - nur aus deinem Kommentaren geht das nicht klar 
hervor.

Soweit so gut. Den Rest kann ich mir hoffentlich am Montag näher 
anschauen.

Nur so als Tipp. Taster prellen. Und µC arbeiten meistens rasend schnell 
- der Simulator nicht.


Bernd_Stein

von Amateur (Gast)


Lesenswert?

Mir erscheint das Ganze, als wär’s fast ausschließlich mittels Copy und 
Paste entstanden.

Ich weiß: Heuzutage geht Kopieren über Studieren - ob das aber richtige 
Weg ist, darf bezweifelt werden.

Gerade die Differenzen zwischen Aktion und Kommentar sind ein recht 
guter Hinweis darauf. Auch habe ich es noch nie gesehen, dass jemand ein 
Register (r17) mit einem Namen versieht, alle andren aber nicht. Ich 
kenne nur ent- oder weder.
Wobei man sich trefflich über den Nutzen des einen oder den Nachteil des 
anderen streiten kann.

Vielleicht solltest Du etwas mehr Zeit in "Wie geht's" und weniger in 
"Wo steht's" investieren.

von Bernd (Gast)


Lesenswert?

Woah, das sind schon mal schnell viele Antworten.

zu  Stefan Ernst:
1.Das ich den  Pullup an PB2 ausgeschaltet habe, ist mir gar nicht 
aufgefallen, ich habe mich immer nur auf die Zustände meiner LED's 
konzentriert. Ich habe jetzt in jeder Zeile, die portb bearbeitet mit 
"|(1<<PB2)" erweitert.
Der Pullup bleibt nun dauerhaft an.

2.Da bin ich gerade dabei mich einzumummeln, ist mir gelungen, einzelne 
Bits zu manipulieren aber die direkte Abfrage halt nicht. Deshalb habe 
ich über die summen der einzelnen Bits gearbeitet.
Danke für deine Tipps.
Beim kurzen Überfliegen, denke ich werde ich mich mit sbrc, sbis und die 
Möglichkeiten von andi genauer angucken.

Zu der alte Hanns:
Da hast du Recht. Es ist im Simulator nicht aufgefallen, da ich beim 
Debuggen immer die Schleife ausgestellt habe. Neues Register, Problem 
behoben. Danke :-)

Zu Bern_Stein.

Ja, die Kommentare sind noch ausbaufähig :-)
Ich habe mir im Netz verschiedene Herangehensweisen angeguckt, wie ich 
einen Taster entprellen kann. Die Herangehensweisen waren einleuchtend, 
nur an der Umsetzung bin ich bisher nicht vorrangekommen und mein 
Gedanke war, dass sobald am Taster ein Signal kommt, egal wie oft, soll 
das Programm anfangen zu arbeiten und auf jeden Fall immer einmal die 
Schleife durchlaufen. Da nun mehrere Impulse an PB2 ankommen, wird so 
nur der erste gewertet und erst nach "rjmp ledgruen" wird die nächste 
Abfrage gestellt.
Dass das nicht das Gelbe vom Ei ist, weiß ich. Nur sind meine 
Assemblerkenntnisse nicht genug ausgereift, um ihn noch zu entprellen. 
Das war mein nächster Schritt. Ich wollte jetzt die Struktur des 
Hauptprogrammes aufbauen.

Zu Amateur:
Ich arbeite mich durch das AVR - Tutorial und das kleine Heft des 
Experimeniersets. Beide haben eins gemeinsam, die Formatierung und auch 
Schreibweisen. In beiden wird auch per Quellcode erklärt. Ich kann dir 
aber sagen, dass ich mir für bei diesem Quellcode an die Atmel Libary 
Home und dem Datasheet gehalten habe, als nach der Copy und Paste 
Methode vorzugehen.
Das war am Anfang (bei meinem aller ersten Versuch) meine Strategie, die 
ich schnell verworfen, nachdem ich erkannt habe, wie umfangreich die 
Thematik mit dem uC ist.
Es stimmt, dass das "Wie" wichtiger ist als das "Wo". Nur bin ich jetzt 
auch nicht weitergekommen und habe mich an das Forum gewandt, damit mir 
hier geholfen wird. Ich erwarte nicht, dass mir jemand meinen Code 
korrigiert und für mich schreibt. Das will ich selber nicht, denn dann 
lerne ich es ja nichts. Aber das Hinweise gegeben werden, was ich falsch 
gemacht habe oder wo ich nochmal was nachlesen sollte, das erhoffe ich 
mir hier.


An alle:

Ich habe mir mein fertiges Programm in mehrere kleine Aufgaben geteilt, 
sodass ich immer wieder eine neue Eigenheit habe. Nun war ich soweit, 
dass ich einen nicht entprellten Taster hatte, der mit einer LED lief, 
die Ansteuerung einer zweiten led, eine endlos & endende blinkschleife 
und letztes jeweils mit einem Taster gekoppelt.
Diese Puzzelt eile wollte ich jetzt zu einer kleinen Grundstruktur 
zusammensetzen.

Danke für eure Beiträge.
Bin mal gespannt, was noch dazukommt und morgen werde ich weiter lesen, 
programmieren und euch berichten, wie ich vorangekommen bin.
In diesem Sinne gute Nacht. :-)

von Uwe (Gast)


Lesenswert?

Hi,
>rcall DLY1
.
.
ret
ohne Stackinit geht glaube auch in die Hosen.....

Viel Erfolg, Uwe

von der alte Hanns (Gast)


Lesenswert?

SPL wird hardwaremäßig mit RAMEND = 0x009f initialisiert.

von Rush (Gast)


Lesenswert?

der alte Hanns schrieb:
> SPL wird hardwaremäßig mit RAMEND = 0x009f initialisiert.

Wo hast Du das gelesen? In jedem Datenblatt und auch in den App-Notes 
wird darauf hingewiesen, dass der Stack initialisiert werden soll/muss.
Würde mich wirklich interessieren wo das geschrieben steht, denn ich 
lerne gerne immer noch etwas dazu.

Grüße

von Dietrich L. (dietrichl)


Lesenswert?

Rush schrieb:
> Wo hast Du das gelesen?

Im Datenblatt unter "4.5.1 SPL - Stack Pointer Low.: Initial Value"

Grüße Dietrich

von c-hater (Gast)


Lesenswert?

Rush schrieb:

> Wo hast Du das gelesen? In jedem Datenblatt und auch in den App-Notes
> wird darauf hingewiesen, dass der Stack initialisiert werden soll/muss.

Wann hast du das letzte Mal ein AVR-Datenblatt gelesen?

Alle neueren AVRs intialisieren ihren Stack selber sinnvoll, also auf's 
Ende des vorhandenen RAM.

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
Noch kein Account? Hier anmelden.