Aquesta és una placa que hem desenvolupat per a fer projectes. En ella hi tenim els mateixos elements que a la placa PICkit 2 i, a més, una pantalla sèrie, un brunzidor piezoelèctric, un conjunt de cinc polsadors connectats a una entrada analògica i una matriu de vuit per vuit LED tricolor que podrem fer servir com ens sembli més convenient.

En la placa, les següents potes del microcontrolador ja tenen utilitat:
| Nom | Entrada | Pota PIC | Utilització |
| VDD | 5 V | 1 | Alimentació |
| VSS | GND | 20 | |
| ICSPDAT | RA0 | 19 | Programació |
| ICSPCLK | RA1 | 18 | |
| VPP | RA3 | 4 | |
| T1G | RA4 | 3 | |
| AN0 | RA0 | 19 | Potenciòmetre |
| AN2 | RA2 | 17 | Cinc polsadors |
| RA3 | RA3 | 4 | Polsador |
| RA5 | RA5 | 2 | Lliure |
| RB4 | RB4 | 13 | Matriu de LED |
| RB5 | RB5★ | 12 | |
| RB6 | RB6 | 11 | |
| TX | RB7 | 10 | Pantalla sèrie |
| RC0 | RC0 | 16 | LED |
| RC1 | RC1 | 15 | |
| RC2 | RC2 | 14 | |
| RC3 | RC3 | 7 | |
| P1A | RC5 | 5 | Brunzidor piezoelèctric |
| RC4 | RC4 | 6 | Lliures |
| AN8 | RC6 | 8 | |
| AN9 | RC7 | 9 |
★Important: Si es fa servir la pantalla sèrie i la matriu de LED en el mateix programa hi pot haver conflictes. Quan s'inicia la comunicació sèrie (activant el bit SPEN) la pota RB5 passa a estar configurada com a entrada (independentment de l'estat de TRISB) i, per tant, la comunicació amb la matriu de LED queda bloquejada. Per evitar el problema cal fer dues coses. Per un costat convé desactivar les interrupcions del timer 0 (per evitar que aquestes enviïn dades a la matriu de LED) i activar la comunicació sèrie abans de cada transmissió. A l'acabar la transmissió desactivarem la comunicació i tornarem a activar les interrupcions. Atès que la comunicació sèrie l'activem cada cop, no l'hem d'activar a la part de configuració del programa, o sigui que hi haurà quatre línies que no posarem perquè ja les posem dins la funció.
; Aquestes dues línies no les posarem a la part de configuració perquè ; ens bloquejarien la matriu de LED. Ja estan dins la funció EnviaL. ; bsf RCSTA,SPEN ; Activa comunicació sèrie ; bsf STATUS,RP0 ; Tria el banc 1 ; bsf TXSTA,TXEN ; Activa comunicació ; bcf STATUS,RP0 ; Tria el banc 0
Retard1 ; Variable de retard
; ; Enviem caràcters a visualitzar ; EnviaL bcf INTCON,GIE ; Desactiva les interrupcions momentàniament bsf RCSTA,SPEN ; Activa comunicació sèrie bsf STATUS,RP0 ; Tria el banc 1 bsf TXSTA,TXEN ; Activa comunicació bcf STATUS,RP0 ; Tria el banc 0 movf Caracter,w ; Agafa el caràcter movwf TXREG ; L'envia Ret1 nop decfsz Retard1,f ; Retard de 1,6 ms goto Ret1 btfss PIR1,TXIF ; El registre TXREG ha quedat lliure? goto $-1 ; No, doncs esperem bcf RCSTA,SPEN ; Desactiva comunicació sèrie bsf STATUS,RP0 ; Tria el banc 1 bcf TXSTA,TXEN ; Desactiva comunicació bcf STATUS,RP0 ; Tria el banc 0 bsf INTCON,GIE ; Activa les interrupcions return ; Tornem al lloc des d'on hem vingut
L'entrada RA3 està habitualment activada i es desactiva quan es prem el polsador.
No és convenient emprar els pins de programació si es preveu alimentar la placa a través del programador.
La pota RA3 en la que està connectat el polsador també és emprada pel programador. Això pot fer que hi hagi conflictes entre ells. A l'exemple PB es comenten les precaucions que cal tenir per a evitar-ho.

