Forum: Mikrocontroller und Digitale Elektronik Aus Schleife entfliehen


von Klaus M. (Gast)


Lesenswert?

Hallo,
ich habe einen Counter für einen PIC 16F73 programmiert. Es funktioniert 
auch alles soweit das ich den Counter mit einem Taster (PORTC, 2) 
starten kann. Doch irgendwie schaffe ich es nicht das der Counter 
entweder durch einen weiteres drücken des Tasters bzw. bei erreichen der 
Zahlen 0000 stoppt. Der Counter wird gestartet sobald das bit 0 im 
Register Starten gesetzt ist. Die aktuellen Werte der Zahlen die 
angezeigt werden befinden sich in den Registern ziffer1 - ziffer4. Das 
Register ZZZZ dient nur als zwischenspeicher. Kann mir vllt jemand sagen 
warum es nicht funktioniert, was mache ich falsch? Habe schon mehrere 
Möglichkeiten ausprobiert aber es ist immer das gleiche Ergenist, es 
leuchten nur "achter" und dann wirre LED-kominationen.

Danke im Vorraus
Klaus M.

MAIN
ZEAHLEN
  btfss  PORTC, 2
  goto     ZAEHLEN
  call  Wait
  comf  STARTEN, F
ZAEHLER2
  incf  ziffer1, W
  movwf  ZZZZ
  decfsz  ZZZZ, F
  goto  ZAEHLER2

  incf  ziffer2, W
  movwf  ZZZZ
  decfsz  ZZZZ, F
  goto  ZAEHLER2

  incf  ziffer3, W
  movwf  ZZZZ
  decfsz  ZZZZ, F
  goto  ZAEHLER2

  incf  ziffer4, W
  movwf  ZZZZ
  decfsz  ZZZZ, F
  goto  ZAEHLER2

  comf  STARTEN, F
  goto  MAIN

von Martin (Gast)


Lesenswert?

spagetticode!

von Dennis (Gast)


Lesenswert?

@ Martin:

schon mal assembler programmiert?

von Peter D. (peda)


Lesenswert?

Du solltest zuerst mal den Code kommentieren.
Das hilft vor allem Dir, den Ablauf zu verstehen. Und dann die Stelle zu 
sehen, wo Du was ändern mußt.
Aber es erhöht auch drastisch die Warscheinlichkeit, daß ein anderer 
sich den Code überhaupt ansieht.

Du sprichst von Ziffern, aber ich sehe nirgends einen Vergleich mit 10.
Und wenn was falsches angezeigt wird, mußt Du auch die Anzeigefunktion 
mit posten (längeren Code >20 Zeilen als Anhang).
Ich sehe auch nirgends den Aufruf einer Anzeigefunktion.

Code sollte auch immer assemblierbar sein, d.h. alle Unterfunktionen und 
Variablendefinitonen enthalten.


Ich weiß jetzt nicht, wie groß der Stack dieses PIC ist, aber Code läßt 
sich deutlich besser verstehen, wenn man die einzelnen Aufgaben in 
Unterfunktionen aufteilt.
Z.B. eine zum Taste Abfragen, eine zum Hochzählen, eine zum Anzeigen 
usw.


Peter

von Klaus m. .. (magic-moe)


Angehängte Dateien:

Lesenswert?

So, nun habe ich den ganzen Code angehängt.

MFG
Klaus M.

von Klaus m. .. (magic-moe)


Lesenswert?

Hmm...weiß keiner eine Lösung?

MFG
Klaus M.

von Peter D. (peda)


Lesenswert?

Du hast immer noch nicht kommentiert, wie die Routine "ZEAHLEN" 
funktionieren soll.
Wenn ich das richtig sehe, zählt sie mit nem Affenzahn Bytes und keine 
Ziffern.


Peter

von Klaus m. .. (magic-moe)


Lesenswert?

Also...die folgende Erklärung bezieht sich auf meine erste Nachricht!

Als erstes wird überprüft ob am Eingangspin "PORTC 2" ein Signal (5V) 
anliegt. Ist das nicht der Fall, läuft das Programm weiter in eine 
nichts-tuhenden Endlosschleife. Liegen jedoch 5 Volt an, so wird der 
Taster entprellt (call Wait) und anschließend das Byte Starten 
invertiert, also mit '11111111' gefüllt. In einem Interrupt der alle 4ms 
ausgelöst wird (überlauf von TMR0), wird das Bit o des Byte Starten 
überprüft: Ist es gesetzt, läuft der Counter. Ist es 0, steht der 
Counter. Nachdem also das Bit o gesetzt ist und der Counter läuft, wird 
zum Byte ziffer 1 (indem sich der Wert der ersten 7-Segment Anzeige 
befindet) "1" addiert und das Ergebnis in W gespeichert (incf ziffer1, 
W). Dannach wird W in das Zwischenspeicherregister ZZZZ kopiert. Nun 
wird von ZZZZ der Wert 1 subtrahiert. Ist das Ergenis nicht 0, wird der 
nächste Befehl (wieder zum start der Routeine springen) ausgeführt, ist 
das Ergebnis 0, wird das nächste Ziffern-Byte auf diese Weiße überprüft. 
Sind alle Bytes 0, so wird das Starten Byte wieder zurück-invertiert 
('00000000') und der Counter müsste aufhören zu laufen.

