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.
Per a la gestió del temps fan servir el temporitzador 1 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 #define clrbit(var, bit) ((var) &= ~(1 << (bit))) #define flipbit(var, bit) ((var) ^= (1<<(bit))) #define FiTimer0 INTCONbits.T0IF // Li assigna un nom al bit que indica el final del Timer 0 #define FiTimer1 PIR1bits.TMR1IF // Li assigna un nom al bit que indica el final del Timer 1 #define FiTimer2 PIR1bits.TMR2IF // Li assigna un nom al bit que indica el final del Timer 2
char Polsad; // variable que et diu quin polsador està premut
char menu; // indica en quina pantalla et trobes (hora, alarma o data). Es modifica amb el polsador RA3
char canvi; // indica en quina posició està el cursor en la configuració de l'hora
// (o quan ja està configurada, que val 2)
char canviala; // indica en quina posició està el cursor en la configuració de l'alarma
// (o quan ja està configurada, que val 2)
char canvidata; // indica en quina posició està el cursor en la configuració de la data
// (o quan ja està configurada, que val 3)
char hora; // indica si l'hora està configurada i en funcionament
char conf_alarm; // indica si l'alarma està activada (on) o desactivada (off). Es modifica amb el polsador 3
char alarma; // indica si l'alarma està activada i configurada (llesta per sonar)
char so; // indica si l'hora coincideix amb l'alarma (un cop aquesta està configurada i activada).
// Es posa a sonar
char ComptaTimer; // va comptant els cops que el Timer1 arriba a 0.05 s. Cada 20 repeticions se suma un segon
char Port;
char Compta;
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] = { {0b00111100, 0b01111110, 0b11111111, 0b11111111,
0b11111111, 0b11111111, 0b01111110, 0b00111100},
{0b00000000, 0b00000000, 0b00000000, 0b01111110,
0b01111110, 0b00000000, 0b00000000, 0b00000000},
{0b00000000, 0b00000000, 0b00000000, 0b01111110,
0b01111110, 0b00000000, 0b00000000, 0b00000000} };
signed char seg_un = 0; // variable que conta les unitats de segon
// (apareix en el menú de l'hora, un cop configurat)
signed char seg_des = 0; // variable que conta les desenes de segon
// (apareix en el menú de l'hora, un cop configurat)
signed char min_un = 0; // variable que conta les unitats de minut (apareix al menú de l'hora)
signed char min_des = 0; // variable que conta les unitats de segon (apareix al menú de l'hora)
signed char hor_un = 0; // variable que conta les unitats de segon (apareix al menú de l'hora)
signed char hor_des = 0; // variable que conta les unitats de segon (apareix al menú de l'hora)
signed char min_un_ala = 0; // variable que emmagatzema les unitats de minut (apareix al menú de l'alarma)
signed char min_des_ala = 0; // variable que emmagatzema les desenes de minut (apareix al menú de l'alarma)
signed char hor_un_ala = 0; // variable que emmagatzema les unitats de l'hora (apareix al menú de l'alarma)
signed char hor_des_ala = 0; // variable que emmagatzema les desenes de l'hora (apareix al menú de l'alarma)
signed char dia_un = 1; // variable que conta les unitats del dia (apareix en el menú de la data)
signed char dia_des = 0; // variable que conta les desenes del dia (apareix en el menú de la data)
signed char mes_un = 1; // variable que conta les unitats del mes (apareix en el menú de la data)
signed char mes_des = 0; // variable que conta les desenes del mes (apareix en el menú de la data)
signed char any_un = 0; // variable que conta les unitats de l'any (apareix en el menú de la data)
signed char any_des = 0; // variable que conta les desenes de l'any (apareix en el menú de la data)
signed char repe; // variable que compta 5 'comptaTimers', és a dir, 0.25s
char defrepe = 0; // val 1 si l'alarma passa a començar a sonar
char inter_alarm = 0; // variable que compta 0.25s i ens serveix per coordinar el so de l'alarma
// amb la matriu LED mitjançant interrupcions
char port; // Variable auxiliar del port C
char control; // Variable de control de la funció TocaNota
// Si és 0 nota, si és 1 silenci
int bucles; // Comptador d'iteracions de la nota
int silenci; // Durada del silenci
// 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); // Polsador que s'ha premut void TocaNota(char valPre, char valPos, char valPR2, int numbuc, int numsil); void Envia3max(char Valor[]); // Envia un joc de valors als tres MAX7221 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
void main (void) {
__delay_ms(1500);
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
ANSEL = 0b00000101; // Configura AN0 i AN2 com entrada analògica
OPTION_REG = 0b10000101; // Configuració de Timer0
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
TRISA = 0xFF; // Tot el port A és d'entrada
ADCON1 = 0b00010000; // Posa el conversor a 1/8 de la freqüència
ADCON0 = 0b00001001; // Activa el conversor A/D connectat a AN2
port = 0;
PORTC = 0; // Desactiva les sortides del port C
PORTB = 0;
Ini3max(); // Inicialitza els tres MAX7221
Actiu = 1; // Activa el color vermell
TMR0 = 100; // Presselecció de 100, que són 156 iteracions
INTCON = 0b11100000; // Activa GIE, PEIE, T0IE
Apaga();
FiTimer1 = 0; // Aquest bit es posarà a 1 quan el temporitzador acabi
T1CON = 0b00110001; // Configuració de Timer1
INTCONbits.PEIE = 1; // Habilitem les interrupcions a nivell genera
INTCONbits.GIE = 1; // Habilitem les interrupcions a nivell general
TMR1H = 231; // Inicialitza el Timer1
TMR1L = 150;
PIE1bits.TMR1IE = 1; // Habilita la interrupción del Timer1
while (1) {
Polsad = Polsador(); // Llegim els polsadors
// pas de l'hora i la data automàticament a través de l'avançamnent progressiu dels seg_un:
if (seg_un > 9){
seg_des++;
seg_un = 0;
}
if (seg_des > 5){
min_un++;
seg_des = 0;
}
if (min_un>9) {
min_un=0;
min_des++;
}
if (min_des > 5){
min_des = 0;
if (hora == 1){
hor_un++;
}
}
if (hor_un>3 && hor_des == 2) {
hor_un=0;
hor_des=0;
if ((hora == 1) && (canvidata == 3)){
dia_un++;
}
}
if (hor_un > 9){
hor_des++;
hor_un = 0;
}
if (dia_un>9) {
dia_un=0;
dia_des++;
}
if(mes_des==0&&(mes_un==1||mes_un==3||mes_un==5||mes_un==7||mes_un==8)||(mes_des==1&&(mes_un==0||mes_un==2))){
// mesos de 31 dies
if (dia_des==3 && dia_un>1){
dia_des=0;
dia_un=1;
if (canvidata == 3){
mes_un++;
}
}
} else { //mesos de 30 dies
if (dia_des==3 && dia_un>0){
dia_des=0;
dia_un=1;
if (canvidata == 3){
mes_un++;
}
}
}
if (mes_des==0 && mes_un==2){ //febrer
if (any_un%4==0){
if (dia_des>2){
dia_des=0;
dia_un = 1;
if (canvidata == 3){
mes_un++;
}
}
} else {
if ((dia_des == 3) || ((dia_des == 2) && (dia_un == 9))){
dia_des=0;
dia_un=1;
if (canvidata == 3){
mes_un++;
}
}
}
}
if (dia_des > 3){ // evitar errors innecessàris
dia_des = 0;
}
if (((mes_un > 2)&&(mes_des == 1)) && (hora == 1)){
mes_des = 0;
mes_un = 1;
any_un++;
}
if (any_un > 9){
any_des++;
any_un = 0;
}
if (any_des > 9){
any_des = 0;
}
// útil per correcte funcionament a l'hora de configurar l'alarma:
if (min_un_ala>9) {
min_un_ala=0;
min_des_ala++;
}
if (min_des_ala > 5){
min_des_ala = 0;
}
if (hor_un_ala>3 && hor_des_ala == 2) {
hor_un_ala=0;
hor_des_ala=0;
}
if (hor_un_ala > 9){
hor_des_ala++;
hor_un_ala = 0;
}
if (menu == 0) { // si estem al menú de l'hora
__delay_ms(200); // Esperem que arrenqui la pantalla
Esborra(); // Neteja la pantalla
Cursor(1,1);
EnviaL('T');
EnviaL('I');
EnviaL('M');
EnviaL('E');
Cursor(2, 12);
EnviaL('0' + hor_des);
EnviaL('0' + hor_un);
EnviaL(':');
EnviaL('0' + min_des);
EnviaL('0' + min_un);
// canvi de configuració (passar de minuts a hores o a mode configurat):
if (Polsad == 5){ // si premem el polsador 5 canviem el cursor
while (Polsador() > 0){
;
}
canvi++;
if (canvi > 2){
canvi = 0;
seg_un = 0;
seg_des = 0;
}
}
if (canvi == 0){ // configurar minuts
Cursor(1,15);
EnviaL('_');
EnviaL('_');
}
if (canvi == 1){ // configurar hores
Cursor(1,12);
EnviaL('_');
EnviaL('_');
}
if (canvi == 2){ // mode ja configurat (l'hora passa automàticament)
hora = 1;
Esborra(); // Neteja la pantalla
EnviaL('T');
EnviaL('I');
EnviaL('M');
EnviaL('E');
Cursor(2, 9);
EnviaL('0' + hor_des);
EnviaL('0' + hor_un);
EnviaL(':');
EnviaL('0' + min_des);
EnviaL('0' + min_un);
EnviaL(':');
EnviaL('0' + seg_des);
EnviaL('0' + seg_un);
}else{
hora = 0;
}
}
if (menu == 1) { // si estem al menú de l'alarma
__delay_ms(200); // Esperem que arrenqui la pantalla
Esborra(); // Esborra la pantalla
EnviaL('A');
EnviaL('L');
EnviaL('A');
EnviaL('R');
EnviaL('M');
Cursor(2, 12);
EnviaL('0'+hor_des_ala);
EnviaL('0'+hor_un_ala);
EnviaL(':');
EnviaL('0'+min_des_ala);
EnviaL('0'+min_un_ala);
// canvi de configuració de l'alarma:
if (Polsad == 5){ // si premem el polsador 5 canviem el cursor
while (Polsador() > 0){
;
}
canviala++;
if (canviala > 2){
canviala = 0;
}
}
if (canviala == 0){ // configurar minuts de l'alarma
Cursor(1,15);
EnviaL('_');
EnviaL('_');
}
if (canviala == 1){ // configurar hores de l'alarma
Cursor(1,12);
EnviaL('_');
EnviaL('_');
}
if (Polsad == 3){ // premer el polsador 3 per activar l'alarma
while (Polsador() > 0){
;
}
conf_alarm++;
if (conf_alarm > 1){
conf_alarm = 0;
}
}
if (conf_alarm == 0){ // alarma NO activada
Cursor(2, 1);
EnviaL('o');
EnviaL('f');
EnviaL('f');
}
if (conf_alarm == 1){ // alarma activada
Cursor(2, 1);
EnviaL('o');
EnviaL('n');
}
if (canviala == 2 && conf_alarm == 1){ // indica si, a més a més d'estar activada (on),
// també està configurada
alarma = 1;
} else{
alarma = 0;
}
}
if (menu == 2) { // si estem al menú de la data
__delay_ms(200); // Esperem que arrenqui la pantalla
Esborra(); // Esborra la pantalla
EnviaL('D');
EnviaL('A');
EnviaL('T');
EnviaL('E');
Cursor(2, 9);
EnviaL('0' + dia_des);
EnviaL('0' + dia_un);
EnviaL('/');
EnviaL('0' + mes_des);
EnviaL('0' + mes_un);
EnviaL('/');
EnviaL('0' + any_des);
EnviaL('0' + any_un);
// canvi de configuració de la data:
if (Polsad == 5){ // si premem el polsador 5 canviem el cursor
while (Polsador() > 0){
;
}
canvidata++;
if (canvidata > 3){
canvidata = 0;
}
}
if (canvidata == 0){ // configurar l'any
Cursor(1,15);
EnviaL('_');
EnviaL('_');
}
if (canvidata == 1){ // configurar el mes
Cursor(1,12);
EnviaL('_');
EnviaL('_');
}
if (canvidata == 2){ // configurar el dia
Cursor(1,9);
EnviaL('_');
EnviaL('_');
}
}
if (Polsad == 2) { // polsador per pujar en el mode configuració (en qualsevol dels tres menús)
if (menu == 0){ // pujar en el menú de l'hora
if (canvi == 0){ // si estem amb el cursor sobre els minuts
min_un++;
}
if (canvi == 1){ // si estem amb el cursor sobre les hores
hor_un++;
}
}
if (menu == 1){ // pujar en el menú de l'alarma
if (canviala == 0){ // si hi ha el cursor sobre els minuts
min_un_ala++;
}
if (canviala == 1){ // si hi ha el cursor sobre les hores
hor_un_ala++;
}
}
if (menu == 2){ // pujar en el menú de la data
if (canvidata == 2){ // si el cursor està sobre els dies
dia_un++;
}
if (canvidata == 1){ // si el cursor està sobre els mesos
mes_un++;
// instruccions per aconseguir un correcte funcionament en el pas dels mesos:
if (mes_un>9) {
mes_un=0;
mes_des++;
}
if (mes_des == 1 && mes_un > 2){
mes_des = 0;
mes_un = 1;
}
}
if (canvidata == 0){ // si el cursor està sobre els anys
any_un++;
// instruccions per aconseguir un correcte funcionament en el pas dels anys:
if (any_un > 9 && any_des == 9){
any_un = 0;
any_des = 0;
}
if (any_un > 9){
any_des++;
any_un = 0;
}
}
}
}
if (Polsad == 1) { // polsador per baixar en el mode configuració (en qualsevol dels tres menús)
if (menu == 0){ // si estem en el menú de l'hora
if (canvi == 0){ // si el cursor està sobre els minuts
min_un--;
if (min_un<0) {
min_un=9;
min_des--;
}
if (min_des < 0){
min_des = 5;
}
}
if (canvi == 1){ // si el cursor està sobre les hores
hor_un--;
if (hor_un<0 && hor_des == 0) {
hor_un=3;
hor_des=2;
}
if (hor_un < 0){
hor_des--;
hor_un = 9;
}
}
}
if (menu == 1){ // si estem en el menú de l'alarma
if (canviala == 0){ // si el cursor està sobre els minuts
min_un_ala--;
if (min_un_ala<0) {
min_un_ala=9;
min_des_ala--;
}
if (min_des_ala < 0){
min_des_ala = 5;
}
}
if (canviala == 1){ // si el cursor està sobre les hores
hor_un_ala--;
if (hor_un_ala<0 && hor_des_ala == 0) {
hor_un_ala=3;
hor_des_ala=2;
}
if (hor_un_ala < 0){
hor_des_ala--;
hor_un_ala = 9;
}
}
}
if (menu == 2){ // si estem en el menú de la data
if (canvidata == 2){ // si el cursor està sobre els dies
dia_un--;
if (dia_un < 0 && dia_des > 0) {
dia_un=9;
dia_des--;
}
if(mes_des==0&&(mes_un==1||mes_un==3||mes_un==5||mes_un==7||mes_un==8)||(mes_des==1&&(mes_un==0||mes_un==2))){
// mesos de 31 dies
if (dia_des==0 && dia_un < 1){
dia_des=3;
dia_un=1;
}
} else{ // mesos de 30 dies
if (dia_des == 0 && dia_un < 1){
dia_des = 3;
dia_un = 0;
}
}
if (mes_des==0 && mes_un==2){ // febrer
if (any_un%4==0){
if (dia_des == 0 && dia_un < 1){
dia_des=2;
dia_un = 9;
}
} else {
if (dia_des == 0 && dia_un < 1){
dia_des=2;
dia_un=8;
}
}
}
}
if (canvidata == 1){ // si el cursor està sobre els mesos
mes_un--;
if (mes_un<0 && mes_des == 1) {
mes_un=9;
mes_des--;
}
if (mes_des == 0 && mes_un < 1){
mes_des = 1;
mes_un = 2;
}
}
if (canvidata == 0){ // si el cursor està sobre els anys
any_un--;
if (any_un < 0 && any_des == 0){
any_un = 9;
any_des = 9;
}
if (any_un < 0){
any_des--;
any_un = 9;
}
}
}
}
if (RA3 == 0){ //POLSADOR 0
while (RA3 == 0){
;
}
menu = (menu +1) % 3; // el polsador 0 ens servirà per canviar de menús
// (entre l'hora, l'alarma i la data)
}
if (alarma == 1 && hora == 1){ // si l'alarma està configurada i activada
// i l'hora també està configurada
if((min_un_ala==min_un)&&(min_des_ala==min_des)&&(hor_un_ala==hor_un)&&(hor_des_ala==hor_des)){
// si l'hora de l'alarma és la mateixa que la real
so = 1; // variable que indica que l'alarma s'ha de posar a sonar
}
}
if (so == 1){ // si sona l'alarma
// Matriu 1
defrepe++;
if (inter_alarm == 0){ // aquesta variable va comptant mitjançant interrupcions 0.25s
for (unsigned char k = 0; k < 8; k++){ // apareix una figura en la matriu LED
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);
}
}
if (inter_alarm == 1){ // al cap de 0.25s comença a tocar la primera melodia
TocaNota(0, 7, 239, 105, 105); // Valor que correspon aproximadament a do3
TocaNota(0, 6, 243, 118, 118); // Valor que correspon aproximadament a re3
TocaNota(0, 7, 239, 105, 105); // Valor que correspon aproximadament a do3
TocaNota(0, 6, 243, 118, 118); // Valor que correspon aproximadament a re3
TocaNota(0, 5, 253, 132, 132); // Valor que correspon aproximadament a mi3
}
if (inter_alarm == 4){ // al cap d'1s comença a tocar la segona
TocaNota(0, 7, 239, 105, 105); // Valor que correspon aproximadament a do3
TocaNota(0, 6, 243, 118, 118); // Valor que correspon aproximadament a re3
TocaNota(0, 7, 239, 105, 105); // Valor que correspon aproximadament a do3
TocaNota(0, 6, 243, 118, 118); // Valor que correspon aproximadament a re3
TocaNota(0, 5, 253, 132, 132); // Valor que correspon aproximadament a mi3
}
if (inter_alarm == 7){ // al cap de 1.75s comença a tocar l'última
TocaNota(0, 7, 239, 105, 105); // Valor que correspon aproximadament a do3
TocaNota(0, 6, 243, 118, 118); // Valor que correspon aproximadament a re3
TocaNota(0, 7, 239, 105, 105); // Valor que correspon aproximadament a do3
TocaNota(0, 6, 243, 118, 118); // Valor que correspon aproximadament a re3
TocaNota(0, 5, 253, 132, 132); // Valor que correspon aproximadament a mi3
}
if (inter_alarm == 8){ // al cap de 2s s'apaga la figura de la matriu LED
Apaga(); // Matriu 2
}
if (inter_alarm == 14){ // al cap de 3.5s es reinicia la variable i es torna a començar a dalt
inter_alarm = 0;
}
}
if (Polsad == 4 && so == 1){ // el polsador 4 ens servirà per parar l'alarma quan soni
conf_alarm = 0;
so = 0;
canviala = 0;
hor_un_ala = 0;
hor_des_ala = 0;
min_un_ala = 0;
min_des_ala = 0;
Apaga();
}
}
}
void __interrupt() temporit(void){
if (FiTimer1 == 1){ // Si ha acabat el temporitzador
T1CONbits.TMR1ON = 0; // Atura momentàniament el Timer1
TMR1H = 231; // Inicialitza el Timer1
TMR1L = 150;
T1CONbits.TMR1ON = 1; // Torna a engegar el Timer1
FiTimer1 = 0; // Tornem a posar el bit a zero
if(hora == 1){
ComptaTimer++; // Incrementa Compta
if (ComptaTimer == 20) { // Si ha acabat vint vegades
seg_un++;
ComptaTimer = 0;
}
if (so == 1 && defrepe == 1){
if (ComptaTimer < 15){
repe = ComptaTimer;
}else{
repe = ComptaTimer - 20;
}
}
if (so == 1){
if (ComptaTimer - repe == 5) {
inter_alarm++;
}
}
}
}
if (FiTimer2) { // Comprovem que hi ha interrupció per Timer2
FiTimer2 = 0; // Desactiva el bit que indica interrupció pel Timer2
if (control == 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 ((control == 1) || (silenci == 0)){ // Si s'acaba el silenci
T2CONbits.TMR2ON = 0; // Desactiva el Timer2
PIE1bits.TMR2IE = 0; // Desactiva les interrupcions per Timer2
}
if (control == 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
control = 1; // Toca silenci
}
}
}
}
if (FiTimer0 = 1) { // Comprovem que hi ha interrupció per Timer 0
TMR0 = 100; // Preselecció de Timer0
FiTimer0 == 0;
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
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--; // 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 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
control = 0; // Comencem tocant la nota
PIE1bits.TMR2IE = 1; // Activem les interrupcions per Timer2
T2CONbits.TMR2ON = 1; // Activem el Timer2
}
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("banksel PORTB");
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("banksel PORTB");
asm("movwf PORTB"); // I el posa al port B
asm("banksel _Port");
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("banksel PORTB");
asm("movwf PORTB"); // I el posa al port B
asm("banksel _Port");
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("banksel PORTB");
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");
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("banksel PORTB");
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
}
}

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