La matriu de LED conté 64 LED tricolor o sigui que hi ha 192 elements. Seria realment complex fer el connexionat d'aquests elements amb el microcontrolador, fins i tot fent servir registres de desplaçament. Per això el fabricant ha optat per un disseny en el que només cal connectar 32 potes, que ja és prou complicat. La següent imatge mostra com estan disposats els LED i el lloc on queden les potes. Encara que les potes estan a la part inferior, la imatge és vista des de la part superior.

Els LED estan connectats de manera que tots els LED de la mateixa filera tenen el càtode (born negatiu) comú i tots els de la mateixa columna i el mateix color tenen l'ànode (born positiu) comú. La següent imatge ens mostra l'esquema de connexionat en el que s'indica el número de pota que correspon a cada punt de connexió.

Aquestes matrius no permeten encendre simultàniament tots els LED desitjats ja que per activar un LED cal posar a 1 la seva columna (ànode, positiu) i a 0 la seva filera (càtode, negatiu). La manera de funcionar serà doncs treballar de forma seqüencial, filera per filera o columna per columna.
Els LED tricolor no només ens permeten obtenir els tres colors que incorporen (vermell, blau i verd) sinó alguns colors més. En teoria, combinant aquests tres colors (amb diferents intensitats) podem obtenir quasi infinits colors. Però nosaltres només podem tenir els colors activats o desactivats (sense variar-ne la intensitat) i, per tant, el nombre de possibles colors és reduït. En principi, disposem dels de la taula següent:
| Vermell (R) | Verd (G) | Blau (B) | Color |
| 1 | 0 | 0 | Vermell |
| 0 | 1 | 0 | Verd |
| 0 | 0 | 1 | Blau |
| 1 | 1 | 0 | Groc |
| 1 | 0 | 1 | Magenta |
| 0 | 1 | 1 | Cian |
| 1 | 1 | 1 | Blanc |
Alternant de forma ràpida dues o més combinacions podem fer alguns colors intermedis; per exemple:
| Vermell (R) | Verd (G) | Blau (B) | Color |
| 1 | 0 | 1 | Morat |
| 0 | 0 | 1 |
Aquests LED els controlarem amb uns xips especials per controlar blocs de LED, els MAX7221.
El circuit que farem servir és el següent. Només hem representat la part corresponent a la matriu de LED, els polsadors i el brunzidor.

