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.
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
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
Nein, habe ich ncht... :-| Aber nein, "INCF ziffer1, W" ist richtig. MFG
.. 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.
@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
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
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
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
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.