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 5

El programa del grup 5 a més de mostrar la temperatura i la humitat, permet programar uns llindars d'alarma. També té un mode d'espera que deixa el microcontrolador en repòs.

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 <string.h>				// LA NECESSITEM A LA FUNCIO EnviaSTR())
#include <xc.h>					// Carrega el fitxer de funcions necessari per al compilador XC8
#define _XTAL_FREQ  4000000			// La freqüència del rellotge és 4 MHz
#define Sens   RA5			// Li assigna un nom a l'adreça del sensor
unsigned char Visualit;				// Variable on guardem el que mostrara la pantalla
char Bloqueig;					// variables per modo espera
						// Variable que farà el bloqueig del programa
						// Si no val 0 es bloqueja
unsigned int Valor;				// Variable de treball
unsigned int Valormodi;
unsigned int Valormodi2;
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
int p;
char Digits[5];					// Vector amb el número dígit a dígit
						// Digits[0] és el decimal
char Fahrenheit;
char Negatiu;					// Guarda si el valor de la temperatura és negatiu o positiu
char Modi;
char Modi2;
char eshumitat;
char alarma;
						// Definició de les funcions que farem servir
char Sensor(void);				// Lectura del sensor. dona 0 si la suma de control és correcta
void EnviaL(char Caracter);			// Envia un caràcter
void EnviaSTR(char cadena[]);
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 Polsador(void);				// Funció de lectura dels polsadors
char Polsad;
void TocaNota(char ValPR2, char ValCCPR1L, char ValDC1B);
void enviavalor(int Valor);
void corretextalarma(void);
void main(void) {
	Bloqueig = 1;				// inicialment esta en repos
	TRISC = 0b00100000;			// Definim com volem les E/S del port C
	TRISB = 0;				// tot el port b es de sortida
	ANSELH = 0;				// Desactiva les altres entrades analògiques
	ANSEL = 0b00000101;			// Configura AN0 i AN2 com entrada analògica
	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
	Fahrenheit = 0;				// celsius*1.8+32
	Modi = 0;
	Modi2 = 0;
	Valormodi = 300;
	Valormodi2 = 100;
	alarma = 0;
	p = 0;
	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
	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ó
	OPTION_REG = 0b11000000;		// interrupcio a l'activacio
	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
    while (1) {					// Inici del bucle de programa
		Polsad = Polsador();
		if (Modi == 1) {
			p = 0;
			PORTC = 0b00000110;
			if (RA3 == 0) {
				TocaNota(212, 106, 2);
				Modi2 = ~Modi2;
			}
			Esborra();
			if (Modi2 == 0) {
				EnviaSTR("Tmax-> ");
				Cursor(2, 0);
				EnviaSTR("Tmin : ");
				if (Polsad == 5) {		// Sumar
					Valormodi++;
				}
				if (Polsad == 4) {		// Restar
					Valormodi--;
				}
				if (Polsad == 3) {
					Valormodi = Valormodi + 10;
				}
				if (Polsad == 2) { //Restar
					Valormodi = Valormodi - 10;
				}
			}
			if (Modi2 == 1) {
				EnviaSTR("Tmax : ");
				Cursor(2, 0);
				EnviaSTR("Tmin-> ");
				if (Polsad == 5) {		// Sumar
					Valormodi2++;
				}
				if (Polsad == 4) {		// Restar
					Valormodi2--;
				}
				if (Polsad == 3) {
					Valormodi2 = Valormodi2 + 10;
				}
				if (Polsad == 2) {		// Restar
					Valormodi2 = Valormodi2 - 10;
				}
			}
			eshumitat = 0;
			Valor = Valormodi;
			Cursor(0, 7);		// Posició
			enviavalor(Valor);
			Valor = Valormodi2;
			Cursor(2, 7);		// Posició
			enviavalor(Valor);
			Cursor(0, 16);
			if (Valormodi < Valormodi2) {
				EnviaL('!');
				PORTC = 0b00001111;
			}
			Cursor(2, 16);
			if (Valormodi < Valormodi2) {
				EnviaL('!');
				PORTC = 0b00001111;
			}
			__delay_ms(200);
			if (Polsad == 1) {
				Modi = 0;
				alarma = 1;
			}
		}
		if (Modi == 0) {
			OSCCON = 0b01111000;	// IRCF = 111, rellotge a 8 MHz
			Error = Sensor();
			OSCCON = 0b01101000;	// IRCF = 111, rellotge a 8 MHz
			if (RA3 == 0) {
				Bloqueig = 1;
			}
			if (Bloqueig == 1) {
				Esborra();	// esborra la pantalla i posa el cursor en (0,0)
						// MISSATGE BLOQUEIG 
				p = 0;
				EnviaSTR("PRESS BTN1");
				__delay_ms(100);
				INTCON = 0b00010000;
				PORTC = 0b00000000;		// PORT C(LEDS)APAGAT
				ANSEL = 0;	// desactiva entrades analogiques 
				ANSELH = 0;	// Desactiva les altres entrades analògiques
				SLEEP();
				ANSEL = 0b00000101;		// Configura AN0 i AN2 com entrada analògica
				Bloqueig = 0;
				PORTC = 0b00000100;
				TocaNota(238, 119, 2);		// Valor que correspon aproximadament a do3
			}
						// AQUI POSAR COSES FORA DEL BLOQUEIG
			if (Polsad == 1) {
				TocaNota(212, 106, 2);
				PORTC = 0b000000110;
				alarma = 1;
				p = 0;
			}
			if (Polsad == 3) {
				TocaNota(212, 106, 2);
				PORTC = 0b000000100;
				alarma = 0;
			}
			if (Polsad == 4) {
				Fahrenheit = 0;
				TocaNota(212, 106, 2);		// Valor que correspon aproximadament a re3
				Valormodi = 300;
				Valormodi2 = 100;
			}
			if (Polsad == 5) {
				Fahrenheit = 1;
				TocaNota(212, 106, 2);		// Valor que correspon aproximadament a re3
				Valormodi = (300 * 1.8 + 320);
				Valormodi2 = (100 * 1.8 + 320);
			}
			if (Error == 0) { // Llegeix el sensor i si és correcte segueix
						// Enviem la humitat
				Valor = Lectura[2];		// Humitat 
				Esborra();
				Cursor(2, 0);	// Posició
				EnviaL('H');
				Cursor(2, 2);
				eshumitat = 1;
				enviavalor(Valor);
						// Enviem Temperatura 
				Valor = Lectura[1];		// Temperatura
				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
				}
				if (Fahrenheit == 1) {
					Valor = (Valor * 1.8 + 320);
				}
				Cursor(0, 0);			// Posició
				EnviaL('T');
				Cursor(0, 2);
				eshumitat = 0;
				enviavalor(Valor);
				if (Valormodi < Valor) {
					if (alarma == 1) {
						TocaNota(212, 106, 2);		// Valor que correspon aproximadament a re3
						corretextalarma();
					}
				}
				if (Valormodi2 > Valor) {
					if (alarma == 1) {
						TocaNota(400, 63, 2); 
						TocaNota(400, 63, 2);
						TocaNota(400, 63, 2);
						corretextalarma();
					}
				}
				Cursor(0, 0);	// Posició
				if (Polsad == 2) {
					Modi = 1;
				}
			} else {
				Esborra();	// Posició
				EnviaSTR("ERROR DE LECTURA error code: ");
				Error = Error + '0';		// Passa el valor a ASCII
				EnviaL(Error);	// Número
			}
			__delay_ms(500);	// Retard d'1 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 bytes
						// 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
}
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 EnviaSTR(char cadena[]) {			// PER A QUE FUNCIONI CAL CADENA "string"==> "" I NO ''.
	int j;
	j = strlen(cadena);
	for (int i = 0; i < j; i++) {
		if (p + i < 17) {
			EnviaL(cadena[i]);
		}
	}

}
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;
}
						// Funcio que fa sonar sons al brunzidor