Ich hoffe das Hilft

MFG
Klaus M.

von klaus m. (Gast)


Lesenswert?

Das ist doch eine prima Erklärung!!
Weiß denn keiner woran es liegen könnte das es nicht klappt so wie ich 
es gemacht habe?

MFG

von Peter D. (peda)


Lesenswert?

klaus m. schrieb:
> Das ist doch eine prima Erklärung!!

Nö.

Kommentare schreibt man mit in den Quelltext hinein, an die Stelle, wo 
das Entsprechende ausgeführt wird.
Du kannst nicht erwarten, daß sich das jeder erstmal umständlich selber 
raussuchen muß.

Meine Anmerkungen zu der Routine "ZEAHLEN" hast Du auch vollkommen 
ignoriert. Ich sehe auch nicht, daß diese was mit nem Interrupt zu tun 
hat.
Oder geht es jetzt garnicht mehr um die Routine "ZEAHLEN"?


Peter

von Klaus m. .. (magic-moe)


Angehängte Dateien:

Lesenswert?

Hallo,
ich habe den Assemblercode nun kommentiert und versucht, ihn so gut es 
ging optisch bzw. grafisch übersichtlich zu gestalten.

Es geht im Prinzip "nur" um das Unerprogramm (ist keins da es nicht mit 
call sondern mit goto aufgerufen wird) "ZAEHLEN2". Der Counter soll 
stoppen, wenn alle vier Ziffern auf 0 ist. Doch aus mir unbekannten 
Gründen funktioniert es nicht.

Danke im Vorraus
MFG

von Eschi (Gast)


Lesenswert?

Hallo,
hast Du schon mal mit z.B. im MPLAB debugt?
Der Befehl INCF Ziffer1, W erhöht aber nicht das Register Ziffer1 was er 
vermutlich tun soll. Schau da mal nach. Vermutlich muss es heißen INCF 
Ziffer1, F.

Gruss Martin

von Klaus m. .. (magic-moe)


Lesenswert?

Nein, habe ich ncht...  :-|

Aber nein, "INCF ziffer1, W" ist richtig.

MFG

von Eschi (Gast)


Lesenswert?

.. glaub ich nicht! Das INCF x,W besagt doch, dass das Ergebniss der 
Operation in W gespeichert werden soll. Wie soll sich der Wert in 
Ziffer1 denn dann ändern? Probiers mit INCF Ziffer1, F aus.

von Martin (Gast)


Lesenswert?

@Dennis
habe ich müssen(für die uni) und aus dem grund werde ich es nie wieder 
tun, c ist einfach so viel übersichtlicher

von Klaus m. .. (magic-moe)


Lesenswert?

So, ich habe besagte W´s durch F´s ersetz. Es funktioniert wie ich 
vorraisprognostiziert habe jedoch nicht, denn ich will ja auch nicht den 
eigentlichen Wert von ziffer1 verrändern, sondern ihn nur als 
referenzwert benutzen. Nachdem er erhöht wurde, wird er ja in das 
Zwischenspeicherregister ZZZZ geschrieben (siehe programm fast ganz 
unten).

Es ist wie verflixt, wenn ich den Programmcode von der Sprungadresse 
"ZAEHLEN2" bis "SEGMENTE" lösche und durch eine einfache Endlosschleife 
(LOOP - goto LOOP) ersetzt funktioniert es. Der Fehler muss also in 
diesen 20 Zeilen liegen. Ich bin am verzweifeln...

MFG

von Eschi (Gast)


Lesenswert?

...oh, jetzt habe ich kapiert was die Routine tun soll. Du hast recht, 
INCF x,W sollte funktionieren. Ich haben den Kommentar falsch 
verstanden. Das Unterprogramm Zaehlen2 soll testen ob Ziffer1 bis 
Ziffer4 0 enthalten. Lade Ziffer1 ins W und prüfe das Zerobit im 
Statusregister.

Gruss Martin

von Eschi (Gast)


Lesenswert?

