En aquest cas, el programa contempla dos modes de funcionament que es poden triar amb els polsadors, el mode públic i el mode professional. En el mode públic s'indica només el nivell de so classificat en alt, mitjà o baix i es mostra el dibuix corresponent a la matriu de LED. En el mode professional es fa la mitjana de diverses mesures del valor eficaç, s'escala el valor i el resultat es mostra a la pantalla. En cas que el nivell sigui molt elevat, també sona el brunzidor.
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 "pic16f690.h" // Carrega el fitxer d'adreces i paràmetres del PIC 16F690 #include <xc.h> // Carrega el fitxer de funcions #define _XTAL_FREQ 4000000 #define PolsadorMenu RA3 // Li assigna un nom a l'adreça del polsador de dalt #define FiTimer1 PIR1bits.TMR1IF // Li assigna un nom al bit que indica el final del Timer 1
// VARIABLES
unsigned int Rms_acumulat = 0; // sumatori dels multiples RMS abans de fer la mitja
unsigned int mitja_Rms; // Mitjana dels multiples RMS
char contador = 0; // Contador de quants RMS es porten calculats abans de fer la mitjana
char Vcontador; // nre de veguades que calculem el RMS
char mitja_ON; // indica si estem en el mode Mitja
char Mode; // 0-pro, 1-públic
char ValorC; // Valor llindar general
char vPR; // Valor mode pro
char vPB; // Valor mode public
char arrValorPB[3] = {40,70,100}; // Valors llindar pel modes públics LOW-MED-HI
char Polsad; // Valor polsador
char TextP[9] = {'L','O','W','M','E','D','H','I',' '}; // Text mostrat a la configuració del mode públic
char Text1[6] = {'P','R','O','P','U','B'}; // Text mostrat amb informació del mode on ens trobem
char Text2[6] = {'C','O','N','F','I','G'}; // Text de configuració
char Text3[7] = {'M','I','T','J','A','N','A'}; // Text quan s'està calculant la mitjana
// Caracters especials
char logo1[8] = {0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00010001, 0b00011001, 0b00011001};
char logo2[8] = {0b00011001, 0b00011111, 0b00001111, 0b00000110, 0b00000000, 0b00000000, 0b00000000, 0b00000000};
char logo3[8] = {0b00000000, 0b00000000, 0b00001100, 0b00011110, 0b00011110, 0b00010011, 0b00010011, 0b00010011};
char logo4[8] = {0b00010011, 0b00000001, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000};
unsigned int Lectura[16]; // Per guardar els valors llegits
unsigned int intensitatAnalog; // valor de la intensitat sonora
unsigned int intensitatPerc; // valor de la intensitat de 0-100
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 fig[3][8] = { {0b00000001, 0b00000011, 0b00000111, 0b10001110,
0b11011100, 0b01111000, 0b00110000, 0b00000000},
{0b00011000, 0b00111100, 0b00100100, 0b01100110,
0b01111110, 0b11100111, 0b11111111, 0b00000000},
{0b11000011, 0b11100111, 0b01111110, 0b00111100,
0b00111100, 0b01111110, 0b11100111, 0b11000011} };
char prevPos = 4; // Guarda la figura que s'ha mostrat al bucle anterior a la matriu de LED
// Prendra un valor entre 0 i 2 però s'hinicialitza a 4 per assegurar-nos que es mostra alguna figura
// FUNCIONS void Pro(void); // Mode Pro void Config(void); // Configuració char Polsador(void); // Quin dels 5 polsadors età actiu void EnviaL(char Caracter); // Envia un caràcter void Esborra(void); // Esborra la pantalla i posa el cursor a l'inici void escriuValor(unsigned int Valor); // Escriu un int a la pantalla LCD void Cursor(char Filera, char Columna); // Posa el cursor a la posició desitjada void DefCarac(char Numero, char Fileres[8]);// Defineix caracters especials void Avalint(void); // avalua el nivell d'intensitat mitjana void Canvi(void); // Canvia l'escala i dona in valor a la intensitatPerc void Rms(void); // Fa el valor eficaç de les lectures void TocaNota(char ValPR2, char ValCCPR1L, char ValDC1B); void Envia3max(char Valor_M[]); // 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) {
// ESTABLIR PARÀMETRES
OPTION_REG = 0b10000101;
// Com a temporitzador basat en rellotge
// 001 - Factor d'escala de 4
// I resistències de pull-up desactivades
TRISA = 0xFF; // Tot el port A és d'entrada
TRISB = 0; // Tot el port B és de sortida
TRISC = 0b01000000; // Posa RC6 (AN8) com a entrada
// La resta del port C és de sortida
ADCON1 = 0b00010000; // Posa el conversor a 1/8 de la freqüència
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
ANSELH = 0b00000001; // Configura AN8 com entrada analògica
PORTB = 0; // Inicialitza a 0 el port B
PORTC = 0; // Inicialitza a 0 el port C
PIR1bits.TMR2IF = 0; // Desactiva el bit d'interrupció del Timer 2
T2CON = 0b00000011; // Configura el Timer 2
ADCON0 = 0b00001001; // Activa el conversor connectat a AN8 i AN2
Ini3max(); // Inicialitza els tres MAX7221
Actiu = 1; // Activa el color vermell
TMR0 = 100; // Presselecció de 100, que són 156 iteracions
// Correspon a una interrupció cada 7,5 ms
INTCON = 0b10100000; // Activem GIE i T0IE
Apaga(); // Apaga tots els LED de la matriu
// VARABLES INICIALS
Mode = 1; // mode pro com a predeterminat
vPR = 80; // Valor llindar inicial mode pro
vPB = 1; // Valor mode Públic - MED
Vcontador = 4; // Màxim valor que podrà prendre el contador
mitja_ON = 0; // Iniciem sense calcular la mitjana
// LOGO
DefCarac(0, logo1); // Defineix el caracter 0
_delay(50);
DefCarac(1, logo2); // Defineix el caracter 1
_delay(50);
DefCarac(2, logo3); // Defineix el caracter 2
_delay(50);
DefCarac(3, logo4); // Defineix el caracter 3
_delay(50);
Esborra(); // Esborra la pantalla LCD
Cursor(1, 8); // Cursor a la primera posició
EnviaL(0); // Escriu el caracter 1
Cursor(1, 9); // Cursor a la tercera posició
EnviaL(2); // Escriu el caracter 3
Cursor(2, 8); // Cursor a la segona posició
EnviaL(1); // Escriu el caracter 2
Cursor(2, 9); // Cursor a la cuarta posició
EnviaL(3); // Escriu el caracter 4
while(1){ // Bucle infinit (mostrar el logo)
Polsad = Polsador(); // Comprova si algun polsador està actiu
if (Polsad != 0 || PolsadorMenu == 0) // Si algun està actiu
break; // Surt del bucle
}
// BUCLE PRINCIPAL
while(1){ // Bucle infinit
for (char k = 0; k < 16; k++){ // Llegim 32 valors
while (INTCONbits.T0IF == 0) // Mira si Timer0 ha arribat a zero
; // Si no hi ha arribat, espera
TMR0 = 100; // Presselecció de 100, que són 156 iteracions
INTCONbits.T0IF = 0; // Desactivem el bit de final de temporització
ADCON0bits.GO = 1; // Posa en marxa el conversor
while (ADCON0bits.GO == 1) // Mentre no acabi
; // ens esperem
Lectura[k] = ADRESH * 256 + ADRESL; // Guardem el resultat
__delay_ms(1);
}
__delay_ms(500); // Delay per donar temps entre mesures
Rms(); // fem la mitjana dels 32 valors llegits per el sensor
Rms_acumulat = Rms_acumulat + intensitatAnalog; // acumulem el valor;
contador++; // Augmentem en un el valor del contador
if (contador >= Vcontador){ // Quan el contador es igual o superior al màxim preestablert
mitja_Rms = Rms_acumulat/contador; // Calcula la mitjana en funció dels cicles que s'ha trigat a calcular
contador = 0; // Reinicia el contador
Rms_acumulat = 0; // Reinicia el valor del sumatori abans de la mitjana
Esborra(); // Esborra la pantalla LCD
Cursor(1,14); // Posa el cursor alineat a la dreta
for (char k = 0; k < 3; k++){
EnviaL(Text1[k+Mode*3]); // Escriu el text PRO o PUB segons el mode
}
Canvi(); // transforama la intensitat llegida a tant per cent
Avalint(); // Encén la matriu led o comprova si s'ha superat el valor llindar
if (Mode == 0) // Si estem al mode professional
Pro(); // Executem la funció professional
else // Si estem al mode públic
ValorC = arrValorPB[vPB]; // Canviem el valor llindar al que toqui
if (PolsadorMenu == 0) { // Si es prem el polsador 0
while (PolsadorMenu == 0) // Mentre el polsador estigui premut
; // No fa res
Config(); // Quan es deixa anar anem a la CONFIGURACIÓ
}
__delay_ms(10);
}
}
}
void __interrupt() temporit(void){
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
}
}
void Pro(void){
Polsad = Polsador(); // Comprova quin polsador està actiu
Cursor(2, 1); // Segona fila
escriuValor(intensitatPerc); // Escriu el valor de la intensitat
ValorC = vPR;
if (mitja_ON == 1){ // MITJANA
// Toca una nota
CCP1CON = 0b00001100; // Configura el PWM, bits P1M (bits 7-6) a 00 mode senzill
CCPR1L = 49; // Valor que correspon a un cicle del 35 % a 440 Hz
TocaNota(158, 79, 2); // Toca dos notes par alertar que ja s'ha calculat la mitjana
TocaNota(158, 79, 2);
// Escriu valor
Cursor(2, 1); // Segona fila
escriuValor(intensitatPerc); // Escriu el valor de la intensitat
__delay_ms(3000); // Delay per mostrar el valor mitjà més estona
mitja_ON = 0; // torna a l'estat normal
Vcontador = 4; // Estableix al valor màxim del contador més petit per calcular mnys valors
}
if (Polsad == 3){ // Si es prem el pulsador 3
Esborra(); // Esborra la pantalla
for (char k = 0; k < 7; k++)// Escriu el text MITJANA
EnviaL(Text3[k]);
while (Polsad == 3) // Mentre el polsador 3 estigui premut
Polsad = Polsador(); // Comprova si s'ha deixat de premer
mitja_ON = 1; // Ves a l'estat de calcular mitjana
Vcontador = 12; // Estableix al valor màxim del contador més gran per calcular més valors
}
return; // Tornar al bucle principal
}
void Config(void){ // Menu de configuració
while (1){ // Bucle infinit
Polsad = Polsador(); // Lectura polsadors
Apaga(); // Apaga la matriu de LED
// TÍTOL
Esborra(); // Esborra pantalla LCD
for (char k = 0; k < 6; k++) // Escriu el text CONFIGURACIO
EnviaL(Text2[k]);
EnviaL(' ');
EnviaL('-');
EnviaL(' ');
for (char k = 0; k < 3; k++)
EnviaL(Text1[k+Mode*3]); // Escriu el text PRO o PUB segons el mode
if (Mode == 0){ // COSES ESPECÍFIQUES MODE PRO
// Escriu valor
Cursor(2, 1); // Segona fila
escriuValor(vPR); // Escriu el valor llindar del mode professional
// Lógica de polsadors
if (Polsad == 5){ // Si es prem el polsador 5
Mode = 1; // Canvia al mode 1
while (Polsad == 5) // Mentre no es deixi anar el polsador
Polsad = Polsador(); // Comprova si s'ha deixat anar
}
if (Polsad == 1 && vPR > 0){ // Si es prem el polsador 1 i no estem en el valor mínim
vPR--; // Baixa el valor llindar del mode professional una posició
__delay_ms(20); // Delay perque no baixi de cop
}
if (Polsad == 2 && vPR < 100){ // Si es prem el polsador 2 i no estem en el valor màxim
vPR++; // Puja el valor llindar del mode professional una posició
__delay_ms(20); // Delay perque no pugi de cop
}
}
if (Mode == 1){ // COSES ESPECÍFIQUES MODE PÚBLIC
// Escriu valor
Cursor(2, 3); // Segona fila
for (char k = 0; k < 3; k++) // text valor llindar mode públic
EnviaL(TextP[k + vPB*3]); // (LOW, MED, HI )
// Lógica de polsadors
if (Polsad == 5){ // Si es prem el polsador 5
Mode = 0; // Canvia al mode 0
while (Polsad == 5) // Mentre no es deixi anar el polsador
Polsad = Polsador(); // Comprova si s'ha deixat anar
}
if (Polsad == 1 && vPB > 0){ // Si es prem el polsador 1 i no estem en el valor mínim
vPB--; // Baixa el valor llindar del mode públic una posició
while (Polsad == 1) // Mentre no es deixi anar el polsador
Polsad = Polsador(); // Comprova si s'ha deixat anar
}
if (Polsad == 2 && vPB < 2){ // Si es prem el polsador 2 i no estem en el valor màxim
vPB++; // Puja el valor llindar del mode públic una posició
while (Polsad == 2) // Mentre no es deixi anar el polsador
Polsad = Polsador(); // Comprova si s'ha deixat anar
}
}
__delay_ms(20); // Delay perque no s'actualitzi instantàniament la pantalla
if (PolsadorMenu == 0) { // SORTIR DEL CONFIG
while (PolsadorMenu == 0) // Mentre el polsador estigui premut
; // No fa res
contador = 0; // Reinicia els valors per una bona mesura inicial
Rms_acumulat = 0;
prevPos = 4; // Posa la figura anterior com una no existent
return; // Quan deixis de polsar surt del bucle
}
}
}
void Avalint(void) { // introduim en valor mesurat % i el comparem amb el llindar definit a config. Encenem leds
char pos; // indica la figura que s'està mostrant a la matriu de LED
char color[2] = {0,2}; // indica el color de la figura que es mostra, s'inicialitza en aquest cas groc
if (intensitatPerc < ValorC/3){
pos = 0; // pos 1 correspon a la segona figura
color[0] = 2; // El color de la primera figura és verd
}
if (intensitatPerc >= ValorC/3 && intensitatPerc < ValorC*2/3){
pos = 1; // pos 1 correspon a la segona figura
// Deixa el color en groc que és el de la segona figura
}
if (intensitatPerc >= ValorC*2/3 ){
pos = 2; // pos 1 correspon a la segona figura
color[1] = 0; // El color de la primera figura és verd
}
if (intensitatPerc >= ValorC){
if (Mode ==1 && vPB != 0){
CCP1CON = 0b00001100; // Configura el PWM, bits P1M (bits 7-6) a 00 mode senzill
CCPR1L = 49; // Valor que correspon a un cicle del 35 % a 440 Hz
TocaNota(158, 79, 2); // Si el valor obtingut supera al llindar toca una nota per alertar
}
}
// MARTIU DE LED
if (Mode ==1 && prevPos != pos){ // S'envia una figura a la matriu si estem en el mode 1 i la figura d'abans no és la mateixa que volem mostrar
for (signed char k = 0; k < 8; k++){
Sortida[1] = k+1; // Filera
Sortida[3] = k+1;
Sortida[5] = k+1;
Sortida[color[0]] = fig[pos][k]; // Color 1
Sortida[color[1]] = fig[pos][k]; // Color 2
Envia3max(Sortida); // Ho envia al MAX7221
__delay_ms(1);
}
prevPos = pos; // Establir la figura anterior com l'actual al acabar de enviar-la
}
}
void Canvi(void){ // Dona un valor a intencitatPercent entre 0 i 100 en funció del valor de la intensitat real
if (mitja_Rms <= 5)
intensitatPerc=0;
else if (mitja_Rms <= 80)
intensitatPerc=(unsigned int)(mitja_Rms - 0) * (58 - 0) / (80 - 5) + 0;
else if (mitja_Rms <= 400)
intensitatPerc=(unsigned int)(mitja_Rms - 80) * (80 - 58) / (400 - 80) + 40;
else if (mitja_Rms <= 900)
intensitatPerc=(unsigned int)(mitja_Rms - 400) * (100 - 80) / (900 - 400) + 80;
else
intensitatPerc=100;
}
void Rms(void){
unsigned int total = 0;
unsigned int mitjana;
unsigned long sumatori = 0;
for (char x = 0; x < 16; x++) {
total = total + Lectura[x]; // fem una suma total dels valors llegits
}
mitjana = total/16;
for (char x = 0; x < 16; x++) {
sumatori = sumatori + ((Lectura[x]-mitjana)*(Lectura[x]-mitjana)); // fem una suma total dels valors llegits
}
intensitatAnalog = (unsigned int) (sumatori/16)/16;
}
void TocaNota(char ValPR2, char ValCCPR1L, char ValDC1B) {
TRISC = 0b01100000; // 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 = 0b01000000; // Posem RC5 (sortida del PWM) com a sortida
__delay_ms(200); // Retard de 0,2 s
TRISC = 0b01100000; // Posem RC5 (sortida del PWM) com a entrada
// O sigui, silenci
__delay_ms(200); // Retard de 0,2 s
}
char Polsador(void) {
ADCON0 = 0b00001001; // Activa el conversor connectat a AN8 i AN2
__delay_ms(1);
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
ADCON0 = 0b10100001; // Activa el conversor connectat a AN8 i AN2
return Pols;
}
void escriuValor(unsigned int Valor){
char Digits[5]; // Variable amb el número dígit a dígit
// Digits[0] són les unitats
// Convertim a BCD
Digits[0] = Valor % 10; // Unitats
Valor = Valor / 10;
Digits[1] = Valor % 10; // Desenes
Valor = Valor / 10;
Digits[2] = Valor % 10; // Centenes
Valor = Valor / 10;
Digits[3] = Valor % 10; // Centenes
Valor = Valor / 10;
Digits[4] = Valor % 10; // Milers
// Passem els dígits a ASCII
for (char j = 0; j < 5; j++){ // 5 dígits
Digits[j] = Digits[j] + '0'; // Li sumem el codi ASCII de 0
}
// Suprimim zeros innecessaris
if (Digits[4] == '0') { // I mirem si ho és el quart
Digits[4] = ' '; // Si ho és, hi posem un espai
if (Digits[3] == '0') { // I mirem si ho és el tercer
Digits[3] = ' '; // Si ho és, hi posem un espai
if (Digits[2] == '0') { // I mirem si ho és el tercer
Digits[2] = ' '; // Si ho és, hi posem un espai
if (Digits[1] == '0') { // I mirem si ho és el quart
Digits[1] = ' '; // Si ho és, hi posem un espai
}
}
} // El 0 de les unitats el mostrarem sempre
}
for (int k = 4; k >= 0; k--){ // Només escrivim quatre valors
EnviaL(Digits[k]); // Escriu un dígit a la pantalla
}
}
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 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 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"); // 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
}
}

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