Programació en C del PIC 16F690 amb PICkit 2

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

Exemple TM - Temporitzadors

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 Timer0 que és un comptador de 8 bits. 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 un registre. Quan aquest registre arriba a zero s'activa un bit en un altre registre.

En aquest exemple cada cop que Timer0 acabi de comptar farem rodar els bits de la variable Valor i en copiarem el resultat sobre els LED.

#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
#define Polsador   PORTAbits.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
unsigned char Valor;  				// Variable de 8 bits sense signe (0 a 255)
bit Premut;					// Estat del polsador
bit 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 0
	FiTimer0 = 0;       			// Aquest bit es posarà a 1 quan el temporitzador acabi
						// cal desactivar-lo des del programa
	OPTION_REG = 0b10000111;       		// Configuració de Timer0
						// Com a temporitzador basat en rellotge
						// 111 - Factor d'escala de 256
						// I resistències de pull-up desactivades (valor per defecte)
	while (1)				// Inici del bucle de programa
	{
		PORTC = Valor;			// Copiem el valor al port (als LED)
		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
		}
		do				// Bucle que repetim mentre esperem que el temporitzador acabi
		{ 				// En el bucle 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
			{ 
				Adreta = ~Adreta;		// Invertim el sentit de gir
				Premut = 1;	// Memoritzem el nou estat del polsador
			}
		} while (FiTimer0 == 0);	// Sortirà del bucle quan el bit es posi a 1
						// és a dir, quan Timer 0 acabi
		FiTimer0 = 0;          		// Tornem a posar el bit a zero
	}
}

El comptador s'incrementa cada 256 μs i la rotació es fa cada 256 increments, o sigui cada 65536 μs per tant cada 65 ms (0,065 s). Podem posar una pre-escala més petita per aconseguir valors més ràpids però ja no podem posar una pre-escala més gran 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:

#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
#define Polsador   PORTAbits.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
unsigned char Valor;  				// Variable de 8 bits sense signe (0 a 255)
unsigned char Compta;  				// Variable de 8 bits sense signe (0 a 255)
bit Premut;					// Estat del polsador
bit 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 0
	FiTimer0 = 0;       			// Aquest bit es posarà a 1 quan el temporitzador acabi
						// cal desactivar-lo des del programa
	OPTION_REG = 0b10000111;       		// Configuració de Timer0
						// Com a temporitzador basat en rellotge
						// 111 - Factor d'escala de 256
						// I resistències de pull-up desactivades (valor per defecte)
	while (1)				// Inici del bucle de programa
	{	
		Compta++;			// Incrementa Compta
		if (Compta == 16) {		// Si ha acabat setze 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
			}
		}
		do				// Bucle que repetim mentre esperem que el temporitzador acabi
		{ 				// En el bucle 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
			{ 
				Adreta = ~Adreta;			// Invertim el sentit de gir
				Premut = 1;	// Memoritzem el nou estat del polsador
			}
		} while (FiTimer0 == 0);	// Sortirà del bucle quan el bit es posi a 1
						// és a dir, quan Timer 0 acabi
		FiTimer0 = 0;          		// Tornem a posar el bit a zero
	}
}

Ara el moviment és aproximadament cada segon (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 256 vol dir que cada increment del comptador són 256 μs. Si volem que el final del temporitzador sigui cada 0,05 s (és a dir cada 50 000 μs) ens caldrà comptar fins a 50 000 /256 = 195. Per posar aquest valor, farem:

	TMR0 = 256 - 195 = 61

En el programa següent el temporitzador acaba cada 0,05 s, com hem calculat, i la rotació dels LED es fa cada 20 cops, o sigui cada segon.:

#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
#define Polsador   PORTAbits.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
unsigned char Valor;  				// Variable de 8 bits sense signe (0 a 255)
unsigned char Compta;  				// Variable de 8 bits sense signe (0 a 255)
bit Premut;					// Estat del polsador
bit 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 0
	FiTimer0 = 0;       			// Aquest bit es posarà a 1 quan el temporitzador acabi
						// cal desactivar-lo des del programa
	OPTION_REG = 0b10000111;       		// Configuració de Timer0
						// Com a temporitzador basat en rellotge
						// 111 - Factor d'escala de 256
						// I resistències de pull-up desactivades (valor per defecte)
	TMR0 = 61;				// Inicialitza el Timer0
	while (1)				// Inici del bucle de programa
	{	
		Compta++;			// Incrementa Compta
		if (Compta == 20) {		// Si ha acabat vint 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
			}
		}
		do				// Bucle que repetim mentre esperem que el temporitzador acabi
		{ 				// En el bucle 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
			{ 
				Adreta = ~Adreta;			// Invertim el sentit de gir
				Premut = 1;	// Memoritzem el nou estat del polsador
			}
		} while (FiTimer0 == 0);	// Sortirà del bucle quan el bit es posi a 1
						// és a dir, quan Timer 0 acabi
		FiTimer0 = 0;          		// Tornem a posar el bit a zero
		TMR0 = 61;			// Inicialitza el Timer0
	}
}

 

 

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