Forum: Mikrocontroller und Digitale Elektronik PIC führt Befehl nicht aus


von Fred (Gast)


Lesenswert?

Hallo, ich muss heute Abend noch einmal nerven... und zwar habe ich 
leider ein Problem in meinem Programm. Ich habe ein Programm auf einem 
PIC18F1220 geschrieben, welches eine analoge Spannung misst und 
hinterher den Wert der Spannung auf einer 3-stelligen 7Segmentanzeige 
ausgibt... Nun funktioniert mein Programm bis zur Ausgabe perfekt. Erst 
bei der Ausgabe entsteht ein Problem.

Hier erstmal der Problematische Teil:

Segmente
  addwf    PCL,W,1
  retlw    b'11000000'      ; Zero
  retlw    b'11111001'      ; One
  retlw    b'10100100'      ; Two
  retlw    b'10110000'      ; Three
  retlw    b'10011001'      ; Four
  retlw    b'10010010'      ; Five
  retlw    b'10000010'      ; Six
  retlw    b'11111000'      ; Seven
  retlw    b'10000000'      ; Eight
  retlw    b'10010000'      ; Nine

Ich springe also für die Ausgabe des Wertes auf der 7-Segmentanzeige zur 
Sprungmarke "Segmente". Hier addiere ich den in W-gespeicherten 
Anzeigewert des jeweiligen Segmentes zum PCL, damit dieser dann zur 
jeweiligen retlw-Zeile springt, sich den Wert für den PORTB holt und 
wieder in den Code zurückkehrt. Leider springt das Programm aber immer 
zur Sprungmarke Zero. Vollkommen egal welcher Wert in W gespeichert ist, 
es wird immer Zero ausgeführt und dementsprechend Null angezeigt.

Meine ADC-Wandlung klappt perfekt und sonst gibt es auch keine Probleme, 
der ADDWF Befehl funktioniert in anderen Speicherzellen auch sehr gut, 
ich weiss nicht warum es hier nicht klappt...

Habe ich etwas nicht bedacht und einen großen Fehler in der ganzen 
Sache? Vielleicht kennt jemand das Problem und hat nen Tipp für mich....



LG Fred

von Torsten K. (ago)


Lesenswert?

Ich vermute, "segmente" liegt recht Nahe an einer Page-Grenze.
Beispiel: Wenn segmente = 0x01fd ist, dann springt der Prozessor je nach 
W zu 0x1fe, 0x1ff, 0x100 (statt 0x200). PCH bleibt 0x1.

PCH wird nicht automatisch incrementiert wenn durch deine Addition PCL 
einen überlauf hat.

(Vermute ich nur)

von Fred (Gast)


Lesenswert?

Page Grenze? Du meinst, dass der PCL einen Überlauf hat und daher nicht 
klarkommt?

von Holger (Gast)


Lesenswert?

Genau, Page Grenze könnte es sein.
Weiterhin belegt der RETLW 2 Bytes, also vorher mit 2 multiplizieren 
onder verschieben.
So hab ich das für eine ähnliche Anwendung gelöst, bei mir ein 18F2520

Holger

; -----------------------------------------
; input: W Zahl 0-7
; return W mit gesetztem Bit 0-7


get_bit:
        andlw   .7              ; Nur 0- 7  zulässig
        mullw   .2              ; mit 2 multiplizieren

        movlw   HIGH(bits)      ; Highteil von Tabelle holen
        movwf   PCLATH
        movlw   LOW(bits)       ; Lowteil von Tabelle holen
        addwf   PRODL,w         ; Offset dazu
        btfsc  STATUS,C      ; Überlauf ?
  incf  PCLATH,f    ; ja um eins erhöhen
  movwf  PCL

bits:   retlw    B'00000001'    ; gesetztes Bit 0
        retlw    B'00000010'
        retlw    B'00000100'
        retlw    B'00001000'
        retlw    B'00010000'
        retlw    B'00100000'
        retlw    B'01000000'
        retlw    B'10000000'

von Edi R. (edi_r)


Lesenswert?

Fred schrieb:
> Segmente
>   addwf    PCL,W,1

Das ist falsch, richtig wäre:

> Segmente
>   addwf    PCL,F

Sonst addierst Du den PCF und W, und legst das Ergebnis in W (statt im 
PCF) ab.