..das oben war ein Vorschlag, um die Aufgabe anders zu lösen.
Nochmals zu Deiner Lösung eine Nachfrage. Wo wird das Register "zzzz" 
definiert? Konnte ich im Listing nicht finden. Gibt es keine 
Fehlermeldung?

Gruss Martin

von Klaus m. .. (magic-moe)


Lesenswert?

Ja ist richtig, das habe ich dort nicht deklariert, da ich 
zwischenzeitlich schon wieder eine andere Version veruscht hatte. Daran 
liegt es wie du dir sicher denken kannst aber nicht.

Es leuchten alle zeichen (auser punkt) und wenn mann eine taste drückt 
kommt wirr-warr.

MFG

von Klaus M. (Gast)


Lesenswert?

Weiß denn wirklich niemand warum es nicht geht? Ein Problem mit dem 
Stack dürfte es ja eigentlich auch nicht sein, denn ich spinge ja mit 
goto einfach in eine andere Schleife, und will dann zu gegebenem 
Zeitpunbkt wieder in die andere Schleife zurückspringen. Könnte es vllt 
mit dem Z-Bit zusammenhängern? Es gibt ja nicht viele Befehle in der 
Schleife woran es liegen könnte...MHMMM

MGF

von Peter D. (peda)


Lesenswert?

Klaus m. ... schrieb:
> Der Counter soll
> stoppen, wenn alle vier Ziffern auf 0 ist. Doch aus mir unbekannten
> Gründen funktioniert es nicht.

Naja, PIC-Assembler ist so ziemlich der komplizierteste Assembler, den 
ich kenne.

Da Du meine Fragen nicht beantwortest, versuche ich mal zu erklären, was 
Deine Routine macht.

1.
Sie springt immer direkt zu ZAEHLEN2, ohne auf nen Timer oder ne Taste 
zu warten.

2.
Sie zählt keine Ziffern, sondern Bytes und das äußerst merkwürdig.
Für 2 Bytes gesehen:
1
ziffer2 ziffer1
2
0       0
3
1       1
4
1       2
5
1       3
6
...
7
1       254
8
1       255
9
1       0
10
2       1
11
2       1
12
...

Du testest ja auf 0 nach dem Decrement, d.h. der Überlauf erfolgt bei 
Byte = 1.


Peter

von XXX (Gast)


Lesenswert?

Hallo

ZAEHLEN2
  incf  ziffer1, W  ; ziffer1 um 1 erhöhen
  movwf  ZZZZ           ; Wert in ZZZZ zwischenspeichern
  decfsz  ZZZZ, F    ; von ZZZZ 1 abziehen
  goto  ZAEHLEN2    ; ist das Ergebnis <> 0 von vorn überprüfen,

Wie kommst due eigentlich aus dieser Schleife wieder raus????

Gruß
Joachim

von Peter D. (peda)


Lesenswert?

Hier mal ein Beispiel, wie einfach ein Zähler 0000-9999 auf nem 8051 
ist:
1
count:                                  ; Zähler 0000 ... 9999
2
        mov     a, #10                  ; Vergleichswert laden: 10
3
        inc     ziffer1                 ; Ziffer hochzählen
4
        cjne    a, ziffer1, ende        ; vergleiche A mit Variable, springe, wenn ungleich
5
        mov     ziffer1, #0             ; Ziffer nach Überlauf wieder auf 0 setzen
6
        inc     ziffer2
7
        cjne    a, ziffer2, ende
8
        mov     ziffer2, #0
9
        inc     ziffer3
10
        cjne    a, ziffer3, ende
11
        mov     ziffer3, #0
12
        inc     ziffer4
13
        cjne    a, ziffer4, ende
14
        mov     ziffer4, #0
15
ende:


Peter

von Klaus m. .. (magic-moe)


Lesenswert?

Hallo,

@Peter:
Peter Dannegger schrieb:
> Sie springt immer direkt zu ZAEHLEN2, ohne auf nen Timer oder ne Taste
> zu warten.

Das stimmt so nicht, denn am Anfang jeder Schleife (von den vieren die 
die Ziffern einstellen) wird PORTC 2 abgefragt. Und nur wenn das Signal 
1 ist (Taster gedrückt), spingt das Programm in den "Zählermodus".



Peter Dannegger schrieb:
> Du testest ja auf 0 nach dem Decrement, d.h. der Überlauf erfolgt bei
> Byte = 1.

Ich addiere doch zu einem unbekannten Wert 1 dazu und ziehe dann wieder 
1 ab. Ist das Ergebnis 0 (was nur so ist wenn die unbekannte Zahl vorher 
auch 0 war) dann gehts weiter, sonst nicht. Oder irre ich mich da?


