Programació en C del PIC 16F690

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

Exemple T2 - Temporitzador 2

En els exemples anteriors els LED s'encenien a un ritme que marcaven uns bucles de retard marcats per la funció _delay(). Això volia dir que la major part del temps el processador estava fent bucles. En aquest exemple, en lloc de tenir el microcontrolador ocupat fent bucles per comptar el temps, fem que un temporitzador físic (timer) s'encarregui de comptar el temps. En el nostre cas farem servir el Timer2 que és un comptador de 8 bits amb comparació. Quan funciona com a temporitzador, agafa la sortida del rellotge del microcontrolador (període d'un microsegon), el divideix per un factor d'escala i el fa servir per incrementar el registre TMR2. Quan aquest registre coincideix amb el valor guardat al registre PR2, TMR2 es posa a zero i es compta una coincidència. Quan el nombre de coincidències coincideix amb el que s'ha definit al postescalador, s'activa un bit en un altre registre.

En aquest exemple cada cop que s'activi TMR2IF farem rodar els bits de la variable Valor i en copiarem el resultat sobre els LED. Li hem posat un prescalador de 16, de manera que s'incrementa cada 16 μs i ha de comptar fins 256; per tant, fara una coincidència cada 4096 μs. Posarem un post-escalat de 16, de manera que el bit TMR2IF s'activarà cada 65,54 ms.

#pragma config FOSC = INTRCIO, WDTE = OFF, PWRTE = OFF, MCLRE = OFF, CP = OFF
#pragma config CPD = OFF, BOREN = OFF, IESO = OFF, FCMEN = OFF
#include <xc.h>					// Carrega el fitxer de funcions
#define Polsador   RA3		// Li assigna un nom a l'adreça del polsador
#define FiTimer2 PIR1bits.TMR2IF		// Li assigna un nom al bit que indica el final del Timer 2
#define flipbit(var, bit) ((var) ^= (1<<(bit)))
unsigned char Valor;  				// Variable de 8 bits sense signe (0 a 255)
char Premut;					// Estat del polsador
char Adreta;					// Sentit de gir
void main (void){
						// Inicialització de variables
	Adreta = 0;				// Iniciem girant a l'esquerra
	Premut = 0;				// Suposem el polsador no premut
	Valor = 1;          			// Inicialment posem 1 (activem LED 0)
						// Configuració d'entrades i sortides
	TRISC = 0b00000000; 			// Posa el port C com a sortida
	TRISA = 0b00001000; 			// Posa RA3 com a entrada
						// Configuració del Timer 2
	FiTimer2 = 0;       			// Aquest bit es posarà a 1 quan el temporitzador acabi
						// cal desactivar-lo des del programa
	T2CON = 0b01111111;       		// Configuració de Timer2
						// 11 - Pre-escala de 16
						// 1111 - Post-escala de 16
						// I el posem en marxa
	while(1){				// Inici del bucle de programa
		PORTC = Valor;			// Copiem el valor al port (als LED)
		if(FiTimer2 == 1){		// Si ha acabat el temporitzador
			FiTimer2 = 0;		// Tornem a posar el bit a zero
			if (Adreta == 0){
				Valor = (Valor << 1)|(Valor >> 7);	// Desplacem els bits a l'esquerra
				if (Valor == 16)			// Si ja estem al LED 5,
					Valor = 1;    			// tornem al LED 0
			}
			if (Adreta == 1){
				Valor = (Valor >> 1)|(Valor << 7);	// Desplacem els bits a la dreta
				if (Valor == 128)			// Ja hem sortit fora,
					Valor = 8;    			// tornem al LED 4
			}
		}
	 					// Mirem si s'ha premut el polsador i, si és així, 
						// canviem el sentit de gir
		if (Polsador == 1)		// Si el polsador no està premut (1 és no premut)
			Premut = 0;		// Memoritzem l'estat del polsador
		else if (Premut == 0){		// Si el polsador està premut però fa un moment no ho estava
			flipbit(Adreta, 0);	// Invertim el sentit de gir
			Premut = 1;		// Memoritzem el nou estat del polsador
		}
	}
}

Podem posar una pre-escala i/o una post-escala més petites per aconseguir valors més ràpids però ja no podem posar-les més grans si en volem de més lents. El que sí podem fer és que el moviment es faci només cada, per exemple, 16 finals del temporitzador (que comptem amb la variable Compta):

#pragma config FOSC = INTRCIO, WDTE = OFF, PWRTE = OFF, MCLRE = OFF, CP = OFF
#pragma config CPD = OFF, BOREN = OFF, IESO = OFF, FCMEN = OFF
#include <xc.h>					// Carrega el fitxer de funcions
#define Polsador   RA3		// Li assigna un nom a l'adreça del polsador
#define FiTimer2 PIR1bits.TMR2IF		// Li assigna un nom al bit que indica el final del Timer 2
#define flipbit(var, bit) ((var) ^= (1<<(bit)))
unsigned char Valor;  				// Variable de 8 bits sense signe (0 a 255)
unsigned char Compta;  				// Variable de 8 bits sense signe (0 a 255)
char Premut;					// Estat del polsador
char Adreta;					// Sentit de gir
void main (void){
						// Inicialització de variables
	Adreta = 0;				// Iniciem girant a l'esquerra
	Premut = 0;				// Suposem el polsador no premut
	Valor = 1;          			// Inicialment posem 1 (activem LED 0)
	Compta = 0;				// Compta el nombre de cops que ha acabat el Timer
						// Configuració d'entrades i sortides
	TRISC = 0b00000000; 			// Posa el port C com a sortida
	TRISA = 0b00001000; 			// Posa RA3 com a entrada
						// Configuració del Timer 2
	FiTimer2 = 0;       			// Aquest bit es posarà a 1 quan el temporitzador acabi
						// cal desactivar-lo des del programa
	T2CON = 0b01111111;       		// Configuració de Timer2
						// 11 - Pre-escala de 16
						// 1111 - Post-escala de 16
						// I el posem en marxa
	while (1){				// Inici del bucle de programa
		if(FiTimer2 == 1){		// Si ha acabat el temporitzador
			FiTimer2 = 0;          	// Tornem a posar el bit a zero
			Compta++;		// Incrementa Compta
			if (Compta == 4) {	// Si ha acabat quatre vegades
				PORTC = Valor;	// Copiem el valor al port (als LED)
				Compta = 0;	// Reinicialitza Compta
				if (Adreta == 0){
					Valor = (Valor << 1)|(Valor >> 7);	// Desplacem els bits a l'esquerra
					if (Valor == 16)			// Si ja estem al LED 5,
						Valor = 1;    			// tornem al LED 0
				}
				if (Adreta == 1){
					Valor = (Valor >> 1)|(Valor << 7);	// Desplacem els bits a la dreta
					if (Valor == 128)			// Ja hem sortit fora,
						Valor = 8;    			// tornem al LED 4
				}
			}
		}
	 					// Mirem si s'ha premut el polsador i, si és així, 
						// canviem el sentit de gir
		if (Polsador == 1)		// Si el polsador no està premut (1 és no premut)
			Premut = 0;		// Memoritzem l'estat del polsador
		else if (Premut == 0){		// Si el polsador està premut però fa un moment no ho estava
			flipbit(Adreta, 0);	// Invertim el sentit de gir
			Premut = 1;		// Memoritzem el nou estat del polsador
		}
	}
}

Ara el moviment és aproximadament cada un segons (de fet, cada 1,05 s).

També podem inicialitzar el comptador amb un valor per comptar el temps desitjat. Si mantenim el pre-escalat de 16 vol dir que cada increment del comptador són 16 μs. Si volem que el final del temporitzador sigui cada 2 ms (és a dir cada 2000 μs) ens caldrà comptar fins a 2000 /16 = 125, que és el valor que posarem a PR2.

En el programa següent el temporitzador acaba cada 2 ms, com hem calculat. Hi ha un post-escalador de 10 que fa que el bit TMR2IF sigui cada 20 ms i la rotació dels LED es fa cada 50 cops, o sigui cada segon.

	T2CKPS = 11		1/16
	TOUTPS = 1001		1/10
	T2CON  = 0b01001111

#pragma config FOSC = INTRCIO, WDTE = OFF, PWRTE = OFF, MCLRE = OFF, CP = OFF
#pragma config CPD = OFF, BOREN = OFF, IESO = OFF, FCMEN = OFF
#include <xc.h>					// Carrega el fitxer de funcions
#define Polsador   RA3		// Li assigna un nom a l'adreça del polsador
#define FiTimer2 PIR1bits.TMR2IF		// Li assigna un nom al bit que indica el final del Timer 2
#define flipbit(var, bit) ((var) ^= (1<<(bit)))
unsigned char Valor;  				// Variable de 8 bits sense signe (0 a 255)
unsigned char Compta;  				// Variable de 8 bits sense signe (0 a 255)
char Premut;					// Estat del polsador
char Adreta;					// Sentit de gir
void main (void){
						// Inicialització de variables
	Adreta = 0;				// Iniciem girant a l'esquerra
	Premut = 0;				// Suposem el polsador no premut
	Valor = 1;          			// Inicialment posem 1 (activem LED 0)
	Compta = 0;				// Compta el nombre de cops que ha acabat el Timer
						// Configuració d'entrades i sortides
	TRISC = 0b00000000; 			// Posa el port C com a sortida
	TRISA = 0b00001000; 			// Posa RA3 com a entrada
						// Configuració del Timer 2
	FiTimer2 = 0;       			// Aquest bit es posarà a 1 quan el temporitzador acabi
						// cal desactivar-lo des del programa
	PR2 = 125;				// Valor de comparació del Timer2
	T2CON = 0b01001111;       		// Configuració de Timer2
						// 11 - Pre-escala de 16
						// 1001 - Post-escala de 10
						// I el posem en marxa
	while (1){				// Inici del bucle de programa
		if(FiTimer2 == 1){		// Si ha acabat el temporitzador
			Compta++;		// Incrementa Compta
			FiTimer2 = 0;          	// Tornem a posar el bit a zero
			if (Compta == 50) {	// Si ha acabat 50 vegades
				PORTC = Valor;	// Copiem el valor al port (als LED)
				Compta = 0;	// Reinicialitza Compta
				if (Adreta == 0){
					Valor = (Valor << 1)|(Valor >> 7);	// Desplacem els bits a l'esquerra
					if (Valor == 16)			// Si ja estem al LED 5,
						Valor = 1;    			// tornem al LED 0
				}
				if (Adreta == 1){
					Valor = (Valor >> 1)|(Valor << 7);	// Desplacem els bits a la dreta
					if (Valor == 128)			// Ja hem sortit fora,
						Valor = 8;    			// tornem al LED 4
				}
			}
		}
	 					// Mirem si s'ha premut el polsador i, si és així, 
						// canviem el sentit de gir
		if (Polsador == 1)		// Si el polsador no està premut (1 és no premut)
			Premut = 0;		// Memoritzem l'estat del polsador
		else if (Premut == 0){		// Si el polsador està premut però fa un moment no ho estava
			flipbit(Adreta, 0);	// Invertim el sentit de gir
			Premut = 1;		// Memoritzem el nou estat del polsador
		}
	}
}

 

 

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