von Torsten K. (ago)


Lesenswert?

siehe Beitrag "[PIC] Assembler Problem Sprungtabelle in Externer ASM Datei"

Du mußt PCLATH auf das high-Byte des Labels "segmente" setzen.

von Rainer Unsinn (Gast)


Lesenswert?

Wenn ich mich recht erinnere, ist die "Page" bei den 18er PICs nur 128 
Worte groß. Also ist die Chance ziemlich hoch, einen PCL-Überlauf zu 
erwischen. Es gibt zwei Möglichkeiten zur Lösung des Problems:
1. Tabelle an den Anfang des Programms legen, direkt hinter die 
Interuptvektoren
2. Tabelle ans Programmende legen und mit ORG eine runde Adresse 
festlegen.

Alternativ geht auch noch der Befehl TABLRD, dafür muss die Tabelle im 
Speicher angelegt werden.

von Holger (Gast)


Lesenswert?

3. Möglichkeit, es richtig zu machen, siehe oben

von Fred (Gast)


Lesenswert?

Herzlichen Dank für die ganze nette Hilfe und Unterstützung... der 
Einstieg ist gar nicht so einfach, es gibt immer wieder so Kleinigkeiten 
die man nicht weiss, vergessen hat oder einfach wissen muss^^

Ihr habt mir damit grad bestimmt mehrere Stunden oder Tage Sucherei 
erspart. Herzlichen Dank, ich arbeite mich da mal eben etwas durch. Muss 
das erstmal alles verstehen jetzt hier an Input^^



LG Fred

von Fred (Gast)


Lesenswert?

Hm, anscheinend bin ich doch zu doof dafür... Egal mit welchen Mitteln, 
es läuft einfach nicht...

Habe versucht einen org-Befehl davor zu setzen, dann läuft nix mehr....

Die Lösung von Dir, Holger, habe ich leider nicht richtig verstanden, 
aber auch versucht. Ich denke die läuft einfach nicht weil ich sie nicht 
verstanden und mit Sicherheit was falsch gemacht habe...

Ich verstehe bei der Lösung nicht, wo HIGH usw herkommt und was das 
bewirken soll... komme mir grad etwas doof vor... Konnte leider auch bei 
sprut.de keine weiteren Hinweise finden.

Was mich noch vor ein Rätsel stellt:

Wie bekomme ich denn überhaupt die Programmadresse raus, in der sich in 
meinem Programm irgendein Befehl befindet? Ich meine ich habe das vor 
langer Zeit schonmal gemacht, aber komme nicht mehr darauf....



Ich hoffe, ich nerve nicht zu sehr. Werde gleich auch nochmal inne 
Bücher schauen ob ich dort was hilfreiches finde, ansosnten bin ich fpr 
jeden Tipp sehr dankbar.



LG Fred

von Edi R. (edi_r)


Lesenswert?

Fred schrieb:
> Habe versucht einen org-Befehl davor zu setzen, dann läuft nix mehr....

Kannst Du dann mal posten, wie es jetzt ausschaut?

Fred schrieb:
> Ich verstehe bei der Lösung nicht, wo HIGH usw herkommt und was das
> bewirken soll...

HIGH() gibt das höherwertige Byte des Wertes zurück. Mit welchem 
Assembler arbeitest Du denn eigentlich?

von Holger W. (holgerw)


Lesenswert?

Arbeitest du mit MPLab ? Würde ich dir dringen raten diesen zu nehmen, 
Der hat auch einen Simulator drin, damit kann man das schön testen.
Zu meinem Beispiel, dur brauchst doch nur get_bit: mit deinem Einsprung 
zu ersetzen (mit CALL aufrufen !!) und die RETLW mit deinen Werten.

Poste mal deinen Versuch.

Holger

von Fred (Gast)


Lesenswert?

Also wenn ich meien Ausgabe starten will, rufe ich mit CALL "Segmente" 
auf, dort wird dann der Wert der Anzeigezahl geladen. So sieht es 
aktuell wieder aus, weil alles andere nicht richtig funktionierte:

Segmente
  addwf    PCL
  retlw    b'11000000'      ; Zero
  retlw    b'11111001'      ; One
  retlw    b'10100100'      ; Two
  retlw    b'10110000'      ; Three
  retlw    b'10011001'      ; Four
  retlw    b'10010010'      ; Five
  retlw    b'10000010'      ; Six
  retlw    b'11111000'      ; Seven
  retlw    b'10000000'      ; Eight
  retlw    b'10010000'      ; Nine


