Programació en pic-as del PIC 16F690

Referència Trucs Perifèrics   Recursos CITCEA
Tutorial Exemples Projectes   Inici

Exemple PM - Mitjana de dades

En aquest programa guardarem les vuit darreres lectures del potenciòmetre (només els vuit bits més significatius) i en farem la mitjana. Ens caldrà utilitzar un registre on guardar les vuit darreres lectures. Per fer la mitjana haurem de sumar i el resultat pot passar de 8 bits; així que caldrà treballar amb un registre de dos bytes. Treballar amb vuit lectures (8 és 23) és molt pràctic ja que per dividir per potències de dos només cal rodar els bits.

En lloc de sumar cada vegada els vuit elements del registre, el que fem és restar de la suma el valor més antic i quan posem el nou valor al registre el sumem a la suma. D'aquesta manera estalviem operacions.

En aquest exemple farem servir adreçament indirecte, variables de més d'un byte i operacions matemàtiques de més de 8 bits. També fem comparacions.

PROCESSOR 16F690
#include <xc.inc>
config FOSC = INTRCIO, WDTE = OFF, PWRTE = OFF, MCLRE = OFF, CP = OFF
config CPD = OFF, BOREN = OFF, IESO = OFF, FCMEN = OFF
Visualit EQU 0x20  ; Definim una variable on guardem el que mostren els LED
Vector EQU 0x21  ; Registre de 8 bytes on guardem les darreres 8 lectures (8 bytes)
Retard EQU 0x29  ; Definim un registre de 2 bytes per fer els retards (2 bytes)
Suma EQU 0x2B  ; Suma (16 bits, 2 bytes) de les darreres lectures (2 bytes)
Arrodon EQU 0x2D  ; Mitjana (suma/8) arrodonida (16 bits, 2 bytes)
temp EQU 0x2F  ; Variable d'emmagatzematge temporal
PSECT code, class=CODE, delta=2, abs
main:
  bsf RP0  ; Tria el banc 1
  movlw 0xFF  ; Posa l'acumulador a FFh (tot uns)
  movwf TRISA  ; Posa tots els bits del port A com a entrada
  movlw 0xF0  ; Posa les potes dels LED com a sortida
  movwf TRISC  ; i la resta del PORT C com a entrada
  movlw 0x10  ; Posa el valor 10h (0001 0000) al registre W
  movwf ADCON1  ; Copia W a la configuració del conversor A/D
                ; Posa el conversor a 1/8 de la freqüència
  bcf RP0
  bsf RP1  ; Tria el banc 2
  movlw 0xFF  ; Posa l'acumulador a FFh (tot uns)
  movwf ANSEL  ; Configura AN0-AN7 com entrades analògiques
  bcf RP0
  bcf RP1  ; Tria el banc 0
  movlw 0x01  ; Posa el valor 01h (0000 0001) al registre W
  movwf ADCON0  ; activa el conversor A/D connectat a AN0
                ; amb el resultat justificat per l'esquerra
  call Inicialit  ; Inicialització del filtre
Bucle:
  call Retarda  ; Funció de retard de 0,2 s
  bsf GO_DONE  ; Inicia la conversió
  btfss GO_DONE  ; Quan el bit sigui 0 la conversió haurà acabat
  goto $-1  ; repetim la línia fins que deixi de ser 0
  movf ADRESH,w  ; Copia els bits superiors a l'acumulador
  call Filtre  ; Envia la lectura a la funció filtre
  movwf Visualit  ; Guarda el resultat filtrat a Visualit
  swapf Visualit,w  ; Permuta els nibbles i ho guarda a W
  movwf PORTC  ; Copia el resultat sobre els LED
  goto Bucle  ; Repetim-ho...
;
; Funció d'inicialització del filtre
;
Inicialit:
  clrf Suma  ; Esborrem el primer byte de la suma
  clrf Suma+1  ; i també el segon
  movlw Vector  ; Copia a W l'adreça del primer byte de Vector
  movwf FSR  ; Ho guarda al registre d'adreçament indirecte
