Aquest dispositiu mostra la data i l'hora. A més, es pot configurar una alarma que, a l'hora programada, fa sonar una melodia i mostra un dibuix a la matriu de leds. També incorpora funcions de cronòmetre i temporitzador.
Per a la gestió del temps fan servir el temporitzador 0 i una interrupció.
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 clrbit(var, bit) ((var) &= ~(1 << (bit))) #define FiTimer0 INTCONbits.T0IF // Li assigna un nom al bit que indica el final del Timer 0 #define flipbit(var, bit) ((var) ^= (1<<(bit))) #define PolsadorGeneral RA3 // Li assigna un nom a l'adreça del polsador
char Cuenta;
char Primero;
char ActivaAlarma; // 0 desactivado, 1 activado, 2 listo para ejecutar alarma
char ActivaTempo; // 0 desactivado, 1 activado, 2 listo para ejecutar alarma
char ActivaCrono; // 0 desactivado, 1 activado
char Polsad; // Polsador que s'ha premut
char Polsad2;
char H[8] = {0,0,0,0,0,0}; // Vector hora
char A[8] = {0,0,0,0,0,0}; // Vector alarma
char T[8] = {0,0,0,0,0,0}; // Vector temporizador
char C[8] = {0,0,0,0,0,0}; // Vector cronometro
// Definició de les funcions que farem servir void EnviaL(char Caracter); // Envia un caràcter void Esborra(void); void EnviaVector (char V[]); void SuenaAlarma(void); void FormatoHora(char V[]); void Hora(char V[]); void CambioHora (char V[],char Valor); void TocaNota(char ValPR2, char ValCCPR1L, char ValDC1B); char VectorIgual(char V[],char U[], char Valor); char Temporizador (char V[]); char OnOff (char Boton, char Valor, char V[]); char Polsador(void); // Funció de lectura dels polsadors
void main (void) {
TRISA = 0xFF; // Tot el port A és d'entrada
TRISB = 0; // Tot el port B és de sortida
TRISC = 0b11110000; // Posa els bit 0 a 3 del port C com a sortida
PORTC = 0; // Desactiva les sortides del port C
ANSEL = 0b00000101; // Configura AN0 i AN2 com entrada analògica
ANSELH = 0; // Desactiva les altres entrades analògiques
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, mode senzill
PIR1bits.TMR2IF = 0; // Desactiva el bit d'interrupció del Timer 2
T2CON = 0b00000011; // Configura el Timer 2
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
RCSTAbits.SPEN = 1; // Activa comunicació sèrie
TXSTAbits.TXEN = 1; // Activa transmissió
OPTION_REG = 0b10000111; // Configuració de Timer0
TMR0 = 61; // Inicialitza el Timer0
INTCON = 0b00100000; // Habilitem la interrupció per Timer0
INTCONbits.GIE = 1; // Habilitem les interrupcions a nivell general
ActivaAlarma = 0;
ActivaTempo = 0;
ActivaCrono = 0;
Cuenta = 0;
FiTimer0 = 0; // Aquest bit es posarà a 1 quan el temporitzador acabi
__delay_ms(1000); // Esperem que arrenqui la pantalla
while(1){
Polsad = Polsador(); // Llegim els polsadors
Primero = 0;
// Cambio de Hora
while (Polsad==5){ // Si s'ha premut el polsador 5
RC0 = 1; // LED1
Polsad2 = Polsador();
Esborra();
if (Primero <= 3){ // Dejamos un rato para mostrar el modo
EnviaL('A');
EnviaL('D');
EnviaL('J');
Primero++;
Polsad2 = 0;
__delay_ms(500);
} else
EnviaVector(H);
__delay_ms(100);
CambioHora(H,Polsad2);
if (Polsad2 == 5)
;
else
OnOff(Polsad2,0,H);
if (PolsadorGeneral == 0){
RC0 = 0; // LED1
Esborra();
EnviaL('R');
EnviaL('T');
__delay_ms(500);
break;
}
}
// Configuración Alarma
while (Polsad==4){
RC1 = 1; // LED2
Polsad2 = Polsador();
Esborra();
if (Primero <= 3){ // Dejamos un rato para mostrar el modo
EnviaL('A');
EnviaL('L');
EnviaL('M');
Primero++;
Polsad2 = 0;
__delay_ms(500);
} else
EnviaVector(A);
__delay_ms(100);
CambioHora(A,Polsad2);
ActivaAlarma = OnOff(Polsad2, ActivaAlarma, A);
if (PolsadorGeneral == 0){
if(ActivaAlarma !=1)
RC1 = 0; // LED2
Esborra();
EnviaL('R');
EnviaL('T');
__delay_ms(500);
break;
}
}
// Configuración Temporizador
while(Polsad == 3){
RC2 = 1; // LED3
Polsad2 = Polsador();
Esborra();
if (Primero <= 3){ // Dejamos un rato para mostrar el modo
EnviaL('T');
EnviaL('M');
EnviaL('R');
Primero++;
Polsad2 = 0;
__delay_ms(500);
} else
EnviaVector(T);
__delay_ms(100);
CambioHora(T,Polsad2);
ActivaTempo = OnOff (Polsad2, ActivaTempo, T);
if (ActivaTempo == 2){
ActivaTempo = 0;
SuenaAlarma();
}
if (PolsadorGeneral == 0){
if(ActivaTempo !=1)
RC2 = 0; // LED3
Esborra();
EnviaL('R');
EnviaL('T');
__delay_ms(500);
break;
}
}
// Activa Cronometro
while(Polsad == 2){
RC3 = 1; // LED4
Polsad2 = Polsador();
Esborra();
if (Primero <= 3){ // Dejamos un rato para mostrar el modo
EnviaL('S');
EnviaL('T');
EnviaL('W');
Primero++;
Polsad2 = 0;
__delay_ms(500);
} else
EnviaVector(C);
__delay_ms(100);
ActivaCrono = OnOff (Polsad2, ActivaCrono, C);
if (PolsadorGeneral == 0){
if (ActivaCrono !=1)
RC3 = 0; // LED4
Esborra();
EnviaL('R');
EnviaL('T');
__delay_ms(500);
break;
}
}
// Reloj
Esborra();
EnviaVector(H);
__delay_ms(100);
// Temporizador y Alarma
if (ActivaTempo == 2){
ActivaTempo = 0; // Paramos el temporizador
SuenaAlarma();
}
if(ActivaAlarma == 2){
ActivaAlarma = 1; // Mantenemos la alarma encendida para las siguentes 24h
Esborra();
for (unsigned char i=0; i<5; i++){ // Dejamos que suene un rato
SuenaAlarma();
if (PolsadorGeneral == 0) // Forzamos que pare
break;
}
}
}
}
void __interrupt() reloj(void){
if(FiTimer0 == 1){ // Si ha acabat el temporitzador
Cuenta++;
// Incrementa Contador
if (Cuenta == 20){
Cuenta = 0;
H[5]++; // Sumamos 1 segundo
Hora(H); // Formato de la hora
if (ActivaCrono == 1){
C[5]++; // Sumamos 1 segundo
Hora(C); // Formato de la hora
}
if (ActivaTempo == 1)
ActivaTempo = Temporizador(T);
if(ActivaAlarma == 1)
ActivaAlarma = VectorIgual(H,A,ActivaAlarma);
}
TMR0 = 61; // Inicialitza el Timer0
FiTimer0 = 0; // Tornem a posar el bit a zero
}
}
void EnviaL(char Caracter) {
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
}
void Esborra(void) {
EnviaL(254); // Caràcter de control
EnviaL(1); // Esborra la pantalla i posa el cursor a l'inici
}
void EnviaVector(char V[]){
for (unsigned char i = 0; i<6;i++){
if (i==2 || i == 4) // Colocamos los ":"
EnviaL(':');
EnviaL(V[i]+'0'); // Convertimos a ASCII
}
}
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
}
void SuenaAlarma(void){ // Definimos melodia en una matriz
char mat[13][3] = {{213, 156, 156},{213, 78, 156},{215, 93, 186}, {239, 104, 209},
{239, 52, 209}, {215, 47, 186},{213, 78, 156}, {239, 104, 209},{215, 93, 186},
{239, 104, 209},{253, 99, 198},{239, 104, 209},{239, 69, 139}};
for (unsigned char i = 0;i<13; i++ )
TocaNota(mat[i][0],mat[i][1],mat[i][2]);
}
// {H1,H2,M1,M2,S1,S2}
void FormatoHora(char V[]){
if (V[5]>9){ // 00:00:0"10"
V[5]=0; // 00:00:00
V[4]++; // 00:00:10
}
if (V[4]>5){ // 00:00:"6"0
V[4]=0; // 00:00:00
V[3]++; // 00:01:00
}
if (V[3]>9){ // 00:0"10":00
V[3]=0; // 00:00:00
V[2]++; // 00:10:00
}
if (V[2]>5){ // 00:"6"0:00
V[2]=0; // 00:00:00
V[1]++; // 01:00:00
}
if (V[1]>9 && V[0]<2){ // 1"10":00:00
V[1]=0; // 10:00:00
V[0]++; // 20:00:00
}
if (V[1]>3 && V[0] == 2){ // 2"4":00:00
V[1] = 0; // 20:00:00
V[0] = 0; // 00:00:00
}
}
void Hora(char V[]){ // Misma función que la anterior para evitar problemas en las interrupciones
if (V[5]>9){
V[5]=0;
V[4]++;
}
if (V[4]>5){
V[4]=0;
V[3]++;
}
if (V[3]>9){
V[3]=0;
V[2]++;
}
if (V[2]>5){
V[2]=0;
V[1]++;
}
if (V[1]>9 && V[0]<2){
V[1]=0;
V[0]++;
}
if (V[1]>3 && V[0] == 2){
V[1] = 0;
V[0] = 0;
}
}
void CambioHora (char V[],char Valor){
if (Valor ==1){
V[1]++; // Sumamos 1 a las horas
FormatoHora(V);
}
if (Valor ==2){
V[3]++; // Sumamos 1 a los minutos
if(V[2] == 5 && V[3] > 9){ // Inicializamos minutos, no suma horas
V[2] = 0;
V[3] = 0;
} else
FormatoHora(V);
}
if (Valor ==3){
V[5]++; // Sumamos 1 a los segundos
if(V[4] == 5 && V[5] > 9){ // Inicializamos segundos, no suma minutos
V[5] = 0;
V[4] = 0;
} else
FormatoHora(V);
}
}
char VectorIgual (char V[],char U[], char Valor){
char n = 0;
for (unsigned char i = 0; i<6; i++){
if (V[i] == U[i])
n++; // Contamos si coinciden
}
if (n==6)
return 2;
return Valor;
}
char OnOff (char Boton, char Valor, char V[]){
Esborra();
if (Boton == 4){
for (unsigned char i=0; i<6;i++)
V[i] = 0; // Igualamos a 0 cada componente
EnviaL('R');
EnviaL('E');
EnviaL('S');
EnviaL('E');
EnviaL('T');
__delay_ms(500);
}
if (Boton == 5){
if (Valor != 1){
Valor = 1;
EnviaL('O');
EnviaL('N');
__delay_ms(500);
} else{
Valor = 0;
EnviaL('O');
EnviaL('F');
EnviaL('F');
__delay_ms(500);
}
}
return Valor;
}
char Polsador(void) {
char Pols = 0;
ADCON0bits.GO = 1; // Posa en marxa el conversor
while (ADCON0bits.GO == 1) // Mentre no acabi
; // ens esperem
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;
}
char Temporizador (char V[]){
if (V[0] == 0 && V[1] == 0 && V[2] == 0 && V[3] == 0 && V[4] == 0 && V[5] == 0){
return 2;
}
if (V[5] > 0){
V[5]--;
return 1;
}
V[5] = 9;
if(V[4] > 0){
V[4]--;
return 1;
}
V[4] = 5;
if (V[3]> 0){
V[3]--;
return 1;
}
V[3] = 9;
if (V[2] > 0){
V[2]--;
return 1;
}
V[2] = 5;
if (V[1] > 0){
V[1]--;
return 1;
}
V[1] = 9;
if (V[0] > 0){
V[0]--;
return 1;
}
return 1;
}

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