Aquest grup va fer un rellotge amb alarma que també avisa a les hores en punt. Amb els polsadors es pot posar el rellotge en hora i activar i desactivar l'alarma i els avisos. Uns caràcters especials serveixen per indicar si l'alarma i els avisos estan activats o desactivats.
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 #define FiTimer1 PIR1bits.TMR1IF // Li assigna un nom al bit que indica el final del Timer 1 #define _XTAL_FREQ 4000000 // La freqüència del rellotge és 4 MHz #include <stdio.h>
unsigned char Compta;// Variable de 8 bits sense signe (0 a 255)
char Valor=0;
char h1 = '1', h2 = '3', min1 = '0', min2 = '0', sec1 = '0', sec2 = '0', dia1 = '1', dia2 = '9';
char mes1 = '1', mes2 = '2', any1 = '2', any2 = '0', any3 = '2', any4 = '3'; // Variables temps
int i = 1, mes = 12, any = 2023;
char dia[7][3]={ {'L', 'U', 'N'},
{'M', 'A', 'R'},
{'M', 'I', 'E'},
{'J', 'U', 'E'},
{'V', 'I', 'E'},
{'S', 'A', 'B'},
{'D', 'O', 'M'} };
char Polsad = 0; // Polsador que s'ha premut
char Edicio = 0, Edicioalarm = 0, alarma = 0;
char dhms = 1, mute = 0, alarmah1 = '1', alarmah2 = '2', alarmamin1 = '5', alarmamin2 = '6', alarmon = 0;
char campana[8] = {0b00000000, 0b00000100, 0b00001110, 0b00010001,
0b00010001, 0b00011111, 0b00000100, 0b00000000};
char nocampana[8] = {0b00000000, 0b00000100, 0b00001110, 0b00010001,
0b00010001, 0b00011111, 0b00000000, 0b00000000};
char nota[8] = {0b00000000, 0b00000110, 0b00000100, 0b00000100,
0b00001100, 0b00001100, 0b00000000, 0b00000000};
char nonota[8] = {0b00000000, 0b00010110, 0b00001100, 0b00000100,
0b00001110, 0b00001101, 0b00000000, 0b00000000};
// Definició de les funcions que farem servir char Polsador(void); // Funció de lectura dels polsadors 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 void DisplayTime(void); void DisplayAlarm(void); void TocaNota(char ValPR2, char ValCCPR1L, char ValDC1B); void Calculardata(void); void DefCarac(char Numero, char Fileres[8]); // Crea un caràcter definit per l'usuari
void main (void) {
__delay_ms(3000); // Esperem que arrenqui la pantalla
Compta = 0; // Compta el nombre de cops que ha acabat el Timer
// Configuració d'entrades i sortides
TRISC = 0b11111110; // Posa el bit 0 del port C com a sortida
PORTC = 0; // Desactiva les sortides del port C
CCP1CON = 0b00001100; // Configura el PWM, bits P1M (bits 7-6) a 00 mode senzill
FiTimer1 = 0; // Aquest bit es posarà a 1 quan el temporitzador acabi
// cal desactivar-lo des del programa
ANSELH = 0; // Desactiva les altres entrades analògiques
TRISB = 0; // Tot el port B és de sortida
TRISA = 0xFF; // Tot el port A és d'entrada
TMR1H = 231; // Inicialitza el Timer1
TMR1L = 150;
T1CON = 0b00110001; // Configuració de Timer1
// 11 - Factor d'escala de 8
// I el posem en marxa
PIR1bits.TMR2IF = 0; // Desactiva el bit d'interrupció del Timer 2
T2CON = 0b00000011; // Configura el Timer 2
ADCON1 = 0b00010000; // Posa el conversor a 1/8 de la freqüència
ADCON0 = 0b00001001; // Activa el conversor A/D connectat a AN2
PIE1bits.TMR1IE = 1;
INTCONbits.PEIE = 1;
INTCONbits.GIE = 1; // Habilitem les interrupcions a nivell general
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 comunicació
Esborra(); // Esborra la pantalla i posa el cursor a l'inici
DefCarac(0, campana); // Defineix caràcter
DefCarac(1, nota); // Defineix caràcter
DefCarac(2, nonota); // Defineix caràcter
DefCarac(3, nocampana); // Defineix caràcter
while (1){ // Inici del bucle de programa
EnviaL(254);
EnviaL(12);
while(Polsad !=0){
Polsad = Polsador();
} // Mentre el contingut del parèntesi sigui 1
Polsad = Polsador();
if (Polsad == 2){
Edicio = 1;
dhms=1;
}
while (Edicio == 1){
while(Polsad !=0){
Polsad = Polsador();
}
EnviaL(254);
EnviaL(13);
Polsad = Polsador();
if (Polsad == 2){
Edicio = 0;
}
if (Polsad == 3 && dhms != 4){
dhms++;
}
if (Polsad == 3 && dhms == 4){
dhms=1;
}
if (Polsad == 5 && dhms == 1){
h2++;
if (h2 == ':' && h1!='2'){
h2='0';
h1++;
}
if (h2 == '4' && h1 == '2'){
h2='0';
h1='0';
}
}
if (Polsad == 5 && dhms == 2){
min2++;
if (min2 == ':' && min1 != '5'){
min1++;
min2='0';
}
if (min2 == ':' && min1 == '5'){
min2='0';
min1='0';
}
}
if (Polsad == 5 && dhms == 3){
i++;
if (i > 6) {
i=0;
}
if (dia2 != '9' && dia1 != '3' && mes != 2){
dia2++;
} else if (dia2 != '8' && dia1 == '2' && mes == 2){
dia2++;
} else if ((dia2 == '8' && dia1 == '2' && mes == 2 && (any%4 != 0 || (any%4 == 0 && any%100 == 0 && any%400 != 0))) || (dia2 == '9' && dia1 == '2' && mes == 2)){
dia1 = '0';
dia2 = '1';
} else if (dia2 == '8' && dia1 == '2' && mes == 2 && any%4 == 0 && ((any%100 == 0 && any%400 == 0) || any%100 != 0)){
dia2++;
} else if (dia2 == '9' && dia1 != '3'){
dia2='0';
dia1++;
} else if (dia1 == '3' && dia2 == '0' && (mes==4 || mes==6 || mes==9 || mes==11)){
dia2='1';
dia1='0';
} else if (dia1 == '3' && dia2 == '0' && (mes==1 || mes==3 || mes==5 || mes==7 || mes==8 || mes==10 || mes==12)){
dia2++;
} else if (dia1 == '3' && dia2 == '1' && (mes==1 || mes==3 || mes==5 || mes==7 || mes==8 || mes==10 || mes==12)){
dia2='1';
dia1='0';
}
}
if (Polsad == 4 && dhms == 1){
h2--;
if (h2 == '/' && h1!='0'){
h2='9';
h1--;
}
if (h2 == '/' && h1 == '0'){
h2='3';
h1='2';
}
}
if (Polsad == 4 && dhms == 2){
min2--;
if (min2 == '/' && min1 != '0'){
min1--;
min2='9';
}
if (min2 == '/' && min1 == '0'){
min2='9';
min1='5';
}
}
if (Polsad == 4 && dhms == 3){
if (i != 0){
i--;
} else {
i=6;
}
dia2--;
if (dia2 == '/' && dia1!='0'){
dia2='9';
dia1--;
}
if (dia2 == '/' && dia1 == '0'){
if (mes==4 || mes==6 || mes==9 || mes==11){
dia1 = '3';
dia2 = '0';
} else if (mes==1 || mes==3 || mes==5 || mes==7 || mes==8 || mes==10 || mes==12){
dia1 = '3';
dia2 = '1';
} else if (mes==2 && any%4 == 0 && ((any%100 == 0 && any%400 == 0) || any%100 != 0)){
dia1 = '2';
dia2 = '9';
} else if ((mes == 2 && (any%4 != 0 || (any%4 == 0 && any%100 == 0 && any%400 != 0))) || (dia2 == '9' && dia1 == '2' && mes == 2)){
dia1 = '2';
dia2 = '8';
}
}
}
DisplayTime();
if (dhms == 1){
Cursor(1,1);
}
if (dhms == 2){
Cursor(1,4);
}
if (dhms == 3){
Cursor(2,1);
}
}
if (Polsad == 1){
Edicioalarm = 1;
dhms=1;
Esborra();
}
while (Edicioalarm == 1){
while(Polsad !=0){
Polsad = Polsador();
}
EnviaL(254);
EnviaL(13);
Polsad = Polsador();
if (Polsad == 3 && dhms != 3){
dhms++;
}
if (Polsad == 3 && dhms == 3){
dhms=1;
}
if (Polsad == 5 && dhms == 1){
alarmah2++;
if (alarmah2 == ':' && alarmah1!='2'){
alarmah2='0';
alarmah1++;
}
if (alarmah2 == '4' && alarmah1 == '2'){
alarmah2='0';
alarmah1='0';
}
}
if (Polsad == 5 && dhms == 2){
alarmamin2++;
if (alarmamin2 == ':' && alarmamin1 != '5'){
alarmamin1++;
alarmamin2='0';
}
if (alarmamin2 == ':' && alarmamin1 == '5'){
alarmamin2='0';
alarmamin1='0';
}
}
if (Polsad == 4 && dhms == 1){
alarmah2--;
if (alarmah2 == '/' && alarmah1!='0'){
alarmah2='9';
alarmah1--;
}
if (alarmah2 == '/' && alarmah1 == '0'){
alarmah2='3';
alarmah1='2';
}
}
if (Polsad == 4 && dhms == 2){
alarmamin2--;
if (alarmamin2 == '/' && alarmamin1 != '0'){
alarmamin1--;
alarmamin2='9';
}
if (alarmamin2 == '/' && alarmamin1 == '0'){
alarmamin2='9';
alarmamin1='5';
}
}
DisplayAlarm();
if (dhms == 1){
Cursor(1,6);
}
if (dhms == 2){
Cursor(1,9);
}
if (Polsad == 1){
Edicioalarm = 0;
Esborra();
}
}
if (mute == 0){
Cursor(1, 15);
EnviaL(1);
} else if (mute == 1){
Cursor(1, 15);
EnviaL(2);
}
if (alarmon == 0){
Cursor(1, 16);
EnviaL(3);
} else if (alarmon == 1){
Cursor(1, 16);
EnviaL(0);
}
DisplayTime();
Cursor(1,1);
if (alarmon == 1 && min1 == alarmamin1 && min2 == alarmamin2 && h1 == alarmah1 && h2 == alarmah2 && sec1 == '0' && sec2 == '0'){
alarma = 1;
Esborra();
}
while(alarma == 1){
Polsad = Polsador();
DisplayAlarm();
if (Polsad == 1){
alarma = 0;
Esborra();
}
TocaNota(189, 95, 0);
}
if (Polsad == 4 && mute == 0){
mute=1;
} else if (Polsad == 4 && mute == 1){
mute=0;
}
if (mute == 0 && min1 == '0' && min2 == '0' && sec1 == '0' && sec2 == '0'){
TocaNota(189, 95, 0); // Valor que correspon aproximadament a mi3
__delay_ms(600);
}
if (Polsad == 5 && alarmon == 0){
alarmon=1;
} else if (Polsad == 5 && alarmon == 1){
alarmon=0;
}
}
}
void __interrupt() temporit(void){ // Línia alternativa
if (FiTimer1){ // Comprovem que hi ha interrupció per Timer 1
T1CONbits.TMR1ON = 0; // Atura momentàniament el Timer1
TMR1H = 231; // Inicialitza el Timer1
TMR1L = 150;
T1CONbits.TMR1ON = 1; // Torna a engegar el Timer1
Compta++; // Incrementa Compta
FiTimer1 = 0; // Tornem a posar el bit a zero
if (Compta == 20) { // Si ha acabat vint vegades
if (sec2 != '9'){
sec2++;
Compta = 0; // Reinicialitza Compta
} else if (sec1 != '5'){
sec1++;
sec2 = '0';
Compta = 0; // Reinicialitza Compta
} else if (min2 != '9'){
sec1 = '0';
sec2 = '0';
min2++;
Compta = 0;
} else if (min1 != '5'){
sec1 = '0';
sec2 = '0';
min2 = '0';
min1++;
Compta = 0;
} else if (h2 != '9' && h1 != '2'){
sec1 = '0';
sec2 = '0';
min1 = '0';
min2 = '0';
h2++;
Compta = 0;
} else if (h2 == '9' && h1 != '2') {
sec1 = '0';
sec2 = '0';
min1 = '0';
min2 = '0';
h2 = '0';
h1++;
Compta = 0;
} else {
sec1 = '0';
sec2 = '0';
min1 = '0';
min2 = '0';
h2 = '0';
h1 = '0';
i++;
if (i > 6) {
i=0;
}
Compta = 0;
Calculardata();
}
}
}
}
void DisplayTime(void){
Cursor(1, 1); // Posició
EnviaL(h1);
EnviaL(h2);
EnviaL('.');
EnviaL(min1);
EnviaL(min2);
EnviaL('.');
EnviaL(sec1);
EnviaL(sec2);
Cursor(2, 1);
EnviaL(dia[i][0]);
EnviaL(dia[i][1]);
EnviaL(dia[i][2]);
Cursor(2, 7);
EnviaL(dia1);
EnviaL(dia2);
EnviaL('/');
EnviaL(mes1);
EnviaL(mes2);
EnviaL('/');
EnviaL(any1);
EnviaL(any2);
EnviaL(any3);
EnviaL(any4);
}
void DisplayAlarm(void){
Cursor(1, 6); // Posició
EnviaL(alarmah1);
EnviaL(alarmah2);
EnviaL(':');
EnviaL(alarmamin1);
EnviaL(alarmamin2);
}
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 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
}
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
}
PORTC = Pols;
__delay_ms(10);
return Pols;
}
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 DefCarac(char Numero, char Fileres[8]) {
char Posicio = 0; // Variable per a calcular la posició
if (Numero < 8) { // Comprovem que sigui un valor raonable
Posicio = Numero * 8; // Calculem l'adreça de memòria
}
Posicio = Posicio + 64; // Posa el bit de caràcter especial a 1
EnviaL(254); // Control de la posició del cursor
EnviaL(Posicio); // Canvia el cursor de lloc
for (signed char k = 0; k < 8; k++){
EnviaL(Fileres[k]); // Canvia el cursor de lloc
}
}
void Calculardata(void){
if (dia2 != '9' && dia1 != '3' && mes != 2){
dia2++;
} else if (dia2 != '9' && dia1 != '2' && mes == 2){
dia2++;
} else if (dia2 != '8' && dia1 == '2' && mes == 2){
dia2++;
} else if ((dia2 == '8' && dia1 == '2' && mes == 2 && (any%4 != 0 || (any%4 == 0 && any%100 == 0 && any%400 != 0))) || (dia2 == '9' && dia1 == '2' && mes == 2)){
mes++;
mes2++;
dia1 = '0';
dia2 = '1';
} else if (dia2 == '8' && dia1 == '2' && mes == 2 && any%4 == 0 && ((any%100 == 0 && any%400 == 0) || any%100 != 0)){
dia2++;
} else if (dia2 == '9' && dia1 != '3'){
dia2='0';
dia1++;
} else if (dia1 == '3' && dia2 == '0' && (mes==4 || mes==6 || mes==9 || mes==11)){
dia2='0';
dia1='0';
mes++;
if(mes==10){
mes1++;
mes2='0';
} else {
mes2++;
}
} else if (dia1 == '3' && dia2 == '0' && (mes==1 || mes==3 || mes==5 || mes==7 || mes==8 || mes==10 || mes==12)){
dia2++;
} else if (dia1 == '3' && dia2 == '1' && (mes==1 || mes==3 || mes==5 || mes==7 || mes==8 || mes==10 || mes==12)){
mes++;
dia1='0';
if(mes==13){
mes=1;
mes1='0';
mes2='1';
any++;
if(any4 != '9'){
any4++;
} else {
any4='0';
if (any3!='9'){
any3++;
} else {
any3='0';
if (any2 != '9'){
any2++;
} else {
any2='0';
if (any1 != '9'){
any1++;
} else {
any1='2';
}
}
}
}
} else {
mes2++;
}
}
}

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