Ich habe Probleme beim Schreiben des Codes zum Blinken von 6 LEDs von PORTC auf dem Mikrocontroller PIC16F690. Die LEDs sollten wie die Lichter auf einer Landebahn blinken.
Mit dem Code, den ich derzeit habe, blinken die LEDs paarweise und außer Betrieb.
Hier ist der Code, den ich derzeit habe:
list p=16F690
radix hex
include "P16F690.INC"
__config _WDT_OFF & _BOR_OFF & _PWRTE_ON & _INTOSCIO & _MCLRE_OFF
errorlevel -302
org 0
count equ 20 ;we're going to need two variables
count2 equ 21
call initial
call Blink
initial ; initialize registers
bsf STATUS, RP0
movlw B'00000000'
movwf TRISC
bcf STATUS, RP0
bsf STATUS, RP1
clrf ANSEL
clrf ANSELH
bcf STATUS, RP1
return
Blink ;flip the LED on or off
movlw B'00000001'
rlf PORTC,F
call Delay
call Blink
Delay ; waste time
movlw 0xFF
movwf count
movwf count2
Delayloop
decfsz count,f
goto Delayloop
decfsz count2,f
goto Delayloop
return
END
Es gibt einige Probleme mit Ihrem Code. Ich werde sie in der Reihenfolge aufzeigen, in der ich denke, dass sie hier das eigentliche Problem darstellen. Die ganz unten sind nur Best-Practice-Tipps.
Sie initialisieren nie PORTC
. Der Wert von PORTC
ist bei einem Power-On Reset unbekannt . Sie müssen es in Ihrer initial
Routine auf einen bestimmten Wert einstellen:
movlw 0x01
movwf PORTC
Dadurch wird eine LED eingeschaltet, was wahrscheinlich das ist, was Sie wollen. Danach RLF
beginnen Sie mit , dieses Bit zu drehen, um andere LEDs zu beleuchten.
Es kann sein, dass dies die Idee hinter diesen Zeilen in ist blink
:
movlw B'00000001'
rlf PORTC,F
Die erste Zeile hat jedoch keine Auswirkung: Sie speichert 0b00000001
in W, aber W wird nie verwendet. RLF
nimmt register PORTC
, dreht es und speichert es wieder in PORTC
- W wird nicht verwendet. Außerdem führen Sie movlw B'00000001'
jedes Mal aus, wenn Sie eine Schleife durchlaufen blink
. Selbst wenn dies korrekt wäre, würde sich der Wert von PORTC
niemals ändern, da er ständig zurückgesetzt wird: Sie müssen den Port in der initial
Routine initialisieren und ihn in der blink
Routine ändern.
Blink ;flip the LED on or off
movlw B'00000001'
rlf PORTC,F
call Delay
call Blink
Es gibt drei verschiedene Arten von Anweisungen zum Springen im Code: GOTO
, CALL
und RETURN
.
Mit GOTO
springen Sie einfach in den Code - so einfach ist das.
Mit CALL
implementieren Sie GOTO
aber auch den aktuellen Programmzähler auf den Stack. Dieser Stack ist ein LIFO-Speicherbaustein (last in first out), in dem in diesem Fall Programmplätze gespeichert werden können.
Mit RETURN
holen Sie das letzte Element aus dem Stapel und springen zu dieser Stelle. Im Wesentlichen springen Sie zu der Anweisung nach der zuletzt ausgeführten CALL
. Dies ist, was Sie am Anfang verwenden, wo Sie anrufen Initial
und dann zurückkehren und anrufen Blink
.
Der Stapel dieses Chips hat acht Ebenen, wie in Abschnitt 2.3.2 des Datenblatts beschrieben . Das heißt, Sie können maximal acht Programmplätze auf diesen Stapel schieben. Danach wird der erste Index überschrieben (der Stack ist als Ringpuffer implementiert). Das bedeutet im Wesentlichen, dass es dann nicht möglich ist, zur ersten Anweisung zurückzukehren CALL
, und dass der Controller an eine andere Stelle springt. Dies kann viele unerklärliche Probleme in fortgeschrittenerer Software verursachen.
Mit dem oben zitierten Code rufen Sie ständig an Blink
, aber es gibt keine RETURN
Anweisung. Das bedeutet, dass Sie weiterhin Sachen auf den Stapel schieben, ohne sie zu zerplatzen. Ständig wird der Stack überschrieben. Da Sie dort nicht verwenden RETURN
, ist es nicht so wichtig. Aber in dieser Situation sollten Sie wirklich GOTO
statt verwenden CALL
:
Blink ;flip the LED on or off
movlw B'00000001'
rlf PORTC,F
call Delay
goto Blink
Da GOTO
der Stapel nicht verwendet wird, ist dies kein Problem.
Du hast viele Sachen angezogen org 0
. Dies ist keine gute Praxis. Wie in Abschnitt 2.1 des Datenblatts nachzulesen ist , hat dieser Chip einen Interrupt-Vektor bei org 4
. Das bedeutet, dass der Programmzähler bei einem Interrupt auf Platz 4 springt, fast direkt nach 0. Deshalb implementieren wir normalerweise nur eine GOTO
Anweisung auf org 0
. Etwas wie das:
org 0
goto start
org 4
retfie ; return from interrupt (alternatively you could have
; an interrupt handler here)
start:
; your main code...
Wie ich bereits in den Kommentaren erwähnt habe: Oben in Ihrem Programm haben Sie angegeben radix hex
(und dies ist auch die Standardeinstellung). Aus diesem Grund können Sie EQU 20
mit Register auswählen 0x20
. Es ist jedoch viel klarer, wenn Sie einfach EQU 0x20
oder verwenden EQU 20h
. Wenn andere Ihren Code lesen, müssen sie nicht nach der Radix-Spezifikation oder dem Standardwert des Assemblers suchen.
Vielleicht wissen Sie das schon, aber vielleicht finden Sie das hier interessant: http://www.piclist.com/techref/piclist/codegen/delay.htm
Dies ist ein Verzögerungsgenerator, der eine Verzögerung einer bestimmten Zeit für Sie erzeugt. Ihre Verzögerungsroutine ist perfekt, soweit ich das jetzt sehen kann, aber wenn Sie jemals nach etwas suchen, das sie genau berechnet, hier sind Sie!
In Ihrem Beispiel gibt es so viel schlechte Programmierung, dass eine richtige Antwort zu lange dauern würde. Es gibt den absoluten Modus, die manuelle Bankeinstellung, die feste Platzierung von Variablen, versteckte, aber implizite Annahmen über die Bankeinstellung und das Überlaufen des Aufrufstapels. Was für ein Chaos! Vielleicht habe ich morgen Zeit, das alles durchzustehen.
Allerdings ist der Code bei BLINK besonders wirr und wahrscheinlich die Ursache des Ärgers. Ich kann nicht einmal erraten, was Ihrer Meinung nach das Laden von 1 in W bewirken soll. Der Mangel an Kommentaren ist geradezu unverantwortlich. In Ihrer Beschreibung über dem Code sprechen Sie von mehreren LEDs, aber der Kommentar bei BLINK spricht nur vom Umdrehen einer einzelnen LED. Der wirkliche Fehler scheint zu sein, dass RLF nicht so funktioniert, wie Sie denken, obwohl man ohne Kommentare nicht sagen kann, was Sie denken. Beachten Sie, dass die Drehung an 9 Bits, dem Register und dem C-Bit, durchgeführt wird.
Dies sollte einfach zu debuggen sein. Laden Sie dies in MPLAB und führen Sie es im Simulator aus. Dann können Sie das Programm einzeln durchlaufen und sehen, was jede Anweisung tut.
Wladimir Cravero
Wladimir Cravero
Wladimir Cravero
mrplow911