Codici Assembler 1 Istruzioni Assembler Sono riportate le istruzioni assembler più comuni utilizzate nella programmazione del microcontrollore 16F628A: Caricamento e spostamento dati: MOVLW n W = n MOVWF reg (reg) = W MOVF reg,d d = (reg) SWAPF reg,d d = swap nibbles (reg) CLRF reg (reg) = 0 CLRW W = 0 Istruzioni aritmetiche: ADDLW n W = W + n ADDWF reg,d d = W + (reg) SUBLW n W = n - W SUBWF reg,d d = (reg) - W INCF reg,d d = (reg) + 1 DECF reg,d d = (reg) - 1 Istruzioni logiche: ANDLW n W = W AND n ANDWF reg,d d = W AND (reg) IORLW n W = W OR n IORWF reg,d d = W OR (reg) XORLW n W = W XOR n XORWF reg,d d = W XOR (reg) COMF reg,d d = NOT (reg) Rotazioni e set/reset di singoli bit: RLF reg,d d = rlf (reg) RRF reg,d d = rrf (reg) BCF reg,b Bit b di (reg) = 0 BSF reg,b Bit b di (reg) = 1 Istruzioni di controllo sistema: CLRWDT SLEEP NOP Azzera watch dog timer Standby mode Nessuna operazione Controllo flusso e salti: 1
BTFSC reg,b Skip se bit b di (reg) = 0 BTFSS reg,b Skip se bit b di (reg) = 1 INCFSZ reg,d d = (reg) + 1 Skip se d = 0 DECFSZ reg,d d = (reg) - 1 Skip se d = 0 GOTO addr Salto all indirizzo addr CALL addr Chiamata di subroutine Ritorno da subroutine RETLW n Ritorno da subr.con valore in W RETFIE Ritorno da interrupt 2 Operazioni aritmetiche complesse Di seguito sono riportati i codici Assembler appositamente scritti, ad eccezione della divisione a 16 bit, che permettono la creazione di operazione aritmetiche complesse. Queste sono state utilizzate all interno del programma completo (vedi 3) per calcolare ad ogni pressione dei tasti UP e DOWN il nuovo valore da caricare all interno del registro TMR1. 2.1 Sottrazione a 16 bit ;[H,L]=[H,L]-[Hc,Lc] SOT16b movf Lc,W subwf L movf Hc,W btfss STAT,0 incfsz Hc,W subwf H 2.2 Moltiplicazione per 10 di un numero a 16 bit Indicando con X il moltiplicando a 16 bit, con Y il moltiplicatore e con C il fattore si ha: = [ 7 ] 15 Z = X Y = [L x, H x ] L y = a i 2 i + a i 2 i [ 2 3 7 a i 2 i + 2 1 i=0 i=0 i=8 7 b j 2 j = j=0 [ 7 ] 15 = a i 2 i + a i 2 i (2 3 + 2 1) = i=0 i=8 [ ] 7 15 15 a i 2 ]+ i 2 3 a i 2 i + 2 1 a i 2 i = [L c, H c ] i=0 In binario la moltiplicazione per una potenza di due corrisponde alla traslazione dei bit del moltiplicando di un numero di step pari all esponente della potenza nella direzione da quello meno significativo al più significativo. Di seguito è riportato il codice che, per mezzo dell istruzione rlf, implementa quanto formulato: i=8 i=8 2
;10*[H,L]=[Hc,Lc] mol10_16b clrf La clrf Ha clrf Lb clrf Hb clrf Lc clrf Hc clrf Lha clrf Lhb bc STAT,0 ;H*2^1 rlf H, W movwf Ha ;H*2^3 rlf H, W movwf Hb rlf Hb, F rlf Hb, W addwf Ha, W ;W=Ha+W=Ha+Hb movwf Hc ;L*2^1 rlf L, W movwf La bsf Lha,0 ;non incrementi perchè è un roll-->bsf! ;L*2^3 rlf L, W movwf Lb bsf Lhb,2 rlf Lb, F bsf Lhb,1 rlf Lb, F bsf Lhb,0 movf Lha, W addwf Lhb, W movwf Lh movf Lb, W addwf La, W movwf Lc incf Lh, F movf Lh, W addwf Hc, F 3
2.3 Divisione intera 16 bit senza segno Il presente codice non è stato steso dal sottoscritto ma prelevato dal sito http: //stor.altervista.org/pic/div/div.htm. <<Il procedimento consiste nell allineare le cifre del divisore a sinistra sotto il dividendo, effettuare una sottrazione per vedere se il divisore e maggiore del dividendo, segnarsi uno 0 nel caso in cui lo sia e un 1 nel caso in cui non lo sia, dopo di che shiftare il divisore a destra di una posizione e ripetere l operazione. Gli 0 e gli 1 che si ottengono come risultato della sottrazione si aggiungono mano a mano sulla destra del quoziente facendolo scorrere verso sinistra. Essendo una divisione a 16 bit occorre usare una coppia di registri da 8 bit anziche uno solo. Queste coppie sono chiamate QH:QL per il quoziente, VH:VL per il divisore ecc... L unico registro a 8 bit singolo che rimane e il contatore di ciclo per le sottrazioni, infatti al massimo verranno eseguite 16 sottrazioni.>> ;----- Divisione 16 bit intera senza segno----------------------- ; QH:QL=DH:DL/VH:VL DH:DL=resto ; IN: DH:DL=dividendo VH:VL=divisore ; OUT: QH:QL=quoziente DH:DL=resto ; CL = contatore di ciclo FL = salvataggio flag DIV16 CLRF QH ;Azzera quoziente CLRF QL CLRF CL ;Azzera contatore di ciclo DIV16_2 INCF CL,F ;CL=CL+1 BTFSC VH,7 ;Se bit 7 di VH=0 skip GOTO DIV16_3 ;altrimenti vai a DIV16_3 BCF STAT,0 ;Azzera carry RLF VL,F ;Ruota divisore a sinistra RLF VH,F GOTO DIV16_2 ;Vai a DIV16_2 DIV16_3 CALL SUB16 ;Chiama sottraz. DH:DL-VH:VL RLF QL,F ;Ruota carry a destra nel quoziente RLF QH,F BTFSS QL,0 ;Se non overflow skip CALL RESTORING ;altrimenti chiama somma DH:DL+VH:VL BCF STAT,0 ;Azzera carry RRF VH,F ;Ruota divisore a destra RRF VL,F DECFSZ CL,F ;Decrementa contat.ciclo, skip se 0 GOTO DIV16_3 ;altrimenti vai a DIV16_3 ;Fine subroutine SUB16 BSF FL,4 ;Imposta a 1 il bit 4 di FL MOVF VL,W ;W=parte bassa divisore SUBWF DL,F ;ao sottrae a parte bassa dividendo BTFSC STAT,0 ;Se overflow skip GOTO SUB16_2 ;altrimenti vai a SUB16_2 MOVLW 1 SUBWF DH,F ;Sottrae 1 a parte alta dividendo SWAPF STAT,W ;Salva i flag in FL MOVWF FL SUB16_2 MOVF VH,W ;W=parte alta divisore SUBWF DH,F ;la sottrae a parte alta dividendo BTFSS FL,4 ;Controlla bit 4 di FL, se 1 skip BCF STAT,0 ;altrimenti resetta carry 4
RESTORING MOVF VL,W ;W=parte bassa divisore ADDWF DL,F ;la somma a parte bassa dividendo BTFSC STAT,0 ;Se non overflow skip INCF DH,F ;altrimenti incrementa parte alta dividendo MOVF VH,W ;W=parte alta divisore ADDWF DH,F ;la somma a parte alta dividendo 3 Codice progetto oscillatore Di seguito è riportato l intero codice Assembly per il progetto di un oscillatore variabile da 0.1 a 5.0 Hz a passi di 0.1 Hz. TITLE fout_var_4mhzinterno list F=INHX8M,P=16F628A config b 11111111010000 ; ;RB0=square(2*pi*fout*t) RB1=square(2*pi*fout*t+pi) ;---------------------------------------------------------------- PCLATH EQU 0AH TMR0 EQU 01H ; Real Time Clock Counter TMR1L EQU 0EH TMR1H EQU 0FH STAT EQU 03H ; Registro di stato PORTA EQU 05H ; Porta A PORTB EQU 06H ; Porta B INTCON EQU 0BH ; Registro abilitazione interrupt TR_A EQU 85H ; Tris A TR_B EQU 86H ; Tris B OPTIO EQU 81H ; Registro OPTION CMCON EQU 1FH ; Reg comparatori PCON EQU 8EH ; Registro Power Control (contiene f_intosc) PIE1 EQU 8CH ; PIR1 EQU 0CH ; T1CON EQU 10H ; PCL EQU 02H ; Program counter WTEMP EQU 20H ; Buffer per salvataggio W in interrupt STATEM EQU 21H ; Buffer per salvataggio STAT in interrupt REGUP EQU 34H ; Ritardo REGDN EQU 36H INDS EQU 31H ; Indice sinistro INDD EQU 32H ; Indice destro KL EQU 33H ; K=fosctmr1/(2*pretmr1) KH EQU 35H ; K=fosctmr1/(2*pretmr1) F10 EQU 4BH QH EQU 38H ; QL EQU 39H DH EQU 3AH ; DL EQU 3BH ; VH EQU 3CH ; VL EQU 3DH ; CL EQU 3EH FL EQU 3FH L H EQU 40h EQU 41h 5
La EQU 42h Ha EQU 43h Lb EQU 44h Hb EQU 45h Lc EQU 46h Hc EQU 47h Lha EQU 48h Lhb EQU 49h Lh EQU 4Ah CALC EQU 4Bh T1LAP EQU 4Ch T1HAP EQU 4Dh #define UP PORTA,5 ; Pulsante UP #define DN PORTB,3 ; Pulsante DOWN #define DISPSX PORTB,5 ; Abilitazione display 1 #define DISPDX PORTB,2 ; Abilitazione display 2 ;-------------- Def costanti display catodo comune--------------------- ZERO EQU 0CFH ; Codifica numero 0: 11001111-6- UNO EQU 088H ; Codifica numero 1: 10001000 0 7 DUE EQU 0D6H ; Codifica numero 2: 11010110-4- TRE EQU 0DCH ; Codifica numero 3: 11011100 1 3 QUATTR EQU 099H ; Codifica numero 4: 10011001-2-.NC CINQUE EQU 05DH ; Codifica numero 5: 01011101 SEI EQU 05FH ; Codifica numero 6: 01011111 SETTE EQU 0C8H ; Codifica numero 7: 11001000 OTTO EQU 0DFH ; Codifica numero 8: 11011111 NOVE EQU 0DDH ; Codifica numero 9: 11011101 ;---------------------------------------------------------------- ;---------------------------------------------------------------- ORG 0 goto START ;Reset vector nop nop nop movwf WTEMP swapf STAT,W movwf STATEM btfss PIR1,0 ; Interrupt da overflow TMR1? se si skip goto endin ; movlw b 00000011 ; Carica W xorwf PORTB,1 ; PORTB=XOR(PORTB,W) ; ricavo TMR1 bcf PIR1,0 ; Clear flag TMR1IF endin swapf STATEM,w movwf STAT swapf WTEMP,f swapf WTEMP,w retfie ;----- Sottraz 16bit [H,L]=[H,L]-[Hc,Lc] SOT16b movf Lc,W subwf L movf Hc,W btfss STAT,0 incfsz Hc,W 6
subwf H ;----- Divisione 16 bit intera senza segno----------------------- ; QH:QL=DH:DL/VH:VL DH:DL=resto ; IN: DH:DL=dividendo VH:VL=divisore ; OUT: QH:QL=quoziente DH:DL=resto ; CL = contatore di ciclo FL = salvataggio flag DIV16 CLRF QH ;Azzera quoziente CLRF QL CLRF CL ;Azzera contatore di ciclo DIV16_2 INCF CL,F ;CL=CL+1 BTFSC VH,7 ;Se bit 7 di VH=0 skip GOTO DIV16_3 ;altrimenti vai a DIV16_3 BCF STAT,0 ;Azzera carry RLF VL,F ;Ruota divisore a sinistra RLF VH,F GOTO DIV16_2 ;Vai a DIV16_2 DIV16_3 CALL SUB16 ;Chiama sottraz. DH:DL-VH:VL RLF QL,F ;Ruota carry a destra nel quoziente RLF QH,F BTFSS QL,0 ;Se non overflow skip CALL RESTORING ;altrimenti chiama somma DH:DL+VH:VL BCF STAT,0 ;Azzera carry RRF VH,F ;Ruota divisore a destra RRF VL,F DECFSZ CL,F ;Decrementa contat.ciclo, skip se 0 GOTO DIV16_3 ;altrimenti vai a DIV16_3 ;Fine subroutine SUB16 BSF FL,4 ;Imposta a 1 il bit 4 di FL MOVF VL,W ;W=parte bassa divisore SUBWF DL,F ;ao sottrae a parte bassa dividendo BTFSC STAT,0 ;Se overflow skip GOTO SUB16_2 ;altrimenti vai a SUB16_2 MOVLW 1 SUBWF DH,F ;Sottrae 1 a parte alta dividendo SWAPF STAT,W ;Salva i flag in FL MOVWF FL SUB16_2 MOVF VH,W ;W=parte alta divisore SUBWF DH,F ;la sottrae a parte alta dividendo BTFSS FL,4 ;Controlla bit 4 di FL, se 1 skip BCF STAT,0 ;altrimenti resetta carry RESTORING MOVF VL,W ;W=parte bassa divisore ADDWF DL,F ;la somma a parte bassa dividendo BTFSC STAT,0 ;Se non overflow skip INCF DH,F ;altrimenti incrementa parte alta dividendo MOVF VH,W ;W=parte alta divisore ADDWF DH,F ;la somma a parte alta dividendo ;-------- Moltiplicazione 10*16bit 10*[H,L]=[Hc,Lc] mol10_16b clrf La clrf Ha clrf Lb clrf Hb clrf Lc 7
clrf Hc clrf Lha clrf Lhb ;H*2^1 rlf H, W movwf Ha ;H*2^3 rlf H, W movwf Hb rlf Hb, F rlf Hb, W addwf Ha, W ;W=Ha+W=Ha+Hb movwf Hc ;L*2^1 rlf L, W movwf La bsf Lha,0 ;non incrementi perchè è un roll-->bsf! ;L*2^3 rlf L, W movwf Lb bsf Lhb,2 rlf Lb, F bsf Lhb,1 rlf Lb, F bsf Lhb,0 movf Lha, W addwf Lhb, W movwf Lh movf Lb, W addwf La, W movwf Lc incf Lh, F movf Lh, W addwf Hc, F ;----RICAVO TMR1-------- TM1 btfss CALC,0 goto NOCALC movf INDS,W ; W=INDS movwf L ; L=INDS clrf H ; H=0 call mol10_16b movf Lc,W ; W=Lc addwf INDD, W ; W=Lc+INDD=INDS*10+INDD movwf F10 ; F10=W=INDS*10+INDD movf KL,W ;faccio Q=K/F10 8
movwf DL ;QH:QL=DH:DL/VH:VL movf KH,W movwf DH movf F10,W movwf VL clrf VH call DIV16 ; [QH,QL]=Q movf QL,W ; faccio Q*10...W=QL movwf L ; L=QL movf QH,W ; W=QH movwf H ; H=QH call mol10_16b ; [Hc,Lc]=Q*10 movlw b 11111111 ; TMR1max=65535 movwf L ; in realtà sarebbe 65536 ma movlw b 11111111 ; dovrei rappresentarlo a 17bit movwf H ; call SOT16b ; [H,L]=tmr1max-k*10/f10 movf L,W ; W=L movwf TMR1L ; movwf T1LAP movf H,W ; W=H movwf TMR1H ; movwf T1HAP bcf CALC,0 goto ENDCAL NOCALC movf T1LAP,W ; W=L movwf TMR1L ; movf T1HAP,W ; W=H movwf TMR1H ; ENDCAL ;------------ display -------- DISP addwf PCL,1 ; Sommo w al program counter retlw ZERO ; Visualizza 0 retlw UNO ; Visualizza 1 retlw DUE ; Visualizza 2 retlw TRE ; Visualizza 3 retlw QUATTR ; Visualizza 4 retlw CINQUE ; Visualizza 5 retlw SEI ; Visualizza 6 retlw SETTE ; Visualizza 7 retlw OTTO ; Visualizza 8 retlw NOVE ; Visualizza 9 ;-------------- subroutine gestione multiplexer ----------------- VISSX bcf DISPDX ; Disabilita disp dx movf INDS,0 ; W=IND call DISP ; movwf PORTA ; bsf DISPSX ; Abilita disp sx return VISDX bcf DISPSX ; Disabilita disp sx movf INDD,0 ; W=IND call DISP ; Numero dx su porta B movwf PORTA ; bsf DISPDX ; Abilita disp dx 9
return ; ;---------------ritardo--------------------------------- DELA10 ; btfsc UP ; Testo stato UP per pressione bsf REGUP,0 ; btfss UP ; Testo stato UP per rilascio bcf REGUP,1 ; btfsc DN ; Testo stato DN per pressione bsf REGDN,0 ; btfss DN ; Testo stato DN per rilascio bcf REGDN,1 ; btfss INTCON,2 ; goto DELA10 ; movlw.255 ; movwf TMR0 ; bcf INTCON,2 return ; Ritorna dopo la CALL ;---------------------------------------------------------------- ; START PROGRAM ;---------------------------------------------------------------- START bcf STAT,5 ; banco 0 movlw b 00000111 ; Disabilita comparatori e abilita I/O movwf CMCON ; movlw b 00101111 ; osc ext pretmr1=4 e non sincronizzo movwf T1CON ; bsf STAT,5 ; banco 1 bsf PIE1,0 ; enables TMR1 interr overflow bsf PCON,3 ; f_intosc=4mhz movlw b 00100000 ; RA5 in movwf TR_A ; movlw b 00001000 ; movwf TR_B ; movlw b 00000111 ; Prescaler 1:256 movwf OPTIO ; Copia W in OPTION (INTDG=0)(Rpull_up enable) bcf STAT,5 ; banco 0 movlw b 00000000 ; k=32768/(2*pretmr1)=4096=00010000 00000000 movwf KL ; movlw b 00010000 ; movwf KH ; movlw.0 ; movwf INDS ; movlw.1 ; movwf INDD ; bsf CALC,0 clrf PORTA ; RA=0 movlw b 00000010 ; RB0=0 RB1=1 (pilotano braccetto) movwf PORTB ; movlw b 11000000 ; GIE=1 interr da perif movwf INTCON ; movlw.217 movwf TMR0 bcf INTCON,2 10
;---------------------- main program ---------------------------- MAIN bcf REGUP,0 ; Clear memoria P2 pressione bsf REGUP,1 ; Clear memoria P2 rilascio bcf REGDN,0 ; Clear memoria P2 pressione bsf REGDN,1 ; Clear memoria P2 rilascio call VISSX call DELA10 ; Subroutine ritardo 10mS call VISDX call DELA10 btfss REGUP,0 ; Testo UP per pressione goto GOUP ; Vai alla routine GOUP btfsc REGUP,1 ; Testo UP per rilascio bcf REGUP,2 ; Resetta memoria incremento effettuato btfss REGDN,0 ; Testo UP per pressione goto GODN ; Vai alla routine GODN btfsc REGDN,1 ; Testo UP per rilascio bcf REGDN,2 ; Resetta memoria decremento effettuato goto MAIN ; GOUP btfsc REGUP,2 ; goto MAIN ; bsf REGUP,2 ; Setto memoria toggle movlw.5 subwf INDS,0 ; W=INDS-5 btfss STAT,0 ;If INDS=5 skip goto GOUP2 movlw.0 ; movwf INDS ; movlw.1 ; movwf INDD ; bsf CALC,0 ; goto MAIN GOUP2 movlw.9 subwf INDD,0 ; W=INDD-9 btfss STAT,0 ; If INDD=9 skip goto GOUP3 incf INDS,F ; incrementa INDS movlw.0 ; movwf INDD ; bsf CALC,0 ; goto MAIN GOUP3 incf INDD,F bsf CALC,0 ; goto MAIN GODN btfsc REGDN,2 ; goto MAIN ; bsf REGDN,2 ; Setto memoria toggle movf INDS,0 ; W=INDS sublw 0 ; W=0-INDS ; Se INDS>0-->[C]=0 Se INDS<=0-->[C]=1 goto GODN2 movf INDD,0 ; W=INDD 11
sublw 0 ; W=0-INDD btfss STAT,0 ; Se INDD>0-->[C]=0 Se INDD<=0-->[C]=1 goto GODN3 decf INDS,F movlw.9 ; movwf INDD ; bsf CALC,0 ; goto MAIN GODN2 movf INDD,0 ; W=INDD sublw.1 ; W=0-INDS btfss STAT,0 ; Se INDS>1-->[C]=0 Se INDS<=1-->[C]=1 goto GODN3 movlw.5 ; movwf INDS ; movlw.0 ; movwf INDD ; bsf CALC,0 ; goto MAIN GODN3 decf INDD,F ; bsf CALC,0 ; goto MAIN END ;---------------------------------------------------------------- 12