Programació en C del PIC 16F690

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

Traductor de codi Morse

Traductor de codi Morse

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
}

 

 

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