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
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
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
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.
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
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
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
.. 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.
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
...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
..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
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
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
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
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
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
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
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
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
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
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