void TocaNota(char ValPR2, char ValCCPR1L, char ValDC1B) {
	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
	__delay_ms(200);			// Retard de 0,2 s
	TRISC = 0b00100000;			// Posem RC5 (sortida del PWM) com a entrada
						// O sigui, silenci
	__delay_ms(200);			// Retard de 0,2 s
}
void enviavalor(int Valor) {
	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
	for (int j = 0; j < 5; j++) {		// 5 dígits
		Digits[j] = Digits[j] + '0';	// Li sumem el codi ASCII de 0
	}					// Això és la temperatura multiplicada per 10
	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
			}			// Els dos darrers zeros els mostrarem sempre
		}
	}
	if (Negatiu) {
		Digits[4] = '-';		// Si és negatiu, posem el -
	}
	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 (eshumitat == 0) {
		if (Fahrenheit == 0) {
			EnviaL(0b11011111);	// Graus
			EnviaL('C');		// Lletra
		}
		if (Fahrenheit == 1) {
			EnviaL(0b11011111);	// Graus
			EnviaL('F');
		}
	} else {
		EnviaL('%');
	}
}
void corretextalarma(void) {
	for (int k = 16; k > 0; k--) {
		Esborra();			// Posició
		EnviaL('T');
		Cursor(0, 2);
		eshumitat = 0;
		enviavalor(Valor);
		Cursor(2, k);
		p = k;
		if (Valormodi2 > Valor) {
			EnviaSTR("Warning: Tmin!");
			__delay_ms(100);

		}
		if (Valormodi < Valor) {
			EnviaSTR("Warning: Tmax!");
			__delay_ms(100);
		}
		Polsad = Polsador();
		if (Polsad == 3) {
			k = 0;
			alarma = 0;
			PORTC = 0b00000100;
		}
	}
}

 

 

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