Programació en C del PIC 16F690

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

Marcador esportiu

Programa del grup 4

En aquest cas el marcador anava destinat al futbol. La funció dels LED és indicar els modes:

LED Significat
3 S'està jugant la segona part
4 S'està jugant la primera part

El potenciòmetre permet passar d'un mode a l'altre. La funció dels polsadors és la següent:

Polsador Funció
0 Reinicia el marcador
1 Afegeix un gol a l'equip local
2 Afegeix un gol a l'equip visitant
3 Sense ús
4 Canvia de part
5 Inicia o atura el temps

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"
#include <xc.h>					// Carrega el fitxer d'adreces i paràmetres del PIC 16F690
#define _XTAL_FREQ 4000000			// La freqüència del rellotge és 4 MHz
#define Boto RA3			// Li assigna un nom a l'adreça del polsador
#define FiTimer0 INTCONbits.T0IF		// Li assigna un nom al bit que indica el final del Timer 0
#define Limit_Descarta 17			// Limit postescalador (Originalment 20 - Sense Interupcions 17)
#define SensPot 5				// Sensibilitat del Potenciòmetre (menys -> +sensible)
#define V1 (char)(Limit_Descarta/4)
#define V2 (char)(2*Limit_Descarta/4)
#define V3 (char)(3*Limit_Descarta/4)
	// a=target variable, b=bit number to act upon 0-n (Per a modificar un sol bit d'un byte)
#define BIT_SET(a,b) ((a) |= (1<<(b)))
#define BIT_CLEAR(a,b) ((a) &= ~(1<<(b)))
#define BIT_FLIP(a,b) ((a) ^= (1<<(b)))
#define BIT_CHECK(a,b) (!!((a) & (1<<(b)))) 
char Digits[5];					// Variable del vector de caràcters
unsigned char Part;				// Part del partit
unsigned char Gol_L;				// Gols Local
unsigned char Gol_V;				// Gols Visitant
char Polsad;					// Resultat de Polsador()
unsigned int Time;				// Temps en s
char Tex;					// Comptador temps extra 1 -> actiu | 0 -> inactiu
char mode;					// Temps: 0 -> estatic | 1 -> creixent | 2 -> decreixent
char Busy;					// 0 es pot processar acció, 1 esperant a que es deixi de premer el boto
char Descarta;					// Variable del postescalador
char ExLim;					// Temps Extra Màxim
char Pot;					// Últim valor del potènciometre
						// Definició de les funcions que farem servir
void EnviaL(char Caracter);			// Envia un caràcter
void EnviaV(char L1, char L2, char L3, char L4, char L5);	// Envia 5 caràcters
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)
void DefCarac(char Numero, char Fileres[8]);	// Crea un caràcter definit per l'usuari
char Polsador(void);				// Retorna el polsador premut 1 a 5 (0 si no n'hi ha cap)
void TimeUpdate(void);				// Actualitza el temps mostrat a la pantalla
void TocaNota(char ValPR2, char ValCCPR1L, char ValDC1B);	// Toca un sò amb el brunzidor
void Input(char Val);				// Processa la interacció amb els botons
void ResetToPart(void);				// Reseteja els comptadors per al canvi de part
void Reset(void);				// Reseteja tots els comptadors
void CheckPot(void);				// Mira si ha canviat la posició del potenciòmetre
void main (void) {
						// I/O SETUP
	TRISC = 0;				// Posa els LEDs del port C com a sortida
	TRISB = 0;				// Tot el port B és de sortida
	TRISA = 0xFF;				// Posa el boto del port A com a entrada
	ANSEL = 0b00000101;			// Configura AN0 i AN2 com entrada analògica
	ANSELH = 0;				// Desactiva les altres entrades analògiques
	ADCON1 = 0b00010000;
	ADCON0 = 0b00001001;			// Activa el conversor A/D connectat a AN2
						// TIMER SETUP
	OPTION_REG = 0b10000111;		// Configuració de Timer0
	FiTimer0 = 0;				// Aquest bit es posarà a 1 quan el temporitzador acabi
	TMR0 = 61;
	Descarta = 0;				// Variable del postescalador a 0
						// PWM SETUP
	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
						// LCD SETUP
	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(20);
	Reset();				// Posem tots els comptadors a 0 i la pantalla en el estat inicial
						// MAIN LOOP
	while(1){
		if (Boto == 0)
			Reset();
		if(Descarta == V1 || Descarta == V2 || Descarta == V3 || Descarta == Limit_Descarta || mode == 0){
						// Es mira els botons 4 vegades per segon o a cada cicle si el temps està parat
			Polsad = Polsador();	// Mira si hi ha algun polsador premut
			Input(Polsad);		// Calcula l'acció corresponent
		}
		if (Time == 0 && mode == 2)	// Si s'ha acabat el compte enrere para el temps (per als finals dels descansos)
			mode = 0;
		if (FiTimer0 == 1)
			CheckPot();
		if(mode != 0){
			FiTimer0 = 0;
			TMR0 = 61;
			if(Descarta == Limit_Descarta){		// Post escalador
				TimeUpdate();
				Descarta = 0;
			} else
				++Descarta;
		}
	}
	_delay(20);
}
void Input(char Val){
	if (Busy == 0){				// Comprovem que no s'estigui processant cap acció anterior
		if(Val == 1){			// Cas Polsador 1
			Busy = 1;
			TocaNota(212, 106, 2);	// Nota Re
			++Gol_L;		// Suma gol a l'equip local
			if (Gol_L == 10)	// Si hi ha 10 gols o més mostra només la unitat (molt poc probable)
				Gol_L = 0;
			Cursor(2,3);		// Actualitza la pantalla
			EnviaL(Gol_L+'0');
		} else if (Val == 2){		// Cas Polsador 2
			Busy = 1;
			TocaNota(189, 95, 0);	// Nota Mi
			++Gol_V;
			if (Gol_V == 10)
				Gol_V = 0;
			Cursor(2,7);
			EnviaL(Gol_V+'0');
		} else if (Val == 3){		// Cas Polsador 3
			Busy = 1;
			Time = 2690;		// Posa els temps a uns segons del temps extra (per a depuració)
			TimeUpdate();
		} else if (Val == 4){		// Cas Polsador 4
			Busy = 1;
			TocaNota(126, 63, 2);	// Nota Si
			_delay(10);
			TocaNota(126, 63, 2);	// Nota Si
			if (mode != 2){		// Si estem amb el temps actiu i creixent
				if (Part == 1){			// Si estem a la 1a part
					PORTC = 0b00000100;
					Part = 2;
				} else {			// Si estem a la 2a part
					PORTC = 0b00001000;
					Part = 1;
				}
				Time = 900;// Time = 900s = 15'
				mode = 2;	// Compte enrere descans
				ResetToPart();
			} else if (mode == 2)	// Si estem en temps de descans acaba'l
				Time = 1;
		} else if (Val == 5){		// Cas Polsador 5 -- Depuració
			Busy = 1;
			TocaNota(158, 79, 0); 	// Nota Sol
			if (mode == 1) 		// Alternar temps avança - aturat
				mode = 0;	 
			else if (mode == 0)
				mode = 1;
		}
	} else if (Val == 0){
		Busy = 0;
	}
}
void ResetToPart(void){
Tex = 0;
	Cursor(1,3);
	EnviaV('L',' ','-',' ','V');
	Cursor(1,10);
	EnviaV('0','0','.','0','0');
	Cursor(2,9);
	EnviaV(' ',' ',' ',' ',' ');
	EnviaL(' ');
	_delay(1000000);
						// WAIT START
	FiTimer0 = 0;				// Reiniciem el temporitzador
	TMR0 = 61;
	Descarta = 0;
	Polsad = 0;
}
void Reset(void){
	Esborra();
						// INITIAL CONF
	PORTC = 0b00001000;			// Configuracio inicial dels LEDs
	Part = 1;				// Configuracio inicial Part
	Gol_L = 0;				// Configuracio inicial gols locals
	Gol_V = 0;				// Configuracio inicial gols visitant
	Busy = 0;				// Pot processar una acció
	mode = 0;				// Configuracio inicial Temps (parat)
	Cursor(2,3);
	EnviaV('0',' ',':',' ','0');
	Time = 0;
	ResetToPart();
}
						// Funcions Pantalla
