PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : PIC16F84A - CALL Problem - Programm Counter schuld?



t0b4d
16.03.2007, 18:26
Hey !

hab gerade ein riesiges Problem. Mein PIC springt ab einer bestimmten Stelle nicht in ein Unterprogramm. Wenn ich an die gleiche Stelle ein anderes Unterprogramm CALLEN möchte tut er es auch nicht - als könne er von der Programmzeile aus nicht in ein Unterprogramm springen.


Jetzt hab ich in auf der Sprut-Seite PIC fallen gefunden. Und bin auf das Problem mit dem PCL - Programmcounter gestoßen. Kann es sein, das bei mir das gleiche Problem besteht? Wenn ja, wie kann ich es lösen ?

http://www.sprut.de/electronic/pic/fallen/fallen.html#tabellen

BMS
16.03.2007, 20:26
Hi

Ganz nützlich wäre vielleicht ein Codeschnipsel. Könnte sein, dass du irgendeine Bedingung (btfss etc.) eingebaut hast, die nie/immer erfüllt wird und er den call-befehl überspringt
ansonsten - zu call:
Spruts Kommentar zu Call (http://www.sprut.de/electronic/pic/assemble/befehle.html#call)
Call arbeitet 11bittig -> 2^11 Adressen möglich =2048-> reicht für 2k speicher;
erstze mal den call-befehl durch irgendeinen bsf/bcf-Befehl und schalte damit z.B. eine Led an. Wenn sich nichts tut, liegts eindeutig an der Logik des Programms. Du schreibst schon in assembler, oder?
obwohl der call-befehl 11bittig-arbeitet, könntest du probeweise mal mit dem org-befehl den programcounter manipulieren...vielleicht bringts was (wenn man was sucht, ist es immer an der stelle, wo man es am wenigsten vermutet...)

Mfg
BMS

t0b4d
17.03.2007, 00:06
Ah danke!
Am CALL dürfte es dann aber allerding nicht liegen, da ich 1. nicht so viel Befehle habe und 2. mein PIC nur max 1024 Befehle aufnehmen kann.

Hier is mal der Code:

UP_Show_btns wird nicht aufgerufen!
Ich vermute es liegt an der Tabelle tab_Joy, hab aber anstatt der Register auch schon konstante Werte in die Tabelle geschrieben... trotzdem Fehlanzeige.



main
BSF a_ATT ; ATT auf HIGH, Controller wird abgewählt
; (ignoriert alle Daten)
CALL UP_wait_25us
BSF a_CLOCK ; Clock HIGH
BSF a_COMMAND ; Command HIGH

BCF a_ATT ; ATT auf LOW das der Controller
; die Daten annimmt

CALL UP_wait_50us ; Warteschlange bis Controller bereit ist

CALL UP_Start ;Senden: H'01' Startbefehl

CALL UP_Get_Type ;Senden: H'42' Datenanfrage
;------------------------------------
;Empfangen: H'41'=Digital
;ODER H'23'=NegCon
;ODER H'73'=Analogue Red LED
;ODER H'53'=Analogue Green LED

CALL UP_Get_Status ;Empfangen: H'5A' - Status:READY
;------------------------------------
;Senden: H'00' - Idle-Modus

CALL UP_Get_L_btns ;Empfangen: H'xx' - Status der linken Btns
;------------------------------------
;Senden: H'00' - Idle-Modus

CALL UP_Get_R_btns ;Empfangen: H'xx' - Status der rechten Btns
;------------------------------------
;Senden: H'00' - Idle-Modus

CALL UP_Get_R_Joy_X ;Empfangen: H'xx' - rechtes Joystick, X-Achse
;------------------------------------
;Senden: H'00' - Idle-Modus

CALL UP_Get_R_Joy_Y ;Empfangen: H'xx' - rechtes Joystick, Y-Achse
;------------------------------------
;Senden: H'00' - Idle-Modus

CALL UP_Get_L_Joy_X ;Empfangen: H'xx' - linkes Joystick, X-Achse
;------------------------------------
;Senden: H'00' - Idle-Modus

CALL UP_Get_L_Joy_Y ;Empfangen: H'xx' - linkes Joystick, Y-Achse
;------------------------------------
;Senden: H'00' - Idle-Modus

CALL UP_Show_btns ;Ausgabe der gXXXX (g=> GET) Register

GOTO main ;Springe wieder an den Anfang zurück







;################################################# ##############################
UP_Show_btns
MOVLW D'1'
MOVWF zaehler ;Zaehler auf 1 setzten

Show_1 CLRF PORTB ;PORTB (Anzeige löschen)
MOVF zaehler,W ;Zaehler ins Wreg. um mit PCL zu addieren
CALL tab_Joy ;Wert aus Tabelle...
MOVWF PORTB ;... an PORTB anzeigen...

CALL UP_wait_05s ;...(eine halbe Sekunde)

INCF zaehler ;Zaehler erhöhen (+1)
MOVLW D'5' ;Zaehler mit der Zahl 5
SUBWF zaehler,W ;subtrahieren (Ergebnis ins Wreg.) um
BTFSC STATUS,C ;Zaehler auf 5 zu prüfen
RETURN ;<--- Zaehler = 5
GOTO Show_1 ;<--- Zaehler < 5
;################################################# ##############################





;######################### L/R Joystick Tabelle ##########################

tab_Joy ;zaehler maximal bis 5
ADDWF PCL,F ; Anzeigen der Position des
DT gRJoyX,gRJoyY ; des rechten [x-Achse,y-Achse]...
DT gLJoyX,gLJoyY ; und linken [x-Achse,y-Achse] Joysticks


Achso ja.... wenn ich keine Tabellen in meinem Programm habe und UP_Show_btns aus "Spagetti-Code" besteht... funktioniert es!




UP_Show_btns
;Ausgabe der Register in denen der Status und die einzelnen Zustände der Buttons stehen
CLRF PORTB
BSF PORTB,0 ;Register LED (STATUS) [DEBUGGING]
CALL UP_wait_05s
CLRF PORTB
;#########
MOVFW gSTATUS ;Status Register
MOVWF PORTB ;an PORTB anzeigen
CALL UP_wait_05s
;##################

CLRF PORTB
BSF PORTB,1 ;Register LED (LINKS) [DEBUGGING]
CALL UP_wait_05s
CLRF PORTB
;#########
MOVFW gLEFT ;LINKS Register
MOVWF PORTB ;an PORTB anzeigen
CALL UP_wait_05s
;##################

CLRF PORTB
BSF PORTB,2 ;Register LED (RECHTS) [DEBUGGING]
CALL UP_wait_05s
CLRF PORTB
;#########
MOVFW gRIGHT ;RIGHT Register
MOVWF PORTB ;an PORTB anzeigen
CALL UP_wait_05s
;##################

CLRF PORTB
BSF PORTB,3 ;Register LED (rechtes Joxstick x-Achse) [DEBUGGING]
CALL UP_wait_05s
CLRF PORTB
;#########
MOVFW gRJoyX ;RJoyX Register
MOVWF PORTB ;an PORTB anzeigen
CALL UP_wait_05s
;##################

CLRF PORTB
BSF PORTB,4 ;Register LED (rechtes Joxstick y-Achse) [DEBUGGING]
CALL UP_wait_05s
CLRF PORTB
;#########
MOVFW gRJoyY ;RJoyY Register
MOVWF PORTB ;an PORTB anzeigen
CALL UP_wait_05s
;##################

CLRF PORTB
BSF PORTB,5 ;Register LED (linkes Joxstick x-Achse) [DEBUGGING]
CALL UP_wait_05s
CLRF PORTB
;#########
MOVFW gLJoyX ;LJoyX Register
MOVWF PORTB ;an PORTB anzeigen
CALL UP_wait_05s
;##################

CLRF PORTB
BSF PORTB,6 ;Register LED (linkes Joxstick x-Achse) [DEBUGGING]
CALL UP_wait_05s
CLRF PORTB
;#########
MOVFW gLJoyY ;LJoyY Register
MOVWF PORTB ;an PORTB anzeigen
CALL UP_wait_05s

RETURN

kalledom
17.03.2007, 10:40
Der Fehler liegt an der Tabelle:

MOVF zaehler,W ;Zaehler ins Wreg. um mit PCL zu addieren
CALL tab_Joy ;Wert aus Tabelle...
.....


tab_Joy ;zaehler maximal bis 5
ADDWF PCL,F ; Anzeigen der Position des
DT gRJoyX,gRJoyY ; des rechten [x-Achse,y-Achse]...
DT gLJoyX,gLJoyY ; und linken [x-Achse,y-Achse] JoysticksDu rufst mit CALL die Tabelle auf; der ProgrammCounter steht dann auf der Adresse des 1. Tabelleneintrags.
Dort addierst Du zum PCL einen Wert aus dem W-Register; was steht im PCLATH ?
Wenn zum PCL ein Wert addiert wird, springt der µC zu der errechneten Adresse; was sind das für Befehle in der Tabelle ? Und wo kommt ein RETURN für den Rücksprung ?
Wenn Du nur einen 8-Bit-Wert aus der Tabelle laden möchtest, dann trage in die Tabelle 'RETLW Rückgabewert' ein, damit geht es.
Benötigst Du mehrere Bytes, springe mit GOTO an Stellen, wo Bytes in Speicherstellen abgelegt werden.
Alternativ kannst Du eine Tabelle mit Daten erstellen und diese über indirekte Adressierung auslesen.
Eine Tabelle muß für 'Computed GOTO' Befehle enthalten, wobei eigentlich nur GOTO xxx oder RETLW zzz sinnvoll ist.
Schau Dir mal dieses Beispiel (http://www.domnick-elektronik.de/picasm.htm#CompGoto) an.

t0b4d
17.03.2007, 23:32
hey,

danke für die schnelle Antwort!

Ich denk ja auch das es an der Tabelle liegt, aber das
mit RETLW kann ich nicht ganz nachvollziehen da ich
folgendes gelernt habe:



Mit DT lässt sich eine Wertetabelle aufbauen. Dabei steht
jeder Wert für die Anweisung 'RETLW <wert>'. Die Tabelle
lässt sich also alternativ auch mit einer Liste von
'RETLW'-Anweisungen aufbauen.


Ich denk eher das meine "dynamische" Tabelle falsch ist
bzw. das in Assembler keine dyn. Tabellen möglich sind.
RETLW heißt ja das er aus dem Unterprogramm rausgehen
soll und dabei ins W-Reg. eine KONSTANTE läd. In meiner Tabelle
sollen ja aber ein Register zurückgegeben werden, keine KONSTANTEN!

PICture
18.03.2007, 06:36
Hallo t0b4d!

Ich vermute, dass bei Dir vor dem Sprung in die Tabelle, der PCH nicht den richtigen Wert hat. Schau mal, bitte, :

https://www.roboternetz.de/phpBB2/viewtopic.php?t=19714

MfG

kalledom
18.03.2007, 11:27
Hallo t0b4d,
was Du bezüglich 'DT' gelernt hast, ist richtig, mir war es entfallen, weil ich 'DT' nicht benutze; ich mußte erst wieder nachschlagen.
Für mich ist es einfacher 'RETLW' zu lesen, als DA, DB, DE, DT, DW; das sieht nach Daten aus.
Und wie Du siehst, bin ich prompt wieder drauf reingefallen.

Ich hatte ja schon gefragt, was in PCLATH steht und denke auch, daß der Fehler dort liegt.

Edit:

In meiner Tabelle sollen ja aber ein Register zurückgegeben werden, keine KONSTANTEN!Eine Register-Adresse ist auch eine Konstante. Adressen kannst Du in einer RETLW-Tabelle ablegen und anschließend durch indirekte Adressierung den Inhalt des Registers laden.
Alternativ kannst Du in der Tabelle auch 'GOTO' benutzen und bei den Sprungzielen den Inhalt der Register laden ('RETURN' nicht vergessen).

t0b4d
18.03.2007, 12:43
Hallo t0b4d!

Ich vermute, dass bei Dir vor dem Sprung in die Tabelle, der PCH nicht den richtigen Wert hat. Schau mal, bitte, :

https://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=19714

MfG



...
Ich hatte ja schon gefragt, was in PCLATH steht und denke auch, daß der Fehler dort liegt. ....



Ich wollt mich eigentlich vor diesem Problem drücken (weil ich das nicht so ganz verstanden hab),
da es jetzt aber anscheinend nicht mehr anders geht muss ich mir die Funktionsweise des PCLATH genauer anschaun.

Das was ich bis jetzt verstanden hab ist:

Programmcounter besteht aus: PCLATH,PCL
Der PCL deckt folgenden Bereich ab -> 2^0 - 2^7
Der PCLATH deckt folgenden Bereich ab -> 2^8 - 2^10 (mein PIC kann max. 1024 Befehle speichern)

Mit dem 8. stelligen PCL kann ich also nur im Bereich von 0 bis Programmzeile 2^7 (128) springen.
Da mein Code bzw meine Tabelle nicht in diesem Bereich liegt
muss ich jetzt mit dem höherwertigen Byte des Programmzählers arbeiten (PCLATH).

Jetzt stelle ich mir aber die Frage (ohne vorher mich informiert zu haben) wenn ich den PCLATH verändere, wird er nach dem Zeilenaufruf der Tabelle (zb. RETLW gStatus) wieder durch das RETURN zurückgestellt ?

Edit:
Ich hab auf google folgendes gefunden:
http://www.staff.uni-bayreuth.de/~btp918/cmt2004/PIC/Handout/06%20Fortgeschrittene%20Programmiertechniken.pdf
kann es aber erst heute abend testen wenn ich wieder zuhause bin.

kalledom
18.03.2007, 13:08
Programmcounter besteht aus: PCLATH,PCL Nein; der Programmcounter besteht aus PCH und PCL.
Bei "Instruction with PCL as Destination" wird der Inhalt von PCLATH an PCH übergeben, bei Aufrufen in andere ROM-Pages werden die Bits 3...x von PCLATH an PCH übergeben.
Vor der Veränderung von PCL oder bei GOTO / CALL in eine andere Rom-Page mußt Du unbedingt PCLATH bedienen.
Einen Link zu einem Beispiel hatte ich Dir ja schon gegeben.

Edit1: PCL ist 8 Bit breit, also von 0....255 / 0x??00...0x??FF, PCH je nach PIC, maximal 8 Bit.
Edit2: Was in dem Link steht, steht auch im Datenblatt (in englisch).
Das Beispiel setzt für eine 256-Byte-Tabelle voraus, daß diese bei Adresse 0x??00 beginnt, in meinem Beispiel ist das egal.
Edit3: PCLATH = Programm-Counter-LATch-High

t0b4d
18.03.2007, 13:58
Danke für die Verbesserung!

Das das Beispiel im Datenblatt steht hab ich versäumt ;) was kein wunder ist weil ich es mir wirklich nicht ganz angeschaut habe. Wir sind in der Schule die wichtigsten Seiten durchgegangen, was nicht viele waren!

Das Beispiel ist ja aber wie auch beschrieben nur möglich wenn ich die Tabelle an eine konstante Stelle im Speicher schreibe. Ich denk das is bei mir kein Problem ich werde trotzdem auf dein Vorschlag eingehen, wenn ich das andere hinbekommen habe.

Jetzt bleibt mir bisher noch eine Frage offen (kann es zZ. nicht testen).

Kann man mit ...



CBLOCK H'20'
...
gLEFT ;Linke Tasten
...
ENDC

...
...

main
...
MOVLW gLEFT ; Linke Tasten
MOVWF PORTB ; auf PORTB ausgeben
...


... ein Register an PORTB anzeigen lassen? Ich dachte LW steht für konstanter Wert ins Workregister. Ein Register kann sich ja aber aendern (was es bei mir auch macht) und es dafür ja extra den Befehl gibt MOVFW gLEFT ?

wenn es mit MOVLW gehen sollte, dann kann ich in der Tabelle ja weiterhin mit RETLW <register> arbeiten, wenn nicht muss ich wie vorhin gesagt wurde ein GOTO verwenden und darin das Register in das Arbeitsregister kopieren.



MOVFW gLEFT
RETURN ;<---- weil Tabelle mit CALL aufgerufen wurde

kalledom
18.03.2007, 16:55
MOVLW gLeft lädt die Adresse von (Literal) gLeft in das W-Register,
MOVFW gLeft lädt den Inhalt von (FileRegister) gLeft in das W-Register.
Du kannst GOTO und Sprungziele in der Tabelle einsetzten, kannst aber auch, wie ich bereits vorgeschlagen hatte, eine Tabelle mit RETLW und den Register-Adressen (Labelnamen) aufbauen und nach dem Rücksprung mit indirekter Adressierung (FSR und INDF) den Inhalt aus der Adresse auslesen oder reinschreiben Beispiel (http://www.domnick-elektronik.de/picasm.htm#ResRam).

PICture
18.03.2007, 19:01
Hallo t0b4d!



wenn ich den PCLATH verändere, wird er nach dem Zeilenaufruf der Tabelle (zb. RETLW gStatus) wieder durch das RETURN zurückgestellt ?

Ja, der PCH (durch PCLATH) muss vor jedem Aufruf einer Tabelle neu definiert werden. Dank dessen, kann man verschiedene Tabellen mit "retlw" und "goto" abwechselnd aufrufen.

Übrigens, wegen anderer Speicherorganisation, wird bei PIC16FXXX meine Sprungtabelle an ORG 0x(PC-1) und nicht wie bei PIC18FXXX an ORG 0x(PC-2) anfangen, da der Befehl "addwf PCL,1" bei PIC16FXXX ein Byte und bei PIC18FXXX zwei Bytes lang ist. Das betrifft nur Sprungtabellen die 256 Bytes (für PIC16FXXX) oder 128 Words (für PIC18FXXX) lang sind.

Für kürzere Sprungtabellen ist es nur erforderlich, dass die ganze Tabelle sich auf gleicher Seite (Page) des Speichers befindet (wegen PCH).

MfG

t0b4d
23.03.2007, 18:45
So ich bins mal wieder,
hab mir die indirekte Adressierung angeschaut und hab noch eine Frage dazu.

Wenn ich in der "dynamischen Tabelle" neben Fileregistern auch konstante Werte ins Workregister schreibe, kommt es dann zu Problemen wenn ich die Senderoutine nehme:



UP_MAX_send_tabelle

MOVLW D'1'
MOVWF zaehler_tab

MAX_st1 MOVLW D'8'
MOVWF zaehler_bit

CALL tab_MAX ;Öffnet die "dynamische Tabelle"
;Im Workregister steht jetzt die Adresse
;des Registers dessen Inhalt Übertragen werden soll

MOVWF FSR ;der Zeiger zeigt jetzt auf das Register
;dessen Inhalt Übertragen werden soll

MOVFW INDF ;mit dem virtuellen Register INDF kann der
;Inhalt des Registers ausgegeben werden,
;auf das der Zeiger FSR zeigt
MOVWF sMAX

BCF a_MAX_LOAD ;Vor der Übertragung von 2 Bytes auf LOW


MAX_st2 RLF sMAX ;MSB zuerst...
BTFSC STATUS,C
GOTO MAX_send_tabelle_1 ;MAX-Datenleitung auf HIGH (Übertrage 1)
BCF a_MAX_DATA ;MAX-Datenleitung auf LOW (Übertrage 0)

MAX_st3 BCF a_MAX_CLOCK ;
;CALL UP_wait_05s ; #############DEBUGGING#############
BSF a_MAX_CLOCK ;Positive Flanke erzeugen
BCF a_MAX_CLOCK

DECF zaehler_bit
MOVF zaehler_bit,F ; Zähler ...
BTFSS STATUS,Z ; ... auf 0 prüfen,
GOTO MAX_st1 ; <-- Zähler != 0
BTFSS zaehler_tab,0 ; <-- Zähler == 0
BSF a_MAX_LOAD ; <-- Zähler_tab == gerade
; <-- Zähler_tab == ungerade
INCF zaehler_tab
MOVLW D'22'
SUBWF zaehler_tab,W
BTFSS STATUS,Z
GOTO MAX_st1 ;zaehler_tab < 22
RETURN ;zaehler_tab = 22

MAX_send_tabelle_1
BSF a_MAX_DATA
GOTO MAX_st3


Er sieht ja dann den konstanten Wert als Adresse an und ließt den Inhalt aus dieser Adresse im Fileregister aus.
Also müsst ich alle konstanten Werte die ich in der Tabelle hab im Fileregister anlegen und in der Initialisierung mit den vorgesehenen Werten belegen.

Ich hab dieses Unterprogramm geschrieben um an dem MAX-7219 die gewünschten Register anzeigen zu lassen. Da aber die Initialisierung und die Adressen der einzelnen Digits immer gleich ist, hat ich für diese Bytes Konstanten vorgesehen.

...Aber das is ja kein Thema wenn ich mit der Senderoutine keine konstanten Werte mehr übertragen kann. Dann mach ich es einfach wie oben beschrieben....

Edit: Kommentierung im Quellcode

kalledom
23.03.2007, 23:30
Wenn Du in der Tabelle Konstanten und FileRegister-Adressen gemischt einsetzen möchtest, kommst Du mit 8 Bits nicht aus.
Wenn der PIC16F84A 4 Registerbänke hat, muß das Bit IRP zur Bestimmung von Registerbank 0 und 1 bzw. 2 und 3 gesetzt werden. Es sei denn, Du setzt dieses Bit in der Subroutine grundsätzlich auf 0 und benutzt nur die Register-Bank 0 und 1.
Sonst benötigst Du 9 Bits in der Tabelle für die FileRegister.
Zwischen Konstante und FileRegister unterscheiden kannst Du dann immer noch nicht; ein weiteres Bit muß her. Dann sind es 10 Bits.
Im Flash-Speichers geht das, da kannst Du mit LOW() und HIGH() das Low- und High-Byte auslesen, wobei das High-Byte KEINE 8 Bits hat.

t0b4d
24.03.2007, 18:44
Ich lass das mit den Konstanten sein, weil das mir dann doch zu aufwendig ist.

Aber ich hab eine Frage zu den "Bänken" die Du erwähnt hast. Im PIC16F84 Datenblatt steht:

01 = Bank 1 (80h - FFh)
00 = Bank 0 (00h - 7Fh)

In der Bank 1 werden doch die Ein- und Ausgänge festgelegt?

Kann ich in der Bank 0 und 1 jeweils 128 Register festlegen?

Ich brauch ca. 50 Register, also leg ich die am Besten in Bank 0 an. Dann brauch ich auch kein 9. Bit (IRP Bit).



Der Haken daran ist, dass das Register FSR (wie alle Register) nur 8 Bit lang ist, wärend wir bekanntlich im PIC mit 9-Bit Adressen arbeiten (2 bit zur Bankauswahl, 7 Bit zur Adressierung innerhalb der Bank). Der PIC ergänzt daher die 8 Bit (aus dem FSR) zu einer vollständigen Adresse, indem er davor das Bit IRP aus dem STATUS-Register setzt.

Will man auf Speicher in den Bänken 0 und 1 zugreifen muß also IRP gelöscht (=0) sein, will man dagegen auf die Bänke 2 und 3 zugreifen, muß man vorher IRP setzen (=1).

kalledom
24.03.2007, 22:35
Im Datenblatt sind alle benutzten FileRegister in den Bänken 0 und 1 aufgelistet. Dort kannst Du auch sehen, welche Register noch frei sind.
Ich empfehle Dir, nur RegisterBank 0 zu benutzen; bei Zugriffen auf Register in Bank 1 mußt Du sonst immer auf Bank 1 umschalten, das Register ansprechen und wieder auf Bank 0 zurück schalten (so wie bei der Initialisierung z.B. mit den TRIS-Registern)
Bei der indirekten Adressierung ist das Umschalten auf RegisterBänke anders geregelt; für Bank 0 und Bank 1 muß IRP gelöscht sein, für Bank 2 und 3 gesetzt. Da es bei Dir nur die RegisterBänke 0 und 1 gibt, muß da wohl weiter nichts umgeschaltet werden.
Das solltest Du im Datenblatt noch mal nachschlagen, den PIC16F84 kenne ich nicht, ich benutze hauptsächlich den PIC16F877.

t0b4d
25.03.2007, 01:19
http://kripserver.net/hbfi05a/clients/pic16f84a.jpg

Also 68 Register (von 0x0C bis 0x4F) kann ich in der Bank 0 speichern!

Hab das Problem mit der Tabelle behoben, in dem ich die Tabelle ab Speicherblock 0x300 speichere!

Jetzt schreib ich nur noch eine umkehr Funktion (ich lese zZ. die Register durch die Tabelle aus) um mit einer anderen Tabelle in die Register zu schreiben, so das ich so wenig Code wie möglich hab.


just, t0b4d