Programació en C del PIC 16F690 amb PICkit 2

Referència Trucs Perifèrics   Recursos CITCEA
Tutorial Exemples Projectes   Inici

Sensor de so

En realitat es tracta d'un micròfon i un petit amplificador muntat en una placa, com aquest que permet ajustar l'amplificació del senyal.

Sensor de so  [AF]

El sensor es connecta amb tres fils: els d'alimentació (positiu, VCC, i negatiu, GND) i el de senyal que connectarem a una entrada analògica.

El sensor ens dóna una lectura proporcional al senyal de so, que és una ona. Atès que les entrades analògiques només admeten tensions positives, el sensor suma la meitat de la tensió d'alimentació al senyal de sortida. Això vol dir que en silenci llegirem un valor de 511 i quan hi ha so tindrem valors que oscil·laran al voltant d'aquest nombre. En el nostre cas connectarem el sensor a l'entrada AN8 (pota RC6).

Farem un programa de prova que ens permeti llegir 32 valors del sensor durant un temps de 20 ms. Els valors llegits els mostrarem a una pantalla LCD. Si dividim els 20 ms en 32 parts ens surt que cal llegir un valor cada 625 μs. Per comptar el temps farem servir el Timer 0. Ens interessa posar-li un factor de configuració que tingui el màxim nombre d'iteracions possible (per tenir la màxima precisió) però que sigui inferior a 256. La presselecció que candrà posar-hi serà la diferència entre 256 i el nombre d'iteracions. Veiem algun cas:

Bits Escala Període Iteracions Preselecció
111 1/256 256 μs 2 254
... ... ... ... ...
010 1/8 8 μs 78 178
001 1/4 4 μs 156 100
000 1/2 2 μs 313 ---

Ens quedem amb el penúltim valor. El temporitzador partirà d'un valor de 100 i s'anirà incrementant cada 4 μs. Quan arribi a zero hauran passat 624 μs. Cada cop que el temporitzador acabi de comptar el reiniciarem, llegirem l'entrada analògica i guardarem el resultat en un vector. Llegirem 32 valors de dos bytes cada un; en total 64 bytes. Quan l'usuari premi el polsador, escriurem els 32 valors llegits a la pantalla. Inicialment els quatre primers a la primera línia (quatre caràcters per valor) i els quatre següents a la segona; amb això en tindrem 8. Quan premem el polsador n'escriurem 8 més i així fins que al quart cop ja els haurem escrit tots.

#pragma config FOSC = INTRCIO, WDTE = OFF, PWRTE = OFF, MCLRE = OFF, CP = OFF, 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
unsigned int Lectura[32];			// Per guardar els valors llegits
int pos = 0;					// Punter del vector
						// Definició de les funcions que farem servir 
void Linia(void);				// Escriu una línia de resultats
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
						// (filera 1 a 2 i columna 1 a 32, segons pantalla)
void main (void) {
	OPTION_REG = 0b1000000;			// Configuració de Timer0
						// 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
	RCSTAbits.SPEN = 1;			// Activa comunicació sèrie
	TXSTAbits.TXEN = 1;			// Activa comunicació
	ANSEL = 0b00000001;			// Configura AN0 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
	EnviaL('P');				// Lletra
	EnviaL('r');				// Lletra
	EnviaL('e');				// Lletra
	EnviaL('m');				// Lletra
	ADCON0 = 0b10100001;			// Activa el conversor connectat a AN8
						// amb el resultat justificat per la dreta
	__delay_ms(400);			// Retard de 0,4 s
	TMR0 = 100;				// Presselecció de 100, que són 156 iteracions
						// (amb un factor 4 dóna 624)
	INTCONbits.T0IF = 0;			// Desactivem el bit de final de temporització
						// Per assegurar la desconnexió del programador
	for (int k = 0; k < 32; 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
	}
						// Anem a escriure a la pantalla
	for (int k = 0; k < 4; k++){		// A cada pantalla 1/4 dels resultats
		while (PORTAbits.RA3 == 1) 	// Espera a que estigui premut
			;			// No fa res
		__delay_ms(200);		// Retard de 0,2 s
		while (PORTAbits.RA3 == 0) 	// Espera a que no estigui premut
			;			// No fa res
		__delay_ms(200);		// Retard de 0,2 s
		Esborra();			// Esborra la pantalla;
		Linia();			// Escriu una línia de resultats
		Cursor(2, 1);			// Posició
		Linia();			// Escriu una línia de resultats
	}
	while (1)				
		;				// Es bloqueja aquí
}
void Linia(void){
	for (int k = 0; k < 4; k++){		// Escrivim quatre valors
		escriuValor(Lectura[pos++]);	// Escriu un valor a la pantalla
	}
}
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 = 3; k >= 0; k--){		// Només escrivim quatre valors
		EnviaL(Digits[k]);		// Escriu un dígit a la pantalla
	}
}
void EnviaL(char Caracter) {
	TXREG = Caracter;			// Agafa el caràcter i l'envia
	_delay(5);				// 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
}

 

 

Licencia de Creative Commons
Esta obra de Oriol Boix está licenciada bajo una licencia no importada Creative Commons Reconocimiento-NoComercial-SinObraDerivada 3.0.