Programació en C del PIC 16F690

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

Sensor de temperatura i humitat

Programa del grup 4

El grup 4 va fer un programa que mostrava la humitat i la temperatura, aquesta en kelvin, graus Celsius i graus Fahrenheit.

El programa d'aquest grup é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 necessari per al compilador XC8
#define Polsador   RA3		// Li assigna un nom a l'adreça del polsador
#define Sens   RA5			// Li assigna un nom a l'adreça del sensor
#define _XTAL_FREQ  4000000			// La freqüència del rellotge és 4 MHz
unsigned char Vegada = 1;
unsigned char Mode = 0;
unsigned char Surt = 0;
unsigned char Stop = 0;	 
unsigned int Valor;				// Variable de treball
unsigned int Valormax=600;
unsigned int Valorguardat=600;; 
unsigned int Error;				// Error de lectura
unsigned int Lectura[3];			// Valor llegit
						// Lectura[0] és la suma de comprovació
						// Lectura[1] és la temperatura
						// Lectura[2] és la humitat
unsigned int Udc;				// Unitats,decenes, centenes de la suma valor max
char Digits[5];					// Vector amb el número dígit a dígit
						// Digits[0] és el decimal
bit Negatiu;					// Guarda si el valor de la temperatura és negatiu o positiu
void HumiTemp(void);
void Unitator(void);
void Unitatormax(void);
void Ascii (void);
void TocaNota(char ValPR2, char ValCCPR1L, char ValDC1B, char n);
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)
char Sensor(void);				// Lectura del sensor. dona 0 si la suma de control és correcta

