En aquest exemple volem comunicar dos microcontroladors per infrarojos.
Ens basarem en l'exemple EA. A l'emissor hi tindrem el programa d'aquest exemple però, addicionalment, enviarem per infrarojos el mateix valor que enviem als LED. En el receptor, rebrem el valor i el mostrarem als LED. Així doncs, els LED de les dues plaques tindran la mateixa combinació que podrem variar amb el potenciòmetre de la targeta emissora.
Per estalviar energia, esperarem 0,6 s entre una lectura i la següent. L'emissor estarà connectat a RB4 i el receptor a RB6. Fem servir potes diferents perquè en cas de voler implementar un enllaç bidireccional tindríem emissor i receptor en el mateix microcontrolador.
#include <p16F690.inc> __config (_INTRC_OSC_NOCLKOUT&_WDT_OFF&_PWRTE_OFF&_MCLRE_OFF&_CP_OFF&_BOR_OFF&_IESO_OFF&_FCMEN_OFF)
cblock 0x20 Port ; Variable per al contingut del port B ; que permet modificar els bits individualment Comp_bits ; Variable per comptar bits Comp_bytes ; Variable per comptar bytes Control ; Variable per calcular el byte de control Retard ; Comptador per al retard Byte ; Variable de treball per enviar un byte Bytes ; Número de bytes que voldrem enviar ; Un paquet tindrà aquests i el byte de control Ret:3 ; Tres variables per a bucles de retard Vector ; Lloc on es guardaran els bytes a enviar ; Després d'aquesta ja no es poden declarar més variables ; ja que el vector tindrà tantes posicions com hi digui a Bytes ; més una per al byte de control endc
org 0 Inici bsf STATUS,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 clrf TRISB ; Posa tots els bits del port B com a sortida clrf TRISC ; Posa tots els bits del port C com a sortida movlw b'00010000' ; Posa el conversor a 1/8 de la freqüència movwf ADCON1 ; Copia W a la configuració del conversor A/D bcf STATUS,RP0 bsf STATUS,RP1 ; Tria el banc 2 movlw 0xFF ; Posa l'acumulador a FFh (tot uns) movwf ANSEL ; Configura AN0-AN7 com entrades analògiques bcf STATUS,RP0 bcf STATUS,RP1 ; Tria el banc 0 movlw 0 ; Inicialment totes les sortides desactivades movwf Port ; Ho guardem a Port movwf PORTB ; I ho copiem al port B movlw .2 ; Número de bytes que volem enviar movwf Bytes ; Ho guardem a Bytes movlw 0x93 ; Codi d'identificació movwf Vector ; El guarda sobre el primer byte de dades que enviarem movlw b'00000001' ; activa el conversor A/D connectat a AN0 movwf ADCON0 ; amb el resultat justificat per l'esquerra Bucle nop ; espera un microsegon nop ; espera un microsegon nop ; espera un microsegon nop ; espera un microsegon nop ; espera un microsegon, en total 5 bsf ADCON0,GO ; Inicia la conversió btfsc ADCON0,GO ; Quan el bit sigui 0 la conversió haurà acabat goto $-1 ; repetim la línia fins que deixi de ser 1 swapf ADRESH,w ; Permuta els nibbles dels bits superiors movwf PORTC ; Copia el resultat sobre els LED movwf Vector+1 ; i sobre el segon byte de dades que enviarem call Envia ; Envia la dada movlw .3 ; Bucle de retard de 3 * 0,2 = 0,6 s movwf Ret+2 Bucles decfsz Ret,f goto Bucles decfsz Ret+1,f goto Bucles decfsz Ret+2,f goto Bucles goto Bucle
; ; Funció per enviar un paquet ; Envia ; Comencem calculant el byte de control ; Hem de sumar (sense portar-ne) tots els bytes clrf Control ; El posem a zero movf Bytes,w ; Llegim el número de bytes que volem enviar movwf Comp_bytes ; Ho guardem al comptador de bytes movlw Vector ; Llegim l'adreça de Vector movwf FSR ; Ho posem al punter d'adreçament indirecte movlw 0 ; L'acumulador contindrà la suma, comencem a 0 addwf INDF,w ; Hi sumem un dels bytes incf FSR,f ; Desplaça el punter decfsz Comp_bytes,f ; Byte següent goto $-3 ; Si no és el darrer, seguim ; Ja tenim la suma, ara ho restem (sense portar-ne) de Control (= 0) subwf Control,w ; W = Control - suma movwf INDF ; Ho guarda al final del Vector ; Comencem a enviar ; Primer cal enviar la capçalera movlw .15 ; Primer 15 bits a 1 movwf Comp_bits ; Ho guarda al comptador de bits call Envia_1 ; Envia un 1 decfsz Comp_bits,f ; Decrementa els bits pendents goto $-2 ; Repeteix fins que s'acabi call Envia_0 ; Finalment un bit a 0 ; Després cal enviar els bytes movf Bytes,w ; Llegim el número de bytes que volem enviar movwf Comp_bytes ; Ho guardem al comptador de bytes incf Comp_bytes,f ; Incrementa el comptador de bytes per afegir el byte de control movlw Vector ; Llegim l'adreça de Vector movwf FSR ; Ho posem al punter d'adreçament indirecte TI movf INDF,w ; Agafa un dels bytes movwf Byte ; Ho guarda a la variable de treball movlw .8 ; Un byte són 8 bits movwf Comp_bits ; Ho guarda al comptador de bits TR rlf Byte,f ; El bit de més a l'esquerra passa a C btfss STATUS,C ; Mira sí és 0 goto T0 ; Sí, envia un 0 call Envia_1 ; No, envia un 1 goto TF T0 call Envia_0 ; Envia un 0 TF decfsz Comp_bits,f ; Següent bit goto TR ; Al final de cada byte s'envia un 1 i un 0 call Envia_1 ; Envia un 1 call Envia_0 ; Envia un 0 incf FSR,f ; Desplaça el punter decfsz Comp_bytes,f ; Byte següent goto TI bcf Port,4 ; Desactiva l'emissor movf Port,w ; Ho canviem a Port movwf PORTB ; I ho copiem al port B return Envia_0 ; Funció per enviar un 0 bsf Port,4 ; Un bit 0 comença amb 1 movf Port,w ; Ho canviem a Port movwf PORTB ; I ho copiem al port B movlw .166 ; Cada dec són 1 us i cada goto són 2 us movwf Retard ; 165 * 3 (a la darrera no hi ha goto) dona 495 decfsz Retard,f ; que amb els 4 dels mov i 1 del dec goto $-1 ; fem 500 us bcf Port,4 ; I canvia a 0 a mig bit movf Port,w ; Ho canviem a Port movwf PORTB ; I ho copiem al port B movlw .166 ; Cada dec són 1 us i cada goto són 2 us movwf Retard ; 165 * 3 (a la darrera no hi ha goto) dona 495 decfsz Retard,f ; que amb els 4 dels mov i 1 del dec goto $-1 ; fem 500 us return ; 0 enviat Envia_1 ; Funció per enviar un 1 bcf Port,4 ; Un bit 1 comença amb 0 movf Port,w ; Ho canviem a Port movwf PORTB ; I ho copiem al port B movlw .166 ; Cada dec són 1 us i cada goto són 2 us movwf Retard ; 165 * 3 (a la darrera no hi ha goto) dona 495 decfsz Retard,f ; que amb els 4 dels mov i 1 del dec goto $-1 ; fem 500 us bsf Port,4 ; I canvia a 1 a mig bit movf Port,w ; Ho canviem a Port movwf PORTB ; I ho copiem al port B movlw .166 ; Cada dec són 1 us i cada goto són 2 us movwf Retard ; 165 * 3 (a la darrera no hi ha goto) dona 495 decfsz Retard,f ; que amb els 4 dels mov i 1 del dec goto $-1 ; fem 500 us return ; 1 enviat end
#include <p16F690.inc> __config (_INTRC_OSC_NOCLKOUT&_WDT_OFF&_PWRTE_OFF&_MCLRE_OFF&_CP_OFF&_BOR_OFF&_IESO_OFF&_FCMEN_OFF)
cblock 0x20 Estat ; Variable per memoritzar estats Comp_bits ; Variable per comptar bits Comp_bytes ; Variable per comptar bytes Byte ; Variable temporal per construir un byte Bytes ; Número de bytes que rebrem Temps ; Variable per comptar el temps minS ; Valor mínim per a la durada d'un semiperíode maxS ; Valor màxim per a la durada d'un semiperíode minP ; Valor mínim per a la durada d'un període maxP ; Valor màxim per a la durada d'un període Vector ; Lloc on es guardaran els bytes rebuts ; Després d'aquesta ja no es poden declarar més variables ; ja que el vector tindrà tantes posicions com hi digui a Bytes ; més una per al byte de control endc
org 0 Inici ; Comencem amb la inicialització bsf STATUS,RP0 ; Tria el banc 1 movlw b'01000000' ; RB6 és entrada, la resta del port B és sortida movwf TRISB clrf TRISC ; Posa tots els bits del port C com a sortida movlw b'10000010' ; Configuració de Timer0 ; Com a temporitzador basat en rellotge ; 010 - Factor d'escala de 8 ; TMR0 s'incrementarà cada 8 us ; I resistències de pull-up desactivades (valor per defecte) movwf OPTION_REG ; Ho guarda al registre de configuració del Timer0 bcf STATUS,RP0 ; Tria el banc 0 ; Inicialització de variables clrf Estat ; De moment, desactiva tots els bits d'estat movlw .3 ; Número de bytes que rebrem movwf Bytes ; Ho guardem a Bytes ; Semiperíode de 500 us ; Marge d'error: 30 % 500 * 0,3 = 150 movlw .43 ; (500 - 150)/8 movwf minS ; Valor mínim per a la durada d'un semiperíode movlw .82 ; (500 + 150)/8 movwf maxS ; Valor màxim per a la durada d'un semiperíode movlw .87 ; 2 * (500 - 150)/8 movwf minP ; Valor mínim per a la durada d'un període movlw .163 ; 2 * (500 + 150)/8 movwf maxP ; Valor màxim per a la durada d'un període clrf PORTC ; Comencem amb els LED apagats Bucle call Rebre ; Espera que arribi un paquet andlw 0xFF ; Anem a veure si W és zero btfss STATUS,Z ; Si és zero, and donarà zero goto Bucle ; No és zero, esperem un altre paquet movlw 0x93 ; Sí és zero, anem a veure el Codi d'identificació xorwf Vector,w ; Compara amb el codi d'identificació btfss STATUS,Z ; Si Z = 1 es que són iguals goto Bucle ; Z = 0, esperem un altre paquet movf Vector+1,w ; Agafem el byte de dades movwf PORTC ; i el copia sobre els LED goto Bucle ; Acabat, esperem un altre paquet
; ; Funció per rebre un paquet ; Rebre ; Comencem inicialitzant variables movlw Vector ; Carreguem l'adreça del lloc on es guardaran els bytes rebuts movwf FSR ; Punter per a l'adreçament indirecte clrf Comp_bits ; Posem a zero la variable que compta els bits rebuts movf Bytes,w ; Número de bytes que rebrem movwf Comp_bytes ; Variable de comptatge bsf Estat,5 ; Cap = 1 ; Ara esperem la primera activació (primer 1) btfsc PORTB,6 ; S'ha activat el LED? O sigui, s'ha desactivat l'entrada? goto $-1 ; No, doncs esperem clrf TMR0 ; Sí, comencem a comptar el temps Espera ; Esperem a que es desactivi l'entrada btfsc PORTB,6 ; S'ha desactivat el LED? O sigui, s'ha activat l'entrada? goto PrimerBit ; Sí, doncs el primer bit ja està movf TMR0,w ; No, agafa el valor actual del temps movwf Temps ; i el guarda movf maxS,w ; Mirem que no passem de maxS subwf Temps,w ; W = Temps - W btfss STATUS,C ; C = 1 si Temps >= maxS goto Espera ; És més petit, seguim esperant retlw .129 ; És més gran: Error 129 - Bit d'inici massa llarg PrimerBit ; El primer bit ja està movf TMR0,w ; Agafa el valor actual del temps movwf Temps ; i el guarda clrf TMR0 ; Comencem a comptar el temps movf minS,w ; Mirem que no sigui menor que minS subwf Temps,w ; W = Temps - W btfss STATUS,C ; C = 1 si Temps >= minS retlw .130 ; És més petit: Error 130 - Bit d'inici massa curt incf Comp_bits,f ; Ja tenim un bit bsf Estat,6 ; Pre = 1 bcf Estat,7 ; Rebut = 0 SegTran ; Esperem al següent canvi a l'entrada btfsc Estat,7 ; Quin és el darrer valor de l'entrada? goto Espera0 ; 1, doncs hem de rebre un 0 goto Espera1 ; 0, doncs hem de rebre un 1 Espera0 ; Esperem que es desactivi l'entrada btfsc PORTB,6 ; S'ha desactivat el LED? O sigui, s'ha activat l'entrada? goto Canvi ; Sí movf TMR0,w ; No, agafa el valor actual del temps movwf Temps ; i el guarda movf maxP,w ; Mirem que no passem de maxP subwf Temps,w ; W = Temps - W btfss STATUS,C ; C = 1 si Temps >= maxP goto Espera0 ; És més petit, seguim esperant retlw .17 ; És més gran: Error 17 - Període massa llarg Espera1 ; Esperem que s'activi l'entrada btfss PORTB,6 ; S'ha activat el LED? O sigui, s'ha desactivat l'entrada? goto Canvi ; Sí movf TMR0,w ; No, agafa el valor actual del temps movwf Temps ; i el guarda movf maxP,w ; Mirem que no passem de maxP subwf Temps,w ; W = Temps - W btfss STATUS,C ; C = 1 si Temps >= maxP goto Espera1 ; És més petit, seguim esperant retlw .17 ; És més gran: Error 17 - Període massa llarg Canvi ; L'entrada ja ha canviat movf TMR0,w ; Agafa el valor actual del temps movwf Temps ; i el guarda clrf TMR0 ; Comencem a comptar el temps movf minS,w ; Mirem que no sigui menor que minS subwf Temps,w ; W = Temps - W btfss STATUS,C ; C = 1 si Temps >= minS retlw .18 ; És més petit: Error 18 - Semiperíode massa curt movlw b'10000000' ; Invertim bit 7 xorwf Estat,f ; o sigui, invertim Rebut movf maxS,w ; Mirem si és més gran que maxS subwf Temps,w ; W = Temps - W btfss STATUS,C ; C = 1 si Temps >= maxS goto Curt ; És més petit, és un pols curt movf minP,w ; També mirem si és més gran que minP subwf Temps,w ; W = Temps - W btfsc STATUS,C ; C = 1 si Temps >= minP goto Llarg ; És més gran, és un pols llarg retlw .19 ; Ni curt ni llarg ; Error 19 - Semiperíode massa llarg o període massa curt Llarg ; És un pols llarg btfsc Estat,6 ; Pre = 1? retlw .9 ; Sí: Error 9 - No hi ha canvi a mig període goto CanviFinal ; No, esperem canvi al final de període Curt ; És un pols curt movlw b'01000000' ; Invertim Pre ara xorwf Estat,f ; per no haver-ho de fer dos cops btfsc Estat,6 ; Pre = 1? goto SegTran ; No, esperem canvi a mig període CanviFinal ; Sí, esperem canvi al final de període btfss Estat,5 ; Cap = 1? goto NoCap ; No, ja no estem rebent capçalera btfss Estat,7 ; Rebut = 1? goto Cap0 ; No, hem rebut un zero a la capçalera incf Comp_bits,f ; Tenim un altre 1 de capçalera movlw .16 ; Hem arribat al final de la capçalera? xorwf Comp_bits,w ; Comp_bits = 16? btfsc STATUS,Z ; Z = 1 si Comp_bits = 16 retlw .66 ; Sí: Error 66 - Massa 1 a la capçalera goto SegTran ; No, esperem el següent Cap0 ; Hem rebut un zero a la capçalera movlw .15 ; Hem arribat al final de la capçalera? xorwf Comp_bits,w ; Comp_bits = 15? btfss STATUS,Z ; Z = 1 si Comp_bits = 15 retlw .65 ; Sí: Error 65 - Pocs 1 a la capçalera bcf Estat,5 ; Cap = 0 - Capçalera ja acabada, ara rebrem el missatge movlw .10 ; Cada byte són 10 bits movwf Comp_bits ; 8 de dades i dos d'aturada clrf Byte ; De moment, no hem rebut cap bit de Byte goto SegTran ; Anem a esperar el primer bit NoCap ; Ja no estem rebent capçalera decfsz Comp_bits,f ; Decrementem, és 0? goto NoEs0 ; No, cal saber si és 1 o més gran btfsc Estat,7 ; Sí, darrer bit d'aturada - Rebut = 1? retlw .34 ; Sí: Error 34 - No hi ha 0 als bits d'aturada movf Byte,w ; Agafa el byte rebut movwf INDF ; I el guarda a Vector incf FSR,f ; Incrementa el punter decfsz Comp_bytes,f ; Decrementem, és 0? goto NoFi ; No, cal rebre un altre byte ; Ja hem acabat, anem a fer la suma de control movlw Vector ; Carreguem l'adreça del lloc on es guardaran els bytes rebuts movwf FSR ; Punter per a l'adreçament indirecte movf Bytes,w ; Número de bytes que hem rebut movwf Comp_bytes ; Variable de comptatge movlw 0 ; Comencem amb zero per anar sumant SumaControl ; i anem a fer el bucle de suma addwf INDF,w ; Suma el valor de Vector incf FSR,f ; Incrementa el punter decfsz Comp_bytes,f ; Decrementa, és 0? goto SumaControl ; No, sumem un altre andlw 0xFF ; Sí, anem a veure si surt zero btfss STATUS,Z ; Si és zero, and donarà zero retlw .5 ; No és zero: Error 5 - La suma de control no dona 0 retlw 0 ; Sí és zero: Error 0 - Recepció correcta NoFi ; Cal rebre un altre byte movlw .10 ; Cada byte són 10 bits movwf Comp_bits ; 8 de dades i dos d'aturada clrf Byte ; De moment, no hem rebut cap bit de Byte goto SegTran ; Anem a esperar el primer bit NoEs0 ; Cal saber si és 1 o més gran decfsz Comp_bits,w ; Decrementem provisionalment, és 0? goto Dades ; No, doncs encara és un bit de dades btfss Estat,7 ; Sí, és un bit d'aturada - Rebut = 1? retlw .33 ; No: Error 33 - No hi ha 1 als bits d'aturada goto SegTran ; Sí, esperem el següent bit d'aturada Dades ; És un bit de dades rlf Estat,w ; Passa Rebut a C rlf Byte,f ; I el col·loca a la dreta de Byte desplaçant els que ja hi són goto SegTran ; Esperem el següent bit end

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