En aquest cas, l'usuari introdueix una seqüència de ratlles i punts, corresponents al codi Morse d'algun caràcter, i a la pantalla es mostra el caràcter introduït. L'ús dels polsadors és el següent:
| Polsador | Finalitat |
| 0 | Esborrar la pantalla |
| 1 | Punt |
| 2 | Ratlla |
| 3 | Enviar a traduir |
| 4 | Deixar un espai |
| 5 | Esborrar el darrer caràcter |
El programa és el següent:
#pragma config FOSC = INTRCIO, WDTE = OFF, PWRTE = OFF, MCLRE = OFF, CP = OFF #pragma config CPD = OFF, BOREN = OFF, IESO = OFF, FCMEN = OFF #include <xc.h> // Carrega el fitxer de funcions necessari per al compilador XC8 #define _XTAL_FREQ 4000000 // La freqüència del rellotge és 4 MHz #define Polsador0 RA3 // Li assigna un nom a l'adreça del polsador
// Definició de les variables
char Polsad; // Polsador que s'ha premut
char mirar = 1; // Espera que es deixi anar el polsador
char codi=0b00000001; // Codi original que utilitzem per relacionar les polsacions amb les lletres
char c=0; // Posició del cursor a la pantalla LCD
char m=1; // Linea de la pantalla LCD en la que ens trobem
char a=0; // Variable per poder comparar la posició
//Matriu de codis que utlitzem per les lletres, números i simbols
char Matriu[40][2]={{0b00000101,'A'}, {0b00011000,'B'}, {0b00011010,'C'}, {0b00001100,'D'},
{0b00000010,'E'}, {0b00010010,'F'}, {0b00001110,'G'}, {0b00010000,'H'},
{0b00000100,'I'}, {0b00010111,'J'}, {0b00001101,'K'}, {0b00010100,'L'},
{0b00000111,'M'}, {0b00000110,'N'}, {0b00001111,'O'}, {0b00010110,'P'},
{0b00011101,'Q'}, {0b00001010,'R'}, {0b00001000,'S'}, {0b00000011,'T'},
{0b00001001,'U'}, {0b00010001,'V'}, {0b00001011,'W'}, {0b00011001,'X'},
{0b00011011,'Y'}, {0b00011100,'Z'}, {0b00111111,'0'}, {0b00101111,'1'},
{0b00100111,'2'}, {0b00100011,'3'}, {0b00100001,'4'}, {0b00100000,'5'},
{0b00110000,'6'}, {0b00111000,'7'}, {0b00111100,'8'}, {0b00111110,'9'},
{0b01010101,'.'}, {0b01110011,','}, {0b01001100,'?'}, {0b00110010,'/'}};
char Port; // Gestió del port a la funció Envia_max
char Compta; // Comptador de bits a la funció Envia_max
char Sortida[6]; // Valors a enviar al MAX7221 (48 bits)
char Sorti[6]; // Valors a enviar al MAX7221 des de la interrupció
char Actiu; // Variable que diu quin color està actiu
// Actiu = 0 Apagat
// Actiu = 1 Vermell
// Actiu = 2 Verd
// Actiu = 3 Blau
char fig1[3][8] = { {0b10000001, 0b01000010, 0b00100100, 0b00011000,
0b00011000, 0b00100100, 0b01000010, 0b10000001},
{0b00000000, 0b00000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00000000, 0b00000000},
{0b00000000, 0b00000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00000000, 0b00000000},}; //Creu vermella
char fig2[3][8] = { {0b00000000, 0b00000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00000000, 0b00000000},
{0b00000000, 0b00000001, 0b00000010, 0b00000100,
0b10001000, 0b01010000, 0b00100000, 0b00000000},
{0b00000000, 0b00000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00000000, 0b00000000} }; //Tick verd
// Definició de les funcions
void Envia3max(char Valor[]); // Envia un joc de valors als tres MAX7221
// desactivant interrupcions
void Envia_max(void); // Envia un joc de valors als tres MAX7221
void Ini3max(void); // Inicialitza els tres MAX7221
void Apaga(void); // Apaga tots els LED de la matriu LED
void EnviaL(char Caracter); // Envia un caràcter
void Esborra(void); // Esborra la pantalla i posa el cursor a l'inici
void Cursor(char Filera, char Columna); // Posiciona el cursor
// (filera 1 a 2 i columna 1 a 32, segons pantalla)
void TocaNota(char ValPR2, char ValCCPR1L, char ValDC1B); //Envia la nota musical al brunzidor
char Polsador(void); // Funció de lectura dels polsadors
void main (void)
OPTION_REG = 0b10000101; // Configuració de Timer0
// Com a temporitzador basat en rellotge
// 101 - Factor d'escala de 64
// I resistències de pull-up desactivades (valor per defecte)
TRISC = 0b00100000; // Configuració del port C
TRISB = 0; // Tot el port B és de sortida
TRISA = 0xFF; // Tot el port A és d'entrada
ANSEL = 0b00000101; // Configura AN0 i AN2 com entrada analògica
ANSELH = 0; // Desactiva les altres entrades analògiques
PORTC = 0; // Inicialitza a 0 el port C
PORTB = 0; // Inicialitza a 0 el port B
ADCON1 = 0b00010000; // Posa el conversor a 1/8 de la freqüència
ADCON0 = 0b00001001; // Activa el conversor A/D connectat a AN2
CCP1CON = 0b00001100; // Configura el PWM, bits P1M (bits 7-6) a 00 mode senzill
// amb el resultat justificat per l'esquerra
Ini3max(); // Inicialitza els tres MAX7221
Actiu = 1; // Activa el color vermell
TXSTAbits.BRGH = 1; // Configuració de velocitat
BAUDCTLbits.BRG16 = 0; // Paràmetre de velocitat de 8 bits
SPBRG = 25; // Velocitat de 9600 baud
TXSTAbits.SYNC = 0; // Comunicació asíncrona
TXSTAbits.TX9 = 0; // Comunicació de 8 bits
PIR1bits.TMR2IF = 0; // Desactiva el bit d'interrupció del Timer 2
T2CON = 0b00000011; // Configura el Timer 2
INTCON = 0b10100000; // Activem GIE i T0IE
Esborra(); // Esborra la pantalla i posa el cursor a l'inici
Apaga(); // Apaga tots els LED de la matriu LED
while (1) // Inici del bucle del programa
Esborra(); // Esborra la pantalla i posa el cursor a l'inici
Cursor(1, 1); // Posa el cursor en la posició d'inici
m=1; // Fila 1 de la pantalla LCD
c=0; // Posició 0 del cursor
a=0; // Valor 0 de la variable a
while(Polsador0=1){ // Inici del bucle el qual s'acaba quan es presiona el polador0(BTN0)
// Mirem els polsadors
// Un cop s'ha fet l'acció del polsador, no es tornarà a fer fins
// que es detecti que s'han deixat anar
if (c==16){
Cursor(2, 1);
m=2; // Si la posició es igula a 16 canviar a la segona linea de la pantalla
}
Polsad = Polsador(); // Llegim els polsadors
if (mirar == 1){ // Si es detecta que s'ha polsat un polsador
if (Polsad == 5){ // Si s'ha premut el polsador 5
if (c<16){ // Si la posició es més petita que 16
Cursor(m, c);
EnviaL(' ');
Cursor(m, c);
c=c-1; //Esborra la última lletra escrita a la primera fila de la pantalla LCD
} else if(c==16){ // Si la posició es igual a 16
Cursor(1, c);
EnviaL(' ');
Cursor(1, c);
c=c-1; //Esborra la lletra de la última posició de la primera fila de la pantalla LCD
} else {
Cursor(m, c-16); // Si la posició es més gran que 16
EnviaL(' ');
Cursor(m, c-16);
c=c-1; //Esborra la última lletra escrita a la primera segona de la pantalla LCD
}
PORTC=0b00000001; // Activa el bit 0 del port C i, per tant, encén el LED0 (RC0)
mirar=0; // Evita detectar més d'un polsador a l'hora
}
if (Polsad == 1){ // Si s'ha premut el polsador 1
codi=(codi<<1)|0; // Afegeix un 0 al final del codi (punt)
PORTC=0b00001000; // Activa el bit 3 del port C i, per tant, encén el LED (RC3)
mirar=0; // Evita detectar més d'un polsador a l'hora
}
if (Polsad == 2){ // Si s'ha premut el polsador 2
codi=(codi<<1)|1; // Afegeix un 1 al final del codi (linea)
PORTC=0b00000100; // Activa el bit 2 del port C i, per tant, encén el LED (RC2)
mirar=0; // Evita detectar més d'un polsador a l'hora
}
if (Polsad == 3){ // Si s'ha premut el polsador 3
a=c;
for (unsigned char k = 0; k <41 ; k++){ // Recorre la matriu de codi
if (codi==Matriu[k][0]){ // Si troba una coincidenicia de codis
EnviaL(Matriu[k][1]); // Envia la lletra, número o simbol corresponent
a=c+1; // Suma un a la variable a
}
}
if (a==c){ // Envia a la matriu de LEDs la creu vermella
for (unsigned char k = 0; k < 8; k++){
Sortida[1] = k+1; // Filera
Sortida[3] = k+1;
Sortida[5] = k+1;
Sortida[0] = fig1[0][k]; // Vermells
Sortida[2] = fig1[1][k]; // Verds
Sortida[4] = fig1[2][k]; // Blaus
Envia3max(Sortida); // Ho envia al MAX7221
__delay_ms(1);
}
TocaNota(238, 119, 2); // Enviar al brunzidor un do3
__delay_ms(350); // Retard de 0,35s
Apaga(); // Apaga tots els LED de la matriu LED
} else { // Envia a la matriu de LEDs el tick verd
for (unsigned char k = 0; k < 8; k++){
Sortida[1] = k+1; // Filera
Sortida[3] = k+1;
Sortida[5] = k+1;
Sortida[0] = fig2[0][k]; // Vermells
Sortida[2] = fig2[1][k]; // Verds
Sortida[4] = fig2[2][k]; // Blaus
Envia3max(Sortida); // Ho envia al MAX7221
__delay_ms(1);
}
__delay_ms(350); // Retard de 0,35s
Apaga(); // Apaga tots els LED de la matriu LED
}
c=a; // La posició es igual al valor de la variable a
codi=0b00000001; // Retorna el codi al codi original
mirar=0; // Evita detectar més d'un polsador a l'hora
}
if (Polsad == 4){ // Si s'ha premut el polsador 4
EnviaL(' '); // Envia l'espai
c=c+1; // Augmenta en 1 la posició
PORTC=0b00000010; // Activa el bit 1 del port C i, per tant, encén el LED (RC1)
mirar=0; // Evita detectar més d'un polsador a l'hora
}
} else {
if (Polsad == 0){ // Si no s'ha premut cap polsador (o dos a la vegada)
PORTC=0; // No activa cap bit del port C
mirar = 1; // Torna al inici del bucle
}
}
__delay_ms(100); // Retard de 0,1s
}
__delay_ms(100); // Retard de 0,1s
}
}
void __interrupt() temporit(void){
// void interrupt temporit(void) { // Línia alternativa
if (INTCONbits.T0IF) // Comprovem que hi ha interrupció per Timer 0
TMR0 = 100; // Preselecció de Timer0
INTCONbits.T0IF = 0; // Desactiva el bit que indica interrupció pel Timer0
if (Actiu != 0) // Si la matriu no està apagada
Actiu--; // Passem a activar un altre color
if (Actiu == 0) // Si hem arribat a zero
Actiu = 3; // Torna a posar el 3
}
}
// D'entrada els desactivem els tres
Sorti[0] = 0x00; // Vermell
Sorti[2] = 0x00; // Verd
Sorti[4] = 0x00; // Blau
if (Actiu == 1){ // Si és vermell
Sorti[0] = 0x01; // Vermell activat
}
if (Actiu == 2){ // Si és verd
Sorti[2] = 0x01; // Verd activat
}
if (Actiu == 3){ // Si és blau
Sorti[4] = 0x01; // Blau activat
}
Sorti[1] = 0x0C; // Shutdown mode
Sorti[3] = 0x0C; // Shutdown mode
Sorti[5] = 0x0C; // Shutdown mode
Envia_max(); // Ho envia al MAX7221
}
}
char Polsador(void){
char Pols = 0;
ADCON0bits.GO = 1; // Posa en marxa el conversor
while (ADCON0bits.GO == 1) // Mentre no acabi
; // Ens esperem
__delay_ms(10);
ADCON0bits.GO = 1; // Posa en marxa el conversor
while (ADCON0bits.GO == 1) // Mentre no acabi
; // Ens esperem
__delay_ms(1);
if (ADRESH < 220 && ADRESH > 200) {
Pols = 1; // Comprova polsador 1
}
if (ADRESH < 194 && ADRESH > 174) {
Pols = 2; // Comprova polsador 2
}
if (ADRESH < 163 && ADRESH > 143) {
Pols = 3; // Comprova polsador 3
}
if (ADRESH < 90 && ADRESH > 70) {
Pols = 4; // Comprova polsador 4
}
if (ADRESH < 55 && ADRESH > 35) {
Pols = 5; // Comprova polsador 5
}
return Pols;
}
void EnviaL(char Caracter) {
INTCONbits.GIE = 0; // Desactiva les interrupcions momentàniament
RCSTAbits.SPEN = 1; // Activa comunicació sèrie
TXSTAbits.TXEN = 1; // Activa comunicació
TXREG = Caracter; // Agafa el caràcter i l'envia
__delay_ms(1); // Donem temps
while (PIR1bits.TXIF == 0) // Esperem que s'acabi d'enviar
; // No fem res
RCSTAbits.SPEN = 0; // Desactiva comunicació sèrie
TXSTAbits.TXEN = 0; // Desactiva comunicació
INTCONbits.GIE = 1; // Activa les interrupcions
}
void Esborra(void) {
EnviaL(254); // Caràcter de control
EnviaL(1); // Esborra la pantalla i posa el cursor a l'inici
}
void Cursor(char Filera, char Columna) {
char Posicio = 0; // Variable per a calcular la posició
if (Filera == 2) {
Posicio = 64; // La primera columna de la segona fila és 64;
}
if (Columna > 0 && Columna < 33) { // Comprovem que sigui un valor raonable
Posicio = Posicio + Columna; // Sumem les adreces
Posicio = Posicio - 1; // Restem 1 perquè numera des de 0
}
Posicio = Posicio + 128; // Posa el bit de posicionat a 1
EnviaL(254); // Control de la posició del cursor
EnviaL(Posicio); // Canvia el cursor de lloc
}
void Envia3max(char Valor[]){ // Envia un joc de valors als tres MAX7221
INTCONbits.T0IE = 0; // Desactiva les interrupcions momentàniament
char Port = 0; // Variable on guardem l'estat del port B
char Temp; // Variable temporal
for (signed char j = 5; j >= 0; j--){ // Hem d'enviar 6 bytes
for (signed char k = 1; k < 9; k++){ // De 8 bits
Temp = Valor[j] & 0b10000000; // Agafa el bit de més a l'esquerra
// Temp només podrà valer 0 o 128
if (Temp == 0){ // Si val 0
Port = Port & 0b11101111; // Desactiva Data (bit 4)
} else { // Si val 128
Port = Port | 0b00010000; // Activa Data (bit 4)
}
Valor[j] = Valor[j] << 1; // Rodem els bits per situar el següent
PORTB = Port; // Ho posa al port B
Port = Port | 0b00100000; // Activa Clock (bit 5) i força lectura
PORTB = Port; // Ho posa al port B
Port = Port & 0b11011111; // Desactiva Clock (bit 5)
PORTB = Port; // Ho posa al port B
}
}
Port = Port | 0b01000000; // Activa Latch (bit 6) per copiar a les sortides
PORTB = Port; // Ho posa al port B
INTCONbits.T0IE = 1; // Reactiva les interrupcions a l'acabar
}
void Envia_max(void){ // Envia un joc de valors als tres MAX7221
asm("banksel _Port");
asm("bcf (_Port&7fh),5"); // S'assegura que Clock està desactivat
asm("bcf (_Port&7fh),6"); // S'assegura que Latch està desactivat
asm("movf (_Port&7fh),w"); // Agafa el valor de Port
asm("movwf PORTB"); // I el posa al port B
asm("banksel _Compta");
asm("movlw 48"); // Número de bits a enviar
asm("movwf (_Compta&7fh)"); // Variable per comptar els bits
asm("Bucle:");
asm("banksel _Port");
asm("bcf (_Port&7fh),4"); // Desactiva Data. Si toca activar-ho, ja ho farem
asm("banksel _Sorti");
asm("rlf (_Sorti&7fh),f"); // Fa sortir el bit de més a l'esquerra cap a C
asm("rlf ((_Sorti+1)&7fh),f"); // i roda els altres a l'esquerra
asm("rlf ((_Sorti+2)&7fh),f");
asm("rlf ((_Sorti+3)&7fh),f");
asm("rlf ((_Sorti+4)&7fh),f");
asm("rlf ((_Sorti+5)&7fh),f");
asm("banksel _Port");
asm("btfsc STATUS,0"); // Mira si el bit de l'esquerra era un 1
asm("bsf (_Port&7fh),4"); // Si era 1, activa Data
asm("movf (_Port&7fh),w"); // Agafa el valor de Port. El valor que ha canviat és Data
asm("movwf PORTB"); // I el posa al port B
asm("bsf (_Port&7fh),5"); // Activa Clock, forçant a llegir el bit
asm("movf (_Port&7fh),w"); // Agafa el valor de Port. El valor que ha canviat és Clock
asm("movwf PORTB"); // I el posa al port B
asm("bcf (_Port&7fh),5"); // Desactiva Clock
asm("movf (_Port&7fh),w"); // Agafa el valor de Port. El valor que ha canviat és Clock
asm("movwf PORTB"); // I el posa al port B
asm("banksel _Compta");
asm("decfsz (_Compta&7fh),f"); // Decrementa Compta
asm("goto (Bucle&7ffh)"); // Si Compta no és zero, repeteix el bucle
asm("banksel (_Port&7fh)");
asm("bsf (_Port&7fh),6"); // Torna a activar Latch
// Els valors es copiaran a la sortida del registre
asm("movf (_Port&7fh),w"); // Agafa el valor de Port. El valor que ha canviat és Latch
asm("movwf PORTB"); // I el posa al port B
}
void Ini3max(void){ // Inicialitza els tres MAX7221
char Bytes[6]; // Els sis bytes que cal enviar
Bytes[0] = 0x00; // Desactivat
Bytes[1] = 0x0C; // Shutdown mode
Bytes[2] = 0x00;
Bytes[3] = 0x0C;
Bytes[4] = 0x00;
Bytes[5] = 0x0C;
Envia3max(Bytes); // Els envia
Bytes[0] = 0x00; // No decode
Bytes[1] = 0x09; // Decode mode
Bytes[2] = 0x00;
Bytes[3] = 0x09;
Bytes[4] = 0x00;
Bytes[5] = 0x09;
Envia3max(Bytes); // Els envia
Bytes[0] = 0x07; // Vuit fileres
Bytes[1] = 0x0B; // Scan limit
Bytes[2] = 0x07;
Bytes[3] = 0x0B;
Bytes[4] = 0x07;
Bytes[5] = 0x0B;
Envia3max(Bytes); // Els envia
}
void Apaga(void){ // Apaga tots els LED
char Bytes[6]; // Els sis bytes que cal enviar
for (unsigned char j = 1; j <= 8; j++){ // Hem d'enviar 8 fileres
Bytes[1] = j; // Filera
Bytes[3] = j;
Bytes[5] = j;
Bytes[0] = 0x00; // Vermells
Bytes[2] = 0x00; // Verds
Bytes[4] = 0x00; // Blaus
Envia3max(Bytes); // Els envia
}
}
void TocaNota(char ValPR2, char ValCCPR1L, char ValDC1B){
TRISC = 0b00100000; // Definim com volem les E/S del port C
// RC5 (sortida del PWM), de moment, com a entrada
PR2 = ValPR2; // Carrega PR2
CCP1CON = CCP1CON & 0b11001111; // Posa a zero els bits que corresponen a DC1B
ValDC1B = ValDC1B % 4; // DC1B va de 0 a 3
ValDC1B = ValDC1B * 16; // Desplaça els bits a la posició que els correspon a CCP1CON
CCP1CON = CCP1CON | ValDC1B; // Coloca DC1B al seu lloc
CCPR1L = ValCCPR1L; // Carrega CCPR1L, registre que ens dona l'amplada de tON
PIR1bits.TMR2IF = 0; // Desactiva el bit d'interrupció del Timer 2
T2CON = 0b00000111; // Configura el Timer 2
// bits T2KCPS (bits 1-0) a 11 prescalat de 16
// bit 2 (TMR2ON) a 1, Timer activat
// Postscaler TOUTPS (bits 6-3) no afecten al PWM
while (PIR1bits.TMR2IF == 0) // Espera l'activació del bit d'interrupció del Timer 2
; // Esperem
TRISC = 0b00000000; // Posem RC5 (sortida del PWM) com a sortida
__delay_ms(200); // Retard de 0,2 s
TRISC = 0b00100000; // Posem RC5 (sortida del PWM) com a entrada
// O sigui, silenci
__delay_ms(200); // Retard de 0,2 s
}

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