Programació en pic-as del PIC 16F690

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

Exemple CS - Comunicació síncrona bidireccional

En aquest exemple es fan servir dues unitats de la placa de la matriu de vuit per vuit LED. El que es desitja és establir una comunicació bidireccional entre les dues plaques, de manera que es puguin enviar informació de l'una a l'altra. A més, s'ha fet de manera que totes dues plaques tenen el mateix programa i quan una detecta que l'altra envia dades, ella es posa en mode de recepció. Per fer-ho senzill, s'ha establert que la transmissió sigui sempre de tres bytes.

Abans d'explicar què fa el programa convé comentar que aquest és un programa força complex però això no ens ha de preocupar. No és imprescindible, però, entendre completament el funcionament del programa per poder emprar el mateix mètide en un exemple propi. En el programa que hi ha més avall, s'han escrit en color groc aquelles instruccions que són específiques de l'exemple; això vol dir que tota la resta, llevat de les funcions, són elements necessaris per fer la transmissió. Primer comentarem què fa l'exemple (el que s'ha marcat en groc) i més endavant s'explicarà com funciona el sistema de transmissió.

Quan no hi ha cap transmissió en marxa, el programa mira si l'usuari ha premut algun polsador. En cas que ho hagi fet, escriu a la pantalla sis caràcters; per exemple, si s'ha premut el polsador 4 s'escriurà E: Ps4. A més, enviarà Ps4 a l'altra placa.

Quan el programa detecta que l'altra placa envia informació, es posa en mode de recepció i, a l'acabar, escriu a la pantalla R: seguit dels tres caràcters rebuts.

Atès que durant la major part del temps el programa no fa res més que esperar que es premi un polsador, també s'ha posat un trosset de programa general que l'única cosa que fa és mantenir un LED intermitent.

Podem fer servir aquesta mateixa estructura de programa per a qualsevol aplicació que requereixi la comunicació entre dues plaques, tant si els dos programes són idèntics com si no. En aquells casos que només calgui comunicació en un sentit es podrà eliminar la part corresponent al sentit contrari (emissió en un programa i recepció en l'altre).

S'ha previst que la transmissió consti de tres bytes però no és imprescindible que tots tinguin sentit, sempre es pot posar un valor arbitrari en els bytes que no interessen i ignorar els valors rebuts. D'aquesta manera és possible transmetre un valor de vuit bits (un byte) o de setze (dos bytes) sense més o bé enviar un o dos caràcters de control seguits d'un o dos valors, això permet cobrir la major part de les necessitats.

El programa per a aquest exemple és el següent:

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
#define T1H 255  // Precàrrega de TMR1 per a 0,25 ms
#define T1L 6  // Precàrrega de TMR1 per a 0,25 ms
Control EQU 0x20  ; Bits de control de la comunicació
Enviar EQU 0x21  ; Bytes a enviar (tres bytes, LSB primer)
Rebut EQU 0x24  ; Bytes a enviar (tres bytes, LSB primer)
CompInt EQU 0x27  ; Comptador d'interrupcions
CompBits EQU 0x28  ; Comptador de bits
Portc EQU 0x29  ; Control del port C
Porta EQU 0x2A  ; Control del port A
Polsador EQU 0x2B  ; Variable que conté un bit per a cada polsador per saber si està premut	
Caracter EQU 0x2C  ; Caràcter o codi a enviar a la pantalla
Retard1 EQU 0x2D  ; Variables de retard	
Retard2 EQU 0x2E
Retard3 EQU 0x2F
; Zona de memòria de dades que no depèn del banc triat
W_Copia EQU 0x70  ; Guardarà el contingut de W durant la interrupció
ST_Copia EQU 0x71  ; Guardarà STATUS durant la interrupció
PSECT code, class=CODE, delta=2, abs  ; A l'inici de la memòria
main:  ; Adreça 0 h
  goto Inici  ; Saltem al lloc on hi ha el programa principal
  nop  ; Zona de memòria de programa que no utilitzem
  nop
  nop
Interrup:
  ; Guardem W i STATUS
  movwf	W_Copia  ; Copiem l'acumulador a W_Copia
  swapf	STATUS,w  ; Copiem STATUS a l'acumulador permutant els nibbles
  clrf	STATUS  ; Posa a 0 i així segur que el banc és el 0
  movwf	ST_Copia  ; Guarda STATUS permutat a ST_Copia
  btfss RABIF  ; Mira si la interrupció és per port
  goto NoRAB  ; Si la interrupció no és per port, seguim
  ; Si és per port, cal assegurar que estava activada
  btfss RABIE  ; Mira si la interrupció per port està activada
  goto NoRAB  ; Si la interrupció no és per port, seguim
  ; És important que la comprovació de RA4 sigui abans que la de RA5
  ; perquè quan s'iniciï la transmissió no hi ha dades,
  ; cal esperar la següent interrupció.
  ;
  ; Recepció de dades
  btfsc	RA4  ; Mira si s'ha desactivat RA4
  goto NoRA4  ; Si està activat, seguim
  btfss	Control,1  ; Mira si estem en mode receptor
  goto NoRA4  ; Si no, seguim
  incf CompBits,f  ; Arriba un bit
  ; Anem a mirar si CompBits <= 24
  movlw 25  ; W = 25
  subwf CompBits,w  ; W = CompBits - W
  btfsc CARRY  ; C = 1 si CompBits >= 25
  goto NoBits  ; CompBits > 24
  ; CompBits < 25
  ; Estem rebent bits
  bcf CARRY  ; Preparem per si cal entrar un 0
  btfsc RA5  ; Mirem DT
  bsf CARRY  ; Si arrriba un 1, el posem
  rrf Rebut+2  ; Entrem el bit i rodem la resta
  rrf Rebut+1  ; El primer que arriba és el menys significatiu
  rrf Rebut
NoBits:  ; No estem rebent bits
  ; Anem a mirar si CompBits = 24
  movlw 24  ; W = 24
  xorwf CompBits,w
  btfss ZERO
  goto NoRA4  ; No és CompBits = 24
  bcf Control,1  ; Fi del mode receptor
  bsf Control,2  ; Valors rebuts disponibles
NoRA4:
  ; És important que la comprovació de RA4 sigui abans que la de RA5 perquè
  ; la interrupció per RA5 activa el mode recepció amb RA4 desactivat
  ;
  ; Detecció de que comença una transmissió de dades
  btfsc	RA5  ; Mira si s'ha desactivat RA5
  goto NoRA5  ; Si està activat, seguim
  movf Control,f  ; Mira si Control val 0
  btfss ZERO
  goto NoRA5  ; Si no, seguim
  ; Si la interrupció ha estat per desactivació de RA5
  ; i no estem enviant ni rebent
  ; Entrem en mode recepció
  bsf RP0  ; Tria el banc 1
  movlw 00010000B  ; Volem interrupcions per RA4
  movwf IOCA
  bcf RP0  ; Tria el banc 0
  bsf Control,1  ; Mode receptor
  clrf Rebut+2  ; Inicialitzem variables de recepció
  clrf Rebut+1
  clrf Rebut
  clrf CompBits  ; Comptador de bits
NoRA5:
  bcf RABIF  ; Mira si la interrupció és per port
NoRAB:  
  ;
  ; Emissió de dades
  btfss	TMR1IF  ; Mira si la interrupció és per timer 1
  goto FiInt  ; Si la interrupció no és per timer 1, ja estem
  bsf RP0  ; Tria el banc 1
  btfss	TMR1IE  ; Mira si les interrupcions per timer 1 estan actives
  goto FiInt  ; Si no, ja estem
  bcf RP0  ; Tria el banc 0
  btfss Control,0  ; Mira si estem en mode emissor
  goto FiInt  ; Si no, ja estem
  bcf TMR1ON  ; Atura momentàniament el Timer 1
  movlw T1H  ; Inicialitza el Timer 1
  movwf TMR1H
  movlw T1L
  movwf TMR1L
  bsf TMR1ON  ; Torna a engegar el Timer1
  bcf  TMR1IF  ; Desactiva el bit
  incf CompInt,f  ; Incrementem el comptador
  ; Anem a mirar si CompInt > 48
  movlw 49  ; W = 49
  subwf CompInt,w  ; W = CompInt - W
  btfss CARRY  ; C = 1 si CompInt >= W
  goto NoFiT  ; CompInt < 49
  ; CompInt >= 49
  ; Alliberem la línia
  bsf RP0  ; Tria el banc 1
  movlw 0xFF  ; Posa l'acumulador a FFh (tot uns)
  movwf TRISA  ; Tot el port A és d'entrada
  movlw 00100000B  ; RA5 amb resistència de pull-up
  movwf WPUA
  bcf TMR1IE  ; Desactivem les interrupcions per timer 1
  bcf RP0  ; Tria el banc 0
  bcf TMR1ON  ; Atura el Timer 1
  bcf Control,0  ; Fi del mode emissor
  bsf RP0  ; Tria el banc 1
  movlw 00100000B  ; Volem interrupcions per RA5
  movwf IOCA
  bcf RP0  ; Tria el banc 0
  bsf RABIE  ; Admetem interrupcions del port A
  goto FiInt  ; Fi de la funció d'interrupció
NoFiT:  ; CompInt <= 48
  ; Cal permutar CK (RA4)
  btfss Porta,4  ; Mirem si està activat CK (RA4)
  goto ActRA4  ; Si no ho està, toca activar-lo
  bcf Porta,4  ; Si està activat, desactivem CK (RA4)
  goto FiRA4  ; Ja hem acabat amb RA4
ActRA4:
  bsf Porta,4  ; Si està desactivat, activem CK (RA4)
  ; Toca enviar un bit
  bcf Porta,5  ; Desactivem RA5 en previsió que toqui enviar 0
  btfsc Enviar,0  ; Mirem el bit que toca enviar
  bsf Porta,5  ; Activem RA5 si toca enviar 1
  bcf CARRY  ; Per l'esquerra entrarem 0
  rrf Enviar+2  ; Entrem el bit i rodem la resta
  rrf Enviar+1  ; El primer que marxa és el menys significatiu
  rrf Enviar
FiRA4:
  ; Actualitzem el port
  movf Porta,w  ; Llegeix Porta
  movwf PORTA  ; I ho guarda al PORTA
FiInt:
  bcf RP0  ; Tria el banc 0 (per si venim del goto de TMR1IE)
  ; Recuperem W i STATUS
  swapf ST_Copia,w  ; Copia permutant ST_Copia a l'acumulador
  movwf STATUS  ; I ho passa a STATUS recuperant el valor d'abans
                ; de la interrupció
  swapf W_Copia,f  ; Permuta els bits de W_Copia
  swapf W_Copia,w  ; Torna a permutar els bits de W_Copia
                   ; i els guarda a l'acumulador sense variar STATUS
  retfie  ; Torna al programa principal, on s'havia quedat  
Inici:
  movlw 10  ; Retard de 2 s
  call Rets  ; Esperem que arrenqui la pantalla
  bsf RP1  ; Tria el banc 2
  movlw 00000101B
  movwf ANSEL  ; Configura AN0 i AN2 com entrada analògica
  clrf ANSELH  ; Desactiva les altres entrades analògiques
  clrf WPUB  ; Port B sense resistències de pull-up
  clrf IOCB  ; No volem interrupcions per port B
  bcf RP1
  bsf RP0  ; Tria el banc 1
  movlw 00010000B
  movwf ADCON1  ; Posa el conversor a 1/8 de la freqüència
  bcf OPTION_REG,7  ; Activa el control individual de pull-ups
  movlw 0xFF  ; Posa l'acumulador a FFh (tot uns)
  movwf TRISA  ; Posa tot el port A com a entrada
  clrf TRISB  ; Tot el port B és de sortida
  movlw 11110000B  ; Posa els bits de menys pes del port C com a sortida
  movwf TRISC  ; la resta, com a entrades
  movlw 00100000B
  movwf WPUA  ; RA5 amb resistència de pull-up
  movwf IOCA  ; Volem interrupcions per RA5
  clrf PIE1  ; De moment, no hi ha interrupció per timer 1
  bsf BRGH  ; Configuració de velocitat
  bcf BRG16  ; Paràmetre de velocitat de 8 bits
  movlw 25  ; Velocitat de 9600 baud
  movwf SPBRG  ; Paràmetre de velocitat
  bcf SYNC  ; Comunicació asíncrona
  bcf TX9  ; Comunicació de 8 bits
  bcf RP0  ; Tria el banc 0
  bsf SPEN  ; Activa comunicació sèrie
  bsf RP0  ; Tria el banc 1
  bsf TXEN  ; Activa comunicació
  bcf RP0  ; Tria el banc 0
  movlw 11001000B  ; Permetem interrupcions pels ports A i B
                   ; I les interrupcions per PIE amb control individual
  movwf INTCON  ; La resta d'interrupcions desactivades
  movlw 00001001B  ; activa el conversor A/D connectat a AN2
  movwf ADCON0  ; amb el resultat justificat per l'esquerra
  movlw 00100000B  ; RA5 activat
  movwf Porta
  movwf PORTA
  clrf PORTB
  clrf Portc  ; LED apagats
  clrf PORTC  ; LED apagats
  clrf Control  ; Els bits de control a 0
  movlw 254  ; Caràcter de control
  movwf Caracter  ; Ho guarda a la variable
  call EnviaL  ; Ho envia
  movlw 1  ; Esborra la pantalla i posa el cursor a l'inici
  movwf Caracter  ; Ho guarda a la variable
  call EnviaL  ; Ho envia
  movlw 00000000B  ; Configuració de Timer 1
                   ; 0 - Factor d'escala d'1
                   ; De moment, aturat
  movwf T1CON  ; Ho guarda al registre de configuració del Timer 1
  bcf TMR1IF  ; Desactiva el bit d'interrupció per timer 1
  bcf RABIF  ; Desactivem el bit d'interrupció per port
  bsf RABIE  ; Volem interrupcions per port A
Bucle:
  btfss Control,2  ; Mira si ja tenim dades
  goto NoDades  ; Si no, seguim
  movlw 254  ; Caràcter de control
  movwf Caracter  ; Ho guarda a la variable
  call EnviaL  ; Ho envia
  movlw 1  ; Esborra la pantalla i posa el cursor a l'inici
  movwf Caracter  ; Ho guarda a la variable
  call EnviaL  ; Ho envia
  movlw 'R'  ; Dades rebudes
  movwf Caracter  ; Ho guarda a la variable
  call EnviaL  ; Ho envia
  movlw ':'  ; Dades rebudes
  movwf Caracter  ; Ho guarda a la variable
  call EnviaL  ; Ho envia
  movlw ' '  ; Dades rebudes
  movwf Caracter  ; Ho guarda a la variable
  call EnviaL  ; Ho envia
  movf Rebut+2,w  ; Primer byte
  movwf Caracter  ; Ho guarda a la variable
  call EnviaL  ; Ho envia
  movf Rebut+1,w  ; Segon byte
  movwf Caracter  ; Ho guarda a la variable
  call EnviaL  ; Ho envia
  movf Rebut,w  ; Tercer byte
  movwf Caracter  ; Ho guarda a la variable
  call EnviaL  ; Ho envia
  clrf Control  ; Quedem a l'espera
  clrf CompInt
  bsf RP0  ; Tria el banc 1
  movlw 00100000B  ; Volem interrupcions per RA5
  movwf IOCA
  bcf RP0  ; Tria el banc 0
  bsf RABIE  ; Volem interrupcions per port A
NoDades:
  movf Control,f  ; Mira si Control val 0
  btfss ZERO
  goto NoPols  ; Si no, seguim
  ; Si no hi ha comunicacions actives, podem mirar els polsadors
  call Llegir  ; Llegeix els polsadors
  movf Polsador,f  ; Mirem si s'ha premut un polsador
  btfsc ZERO  ; Si és 0, no n'hi ha cap premut  
  goto NoPols  ; Si no, no enviem res
  ; Si hi ha un polsador premut, primer esborrem la pantalla
  ; ho escrivim a la pantalla, després ho enviem
  movlw 254  ; Caràcter de control
  movwf Caracter  ; Ho guarda a la variable
  call EnviaL  ; Ho envia
  movlw 1  ; Esborra la pantalla i posa el cursor a l'inici
  movwf Caracter  ; Ho guarda a la variable
  call EnviaL  ; Ho envia
  movlw 'E'  ; Dades enviades
  movwf Caracter  ; Ho guarda a la variable
  call EnviaL  ; Ho envia
  movlw ':'
  movwf Caracter  ; Ho guarda a la variable
  call EnviaL  ; Ho envia
  movlw ' '
  movwf Caracter  ; Ho guarda a la variable
  call EnviaL  ; Ho envia
  movlw 'P'  ; Lletra
  movwf Enviar+2  ; Primer valor a enviar
  movwf Caracter  ; Ho guarda a la variable
  call EnviaL  ; Ho envia
  movlw 's'  ; Lletra
  movwf Enviar+1  ; Segon valor a enviar
  movwf Caracter  ; Ho guarda a la variable
  call EnviaL  ; Ho envia
  movf Polsador,w  ; Polsador premut
  movwf Enviar  ; Tercer valor a enviar
  movlw '0'  ; Carrega el codi ASCII del número 0
             ; Sumant-li la xifra tindrem el codi ASCII
  addwf Enviar,f  ; Ara Xifra conté el caràcter ASCII
  movf Enviar,w  ; Agafa el valor
  movwf Caracter  ; Ho guarda a la variable
  call EnviaL  ; Ho envia
  ; Activem la transmissió
  clrf Porta  ; Desactivem RA4 i RA5
  bsf RP0  ; Tria el banc 1
  movlw 11001111B  ; RA4 i RA5 són sortides
  movwf TRISA
  bcf RP0  ; Tria el banc 0
  movf Porta,w  ; Llegeix Porta
  movwf PORTA  ; I ho guarda al PORTA
  movlw T1H  ; Inicialitza el Timer 1
  movwf TMR1H
  movlw T1L
  movwf TMR1L
  movlw 00000001B  ; Configuració de Timer 1
                   ; 0 - Factor d'escala d'1
                   ; I el posem en marxa
  movwf T1CON  ; Ho guarda al registre de configuració del Timer 1
  bcf TMR1IF  ; Desactivem el bit de fi del temporitzador
  clrf CompInt  ; Comptador d'interrupcions
  bsf Control,0  ; Entrem en mode emissor
  bcf RABIE  ; No volem interrupcions per port A
  bsf RP0  ; Tria el banc 1
  bsf TMR1IE  ; Activem les interrupcions per timer 1
  bcf RP0  ; Tria el banc 0
NoPols:
  movlw 2  ; Retard de 0,4 s
  call Rets
  movlw 00000001B  ; Volem invertir el bit 0
  xorwf Portc,f  ; Invertim RC0
  movf Portc,w  ; Llegeix Port
  movwf PORTC  ; Ho posem als LED
  goto Bucle  ; Repetim-ho...
;
; Funció que llegeix els polsadors
;
; Atenció: No és la funció d'altres exemples
; En lloc d'un bit per polsador, retorna el número de polsador
;
Llegir:
  clrf Polsador  ; Si aquest valor no es canvia és que no hi ha cap polsador premut
  nop  ; espera un microsegon
  nop  ; espera un microsegon
  nop  ; espera un microsegon
  nop  ; espera un microsegon
  nop  ; espera un microsegon
  bsf GO_DONE  ; Inicia la conversió
  btfsc GO_DONE  ; Quan el bit sigui 0 la conversió haurà acabat
  goto $-1  ; repetim la línia fins que deixi de ser 0
            ; Comparació P1
  movlw 220  ; Límit superior de P1
  subwf ADRESH,w  ; W = ADRESH - W
  btfsc CARRY  ; C = 1 si ADRESH >= W
  goto NoEsP1  ; ADRESH >= W
  movlw 200  ; Límit inferior de P1
  subwf ADRESH,w  ; W = ADRESH - W
  btfss CARRY  ; C = 1 si ADRESH >= W
  goto NoEsP1  ; ADRESH < W
  movlw 1  ; Polsador P1
  movwf Polsador  ; Ho copia a Polsador
  goto NoEsP5
NoEsP1:  ; Comparació P2
  movlw 194  ; Límit superior de P2
  subwf ADRESH,w  ; W = ADRESH - W
  btfsc CARRY  ; C = 1 si ADRESH >= W
  goto NoEsP2  ; ADRESH >= W
  movlw 174  ; Límit inferior de P2
  subwf ADRESH,w  ; W = ADRESH - W
  btfss CARRY  ; C = 1 si ADRESH >= W
  goto NoEsP2  ; ADRESH < W
  movlw 2  ; Polsador P2
  movwf Polsador  ; Ho copia a Polsador
  goto NoEsP5
NoEsP2:  ; Comparació P3
  movlw 163  ; Límit superior de P3
  subwf ADRESH,w  ; W = ADRESH - W
  btfsc CARRY  ; C = 1 si ADRESH >= W
  goto NoEsP3  ; ADRESH >= W
  movlw 143  ; Límit inferior de P3
  subwf ADRESH,w  ; W = ADRESH - W
  btfss CARRY  ; C = 1 si ADRESH >= W
  goto NoEsP3  ; ADRESH < W
  movlw 3  ; Polsador P3
  movwf Polsador  ; Ho copia a Polsador
  goto NoEsP5
NoEsP3:  ; Comparació P4
  movlw 90  ; Límit superior de P4
  subwf ADRESH,w  ; W = ADRESH - W
  btfsc CARRY  ; C = 1 si ADRESH >= W
  goto NoEsP4  ; ADRESH >= W
  movlw 70  ; Límit inferior de P4
  subwf ADRESH,w  ; W = ADRESH - W
  btfss CARRY  ; C = 1 si ADRESH >= W
  goto NoEsP4  ; ADRESH < W
  movlw 4  ; Polsador P4
  movwf Polsador  ; Ho copia a Polsador
  goto NoEsP5
NoEsP4:  ; Comparació P5
  movlw 55  ; Límit superior de P5
  subwf ADRESH,w  ; W = ADRESH - W
  btfsc CARRY  ; C = 1 si ADRESH >= W
  goto NoEsP5  ; ADRESH >= W
  movlw 35  ; Límit inferior de P5
  subwf ADRESH,w  ; W = ADRESH - W
  btfss CARRY  ; C = 1 si ADRESH >= W
  goto NoEsP5  ; ADRESH < W
  movlw 5  ; Polsador P5
  movwf Polsador  ; Ho copia a Polsador
NoEsP5:
  return
;
; Enviem caràcters a visualitzar
;
EnviaL:
  movf Caracter,w  ; Agafa el caràcter
  movwf TXREG  ; L'envia
  nop			
  nop  ; Espera 2 us
  btfss TXIF  ; El registre TXREG ha quedat lliure?
  goto $-1  ; No, doncs esperem
  return  ; Tornem al lloc des d'on hem vingut
;
; Funció de retard de 0,2 W s
;
Rets:
  movwf Retard3
Bucles:
  decfsz Retard1,f		
  goto Bucles		
  decfsz Retard2,f		
  goto Bucles		
  decfsz Retard3,f	
  goto Bucles
  return
END main

Descripció del funcionament de la comunicació

Per a la comunicació, cal que hi hagi tres fils que uneixin les dues plaques, dos per a la pròpia transmissió i un que correspon al negatiu de l'alimentació i que actua com a referència. Les potes que emprarem són les següents:

Senyal Funció Pota
CK Rellotge de la transmissió RA4
DT Dades de la transmissió RA5
GND Massa o referència VSS

El programa està pensat per casos en els que el volum de dades a enviar és reduït i s'envien només de tant en tant, per això s'ha optat per una transmissió senzilla, sense protocol ni sistemes de detecció d'errors. S'envien sempre tres bytes (24 bits).

La transmissió es basa en un rellotge que va oscil·lant amb un determinat període. En la figura següent hem anomenat t al semiperíode. Durant la transmissió, aquest senyal de rellotge es troba a la pota CK. El transmissor envia un bit per DT cada cop que CK s'activa i el receptor el llegeix cada cop que CK es desactiva; d'aquesta manera ens assegurem que el valor ja es troba a la pota DT i és estable. El rellotge és controlat pel temporitzador 1.

PICkit 2

En l'exemple hem escollit un semiperíode t de 0,25 ms. Configurarem el temporitzador amb un prescalat d'1, de manera que el seu valor s'incrementarà cada 1 μs; això vol dir que el temporitzador ha de comptar 250 vegades per assolir els 250 μs (0,25 ms). Per posar aquest valor, farem:

	TMR1  = 65536 - 250 = 65286
	TMR1H = 65286 / 256 = 255
	TMR1L = 65286 % 256 = 6

En tot cas, hem fet unes definicions d'etiquetes que guarden aquests valors (T1H i T1L, respectivament); de manera que, si és desitja, és fàcil canviar el període del rellotge.

En diversos llocs del programa ens farà falta conèixer l'estat de la transmissió, per això s'ha creat una variable Control, de la qual en farem servir alguns bits.

Bit Significat
2 Dades de recepció vàlides
1 Mode receptor actiu
0 Mode emissor actiu

Tota la gestió de la comunicació es fa mitjançant interrupcions. En repòs, quan no hi ha cap transmissió en marxa, el temporitzador està aturat i les potes DT i CK estan configurades com a entrades. A més, a la pota DT se li ha activat la resistència de pull-up que conecta aquesta pota al positiu mitjançant una resistència interna; això fa que aquesta entrada estigui activada mentre cap de les dues plaques canviï res. La idea és que quan una de les dues plaques vulgui començar la transmissió, posarà a 0 la pota DT. Per això, en repòs està activada la interrupció per canvis en la pota DT.

A l'iniciar la transmissió, doncs, la placa emissora configura DT i CK com a sortides i les desactiva. Quan l'altra placa detecta un canvi en la pota DT, mira si s'ha desactivat; en cas afirmatiu, entra en mode de recepció.

La placa que fa d'emissora desactiva les interrupcions per DT i posa en marxa el temporitzador 1. A més, activa les interrupcions per aquest temporitzador. Cada cop que hi ha una interrupció pel temporitzador, s'incrementa una variable que compta les interrupcions; també es canvia l'estat de CK. Cada cop que s'activa CK es copia un bit a DT, començant pel bit de menys pes (bit menys significatiu). Quan el comptador d'interrupcions arriba a 49 (ja s'han enviat els 24 bits) es dona per acabada la transmissió, s'atura el temporitzador, es posa DT com a entrada amb resistència de pull-up (s'allibera la línia), es desactiven les interrupcions pel temporitzador i es tornen a activar les interrupcions per DT.