Cada un dels tres MAX7221 es connecta a les fileres i a les columnes d'un determinat color. Per tant, hi ha un MAX7221 per a cada un dels tres colors. Per poder controlar tots aquests LED cal fer-ho filera per filera o columna per columna. D'això se n'ocuparà directament el MAX7221 i el microcontrolador no se n'haurà d'ocupar.
A l'hora de funcionar, anirem activant seqüencialment un dels tres xips que s'encarregarà d'encendre els LED corresponents al seu color. Anant prou ràpid com perquè no es noti que els colors s'activen seqüencialment, donarem la sensació de que els tres colors estan actius al mateix temps en els LED que els correspon. Aquesta activació seqüencial dels tres xips sí que serà responsabilitat del microcontrolador. Cal repartir els temps entre els tres xips de manera equilibrada perquè sinó els colors no es combinaran correctament. Per això aquesta tasca l'encomanarem a una imterrupció controlada amb el Timer0
Cada MAX7221 és capaç de memoritzar l'estat dels 64 LED que controla. Això vol dir que nosaltres enviarem als xips el patró del dibuix que volem mostrar un cop i no caldrà tornar-ho a enviar fins que canviem el dibuix. Aquesta és una diferència important respecte als registres de desplaçament als que hauríem hagut d'estar enviant les dades constantment i això ens hauria fet necessari un microcontrolador més ràpid. Per enviar les dades als MAX7221 ho farem en forma sèrie, com amb els registres de desplaçament. A cada xip li haurem d'enviar vuit blocs (un per filera) de vuit bits però ho haurem de fer enviant conjunts de setze bits en els que hi haurà la indicació de la filera i l'estat dels LED d'aquesta filera. Com els xips els connectarem un darrera l'altre (com amb els registres de desplaçament), haurem d'enviar blocs de 48 bits (sis bytes). Atès que només enviem una filera cada cop, només cal enviar aquelles fileres que hagin canviat respecte a la situació anterior.
A l'hora d'enviar els setze bits a un MAX7221, primer hem d'enviar el bit més significatiu (15) i després els següents. Si enviem més de setze bits, els primers que hem enviat passaran cap al xip següent de la cadena. La comunicació es fa mitjançant tres potes dels xips: Data (DIN, 1), Clock (CLK, 13) i Latch (CS, 12). Si CS està desactivat, cada cop que activem CLK es considerarà que el valor a DIN és un nou bit; aquest entrarà i farà rodar tots els que ja estan a dins i els primers que haguem entrat sortiran cap al xip següent. Quan haguem acabat d'enviar-los, activarem CS i cada xip memoritzarà els bits que ha rebut.
Dels setze bits que rep un xip, els bits 12 a 15 no serveixen per a res i nosaltres els posarem sempre a zero. Els bits 8 a 11 són els de control i serveixen per indicar quina filera estem enviant o si enviem valors de configuració. Els bits 0 a 7 són els estats dels LED de la filera o els valors de configuració corresponents. La següent taula indica els valors (en hexadecimal) dels bits de control (8 a 15) segons el que es vol enviar.
| Valor | Nom | Funció | Comentaris |
| 0x01 | Filera 1 | ||
| 0x02 | Filera 2 | ||
| 0x03 | Filera 3 | ||
| 0x04 | Filera 4 | ||
| 0x05 | Filera 5 | ||
| 0x06 | Filera 6 | ||
| 0x07 | Filera 7 | ||
| 0x08 | Filera 8 | ||
| 0x00 | No-Op | No fer res | Serveix quan vols enviar dades a un altre MAX7221 però no en vols enviar a aquest |
| 0x09 | Decode mode | Conversió per a 7 segments | Per a matrius de LED ha d'enviar-se 0x00 (no decode) |
| 0x0B | Scan limit | Nombre de fileres (des de 0) | Nosaltres enviarem 0x07 perquè tenim vuit fileres |
| 0x0C | Shutdown mode | Activa o desactiva el xip | Només n'hi pot haver un d'activat (0x01) cada vegada; la resta desactivats (0x00) |
Per tal que no es noti el pampallugueig dels LED cal treballar a una freqüència d'oscil·lació de 25 Hz o superior. Si treballem a 25 Hz vol dir que cada cicle ha de durar un màxim de 40 ms. En cada cicle hem d'activar, seqüencialment, els tres colors, per tant hem de canviar de color cada 13,3 ms o menys. Hem decidit fer-ho, més o menys, cada 10 ms; per això posarem el temporitzador a 1/64 (incrementarà TMR0 cada 64 μs) i farem una interrupció cada 156 iteracions, és a dir que posarem una preselecció de 100 a TMR0.
La funció d'interrupció per al Timer 0 és la que s'encarrega de canviar els colors. El color actual es controla, amb la variable Actiu, segons la següent taula:
| Actiu | Color |
| 0 | Matriu apagada |
| 1 | Vermell actiu |
| 2 | Verd actiu |
| 3 | Blau actiu |
Si el valor de la variable Actiu no és zero, a cada interrupció es canvia el color. Si, en canvi, val zero es manté a zero. Per tant, a l'estat de desactivació s'hi entra i se'n surt des del programa principal. La funció d'interrupció activa el xip del color que correspon o cap d'ells.
Atès que a la funció Envia3max se la crida tant des del programa principal com de la interrupció, podríem tenir problemes si la interrupció es produeix mentre la funció s'està executant ja que canviaria l'estat de les variables. Per evitar-ho, a la interrupció podríem guardar tots els valors de les variables que fa servir Envia3max i restituir-los a l'acabar. Però també podem tenir problemes si un color s'activa quan s'està a mig enviar. Per això el que hem fet és desactivar les interrupcions del timer 0 durant l'enviament i així ens estalviem de guardar els valors de les variables.
És molt important que la funció d'interrupció durin el mateix per a cada un dels tres colors. A la taula següent determinem quan dura la funció d'interrupció per a cada color. Hem marcat amb color les instruccions que duren doble. A la funció Activar hem afegit a cada color els nop necessaris.
| Color | Vermell | Verd | Blau |
| Valor inicial Actiu | 2 | 3 | 1 |
| Valor final Actiu | 1 | 2 | 3 |
| Instruccions incrementar |
decf Actiu,f btfss STATUS,Z goto NoZero |
decf Actiu,f btfss STATUS,Z goto NoZero |
decf Actiu,f btfss STATUS,Z movlw .3 movwf Actiu |
| Instruccions activar color |
movlw .1 xorwf Actiu,w btfsc STATUS,Z goto Vermell |
movlw .1 xorwf Actiu,w btfsc STATUS,Z movlw .2 xorwf Actiu,w btfsc STATUS,Z goto Verd |
movlw .1 xorwf Actiu,w btfsc STATUS,Z movlw .2 xorwf Actiu,w btfsc STATUS,Z |
| Durada | 9 μs | 13 μs | 13 μs |
| Cal afegir | 4 μs |
La funció d'interrupció (inclosa la funció Envia3max) dura aproximadament 1 ms. Atès que la interrupció es repeteix cada 7,5 ms vol dir que qualsevol bucle de retard que posem al programa principal es veurà incrementat en un 14 %. L'enviament de les dades a una matriu completa dura uns 8,9 ms.
cblock 0x20 Port ; Bits a enviar al port B Sortida:6 ; Valors a enviar al MAX7221 (48 bits) Compta ; Variable per comptar els bits Filera ; Variable per comptar fileres Actiu ; Variable que diu quin color està actiu ; Actiu = 0 Apagat ; Actiu = 1 Vermell ; Actiu = 2 Verd ; Actiu = 3 Blau endc cblock 0x70 ; Zona de memòria de dades que no depèn del banc triat W_Copia ; Guardarà el contingut de W durant la interrupció ST_Copia ; Guardarà STATUS durant la interrupció endc
Interrup 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 INTCON,T0IF ; Mira si Timer0 ha arribat a zero ; Si hi ha arribat, no fa la instrucció següent goto FiInt ; Si la interrupció no és del Timer0 no fem res Timer0 ; Programa corresponent a Timer0 bcf INTCON,T0IF ; Si ha arribat, desactivem el bit movlw .100 ; Nova preselecció movwf TMR0 ; Ho posem a TMR0 ; Anem a gestionar el canvi de color movlw b'00000011' ; Descarta els bits que no serveixen andwf Actiu,f btfsc STATUS,Z goto NoZero ; Si Actiu val 0 no ho canvia decf Actiu,f ; Passem a activar un altre color btfss STATUS,Z ; Si s'activa Z és que hem arribat a zero goto NoZero ; Si és zero, tornem a 3 movlw .3 movwf Actiu NoZero ; Gestiona l'activació de tres MAX7221 ; Segons Actiu, activa un color o un altre movlw b'00000011' ; Descarta els bits que no serveixen andwf Actiu,f btfsc STATUS,Z ; Salta si el resultat no és zero goto Apagat ; Si està apagat ho desactiva tot movlw .1 xorwf Actiu,w btfsc STATUS,Z goto Vermell ; Si val 1, activem el vermell movlw .2 xorwf Actiu,w btfsc STATUS,Z goto Verd ; Si val 2, activem el verd ; Si no és cap d'ells, activem el blau movlw 0x01 ; Activat movwf Sortida+4 ; Blau movlw 0x00 ; Desactivat movwf Sortida ; Vermell movwf Sortida+2 ; Verd movlw .1 goto Activa Vermell movlw 0x01 ; Activat movwf Sortida ; Vermell movlw 0x00 ; Desactivat movwf Sortida+2 ; Verd movwf Sortida+4 ; Blau nop ; Temps a afegir nop nop nop goto Activa Verd movlw 0x01 ; Activat movwf Sortida+2 ; Verd movlw 0x00 ; Desactivat movwf Sortida ; Vermell movwf Sortida+4 ; Blau goto Activa Apagat movlw 0x00 ; Desactivat movwf Sortida ; Vermell movwf Sortida+2 ; Verd movwf Sortida+4 ; Blau Activa movlw 0x0C ; Shutdown mode movwf Sortida+1 ; Ho prepara per enviar-ho movwf Sortida+3 ; Ho prepara per enviar-ho movwf Sortida+5 ; Ho prepara per enviar-ho call Envia_max ; Ho envia als MAX7221 FiInt 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
; ; Apaga tots els LED ; Apaga movlw .8 ; Hem d'apagar vuit fileres movwf Filera ; Ho guarda al comptador Repetir movf Filera,w ; Filera actual movwf Sortida+1 ; Ho prepara per enviar-ho movwf Sortida+3 ; Ho prepara per enviar-ho movwf Sortida+5 ; Ho prepara per enviar-ho movlw b'00000000' ; Apagat movwf Sortida ; Ho prepara per enviar-ho movwf Sortida+2 ; Ho prepara per enviar-ho movwf Sortida+4 ; Ho prepara per enviar-ho call Envia3max ; Ho envia al MAX7221 decfsz Filera,f ; Passem a una altra filera goto Repetir return ; ; Inicialització de tres MAX7221 ; Ini3max movlw 0x0C ; Shutdown mode movwf Sortida+1 ; Ho prepara per enviar-ho movwf Sortida+3 ; Ho prepara per enviar-ho movwf Sortida+5 ; Ho prepara per enviar-ho movlw 0x00 ; Desactivat movwf Sortida ; Ho prepara per enviar-ho movwf Sortida+2 ; Ho prepara per enviar-ho movwf Sortida+4 ; Ho prepara per enviar-ho call Envia_max ; Ho envia al MAX7221 movlw 0x09 ; Decode mode movwf Sortida+1 ; Ho prepara per enviar-ho movwf Sortida+3 ; Ho prepara per enviar-ho movwf Sortida+5 ; Ho prepara per enviar-ho movlw 0x00 ; No decode movwf Sortida ; Ho prepara per enviar-ho movwf Sortida+2 ; Ho prepara per enviar-ho movwf Sortida+4 ; Ho prepara per enviar-ho call Envia_max ; Ho envia al MAX7221 movlw 0x0B ; Scan limit movwf Sortida+1 ; Ho prepara per enviar-ho movwf Sortida+3 ; Ho prepara per enviar-ho movwf Sortida+5 ; Ho prepara per enviar-ho movlw 0x07 ; Vuit fileres movwf Sortida ; Ho prepara per enviar-ho movwf Sortida+2 ; Ho prepara per enviar-ho movwf Sortida+4 ; Ho prepara per enviar-ho call Envia_max ; Ho envia al MAX7221 return ; ; Envia dades (48 bits) a tres MAX7221 ; desactivant les interrupcions ; Envia3max bcf INTCON,T0IE ; Desactiva les interrupcions momentàniament call Envia_max bsf INTCON,T0IE ; Reactiva les interrupcions a l'acabar return ; ; Envia dades (48 bits) a tres MAX7221 ; ; Els bits estan a les variables: ; Sortida Valor vermells ; Sortida+1 Adreça vermells ; Sortida+2 Valor verds ; Sortida+3 Adreça verds ; Sortida+4 Valor blaus ; Sortida+5 Adreça blaus ; Al final de la funció, el valor de Sortida queda corromput ; Si es vol conservar, cal copiar-lo a una altra variable ; ; Aquesta funció dura, aproximadament, 1 ms Envia_max bcf Port,5 ; S'assegura que Clock està desactivat bcf Port,6 ; S'assegura que Latch està desactivat movf Port,w ; Agafa el valor de Port movwf PORTB ; I el posa al port B movlw .48 ; Número de bits a enviar movwf Compta ; Variable per comptar els bits Bucle3max bcf Port,4 ; Desactiva Data. Si toca activar-ho, ja ho farem rlf Sortida,f ; Fa sortir el bit de més a l'esquerra cap a C rlf Sortida+1,f ; i roda els altres a l'esquerra rlf Sortida+2,f rlf Sortida+3,f rlf Sortida+4,f rlf Sortida+5,f btfsc STATUS,C ; Mira si el bit de l'esquerra era un 1 bsf Port,4 ; Si era 1, activa Data movf Port,w ; Agafa el valor de Port. El valor que ha canviat és Data movwf PORTB ; I el posa al port B bsf Port,5 ; Activa Clock, forçant a llegir el bit movf Port,w ; Agafa el valor de Port. El valor que ha canviat és Clock movwf PORTB ; I el posa al port B bcf Port,5 ; Desactiva Clock movf Port,w ; Agafa el valor de Port. El valor que ha canviat és Clock movwf PORTB ; I el posa al port B decfsz Compta,f ; Decrementa Compta goto Bucle3max ; Si Compta no és zero, repeteix el bucle bsf Port,6 ; Torna a activar Latch ; Els valors es copiaran a la sortida del registre movf Port,w ; Agafa el valor de Port. El valor que ha canviat és Latch movwf PORTB ; I el posa al port B return ; ; Funció de retard de 0,2 W s ; Retard movwf Retard3 Bucles decfsz Retard1,f goto Bucles decfsz Retard2,f goto Bucles decfsz Retard3,f goto Bucles return end
El programa de l'exemple NM permet provar el brunzidor i el programa de l'exemple PA permet provar els polsadors. A l'exemple ML mostrem uns dibuixos estàtics a la matriu de LED. A l'exemple DM dibuixem en un sol color sobre la matriu fent servir els polsadors per moure un cursor i a l'exemple D6 ho fem emprant sis possibles colors.

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