En aquest cas és un rellotge amb alarma. S'han preparat els polsadors per poder modificar la data i l'hora quan sigui necessari així com l'hora de l'alarma i si està activada o no.
Aquest grup no va implementar interrupcions per a la gestió del temps i, per tant, és probable que el rellotge tingui un endarreriment a mesura que passa el temps.
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 FiTimer0 INTCONbits.T0IF #define Selector RA3 #define clrbit(var, bit) ((var) &= ~(1 << (bit))) #define flipbit(var, bit) ((var) ^= (1<<(bit)))
// Definició de les variables que farem servir
unsigned char Compta;
unsigned char SU;
unsigned char SD;
unsigned char MU;
unsigned char MD;
unsigned char HU;
unsigned char HD;
char Polsad;
unsigned char Cur;
unsigned char HHU;
unsigned char HHD;
unsigned char Mode;
unsigned char Data;
unsigned char Y4;
unsigned char Y3;
unsigned char Y2;
unsigned char Y1;
unsigned char M2;
unsigned char M1;
unsigned char D2;
unsigned char D1;
unsigned char AMU;
unsigned char AMD;
unsigned char AHU;
unsigned char AHD;
unsigned char T1;
unsigned char T2;
unsigned char T3;
unsigned char T4;
unsigned char Alm_ON;
char Q_Menu;
char Dia_Setmana;
char Dies_Mes[]={31,28,31,30,31,30,31,31,30,31,30,31};
char Setmana[]="SATSUNMONTUEWEDTHUFRI";
char Smes[]="GENFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
char Mes;
char Dia;
char Ret;
int J_Dia;
int Any;
char port;
char controla;
int bucles;
int silenci;
char Sona;
// Definició de les funcions que farem servir 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 Escriu_Temps(char HD, char HU, char MD, char MU, char SD, char SU); void Rellotge(void); void Escriu_Menu(void); void Menu(void); char Polsador(void); void Escriu_Canvi_Mode(void); void Canvi_Mode(void); void Escriu_Canvi_Hora(char HD, char HU, char MD, char MU); void Canvi_Hora(void); void Canvi_Data(void); void Menu_Canvi_Data(void); void Escriu_Data(char D1, char D2, char Mes, char Y1, char Y2, char Y3, char Y4, char Dia_Setmana); char Zeller(char zdia, char zmes,int zany); int Juliano(int Any, char Mes, char J_Dia); char Es_Bisiest(int Any); void Juliano_a_Data(int Juliano); void Pols_Funcio(char x, char p1, char p2, char p3, char p4, char c1, char c2, char c3, char c4); void TocaNota(char valPre, char valPos, char valPR2, int numbuc, int numsil);
void main (void) {
SU = 0;
SD = 0;
MU = 0;
MD = 2;
HU = 3;
HD = 1;
Cur = 0;
Mode = 0;
Data = 0;
Q_Menu = 0;
Sona = 0;
Alm_ON = 0;
D1 = 1;
D2 = 9;
M1 = 1;
M2 = 2;
Y1 = 2;
Y2 = 0;
Y3 = 2;
Y4 = 3;
AMU = 0;
AMD = 0;
AHU = 0;
AHD = 0;
Any = Y1*1000+Y2*100+Y3*10+Y4;
Mes = M1*10+M2;
Dia= D1*10+D2;
J_Dia = Juliano(Any, Mes, Dia);
Dia_Setmana = Zeller(Dia, Mes, Any);
ANSEL = 0b00000101; // Configura AN0 i AN2 com entrada analògica
ANSELH = 0; // Desactiva les altres entrades analògiques
TRISC = 0; // Tot el port C és de sortida
TRISB = 0; // Tot el port B és de sortida
__delay_ms(2000); // Esperem que arrenqui la pantalla
ADCON1 = 0b00010000; // Posa el conversor a 1/8 de la freqüència
ADCON0 = 0b00001001;
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ó
FiTimer0 = 0; // Aquest bit es posarà a 1 quan el temporitzador acabi
OPTION_REG = 0b10000111; // Configuració de Timer0
TMR0 = 58;
Compta = 0;
while (1){
if (Selector == 0){
while (Selector==0)
;
__delay_ms(10);
if (Sona == 1){
Alm_ON = 0;
Sona = 0;
TRISC = 0b00100000;
} else {
Menu();
}
}
if (FiTimer0 == 1) { // Si ha acabat el temporitzador
Rellotge();
Escriu_Data(D1, D2, Mes, Y1, Y2, Y3, Y4, Dia_Setmana);
}
if (PIR1bits.TMR2IF) { // Comprovem que hi ha interrupció per Timer2
PIR1bits.TMR2IF = 0; // Desactiva el bit que indica interrupció pel Timer2
if (controla == 0){ // Si estem tocant una nota
flipbit(port, 5); // Inverteix la sortida del brunzidor
PORTC = port; // Ho copia al port C
}
bucles--; // Comptador per a la durada de la nota
if (bucles == 0){ // Si és zero, ja ha passat la durada de la nota
if ((controla == 1) || (silenci == 0)){ // Si s'acaba el silenci
T2CONbits.TMR2ON = 0; // Desactiva el Timer2
PIE1bits.TMR2IE = 0; // Desactiva les interrupcions per Timer2
}
if (controla == 0){ // Si estem tocant una nota
clrbit(port, 5); // A l'acabar, deixa la sortida desactivada
PORTC = port; // Ho copia al port C
if (silenci > 0){ // Si es preveu silenci
bucles = silenci; // Agafem la durada del silenci
controla = 1; // Toca silenci
}
}
}
}
}
}
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
}
void Rellotge(void){
TMR0 = 58;
FiTimer0 = 0;
Compta++;
if (Compta == 20) {
Compta = 0;
SU++;
if (SU == 10) {
SU = 0;
SD++;
}
if (SD == 6) {
SD = 0;
MU++;
}
if (MU == 10) {
MU = 0;
MD++;
}
if (MD == 6) {
MD = 0;
HU++;
}
if (HU == 10) {
HU = 0;
HD++;
}
if (HD == 2 && HU == 4) {
HD = 0;
HU = 0;
J_Dia++;
if (J_Dia>365 && Es_Bisiest(Any)==0){
J_Dia = 1;
Y4++;
if (Y4>9){
Y4 = 0;
Y3++;
}
if (Y3>9){
Y3 = 0;
Y2++;
}
Any++;
}
if (J_Dia>366){
J_Dia = 1;
Y4++;
if (Y4>9){
Y4 = 0;
Y3++;
}
if (Y3>9){
Y3 = 0;
Y2++;
}
Any++;
}
Juliano_a_Data(J_Dia);
Dia_Setmana = Zeller(Dia, Mes, Any);
}
if (Data == 0 && (Q_Menu == 0 || Q_Menu == 2)){
Escriu_Temps(HD, HU, MD, MU, SD, SU);
}
if (AHD == HD && AHU == HU && AMD == MD && AMU == MU && Alm_ON==1){
Sona = 1;
TRISC = 0b00000000;
TocaNota(0, 5, 253, 132, 132); // Valor que correspon aproximadament a mi3
}
return;
}
}
void Escriu_Temps(char HD, char HU, char MD, char MU, char SD, char SU) {
Esborra();
EnviaL(254);
EnviaL(12);
if (Mode == 0){
Cursor(1, 5);
EnviaL((char) 48 + HD);
EnviaL((char) 48 + HU);
EnviaL((char) 58);
EnviaL((char) 48 + MD);
EnviaL((char) 48 + MU);
EnviaL((char) 58);
EnviaL((char) 48 + SD);
EnviaL((char) 48 + SU);
} else {
if (HD*10 + HU < 13){
HHD = HD;
HHU = HU;
}
if (HD*10 + HU > 12){
HHD = 0;
HHU = HU - 2;
}
if (HD*10 + HU == 20 || HD*10 + HU == 21){
HHD = 0;
HHU = HU + 8;
}
if (HD*10 + HU > 21){
HHD = 1;
HHU = HU - 2;
}
if (HD == 0 && HU == 0){
HHD = 1;
HHU = 2;
}
Cursor(1, 5);
EnviaL((char) 48 + HHD);
EnviaL((char) 48 + HHU);
EnviaL((char) 58);
EnviaL((char) 48 + MD);
EnviaL((char) 48 + MU);
EnviaL((char) 58);
EnviaL((char) 48 + SD);
EnviaL((char) 48 + SU);
if (HD*10 + HU < 12){
Cursor(1, 14);
EnviaL('A');
EnviaL('M');
} else {
Cursor(1, 14);
EnviaL('P');
EnviaL('M');
}
}
if (Alm_ON==1){
Cursor(1, 1);
EnviaL('A');
}
}
void Escriu_Menu(){
EnviaL('M');
EnviaL('O');
EnviaL('D');
EnviaL(' ');
EnviaL('H');
EnviaL('O');
EnviaL('R');
EnviaL(' ');
EnviaL('A');
EnviaL('L');
EnviaL('M');
EnviaL(' ');
EnviaL('D');
EnviaL('A');
EnviaL('T');
EnviaL(254);
EnviaL(14);
return;
}
void Menu(void){
Cur = 0;
Cursor(2, 2);
Escriu_Menu();
while(1){
Polsad = Polsador();
Pols_Funcio(2, 1, 1, 1, 1, 2, 6, 10, 14);
if (FiTimer0 == 1) { // Si ha acabat el temporitzador
Rellotge();
Cursor(2, 2);
Escriu_Menu();
Cursor(2, 2+4*Cur);
}
if (Selector == 0){
while(Selector==0)
;
__delay_ms(10);
switch (Cur){
case 0:
Canvi_Mode();
break;
case 1:
Q_Menu = 1;
Canvi_Hora();
break;
case 2:
Q_Menu = 3;
Canvi_Hora();
break;
case 3:
Q_Menu = 2;
Canvi_Data();
break;
}
}
if (Ret==1){
return;
}
}
}
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;
}
void Escriu_Canvi_Mode(){
EnviaL('H');
EnviaL('2');
EnviaL('4');
Cursor(2, 5);
EnviaL('A');
EnviaL(':');
EnviaL('O');
EnviaL('N');
EnviaL('/');
EnviaL('O');
EnviaL('F');
EnviaL('F');
Cursor(2,14);
EnviaL('H');
EnviaL('1');
EnviaL('2');
EnviaL(254);
EnviaL(14);
return;
}
void Canvi_Mode(void){
Cur=0;
Cursor(2, 1);
Escriu_Canvi_Mode();
while(1){
Polsad = Polsador();
Pols_Funcio(2, 1, 1, 1, 0, 2, 14, 0, 0);
if (FiTimer0 == 1) { // Si ha acabat el temporitzador
Rellotge();
Cursor(2, 1);
Escriu_Canvi_Mode();
if (Cur != 2){
Cursor(2, 1+4*Cur);
} else {
Cursor(2, 14);
}
}
if (Selector == 0){
while(Selector==0)
;
__delay_ms(10);
switch (Cur){
case 0:
Mode=0;
break;
case 1:
if (Alm_ON==1){
Alm_ON=0;
} else {
Alm_ON=1;
}
break;
case 2:
Mode=1;
break;
}
}
if (Ret==1){
return;
}
}
}
void Escriu_Canvi_Hora(char HD, char HU, char MD, char MU) {
Esborra();
Cursor(1, 6);
EnviaL((char) 48 + HD);
EnviaL((char) 48 + HU);
if (Data == 0){
EnviaL((char) 58);
EnviaL((char) 58);
} else if (Data == 1){
EnviaL((char) 47);
EnviaL((char) 47);
} else {
EnviaL((char) 32);
EnviaL((char) 32);
}
EnviaL((char) 48 + MD);
EnviaL((char) 48 + MU);
}
void Canvi_Hora(void){
if (Data == 1) {
Escriu_Canvi_Hora(M1, M2, D1, D2);
} else if (Data == 2) {
Escriu_Canvi_Hora(Y1, Y2, Y3, Y4);
} else {
Escriu_Canvi_Hora(HD, HU, MD, MU);
}
Cur = 0;
Cursor(1, 6);
EnviaL(254);
EnviaL(14);
T1=HD;
T2=HU;
T3=MD;
T4=MU;
while (1){
Polsad = Polsador();
Pols_Funcio(1, 1, 1, 1, 1, 6, 7, 10, 11);
if (FiTimer0==1){
if (Data != 0){
Rellotge();
}
}
if (Selector==0){
while(Selector==0)
;
__delay_ms(10);
if (Data == 0){
switch (Cur){
case 0:
T1++;
if (T1>2){
T1=0;
}
Escriu_Canvi_Hora(T1, T2, T3, T4);
Cursor(1, 6);
break;
case 1:
T2++;
if (T1==2 && T2>3){
T2=0;
}
if (T1<2 && T2>9){
T2=0;
}
Escriu_Canvi_Hora(T1, T2, T3, T4);
Cursor(1, 7);
break;
case 2:
T3++;
if (T3>5){
T3=0;
}
Escriu_Canvi_Hora(T1, T2, T3, T4);
Cursor(1, 10);
break;
case 3:
T4++;
if (T4>9){
T4=0;
}
Escriu_Canvi_Hora(T1, T2, T3, T4);
Cursor(1, 11);
break;
}
} else if (Data == 1){
switch (Cur){
case 0:
M1++;
if (M1>1){
M1=0;
}
Escriu_Canvi_Hora(M1, M2, D1, D2);
Cursor(1, 6);
break;
case 1:
M2++;
if (M1==1 && M2>2){
M2=0;
}
if (M1<1 && M2>9){
M2=1;
}
Escriu_Canvi_Hora(M1, M2, D1, D2);
Cursor(1, 7);
break;
case 2:
D1++;
if (D1>2 && M1*10+M2==2){
D1=0;
}
if (D1>3){
D1=0;
}
Escriu_Canvi_Hora(M1, M2, D1, D2);
Cursor(1, 10);
break;
case 3:
D2++;
if (D1<3 && D2>9){
D2=0;
}
if (D1==3){
if (Dies_Mes[Mes]==30){
D2=0;
} else {
if (D2>1){
D2=0;
}
}
}
Escriu_Canvi_Hora(M1, M2, D1, D2);
Cursor(1, 11);
break;
}
} else {
switch (Cur){
case 1:
Y2++;
if (Y2>9){
Y2=0;
}
Escriu_Canvi_Hora(Y1, Y2, Y3, Y4);
Cursor(1, 7);
break;
case 2:
Y3++;
if (Y3>9){
Y3=0;
}
Escriu_Canvi_Hora(Y1, Y2, Y3, Y4);
Cursor(1, 10);
break;
case 3:
Y4++;
if (Y4>9){
Y4=0;
}
Escriu_Canvi_Hora(Y1, Y2, Y3, Y4);
Cursor(1, 11);
break;
}
}
}
if (Ret==1){
Dia = D1*10+D2;
Mes = M1*10+M2;
Any = Y1*1000+Y2*100+Y3*10+Y4;
Dia_Setmana = Zeller(Dia, Mes, Any);
Escriu_Canvi_Hora(M1, M2, D1, D2);
Cursor(1, 11);
return;
}
}
}
void Menu_Canvi_Data(){
EnviaL('M');
EnviaL('O');
EnviaL('N');
EnviaL('T');
EnviaL('H');
EnviaL((char) 47);
EnviaL('D');
EnviaL('A');
EnviaL('Y');
Cursor(2, 12);
EnviaL('Y');
EnviaL('E');
EnviaL('A');
EnviaL('R');
EnviaL(254);
EnviaL(14);
return;
}
void Canvi_Data(void){
Cursor(2, 1);
Cur = 0;
Menu_Canvi_Data();
while(1) {
Polsad = Polsador();
Pols_Funcio(2, 1, 1, 0, 0, 1, 13, 0, 0);
if (FiTimer0==1){
Rellotge();
Cursor(2, 1);
Menu_Canvi_Data();
Cursor(2, 11*Cur+1);
}
if (Selector==0){
while(Selector==0)
;
__delay_ms(10);
switch (Cur){
case 0:
Data=1;
Canvi_Hora();
break;
case 1:
Data=2;
Canvi_Hora();
break;
}
}
if (Ret==1){
return;
}
}
}
void Escriu_Data(char D1, char D2, char Mes, char Y1, char Y2, char Y3, char Y4, char Dia_Setmana) {
Cursor(2, 1);
EnviaL(Setmana[Dia_Setmana*3]);
EnviaL(Setmana[Dia_Setmana*3+1]);
EnviaL(Setmana[Dia_Setmana*3+2]);
EnviaL((char) 44);
EnviaL((char) 32);
EnviaL((char) 48 + D1);
EnviaL((char) 48 + D2);
EnviaL((char) 32);
EnviaL(Smes[(Mes-1)*3]);
EnviaL(Smes[(Mes-1)*3+1]);
EnviaL(Smes[(Mes-1)*3+2]);
EnviaL((char) 32);
EnviaL((char) 48 + Y1);
EnviaL((char) 48 + Y2);
EnviaL((char) 48 + Y3);
EnviaL((char) 48 + Y4);
}
char Zeller(char zdia, char zmes, int zany){
// Determina dia de la setmana a partir del dia, del mes i de l'any
int h;
char K;
char J;
// Tenim en compte el cas de gener i febrer
if (zmes == 1) {
zmes = 13;
zany--;
}
if (zmes == 2) {
zmes = 14;
zany--;
}
// Calculem K y J.
K = zany % 100;
J = zany / 100;
h = zdia + 13 * (zmes + 1) / 5 + K + K / 4 + J/4 + 5 * J;
h = h % 7;
return h;
}
char Es_Bisiest(int Any){ // Determina si un any és bisiest
if ((Any % 4 == 0 && Any % 100 != 0) || (Any % 400 == 0)){
return 1;
} else {
return 0;
}
}
int Juliano (int Any, char Mes, char Dia){
// Transforma el dia, el mes i l'any a la nostra adaptació del concepte de dia Juliano
int Dia_Juliano=0;
for (char j=0;j<Mes-1;j++){
Dia_Juliano = Dia_Juliano + Dies_Mes[j];
}
if (Mes>2 && Es_Bisiest(Any)==1){
Dia_Juliano++;
}
Dia_Juliano = Dia_Juliano + Dia;
return Dia_Juliano;
}
void Juliano_a_Data(int Juliano){
// Transforma la nostra adaptació del concepte de dia Juliano en data: en dia, mes i any
char g;
int suma;
char j;
suma=0;
j = 0;
g = Es_Bisiest(Any);
while(Juliano>=suma){
j++;
suma=suma+Dies_Mes[j];
if(g==1 && j>2){
suma++;
}
}
if (Juliano == 60 && g==1){
j--;
suma = suma - 28;
}
Mes = j;
M1 = Mes/10;
M2 = Mes-M1*10;
j = Juliano -(suma - Dies_Mes[Mes]);
if(j<10){
D1=0;
D2=j;
} else {
D1=j/10;
D2=j-D1*10;
}
Dia = D1*10+D2;
}
void Pols_Funcio(char x, char p1, char p2, char p3, char p4, char c1, char c2, char c3, char c4){
// Funció que determina quin polsador està actiu i en quina posició col:loca el cursor
Ret = 0;
if (Polsad == 1 && p1==1) {
Cursor(x, c1);
Cur=0;
}
if (Polsad == 2 && p2==1) {
Cursor(x, c2);
Cur=1;
}
if (Polsad == 3 && p3==1) {
Cursor(x, c3);
Cur=2;
}
if (Polsad == 4 && p4==1) {
Cursor(x, c4);
Cur=3;
}
if (Polsad == 5) {
if (Q_Menu == 3){
AHD=T1;
AHU=T2;
AMD=T3;
AMU=T4;
}
if (Q_Menu == 1){
HD=T1;
HU=T2;
MD=T3;
MU=T4;
SD=0;
SU=0;
}
if (Q_Menu == 2){
Dia_Setmana = Zeller(Dia, Mes, Any);
J_Dia = Juliano (Any, Mes, Dia);
}
Q_Menu = 0;
Data = 0;
Ret = 1;
EnviaL(254);
EnviaL(12);
Escriu_Temps(HD, HU, MD, MU, SD, SU);
return;
}
}
void TocaNota(char valPre, char valPos, char valPR2, int numbuc, int numsil) { // Funció per tocar una nota
while(T2CONbits.TMR2ON) // Si està tocant una nota
; // Esperem que acabi
valPos &= 0b00001111; // Per precaució, posem a zero els bits no emprats
valPre &= 0b00000011; // Per precaució, posem a zero els bits no emprats
T2CON = ((valPos<<3) | valPre); // Ho posa a la configuració del temporitzador
PR2 = valPR2; // Preselecció del Timer2
bucles = numbuc; // Comptador d'iteracions
silenci = numsil; // Durada del silenci
controla = 0; // Comencem tocant la nota
PIE1bits.TMR2IE = 1; // Activem les interrupcions per Timer2
T2CONbits.TMR2ON = 1; // Activem el Timer2
}

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