@Joachim:
Der Befehl "decfsz ZZZZ, F" zieht von Register ZZZZ 1 ab und speichert 
das neue Ergebnis im Register ZZZZ. Dannach folgt der nächste Befehl 
(zurück zum Schleifenanfang), es sei denn, das Ergebnis war 0, dann wird 
nämlich der nächste Befehl übersprungen. In diesem Fall wird dann das 
nächste Byte überprüft.

MFG

von Eschi (Gast)


Lesenswert?

Hallo Klaus,

ich denke, dass Deine Routine funktionieren könnte. Vielleicht spuckt 
Dir der Interrupt dawischen und zerstört z.B das W-Register oder 
sonstwas? Im Datenblatt steht z.B dass man die Backupregister ab 0x70 
legen soll wegen der Pageselectgeschichte.

Auch könntest Du (wie schon mal vorgeschlagen) die Routine so 
aufzubauen:
[code]
movf Ziffer1,F :setzt Zerobit bei Null
btfss Status,Z :Zerobit testen
goto Zaehlen2
movf Ziffer2,F :setzt Zerobit bei Null
.
.
[\code]

Gruss Martin

von Eschi (Gast)


Lesenswert?

...ohh faschherum \ /

von Klaus m. .. (magic-moe)


Lesenswert?

Schade, die Idee von Martin funktioniert auch nicht. Aber wenigstens ist 
es jetzt ein anderes LED-Gewirre was erscheint.

Doch eins verstehe ich garnicht: Wenn ich in der Routine ZAEHLEN2 in der 
ersten Zeile "goto ZAEHLEN2" schreibe, müsste das doch eine 
Endlosschleife sein, die dannachfolgenden Zeilen dürften nie eine Rolle 
spielen da das Programm nie dorthingelangt. Aber dennoch Funktioniert es 
nur wenn diese Zeilen lösche oder mit einem Semikolon außer gefecht 
setzte. Es bringt auch nichts sie z.B. kurz vor "end" zu verschieben. 
Kann das sein?

MFG

von Eschi (Gast)


Lesenswert?

Das könnte daran liegen, dass es darauf ankommt wo das Programm im 
Speicher steht. Das ist z.B bei Deinem Unterprogramm "Segmente" der 
Fall. Hier darf es zu keiner Überschreitung eines 256 Byte Blocks 
kommen. Dies ist leicht aus dem Listfile ersichtlich.
Vesuchsweise könntest Du dieses Unterprogramm (Segmente) mit org 0x0700 
verschieben, wenns dort Platz gibt.
Lies dazu doch die AN556 von Microchip. Du wirst wohl nicht umhin 
kommen, den Debuger zu bemühen und den Bits beim Kippen zuzuschauen. Nur 
so wirst Du rausfinden, was tatsächlich passiert.

Gruss Martin

von Klaus m. .. (magic-moe)


Lesenswert?

Juhuuu, es funktioniert.

Ich habe die Segment-Tabelle weiter nach oben geschoben, zwischen die 
erste und zweite Ziffer-Schleife. Und schon funktioniert es einwandfrei.

Vielen Dank euch allen, vorallem Martin, dessen Hinweiß schließich fast 
die Lösung war. Ich habe die Tablle auch nach 0x0700 geschoben, aber 
dort funktionierte es auch nicht.

Aber wiso darf keine Tabelle auf so einem "256Byte übergang" sein, 
andere Routinen jedoch stört es nicht?

MFG

von Peter D. (peda)


Lesenswert?

Klaus m. ... schrieb:
> Aber wiso darf keine Tabelle auf so einem "256Byte übergang" sein,
> andere Routinen jedoch stört es nicht?

Die PIC-Entwickler haben schlichtweg vergessen, einen Befehl zum 
Indexzugriff auf den Flash zu implementieren.
Daher geht es nur über die Brechstange RETLW und Manipulieren des 
PC-Register und das ist nur 8Bit breit.
Du müßtest die Indexberechnung auf die volle Breite des Flash erweitern, 
indem Du auch das PCLATH mit berechnest, dann gehen auch Tabellen über 
die 256Byte-Grenze.

Allen anderen 8-Bittern (z.B. 8051, AVR) sind solche Probleme unbekannt, 
die haben 16Bit Pointer zum Flash adressieren.

Besonders elegant gehen Zugriffe auf Tabellen <=256 Byte auf dem 8051, 
da reicht ein einziger Befehl: "MOVC A,@A+DPTR" (DPTR = 
16Bit-Basisadresse, A = 8Bit-Offset).
Der Befehl macht die 16Bit Addition und liest das Byte.


Peter

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.