char Polsadorse(void);				// Funció de lectura dels polsadors
char Polsad;					// Polsador que s'ha premut
void main (void){
						// TEMPERATURA I HUMITAT
	ANSEL = 0b00000101;			// Configura AN0 com entrada analògica
	ANSELH = 0;				// Desactiva les altres entrades analògiques
	TRISB = 0;				// Tot el port B és de sortida
	TRISA = 0b11011111;			// Tot el port A és d'entrada excepte, de moment, RA5
	PORTA = 0b00100000;			// RA5 a 1
	T1CON = 0b00100001;			// Configuració de Timer1
						// Com a temporitzador basat en rellotge
						// 10 - Factor d'escala de 4
						// TMR1L s'incrementarà cada 2 us
	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ó
	__delay_ms(1000);			// Retard d'1 s
	Esborra();				// Esborra la pantalla i posa el cursor a l'inici
						// PANTALLA
	ANSELH = 0;				// Desactiva les altres entrades analògiques
	TRISB = 0;				// Tot el port B és de sortida
	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ó
						// BRUNZIDOR
	TRISC = 0b00100000;			// Definim com volem les E/S del port C
						// RC5 (sortida del PWM), de moment, com a entrada
	PORTC = 0;				// Desactiva les sortides del port C
	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
	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
						// POLSADORS EN SERIE
	ADCON1 = 0b00010000;			// Posa el conversor a 1/8 de la freqüència
	ADCON0 = 0b00001001;			// Activa el conversor A/D connectat a AN2
						// amb el resultat justificat per l'esquerra
	TocaNota(133, 68, 0, 4);		// Bb
	TocaNota(149, 75, 0, 4);		// Ab
	TocaNota(168, 84, 2, 6);		// Gb
	TocaNota(168, 84, 2, 2);		// Gb
	TocaNota(168, 84, 2, 2);		// Gb
	TocaNota(224, 112, 2, 4);		// Db
	TocaNota(168, 84, 2, 4);		// Gb
	TocaNota(149, 75, 0, 4);		// Ab
	TocaNota(133, 68, 0, 6);		// Bb
	TocaNota(149, 75, 0, 2);		// Ab
	TocaNota(168, 84, 2, 2);		// Gb 
	Mode=1;
	while (1){				// Bucle infinit
		Polsad = Polsadorse();		// Llegim els polsadors
		if (Mode != 0){			// Si ja estem al LED 3, no podem rodar més
			HumiTemp();
			if (Lectura[1]>=Valorguardat){
				while(Stop==0){
					Polsad = Polsadorse();	
					TocaNota(133, 68, 0, 8);		// Bb
					TocaNota(168, 84, 2, 8);		// Gb
					__delay_ms(100);	
					if (Polsad!=0){
						Stop=1;
					}
				}
			}
		}
		if (Polsad == 1){
			Mode=0;
			Valorguardat=600;	 
			Vegada=1;
			while(Mode==0){
				Polsad = Polsadorse();		// Llegim els polsadors
				if (Polsad==2){
					if(Vegada==1){
						Udc=1;
						Vegada++;
						TocaNota(133, 67, 0, 2);
					} else if(Vegada==2){
						Udc=10;
						Vegada++;
						TocaNota(133, 67, 0, 2);
					} else if(Vegada==3){
						Udc=100;
						Vegada++;
						TocaNota(133, 67, 0, 2);
					} else if(Vegada==4){
						Udc=1000;
						Vegada=1;
						TocaNota(133, 67, 0, 2);
					}
				}
				if (Polsad==3){
					Valorguardat=Valorguardat+Udc;
					TocaNota(133, 67, 0, 2);
				}
				if (Polsad==4){
					Valorguardat=Valorguardat-Udc;
					TocaNota(133, 67, 0, 2);
				}
				Valormax=Valorguardat;
				Unitatormax();	//Organitza el vector digits en unitats, decenes
				Ascii();	// Convertim a Ascii 
				Cursor(1, 1);	// Posició
				for (int j = 4; j > 0; j--){	// 4 dígits (el 5è és el decimal)
					EnviaL(Digits[j]);	// Número
				}
				EnviaL(',');			// Coma
				EnviaL(Digits[0]);		// Número
				EnviaL(' ');			// Espai
				EnviaL(0b11011111);		// Tant per cent
				EnviaL('C');			// Espai
				if (Polsad==5){
					Mode=1;
				}
				__delay_ms(500);	    	// Retard per permetre la visualització
			}
			Stop=0;
		}
		if (Polsador == 0){
			if (Mode<3){
				Mode++;
				TocaNota(133, 67, 0, 2);
			} else{
				Mode=1;
				TocaNota(133, 67, 0, 2);
			}
		} 
		__delay_ms(500);		// Retard d'1 s
	}
}
char Polsadorse(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 HumiTemp(void){
	OSCCON = 0b01111000;			// IRCF = 111, rellotge a 8 MHz
	Error = Sensor();
	OSCCON = 0b01101000;			// IRCF = 110, rellotge a 4 MHz
	if (Error == 0) {			// Llegeix el sensor i si és correcte segueix
		Valor = Lectura[2];		// Humitat            
		Unitator();			// Organitza el vector digits en unitats, decenes
		Ascii();			// Convertim a Ascii 
		Cursor(1, 1);			// Posició
		for (int j = 4; j > 0; j--){	// 4 dígits (el 5è és el decimal)
			EnviaL(Digits[j]);	// Número
		}
		EnviaL(',');			// Coma
		EnviaL(Digits[0]);		// Número
		EnviaL(' ');			// Espai
		EnviaL('%');			// Tant per cent
		EnviaL(' ');			// Espai
		if (Mode==1){
			Valor = Lectura[1];	// Temperatura Centigrads
		}
		if (Mode==2){
			Valor = Lectura[1]+2731;		// Temperatura kelvin
		}
		if (Mode==3){
			Valor = (Lectura[1]*1.8)+320;		// Temperatura Farenheit
		}
		if (Valor >= 32768) {		// Si el bit més significatiu està activat és negatiu
			Negatiu = 1;		// És negatiu
			Valor = Valor -32768;	// Agafem el valor absolut
		} else {
			Negatiu = 0;		// És positiu
		}
		Unitator();			// Organitza el vector digits en unitats, decenes...
		Ascii();			// Convertim a Ascii 
		if (Negatiu) {
			Digits[4] = '-';	// Si és negatiu, posem el -
		}
		Cursor(2, 1);			// Posició
		for (int j = 4; j > 0; j--){	// 4 dígits (el 5è és el decimal)
			EnviaL(Digits[j]);	// Número
		}
		EnviaL(',');			// Coma
		EnviaL(Digits[0]);		// Número
		EnviaL(' ');			// Espai
		if (Mode==1){
			EnviaL(0b11011111);	// Graus
			EnviaL('C');		// Lletra
		}
		if (Mode==2){
			EnviaL('K');		// Lletra
			EnviaL(' ');		// Espai
		}
		if (Mode==3){
			EnviaL(0b11011111);	// Graus
			EnviaL('F');		// Lletra
		}
	} else {
		Cursor(1, 1);			// Posició
		EnviaL('E');
		EnviaL('r');
		EnviaL('r');
		EnviaL('o');
		EnviaL('r');
		EnviaL(' ');
		Error = Error + '0';		// Passa el valor a ASCII
		EnviaL(Error);			// Número
	}
}
void Unitator (void){
	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 
}
void Unitatormax (void){
	Digits[0] = Valormax % 10;		// Unitats
	Valormax = Valormax / 10;
	Digits[1] = Valormax % 10;		// Desenes
	Valormax = Valormax / 10;
	Digits[2] = Valormax % 10;		// Centenes
	Valormax = Valormax / 10;
	Digits[3] = Valormax % 10;		// Milers
	Digits[4] = Valormax / 10;		// Desenes de milers
}
void Ascii(void){
	for (int j = 0; j < 5; j++){		// 5 dígits
		Digits[j] = Digits[j] + '0';	// Li sumem el codi ASCII de 0
	}
	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
			}
		}
	}
}
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
}
void TocaNota(char ValPR2, char ValCCPR1L, char ValDC1B, char n) {
	TRISC = 0b00100000;			// 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 = 0b00000000;			// Posem RC5 (sortida del PWM) com a sortida
	while(n--){				// trivial overhead
		__delay_ms(50);
	}
	TRISC = 0b00100000;			// Posem RC5 (sortida del PWM) com a entrada
						// O sigui, silenci
	__delay_ms(200);	   	 	// Retard de 0,2 s
}
char Sensor(void) {
	char Bytes[5];				// Vector per a guardar els cinc bytes que envia el sensor
	char Temps;				// Guarda el valor de TMR1L
	for (int j = 0; j < 5; j++){		// 5 bytes
		Bytes[j] = 0;			// Posem el vector a zero
	}
	TRISA = 0b11011111;			// Tot el port A és d'entrada excepte, de moment, RA5
	PORTA = 0b00000000;			// RA5 a 0
	__delay_ms(2);				// Retard de 2 ms
	PORTA = 0b00100000;			// RA5 a 1
	__delay_us(15);				// Retard de 15 us
						// Un cop activat, esperem la resposta
	TRISA = 0b11111111;			// Tot el port A és d'entrada, inclosa RA5
						// Esperem a rebre el pols d'inici
						// Primer un L d'uns 80 us
						// Per començar, s'ha de desactivar l'entrada
						// i s'ha de reactivar al cap d'entre 70 i 90 us
	while (Sens)				// S'ha desactivat l'entrada?
		;				// No, doncs esperem
	TMR1H = 0;
	TMR1L = 0;				// Sí, doncs comencem a comptar el temps
	while ((!Sens) && (TMR1L < 45))		// Esperem que s'activi l'entrada
		;				// O passin més de 90 us
	Temps = TMR1L;				// Agafa el valor de TMR1L
	TMR1H = 0;
	TMR1L = 0;				// Torna a començar a comptar el temps
	if (Temps > 45) {			// És més gran
		return 1;			// Error 1 - L inicial massa llarg
	}
	if (Temps < 35) {			// Mirem que no sigui menor que 70 us
		return 2;			// Error 2 - L inicial massa curt
	}
						// L inicial ja està
	while (Sens && (TMR1L < 45))		// Esperem a que es desactivi l'entrada
		;				// O passin més de 90 us
	Temps = TMR1L;				// Agafa el valor de TMR1L
	TMR1H = 0;
	TMR1L = 0;				// Torna a començar a comptar el temps
	if (Temps > 45) {			// És més gran
		return 3;			// Error 3 - H inicial massa llarg
	}
	if (Temps < 35) {			// Mirem que no sigui menor que 70 us
		return 4;			// Error 4 - H inicial massa curt
	}
						// H inicial ja està
						// Ara hem de rebre els bits
	TMR1H = 0;
	TMR1L = 0;				// Torna a començar a comptar el temps
	for (int j = 0; j < 5; j++){		// 5 bytes
		for (int k = 0; k < 8; k++){	// 8 bits a cada byte
			Bytes[j] = 2 * Bytes[j];		// Rodem a l'esquerra el bit anterior
								// per deixar lloc al nou
								// Si no n'hi havia cap no canvia res
								// ja que estava a zero
						// Esperem a rebre un bit
						// Primer un L d'uns 80 us
						// Ara l'entrada està a zero
						// S'ha d'activar al cap d'entre 10 i 90 us
			while ((!Sens) && (TMR1L < 45))		// Esperem que s'activi l'entrada
				;		// O passin més de 90 us
			Temps = TMR1L;		// Agafa el valor de TMR1L
			TMR1H = 0;
			TMR1L = 0;		// Torna a començar a comptar el temps
			if (Temps > 45) {	// És més gran
				return 5;	// Error 5 - Valor L del bit massa llarg
			}
			if (Temps < 5) {	// Mirem que no sigui menor que 10 us
				return 6;	// Error 6 - Valor L del bit massa curt
			}
						// Ja tenim el valor L del bit. Ara esperem un H
			while (Sens && (TMR1L < 40))		// Esperem a que es desactivi l'entrada
				;		// O passin més de 80 us
			Temps = TMR1L;		// Agafa el valor de TMR1L
			TMR1H = 0;
			TMR1L = 0;		// Torna a començar a comptar el temps
			if (Temps > 40) {	// És més gran
				return 7;	// Error 7 - Valor H del bit massa llarg
			}
			if (Temps < 6) {	// Mirem que no sigui menor que 12 us
				return 8;	// Error 8 - Valor H del bit massa curt
			}
						// Ja hem comprovat que no sigui massa curt ni massa llarg
						// Si és més petit que 38 us és un pols curt, o sigui un 0
						// Si és curt no cal fer res, el 0 ja hi és
						// Si és més gran que 60 us és un pols llarg, o sigui un 1
			if (Temps > 19) {	// És més gran que 38 us
						// Sí, doncs no és un pols curt
				if (Temps > 30) {		// És més gran que 60 us
						// És un pols llarg
					Bytes[j] = Bytes[j] + 1;			// Entrem un 1
				} else {
					return 9;		// Error 9 - Valor H del bit incorrecte
				}
			}
		}
	}
						// Ja tenim els 5 bytes. Fem la suma de comprovació
						// Cal sumar els quatre primers bytea
						// Però sense portar-ne
	Valor = 0;				// Primer la posem a zero
	for (int j = 0; j < 4; j++){		// 4 bytes
		Valor = Valor + Bytes[j];	// Sumem un dels quatre elements
		if (Valor > 255) {		// Mirem si és més gran del que cap a un byte
						// Si és més gran, només pot haver activat un bit del segon byte
						// el que correspon a 256
			Valor = Valor -256;	// Restem les que en portàvem
		}
	}
	if (Valor != Bytes[4]) {		// No coincideixen
		return 10;			// Error 10 - Falla la suma de comprovació
	}
	Lectura[0] = Bytes[4];			// Suma de comprovació
	Lectura[1] = 256 * Bytes[2] + Bytes[3];			// Temperatura
	Lectura[2] = 256 * Bytes[0] + Bytes[1];			// Humitat
	return 0;				// Recepció correcta
}

 

 

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