Zero:
  clrf INDF  ; Esborrem tots els bytes de Vector
  incf FSR,f  ; Incrementem el punter
              ; Cal comprovar que no sortim fora del registre
  movf FSR,w  ; Copiem el punter a l'acumulador
  xorlw Vector+8  ; Estem a la posició 8?
                  ; XOR dona zero (activa Z) si coincideixen
  btfss ZERO  ; Comprovem si la XOR ha donat zero
              ; si no era zero (Z = 0) no fem la següent
  goto Zero  ; Si era zero, posem el punter a la primera posició
  movlw Vector ; Copia a W l'adreça del primer byte de Vector
  movwf FSR  ; Ho guarda al registre d'adreçament indirecte
  return  ; Fi de la funció
;
; Funció de filtre
;
Filtre:
  ; W té el darrer valor llegit al conversor
  movwf temp  ; Ho guarda a una variable temporal
  movf INDF,w  ; Copia el valor assenyalat per FSR a W
  subwf Suma,f  ; El resta de la suma total
  btfss CARRY  ; S'ha activat C?
					; Si no s'ha activat vol dir que en portem
  decf Suma+1,f  ; Decrementem el byte superior
  movf temp,w  ; Tornem a posar la lectura del conversor a W
  movwf INDF  ; la guardem a la taula
  addwf Suma,f  ; i l'afegim a la suma
  btfsc CARRY  ; Mirem si s'activa C
  incf Suma+1,f  ; Si s'activa, incrementem el byte superior
  incf FSR,f  ; Incrementem el punter
              ; Cal comprovar que no sortim fora del registre
  movf FSR,w  ; Copiem el punter a l'acumulador
  xorlw Vector+8  ; Estem a la posició 8?
                  ; XOR dona zero (activa Z) si coincideixen
  movlw Vector  ; Per si cal, carreguem la primera posició a W
                ; Aquesta funció no afecta als bits d'estat
  btfsc ZERO  ; Comprovem si la XOR havia donat zero
                  ; si no era zero (Z = 0) no fem la següent
  movwf FSR ; Si era zero, posem el punter a la primera posició
  bcf CARRY  ; Posem C a zero
  rrf Suma+1,w  ; Fem rodar el byte de l'esquerra de la suma
                ; i ho posem a W
                ; Rodar a la dreta equival a dividir per dos
  movwf Arrodon+1  ; Posa el resultat al byte de l'esquerra de Round
  rrf Suma,w  ; Ara fem rodar el byte de la dreta de la suma
              ; aprofitant el bit que teníem a C
  movwf Arrodon  ; i ho guardem al byte de la dreta d'Arrodon
  bcf CARRY  ; Posem C a zero
  rrf Arrodon+1,f  ; Dividim per 2 altre cop
  rrf Arrodon,f  ; Per tant, ja hem dividit per 4
  bcf CARRY  ; Posem C a zero
  rrf Arrodon+1,f  ; Dividim per 2 altre cop
  rrf Arrodon,f  ; Per tant, ja hem dividit per 8
                 ; Ens falta arrodonir
  btfsc CARRY  ; Mirem si C és 0 o 1
  incf Arrodon,f  ; Si és 0, incrementem un (arrodonim per excés)
  movf Arrodon,w  ; Copiem el resultat a W per sortir
  return  ; Fi de la funció de filtre
;
; Funció de retard de 0,2 s
;
Retarda:
  decfsz Retard,f  ; És igual a les funcions de retard de programes
  goto $-1  ; anteriors però fent servir un registre de dos
  decfsz Retard+1,f  ; bytes en lloc de dues variables
  goto $-3
  return
END main

Observem que en haver definit el registre Retard com de dos bytes, no cal que totes les variables tinguin nom. Ens adrecem al primer byte posant Retard i al segon posant Retard+1.

Normalment quan feiem servir instruccions com movlw hi posàvem com a paràmetre un valor que era el que es carregava a l'acumulador. Si ens fixem en el començament de la funció d'inicialització veiem que el paràmetre és Vector; això fa que es carregui a l'acumulador l'adreça de la variable. Si volguéssim carregar el valor de la variable, faríem servir movf.

Quan proveu el programa, intenteu fer canvis bruscos a la posició del potenciòmetre. Veureu que el valor llegit als LED no canvia de cop sinó que el valor va augmentant o disminuïnt progressivament fins arribar a la nova lectura.

 

 

Llicència de Creative Commons
Aquesta obra d'Oriol Boix està llicenciada sota una llicència no importada Reconeixement-NoComercial-SenseObraDerivada 3.0.