Du meintest jetzt ich sollte deine kompletten Zeilen unterhalb von 
get_bit mit aufnehmen oder? Ich habe nur noch nicht so richtig 
verstanden was die machen, also wofür du die benutzt.

An sich dachte ich, mit einem "org 0xXX" vor der Segmenttabelle den 
Speicherort der Tabelle festzulegen, sodass mein PCL keinen Überlauf 
mehr haben kann. Denn das scheint ja nun das Problem zu sein wenn ich 
das richtig verstanden habe....

Ich hoffe ich nerve nicht zu sehr.



LG Fred

von Holger W. (holgerw)


Lesenswert?

hier wird W mit 2 multipliziert, das Ergebnis steht dann in PRODL
(RETLW belegt 2 Bytes)

       mullw   .2              ; mit 2 multiplizieren


hier wird der High Teil der Adresse von "bits" in den Adresspeicher 
geholt
HIGH ist eine Hilfe vom Compiler/Assembler, der holt nur den 
höherwertigen Teil, dieser kommt nach PCLATH

        movlw   HIGH(bits)      ; Highteil von Tabelle holen
        movwf   PCLATH


gleiches mit dem Niederwertigen Teil, dann gleich noch der Wert aus der 
Multiplikation dazu, in W steht jetzt der LOW Teil
        movlw   LOW(bits)       ; Lowteil von Tabelle holen
        addwf   PRODL,w         ; Offset dazu

hat es einen Übertrag gegeben, dann wird Carry gesetzt und der High Teil 
des Programmcounters um eins heraufgesetzt
        btfsc  STATUS,C      ; Überlauf ?
        incf  PCLATH,f    ; ja um eins erhöhen

und hier kommt der Absprung, der Programmcounter wird auf den 
entsprechenden RETLW gesetzt
        movwf  PCL

bits:   retlw    B'00000001'    ; gesetztes Bit 0
        retlw    B'00000010'
        retlw    B'00000100'
        retlw    B'00001000'
        retlw    B'00010000'
        retlw    B'00100000'
        retlw    B'01000000'
        retlw    B'10000000'

Füllst du bei dir W auch richtig ? Teste doch mal wenn du direkt einen 
Wert reinschreibst mit movlw .1

Welchen Assembler nutzt du ?

Holger

von fred (Gast)


Lesenswert?

Ich nutze MPLAB. Dir erstmal ganz herzlichen Dank für die Erklärung. Die 
Verwendung von "HIGH" kannte ich noch gar nicht. Jetzt wird einiges 
klarer! Ich sehe mir das mal grad in der Simulation an^^

Damit umgeht man dann also das Problem der Page-Grenze.... Coole Sache

von fred (Gast)


Lesenswert?

Okay, es rennt nun, habe das Ganze auch im Großen und Ganzen verstanden 
wie ich denke. Dir erstmal ganz ganz herzlichen Dank.

Woher weiss man als Anfänger denn sowas über HIGH-Befehle und so? Habe 
das bei sprut und auch in den Büchern die ich hier habe bisher noch 
nirgends gefunden.... will ja nicht immer andere Leute nerven wenn ich 
mal was nicht weiss^^

Stehe nun aber noch vor einem anderen Rätsel... ein Segment geht bei 
meiner Anzeige nie ganz aus, es leuchtet immer ganz leicht nach. Der PIC 
Pin geht dort auch nicht voll auf´s H-Pegel um es abzuschalten.... Finde 
da aber leider keinen Grund für, da auch beim Debuggen der PIN definitv 
auf H ist und alles richtig rennt. Die Hardware ist auch okay, also 
keinerlei Lötverbindungen oder so....



Aber erstmal ganz herlichen Dank, ich denke ich werde mir die Platine 
nochmal mit der Lupe ansehen, irgendwo muss es ja herkommen^^




LG Fred

von Holger W. (holgerw)


Lesenswert?

Woher weiss man sowas. Nach Codebeispielen im Internet suchen, Handbuch 
vom MPLab lesen oder eben hier fragen.
Zum Beschreiben der Ports immer dem LATx benutzen, nicht den Port 
direkt.
Holger

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.