Hallo Forum, bin neu in der Pic-Programmierung und arbeite meine ersten Assembler-Lernmodule ab. Dabei bin ich auf folgendes Problem gestoßen. Der PIC arbeitet soweit und macht die LEDs an den Ports B4-B6 gleichzeitig an. Soweit auch in Ordnung, allerdings kommt beim Erstellen des Projekts folgende Fehlermeldung "Register in operand not in bank 0". Deshalb blinken die LEDs vermutlich auch nicht. Ich schalte doch aber vorher mit den bsf/bcf-Befehlen auf Bank 1 um, oder verstehe ich da etwas falsch? Vielen Dank für eure Erklärungen. list p=16f690 ; list directive to define processor #include <P16F690.inc> ; processor specific variable definitions __CONFIG _CP_OFF & _CPD_OFF & _BOR_OFF & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT & _MCLRE_ON & _FCMEN_OFF & _IESO_OFF ; '__CONFIG' directive is used to embed configuration data within .asm file. ; The labels following the directive are located in the respective .inc file. ; See respective data sheet for additional information on configuration word. ;***** VARIABLE DEFINITIONS w_temp EQU 0x7D ; variable used for context saving status_temp EQU 0x7E ; variable used for context saving pclath_temp EQU 0x7F ; variable used for context saving loops EQU 0x7C ; Variable für Warteschleife loops2 EQU 0x7B ;********************************************************************** ORG 0x000 ; processor reset vector goto main ; go to beginning of program ORG 0x004 ; interrupt vector location movwf w_temp ; save off current W register contents movf STATUS,w ; move status register into W register movwf status_temp ; save off contents of STATUS register movf PCLATH,w ; move pclath register into W register movwf pclath_temp ; save off contents of PCLATH register ; isr code can go here or be located as a call subroutine elsewhere movf pclath_temp,w ; retrieve copy of PCLATH register movwf PCLATH ; restore pre-isr PCLATH register contents movf status_temp,w ; retrieve copy of STATUS register movwf STATUS ; restore pre-isr STATUS register contents swapf w_temp,f swapf w_temp,w ; restore pre-isr W register contents retfie ; return from interrupt main bsf STATUS,RP0 ;Umschalten auf Bank 1 (Bit setzen) bcf STATUS,RP1 movlw B'00000000' ;Schreibe die Binärzahl nach W movwf TRISB ;Schreibe W ins Port-Register bcf STATUS,RP0 ;Umschalten auf Bank 0 (Bit löschen) call Warten clrf PORTB ;alle LEDs ausschalten bsf PORTB,0 ;Bit 0 setzen im Port-Register Schleife call Warten ;Aufruf der Routine "Warten" rlf PORTB,f ;Alle Bits in der Speicherzelle nach links verschieben ;also zur höheren Position goto Schleife ;Zurückspringen zur Marke Warten movlw D'250' movwf loops Warten1 movlw .110 movwf loops2 Warten2 nop nop nop nop nop nop decfsz loops2,F goto Warten2 decfsz loops, F goto Warten1 retlw 0 ; remaining code goes here END
Christian schrieb: > Ich schalte doch aber > vorher mit den bsf/bcf-Befehlen auf Bank 1 um, oder verstehe ich da > etwas falsch? Möglicherweise ist es an einer Stelle falsch. Kann passieren. Ohne deinen Code jetzt zu durchschauen.
Christian schrieb: > Fehlermeldung "Register in operand not in bank 0". Das ist keine Fehlermeldung sondern eine Warnung. Die kommt immer außer man schaltet diese Warnung ab. BTW: Das Umschalten der Bank geht eleganter mit dem BANKSEL-Makro. Gruß Anja
Anja schrieb: > BTW: Das Umschalten der Bank geht eleganter mit dem BANKSEL-Makro. Das ist irgendwo auch in Beispielen des Herstellers drin, und sehr praktisch.
Warscheinlich hast du sowas vergessen, gleich nach main: banksel ANSEL clrf ANSEL banksel ANSELH clrf ANSELH banksel TRISA
Chris schrieb: > Warscheinlich hast du sowas vergessen, gleich nach main: > banksel ANSEL > clrf ANSEL > banksel ANSELH > clrf ANSELH > banksel TRISA Ich machte das zwar einfacherweise nur mit BANKSEL 0 oder BANKSEL 1, aber es waren auch nur kleine Progrämmchen im 12F675.
Also so:
1 | #define BANK1 banksel 0x80 ; Select BANK1 |
2 | #define BANK0 banksel 0x00 ; Select BANK0 |
3 | |
4 | ; Im Code sage ich dann nur: |
5 | |
6 | BANK0 |
7 | BANK1 |
Nein, es ging um ANSEL, bzw um die Pins digital von den Analog auf digital zu schalten. Ob das jetzt auf PortB zutrifft, oder nur PortA betrifft weiss ich nicht, es gehört jedenfalls beim 16f690 dazu.
Ein Codeschnipsel mit den Makros sieht dann so aus:
1 | call InitLED ; Initialize LED Routine Variables |
2 | BANK0 |
3 | clrf GPIO ; Clear Port |
4 | BANK1 |
5 | clrf ANSEL ; PIC12F675 Only |
6 | movlw 0xFF |
7 | movwf TRISIO ; Tri-State All Inputs |
8 | clrf VRCON ; Vref Off |
9 | BANK0 |
10 | movlw 0x07 |
11 | movwf CMCON ; Comparator Off |
12 | BANK1 |
13 | movlw b'10000010' ; TMR0 Prescaler 8 |
14 | movwf OPTION_REG ; TIMER0 Prescaler |
15 | bsf IOCB,3 ; Interrupt on Pin Change GP3 |
16 | bsf INTCON,GPIE ; Interrupt on Change Enabled |
17 | bsf INTCON,T0IE ; Interrupt bei TIMER0 Überlauf Enabled |
18 | bcf INTCON,T0IF ; Reset TIMER0 Überlauf-Flag |
19 | bcf INTCON,GPIF ; Reset Interrupt On Change Flag |
20 | bsf INTCON,GIE ; Globale Interruptfreigabe |
21 | BANK0 |
22 | clrf TMR0 ; Reset Timer und Prescaler |
23 | movlw TMR0_SCALER ; TIMER0 externer Interruptzähler Wert |
24 | movwf TMR0_INTCTR ; TIMER0 externer Interruptzähler laden |
Wilhelm Ferkes schrieb: > Also so: > >
1 | > |
2 | > #define BANK1 banksel 0x80 ; Select BANK1 |
3 | > #define BANK0 banksel 0x00 ; Select BANK0 |
4 | > |
5 | > ; Im Code sage ich dann nur: |
6 | > |
7 | > BANK0 |
8 | > BANK1 |
9 | > |
Hmmmm.... da muss ich dann aber erst wieder nachsehen (oder auswendig gelernt haben) in welcher Bank sich das betroffene SFR befindet. Und der F690 hat die FSR sogar auf 4 Bänke verteilt. Desswegen gibt es ja die Möglichkeit mit BANKSEL auch den SFR-Namen anzugeben.
Chris B. schrieb: > Hmmmm.... da muss ich dann aber erst wieder nachsehen (oder auswendig > gelernt haben) in welcher Bank sich das betroffene SFR befindet. Und der > F690 hat die FSR sogar auf 4 Bänke verteilt. Man muß halt immer die Architektur im Kopf haben, wenn man bei den Bausteinen Assembler programmiert. Beim 8051 muß man sich auch mit den 4 Registerbänken manuell herum scheren, aber das ist halb so wild.
Ok, danke für die Erläuterungen. Bei mir funktioniert soweit auch alles, das einzige Problem dass ich jetzt noch habe ist, dass sich die Bits nicht verschieben lassen! D.h. ich schreibe dann vor die Schleife movlw B'00010000' movfw PORTB die LED an Port4 leuchtet dann auch, aber mehr passiert dann nicht mehr. Liegt es daran, dass am 16F690 nicht alle Ports rausgeführt sind? D.h. lediglich der Befehl rlf lässt sich nicht anwenden. Die Schleifen funktionieren einwandfrei. Wenn ich diese mehrmals einfüge dann dauert es länger bis nur die eine LED angesteuert wird. Den Befehl gibt es laut Datenblatt definitiv. Und auch die Anwendung mit rlf PORTB,1 erscheint mir richtig.
Hallo Christian, beiliegend meine "überarbeitete" Version Deines Programms. Der Fehler lag darin, dass RB7:4 nach dem Reset als analoge Eingänge initialisiert werden. Daher muss eine Umstellung auf digitale IO erfolgen. Dazu dient diese Sequenz: banksel ANSELH clrf ANSELH banksel TRISB clrf TRISB banksel PORTB Du solltest Dir angewöhnen den Code immer in übersichtliche Abschnitte aufzuteilen und grundsätzlich bei einem Problem das Datenblatt zu Rate ziehen! Schau Dir mal die Assembler- Lernbeispiele auf www.sprut.de an! mfG GroberKlotz
Christian schrieb: > main > bsf STATUS,RP0 ;Umschalten auf Bank 1 (Bit setzen) > bcf STATUS,RP1 > movlw B'00000000' ;Schreibe die Binärzahl nach W > movwf TRISB ;Schreibe W ins Port-Register > bcf STATUS,RP0 ;Umschalten auf Bank 0 (Bit löschen) > call Warten > clrf PORTB ;alle LEDs ausschalten > bsf PORTB,0 ;Bit 0 setzen im Port-Register > > Schleife > call Warten ;Aufruf der Routine "Warten" > rlf PORTB,f ;Alle Bits in der Speicherzelle > ;nach links verschieben > ;also zur höheren Position > goto Schleife ;Zurückspringen zur Marke erstmal eines: MOVLW 0 MOVWF TrisB ist bissel überflüssig. CLRF TrisB würde ausgereicht haben weiters: Benutze lieber NICHT all die superschlauen Makros, die dir hier angeraten werden. Die sind nämlich strunzdumm und blähen den Code oftmals nur sinnlos auf, weil sie RPx Bits setzen oder löschen, die bereits gesetzt bzw. gelöscht sind. Überflüssiger Murks. Ansonsten ist dein Code soweit schon in Ordnung, du solltest aber wieder ne 1 rechts reinschieben, wenn selbige nach links ins Carry verschwunden ist, also SKIP NOT Carry ; bzw. BTFSC Status,C INCF PortB,F oder du testest Port B auf zero: SKIP NZ ; bzw. BTFSC Status,Z INCF PortB,F vor dein goto Schleife. Sonst ist dein Bit nämlich weg... Sowas wie RLCF haben wir hier nicht. W.S.
Bei der Rotieraktion muss man beachten, dass es sich um eine Read/Modify/Write Aktion handelt. Der Controller liest aber nicht wirklich die Portregister, sondern den Zustand der Pins, und schreibt diesen rotiert zurück. Das kann manchmal verrückte Effekte ergeben. Am den PIC18F... wird diese Falle durch die Einführung der LAT Register vermieden.
Vielen Dank für die vielen nützlichen Tipps, werde heute Abend mal wieder testen(basteln) und dann Vollzug melden :) @W.S. ja die Makros schienen hier "Kanonen auf Spatzen" zu sein. Macht bei 4 Bänken nicht wirklich Sinn, ich denke die kann man auch so unterscheiden. @Tippgeber, ja ich weiß, niemals in Ausgängen oder Eingängen "arbeiten", aber macht es hier wirklich Sinn diese auszulesen und sie dann erst zu manipulieren? Ich werd's auf jeden Fall mal testen:)
Christian schrieb: > Vielen Dank für die vielen nützlichen Tipps, werde heute Abend mal > wieder testen(basteln) und dann Vollzug melden :) > > @W.S. ja die Makros schienen hier "Kanonen auf Spatzen" zu sein. Macht > bei 4 Bänken nicht wirklich Sinn, ich denke die kann man auch so > unterscheiden. > Willst du jedesmal hochscrollen und nachsehen wie der aktuelle Status der RP-Bits ist um dann zu entscheiden welches der Beiden gesetzt/gelöscht gehört? Und 10 Minuten später musst du mittendrinn ein Codestück einfügen welches auch die RP-Bits manipuliert - hoffentlich checkst du dann den Rest des Programms durch, ob noch alle "individuellen" RP-Bit Manipulationen noch Gültigkeit haben. Also ich habe dies Methode nach dem 2. Reinfall und endloser Fehlersuche abgestellt. Selbst bei popeligen 12Fxxx mit nur 1Kb Flash bin ich nie Speicheplatzmäßig so in Bedrängniss geraten, um darauf zurückgreifen zu müssen. Bei PIC mit mehr Flash gar nicht zu reden... Bleibt noch das Argument "das Programm werde daurch langsamer". Wenn der Controller Timingmäßig schon so am Anschlag läuft, sollte man sich über eine anderen Controller gedanken machen, oder sein Softwarekonzept ;-) Aber jede wie er möchte....
Noch eine Anmerkung zum Bankwechsel: Der Bankwechsel tritt am häufigsten bei der Initialisierung von Portregistern und der SFR und weniger im Porgrammlauf auf, wie dies z.B. bei der Verwendung von Capture, PWM oder des ADC der Fall ist. Dabei genügt es zu wissen, dass die PORTs stets in Bank0 zu finden sind. Z.B.: Init ....(code) banksel PORTA ;bank0 S.59 clrf PORTA ;clear Portlatches banksel TRISA ;bank1 Datenrichtungsregister Datenblatt S.59 ....(code) ;vgl. Beispiel im Datenblatt banksel ANSEL ;bank2 Analog-Select-Register S.61 ....(code) ;1/0 setzt analog/digital I/O banksel ADCON0 ;bank1 ADC-Control-Register Datenblatt S.113 ....(code) banksel PORTA ;zurück zu bank 0 ....(code) GOTO Main Danach erfolgt ja erst der eigentliche Programmablauf. Main ....(code) call ADC GOTO Main Ein Bankwechsel tritt nur noch in unbedeutendem Maße (gemessen am übrigen Code) auf. So z.B. bei der Analog-Digital-Konvertierung, bei der Abfrage des Ergebnis -Lowbytes: ; Subroutines ADC ;vgl. Datenblatt S.108 banksel ADCON0 ;->BANK 0 BSF ADCON0,GO ;Bit2=1, ADC starten ADCloop BTFSC ADCON0,GO ;Bit2=0? ist der ADC fertig? GOTO ADCloop ;NEIN, weiter warten movf ADRESH,w ;JA, Ergebnis (obere 2 Bit) auslesen->WREG movwf Vadc_H ;Arbeitsvariable H-Byte banksel ADRESL ;->BANK 1 movf ADRESL,w ;Ergebnis untere 8 Bit auslesen->WREG banksel PORTB ;->BANK 0 movwf Vadc_L ;Arbeitsvariable Low-Byte ....[Code) Hierbei kann kaum von einer Verzögerung oder einer unnötigen Befehlsfolge die Rede sein. Wem es da wirklich auf die µs ankommt, kann ja mit dem entsprechenden Prozessor fosc bis zum jeweiligen Maximum ausreizen. Hat man bei den "einfachen" 16Fxxx mit der Zeit Erfahrung gesammelt, hat man das Banking sowieso verstanden. Überhaupt dann, wenn man sein Programm systematisch aufbaut und dazu die entsprechenden Kommentare anbringt. mfg Ottmar
Wenn man sich unnötige Bankingoperationen sparen möchte, da sollte man sich STATUS, PCLATH, INTCON, PCL, SFR und INDF "merken" (meinetwegen als Schmierzettel wenn man sichs nicht merkt) - die benötigen keine Bankingoperationen, weil diese in alle Banken gespiegelt werden!
Chris B. schrieb: > Und 10 Minuten später musst du mittendrinn ein Codestück einfügen > welches auch die RP-Bits manipuliert Du bist eher ein Chaot als ein Programmierer, gelle? Da wundert es mich nicht, daß du schon nach kurzer Zeit den Überblick verloren hast. W.S.
W.S. schrieb: > Chris B. schrieb: >> Und 10 Minuten später musst du mittendrinn ein Codestück einfügen >> welches auch die RP-Bits manipuliert > > Du bist eher ein Chaot als ein Programmierer, gelle? > Da wundert es mich nicht, daß du schon nach kurzer Zeit den Überblick > verloren hast. > > W.S. Und du Genie musstest noch niemals in einem Programm was ändern...oder malst du dir erst alles auf Papier vor um es dann fehlerfrei abtippen zu können?! Aber wenn es dich beruhigt, das mit den 10 Minuten war übertrieben, kann ja auch erst am nächsten Tag sein.....
Nicht streiten wegen solch banalen Themen :) ich denke dass bei dem von mir verwendeten Beispiel die Verwendung eines Makros zu viel des Guten wäre. Sollte der Code jedoch umfangreicher werden so bietet sich sicher eine Verwendung von Makros an. Vielen Dank für die reichhaltigen Infos und Erläuterungen.
wie wärs denn mal mit nem Schleifenzähler Herr Tütenkleber? Also da wo de dein bit shiftest, um das eventuell neu zu starten oder Du mußt das C-bit immer retten... oder so vieleicht.... mfg Maik
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.