Forum: Mikrocontroller und Digitale Elektronik PIC 16F690 Assembler


von Christian (Gast)


Lesenswert?

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

von Wilhelm F. (Gast)


Lesenswert?

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.

von Anja (Gast)


Lesenswert?

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

von Wilhelm F. (Gast)


Lesenswert?

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.

von Chris (Gast)


Lesenswert?

Warscheinlich hast du sowas vergessen, gleich nach main:
    banksel ANSEL
    clrf    ANSEL
    banksel ANSELH
    clrf    ANSELH
    banksel TRISA

von Wilhelm F. (Gast)


Lesenswert?

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.

von Wilhelm F. (Gast)


Lesenswert?

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

von Chris (Gast)


Lesenswert?

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.

von Wilhelm F. (Gast)


Lesenswert?

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

von Tippgeber (Gast)


Lesenswert?

Die Warnung kommt leider immer, auch wenn man alles richtig gemacht hat.

von Chris B. (dekatz)


Lesenswert?

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.

von Wilhelm F. (Gast)


Lesenswert?

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.

von Christian (Gast)


Lesenswert?

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.

von GroberKlotz (Gast)


Angehängte Dateien:

Lesenswert?

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

von W.S. (Gast)


Lesenswert?

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.

von Tippgeber (Gast)


Lesenswert?

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.

von Christian (Gast)


Lesenswert?

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:)

von Chris B. (dekatz)


Lesenswert?

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....

von Ottmar K. (wil1)


Lesenswert?

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

von Chris B. (dekatz)


Lesenswert?

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!

von W.S. (Gast)


Lesenswert?

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.

von Chris B. (dekatz)


Lesenswert?

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.....

von Christian (Gast)


Lesenswert?

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.

von Maik W. (werner01)


Lesenswert?

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
Noch kein Account? Hier anmelden.