En aquest cas, el programa contempla quatre modes de funcionament. En el mode 1, que és el més bàsic, es mostra el valor eficaç i l'amplitud de l'ona de so. A més, hi ha una representació gràfica a base de barres verticals, la darrera de les quals pot estar parcialment plena per donar una imatge més visual del nivell de so. En el mode 2, a més, el brunzidor també informa del nivell de so emetent una nota que té una freqüència més aguda a mesura que augmenta el so. En el mode 3 es calcula, també, la mitjana dels valors eficaços llegits durant un cert temps i en el mode 4 es fa servir addicionalment la matriu de LED per mostrar si el nivell de so és adequat o elevat.

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 // La freqüència del rellotge és 4 MHz #define Polsador0 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
unsigned int Lectura[32]; // Per guardar els valors llegits
unsigned int valors[4]; // [ve,max,min,ve_escala]
char Mode; // Per guardar el mode en el que ens trobem
long sumatorimode3;
char Polsad; // Polsador que s'ha premut
char Polsad34; // Polsador que s'ha premut en el mode 3 i en mode 4
char nombreiter; // Temps aaproximat agafant valors en el mode3
char valormin; // Valor minim (limit) en el mode 4
char c1; // Constant de configuracio del brunzidor per PWM
char c2; // Constant de configuracio del brunzidor per PWM
char Omega[8] = {0b00011111, 0b00011111, 0b00011111, 0b00011111, 0b00011111, 0b00011111,
0b00011111, 0b00000000}; // definim un caracter especial
char fig[6][8] = { {0b11111111, 0b11000011, 0b10100101, 0b10011001, // Figura 1
0b10011001, 0b10100101, 0b11000011, 0b11111111},
{0b00000000, 0b00000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00000000, 0b00000000},
{0b00000000, 0b00000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00000000, 0b00000000},
{0b11111111, 0b11111110, 0b11111100, 0b11111001, // Figura 2
0b01110011, 0b00100111, 0b10001111, 0b11011111},
{0b11111111, 0b11111111, 0b11111111, 0b11111111,
0b11111111, 0b11111111, 0b11111111, 0b11111111},
{0b11111111, 0b11111110, 0b11111100, 0b11111001,
0b01110011, 0b00100111, 0b10001111, 0b11011111}};
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
// Definició de les funcions que farem servir
void escriuValor(unsigned int Valor); // Escriu un valor a la pantalla
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
char Polsador(void); // Funció de lectura dels polsadors
void escriuResultat(void); // escriu els a la pantalla el ve_escala, max, min amb de manera ordenada
void registreCalSo(void); // Registre el so i calcula els valors
// característics del so en un interval de uns 20 ms
unsigned int floorSqrt(unsigned long x); // funció que torna la part entera de la arrel quadrada
void menu(void); // Funcio que escriu el menu a la pantalla
void TocaNota(char ValPR2, char ValCCPR1L, char ValDC1B); // funcio que toca una nota
void CompPolsador0(void); // comprova si el Polsador0 està premut
void DefCarac(char Numero, char Fileres[8]); // Crea un caràcter definit per l'usuari
// Funcions que per fer servir la matriu led
void Envia3max(char Valor[]); // Envia un joc de valors als tres MAX7221
// desactivant interrupcions
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 de la matriu
void main (void) {
__delay_ms(1000); // retard de 1 segon perquè s'inicialitzi bé la pantalla
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
// RC5 (sortida del PWM), de moment, com a entrada
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
// Configuracio Mode2
PIR1bits.TMR2IF = 0; // Desactiva el bit d'interrupció del Timer 2
T2CON = 0b00000011; // Configura el Timer 2
// bits T2KCPS (bits 1-0) a 11 prescalat de 16
// bit 2 (TMR2ON) a 0, Timer aturat
// Postscaler TOUTPS (bits 6-3) no afecten al PWM
// configuracio mode 3
nombreiter = 30; // temps aproximat bucle
// Configuració de Timer0 i matriu led del mode 4
OPTION_REG = 0b10000101; // Configuració de Timer0
// Com a temporitzador basat en rellotge
// 101 - Factor d'escala de 64
// I resistències de pull-up desactivades (valor per defecte)
Apaga(); // Apaga tots els LED de la matriu
Ini3max(); // Inicialitza els tres MAX7221
Actiu = 1; // Activa el color vermell
TMR0 = 100; // Presselecció de 100, que són 156 iteracions
valormin=50; // Valor minim (limit) predeterminat
Mode=0; // Inicia amb el mode0, es a dir, el menu
while (1){
ADCON0 = 0b00001001; // Activa el conversor connectat a AN8 i AN2
Polsad = Polsador(); // Llegim els polsadors
if (Mode==0){
Apaga(); // Apaga tots els LED de la matriu
PORTC= 0b00000000; // Apaga tots els LEDs
menu(); // Funcio que escriu el menu a la pantalla
if (Polsad == 1){
Cursor(1,1); // Poscionem el cursor
DefCarac(2,Omega); // Defineix el caracter especial del bloc sencer
Esborra(); // Esborra la pantalla;
Mode=1;
PORTC= 0b00000001; // Activa el bit 0 del port C i, per tant, encén el LED0
}
if (Polsad == 2){
Cursor(1,1); // Poscionem el cursor
DefCarac(2,Omega); // Defineix el caracter especial del bloc sencer
Mode=2;
PORTC= 0b00000010; // Activa el bit 1 del port C i, per tant, encén el LED1.
}
if (Polsad == 3){
__delay_ms(1000); // Retard de 1 segon
Polsad34=1; // comença el mode3 en la configuracio dels segons
Mode=3;
PORTC= 0b00000100; // Activa el bit 2 del port C i, per tant, encén el LED2.
}
if (Polsad == 4){
__delay_ms(1000); // retard de 1 segon
Polsad34=1;
Mode=4;
Esborra(); // Esborra la pantalla;
PORTC= 0b00001000; // Activa el bit 3 del port C i, per tant, encén el LED3.
}
}
if (Mode==1){
registreCalSo(); // Registre el so i calcula els valors característics del so
escriuResultat(); // Escriu a la pantalla el ve_escala, max,min
CompPolsador0(); // comprova si el Polsador0 està premut
__delay_ms(500); // retard de 1 segon
CompPolsador0(); // comprova si el Polsador0 està premut
Esborra(); // Esborra la pantalla;
}
if (Mode==2){
CompPolsador0(); // comprova si el Polsador0 està premut
registreCalSo(); // Registre el so i calcula els valors característics del so
escriuResultat(); // Escriu a la pantalla el ve_escala, max,min
CCP1CON = 0b00001100; // Configura el PWM, bits P1M (bits 7-6) a 00 mode senzill
// DC1B = 11 (bits 5-4) els dos bits de menys pes són 0
// CCP1M = 11xx en mode senzill els bit 0 i 1 no afecten
// Ho posa com a configuració del PWM
CCPR1L = 49; // Valor que correspon a un cicle del 35 % a 440 Hz
// Registre que ens dona l'amplada de tON
// sonen notes depenen del so que hi ha.
c1=238-(6/5)*valors[3]; // escala linieal corresponent a la configuracio
// del Timer2, bit PR2, segons el ve
c2=119-(3/5)*valors[3]; // escala linieal corresponent a la configuracio
// del CCPR1L del brunzidor segons el ve
TocaNota(c1, c2, 2); // Valor que correspon aproximadament a la3-nota aguda
__delay_ms(200); // Retard de 0,2 s
TocaNota(c1, c2, 2); // Valor que correspon aproximadament a la3-nota aguda
CompPolsador0(); // comprova si el Polsador0 està premut
__delay_ms(1000); // retard de 1 segon
Esborra(); // Esborra la pantalla;
}
if (Mode==3){ // aquest mode esta uns segons aproximats(nombreiter), on cada segon calcula el ve
// i llavors torna el valor mitja dels ve calculats
__delay_ms(200); // retard de 0.2 segon
sumatorimode3=0;
CompPolsador0(); // comprova si el Polsador0 està premut
if (Polsad34==1){
Esborra(); // Esborra la pantalla;
EnviaL('S'); // Lletra
EnviaL('E'); // Lletra
EnviaL('G'); // Lletra
EnviaL('O'); // Lletra
EnviaL('N'); // Lletra
EnviaL('S'); // Lletra
Cursor(2,1); // Poscionem el cursor
escriuValor(nombreiter); // Escrivim el valor minim
}
Polsad34 = Polsador(); // Llegim els polsadors
if (Polsad34==3){
if (nombreiter<60){
nombreiter++; // Increment nombre iteracions (segons aproimats)
}
Polsad34=1; // fem que entri en el altre if
}
if (Polsad34==4){
if (nombreiter>1){
nombreiter--; // Decrement nombre iteracions (segons aproimats)
}
Polsad34=1; // fem que entri en el altre if
}
if (Polsad34==2){
Esborra(); // Esborra la pantalla;
EnviaL('E'); // Lletra
EnviaL('S'); // Lletra
EnviaL('P'); // Lletra
EnviaL('E'); // Lletra
EnviaL('R'); // Lletra
EnviaL('A'); // Lletra
EnviaL('N'); // Lletra
EnviaL('T'); // Lletra
for (char k = nombreiter; k !=0; k--){ // Llegim tants valors com el nombreiter
registreCalSo(); // Registre el so i calcula els valors característics del so
sumatorimode3=sumatorimode3+valors[3]; // suma el valor eficaç en el sumatori
__delay_ms(800); // retard de 0.8 segons determinat experimentalment perque es calculi ve cada segon
}
unsigned int veMitja= sumatorimode3/nombreiter;
Esborra(); // Esborra la pantalla;
EnviaL('V'); // Lletra
EnviaL('E'); // Lletra
EnviaL(' '); // Lletra
EnviaL('M'); // Lletra
EnviaL('I'); // Lletra
EnviaL('T'); // Lletra
EnviaL('J'); // Lletra
EnviaL('A'); // Lletra
Cursor(2,1); // Poscionem el cursor
escriuValor(veMitja); // Escrivim valor mitja a la pantalla
CompPolsador0(); // comprova si el Polsador0 està premut
__delay_ms(1000); // retard de 1 segon
}
}
if (Mode==4){
if (Polsad34==1){
Esborra(); // Esborra la pantalla;
Cursor(1,1); // Poscionem el cursor
EnviaL('L'); // Lletra
EnviaL('I'); // Lletra
EnviaL('I'); // Lletra
EnviaL('M'); // Lletra
EnviaL('I'); // Lletra
EnviaL('T'); // Lletra
EnviaL(' '); // Lletra
EnviaL('V'); // Lletra
EnviaL('E'); // Lletra
Cursor(2,5); // Poscionem el cursor
escriuValor(valormin); // Escrivim el valor minim
}
Polsad34 = Polsador(); // Llegim els polsadors
if (Polsad34==3){
if (valormin<100){
valormin+=5; // Increment del valor minim (limit)
}
Polsad34=1; // fem que entri en el altre if
}
if (Polsad34==4){
if (valormin>1){
valormin-=5; // Decrement del valor minim (limit)
}
Polsad34=1; // fem que entri en el altre if
}
CompPolsador0(); // comprova si el Polsador0 està premut
registreCalSo(); // Registre el so i calcula els valors característics del so
INTCON = 0b10100000; // Activem GIE i T0IE
for (char k = 0; k < 8; k++){
Sortida[1] = k+1; // Filera
Sortida[3] = k+1;
Sortida[5] = k+1;
if (valors[3]>=valormin){
Sortida[0] = fig[0][k]; // Vermells
Sortida[2] = fig[1][k]; // Verds
Sortida[4] = fig[2][k]; // Blaus
Envia3max(Sortida); // Ho envia al MAX7221
__delay_ms(1); // Donem temps
}
if (valors[3]<valormin){
Sortida[0] = fig[3][k]; // Vermells
Sortida[2] = fig[4][k]; // Verds
Sortida[4] = fig[5][k]; // Blaus
Envia3max(Sortida); // Ho envia al MAX7221
__delay_ms(1); // Donem temps
}
}
CompPolsador0(); // comprova si el Polsador0 està premut
}
}
}
void __interrupt() temporit(void){ // INTERRUPCIONS PEL TIMER0
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 CompPolsador0(void){ // comprovacio del polsador0
for (char k=11;k!=0; k--){ // farem la comprovació del polsador 10 vegades
if (Mode!=0){
if (Polsador0 == 0){
Mode=0; // canvi de mode al mode 0
Apaga(); // Apaga tots els LED de la matriu
__delay_ms(100); // retard de 0.1 segon
}
} else {
return; // sino es premut el polsador no passa res
}
}
}
// https:// www.geeksforgeeks.org/square-root-of-an-integer/
unsigned int floorSqrt(unsigned long x){ // funció que torna la part entera de la arrel quadrada
// Base cases
if (x == 0 || x == 1){
return x;
}
// Do Binary Search for floor(sqrt(x))
int start = 1,ans;
unsigned long end = x;
while (start <= end){
unsigned long mid = (start + end) / 2;
// If x is a perfect square
if (mid*mid == x){
return mid;
}
// Since we need floor, we update answer when mid*mid is
// smaller than x, and move closer to sqrt(x)
if (mid*mid < x){
start = mid + 1;
ans = mid;
} else { // If mid*mid is greater than x
end = mid-1;
}
}
return ans;
}
void registreCalSo(void){ // Registre el so i calcula els valors característics del so en un interval de uns 20 ms
FiTimer1 = 0; // Aquest bit es posarà a 1 quan el temporitzador acabi
// cal desactivar-lo des del programa
T1CON = 0b00100001; // Configuració de Timer1
// 10 - Factor d'escala de 4
// 1 - comença a comptar
TMR1H=255; // preselecció perque llegeixi un valor del so en 0.620 ms
TMR1L=100; // i per tant quan llegeixi 32 valors serà en un interval total de uns 20 ms
ADCON0 = 0b10100001; // Activa el conversor connectat a AN8 i AN2
valors[1] = 0; // Definim el maxim
valors[2] = 10000; // Definim el minim
unsigned long sum = 0; // Definim una variable per emmagatzemar la suma de tots els valors del so
for (int k = 0; k < 32; k++){ // Llegim 32 valors
while (FiTimer1 == 0) // Mira si Timer0 ha arribat a zero
; // Si no hi ha arribat, espera
TMR1H=255;
TMR1L=100;
FiTimer1 = 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
sum += Lectura[k]; // Els anem sumant
if (Lectura[k] > valors[1]){ // Comprovem si es el maxim
valors[1] = Lectura[k]; // Si ho es, guardem el valor
}
if (Lectura[k]< valors[2]){ // Comprovem si es el minim
valors[2] = Lectura[k]; // Si ho es, guardem el valor
}
}
unsigned long mean = sum/32; // Calculem la mitjana dels valors obtinguts del so
sum = 0; // Posem el sumatori a 0 per reutilitzar la variable
for (int k = 0; k < 32; k++){ // Llegim 32 valors
sum += (Lectura[k]-mean)*(Lectura[k]-mean); // Elevem al quadrat
}
// valors[0] = (unsigned int)sqrt(sum/32); // v.e.
valors[0] = (unsigned int)floorSqrt(sum/32); // calcul del valor eficaç i guardar-lo
// valor eficaç en una escala determinada
valors[3]=(valors[0]*100)/511; // ve_escala=(valors[1]*100)/511
return;
}
void menu(void){
Esborra(); // Esborra la pantalla;
EnviaL('M'); // Lletra
EnviaL('O'); // Lletra
EnviaL('D'); // Lletra
EnviaL('1'); // Lletra
EnviaL(' '); // Lletra
EnviaL('M'); // Lletra
EnviaL('O'); // Lletra
EnviaL('D'); // Lletra
EnviaL('2'); // Lletra
EnviaL(' '); // Lletra
EnviaL('M'); // Lletra
EnviaL('O'); // Lletra
EnviaL('D'); // Lletra
EnviaL('3'); // Lletra
Cursor(2,1); // Poscionem el cursor
EnviaL('M'); // Lletra
EnviaL('O'); // Lletra
EnviaL('D'); // Lletra
EnviaL('4'); // Lletra
__delay_ms(100); // retard de 0.1 segon
}
void escriuResultat(void){ // Escriu a la pantalla el ve_escala, max,min
Esborra(); // Esborra la pantalla;
Cursor(1,1); // Poscionem el cursor
EnviaL('V'); // Lletra
EnviaL('E'); // Lletra
Cursor(1,4); // Poscionem el cursor
escriuValor(valors[3]); // Escriure el valor eficaç a la pantalla
Cursor(1,7); // Poscionem el cursor
EnviaL('R'); // Lletra
EnviaL('A'); // Lletra
EnviaL('N'); // Lletra
EnviaL('G'); // Lletra
Cursor(1,12); // Poscionem el cursor
escriuValor(valors[1]-valors[2]); // Escrivim el rang del so
char bc; // Defim variable per emmagatzemar el nombre de blocs complets
char fb; // Defim variable per emmagatzemar files del ultim bloc
char Omega2[8] = {0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00000000}; // definim el caracter especial en blanc
bc = valors[3]%7;
fb = valors[3]/7;
for (char i=1;i<fb+1;i++){
Cursor(2, i); // Poscionem el cursor
EnviaL(2); // Envia el caracter especial del bloc sencer a la pantalla
}
for (char n=8-bc; n<8; n++){
Omega2[n-1] = 0b00011111; // omplim les files
}
Cursor(1,1); // Poscionem el cursor
DefCarac(0,Omega2);
Cursor(2,fb+1); // Poscionem el cursor
EnviaL(0); // Envia el caracter especial del bloc parcial a la pantalla
}
void DefCarac(char Numero, char Fileres[8]) { // Crea un caràcter definit per l'usuari
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 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; // Milers
Digits[4] = Valor / 10; // Desenes de milers
// Passem els dígits a ASCII
for (int 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') { // Mirem si el primer dígit és 0
Digits[4] = ' '; // Si ho és, hi posem un espai
if (Digits[3] == '0') { // I mirem si ho és el segon
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
if (Digits[k] != ' '){
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
}
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 TocaNota(char ValPR2, char ValCCPR1L, char ValDC1B) {
TRISC = 0b01100000; // Definim com volem les E/S del port C i continua el sonometre com a entrad
// 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 d?na 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 i continua el sonometre com a entrad
__delay_ms(200); // Retard de 0,2 s
TRISC = 0b01100000; // Posem RC5 (sortida del PWM) com a entrada i continua el sonometre com a entrada
// O sigui, silenci
__delay_ms(200); // Retard de 0,2 s
}
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 de la matriu
char Bytes[6]; // Els sis bytes que cal enviar
for (signed char j = 1; j <= 8; j++){ // Hem d'enviar 8 fileres
Bytes[1] = Bytes[3] = Bytes[5] = j; // Filera
Bytes[0] = Bytes[2] = Bytes[4] = 0x00; // Vermells, verds i blaus
Envia3max(Bytes); // Els envia
}
}

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