void EnviaL(char Caracter) {
	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
}
void EnviaV(char L1, char L2, char L3, char L4, char L5) {
	char Vector[5] = {L1, L2, L3, L4, L5};
	for (char j = 0; j < 5; j++){
		TXREG = Vector[j];		// 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
	}
}
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
	_delay(10);
	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 TimeUpdate(void){
	if (mode == 0)				// Temps congelat
		return;
	else if (mode == 1){			// Temps avança
		Time++;
		if(Time == 2701){
			Tex = 1;
			Time = 1;
			Cursor(2,12);
			EnviaL('.');
			Cursor(2,9);
			EnviaL('+');
		}
	} else if (mode == 2)			// Temps retrocedeix
		Time--;
						// LCDUpdate
	if(Tex == 0){
		Cursor(1,10);
	} else{
		Cursor(2,10);
		if((ExLim != 0)&&(Time >= ExLim*60)){
			Busy = 1;
			TocaNota(126, 63, 2); 	// Nota Si
			_delay(10);
			TocaNota(126, 63, 2); 	// Nota Si
				if (Part == 1){	// Si estem a la 1a part
					PORTC = 0b00000100;
					Part = 2;
				} else {	// Si estem a la 2a part
					PORTC = 0b00001000;
					Part = 1;
				}
				Time = 900; 	// Time = 900s = 15'
				mode = 2;	// Compte enrere descans
				ResetToPart();
				Cursor(1,10);
		}				 
	}
	char Min = Time/60;
	char Sec = Time%60;
	EnviaV('0' + Min/10, '0' + Min%10, '.', '0' + Sec/10, '0' + Sec%10);
}
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 CheckPot(void){
	ADCON0 = 0b00000001;			// Posa l'ADC a la pota del potenciòmetre
	ADCON0bits.GO = 1;			// Posa en marxa el conversor
	while (ADCON0bits.GO == 1)		// Mentre no acabi
		;				// ens esperem
	if (ADRESH > 100)
		ExLim = 5;			// Comprova polsador 1
	else if (ADRESH > 80)
		ExLim = 4;			// Comprova polsador 2
	else if (ADRESH > 60)
		ExLim = 3;			// Comprova polsador 3
	else if (ADRESH > 40)
		ExLim = 2;			// Comprova polsador 4
	else if (ADRESH > 20)
		ExLim = 1;			// Comprova polsador 5
	else
		ExLim = 0;			// Comprova polsador 5
	Cursor(1,15);
	if(ExLim != 0){
		EnviaL('+');
		EnviaL('0' + ExLim);
		if (BIT_CHECK(PORTC, 0) == 0)	// Si el LED corresponent és apagat, engega'l
			BIT_SET(PORTC, 0);
	} else {
		if (BIT_CHECK(PORTC, 0) == 1)	// Si el LED corresponent és encès, apaga'l
			BIT_CLEAR(PORTC, 0);
		EnviaL(' ');
		EnviaL(' ');
	}
	ADCON0 = 0b00001001;			// Posa l'ADC a la pota dels polsadors
}

 

 

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