Quan una placa està en repòs i detecta que es desactiva la pota DT, es posa en mode de recepció, desactivant les interrupcions per la pota DT i activant les de la pota CK. Cada cop que varia la pota CK es produeix una interrupció. Si CK s'ha desactivat, es llegeix un bit a DT i es guarda; tenint en compte que el primer bit que arriba és el de menys pes (bit menys significatiu). Hi ha una variable que compta els bits rebuts i quan arriba a 24 (tres bytes) es deixa de llegir. Un cop s'han rebut els tres bytes, es surt del mode de recepció i es marquen les dades com a vàlides.

Anem a comentar els trossos del programa. Comencem pel programa principal. Al començament, tenim les configuracions dels ports, el temporitzador i les interrupcions. També es configuren l'entrada analògica, que controla els polsadors, i la pantalla LCD.

El bucle del programa principal fa tres coses. Si veu que han arribat dades (bit 2 de Control activat) s'esborra la pantalla i s'escriu R: seguit dels tres caràcters rebuts. Després es desactiva l'avís de dades vàlides i es configura la placa en mode de repòs.

Si no hi ha cap transmissió en marxa, es miren els polsadors. En cas que hi hagi un polsador premut, s'escriu a la pantalla E: Ps, seguit del número de polsador. També entra en mode emissor per transmetre tres bytes: P, s i el número de polsador que s'ha premut.

En qualsevol cas, cada cop que s'arriba al final del bucle s'inverteix la sortida RC0, per tal que el led estigui intermitent, indicant que el programa funciona.

D'entrada, la funció d'interrupció mira si aquesta ha estat per canvis al port o pel temporitzador 1. Hi podria haver més fonts d'interrupció, que també s'haurien de mirar. Si la interrupció ha estat per canvis al port (s'activa RABIF) cal veure si és per DT (RA5) o per CK (RA4). Si la interrupció és per desactivació de CK i estem en mode recepció, es fa la recepció del bit corresponent.

Si la interrupció és per desactivació de DT i no estàvem en cap mode de transmissió, vol dir que comença una transmissió i es canvia la configuració convenientment.

Finalment, si la interrupció és pel temporitzador 1 i estem en mode d'emissió, s'envia el bit corresponent; o, si ja s'han enviat tots, es surt del mode d'emissió i s'alliberà la línia.

 

 

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