Programació en C del PIC 18F45K20

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 que, en aquest exemple, serà de 16 bits. Quan funciona com a temporitzador, agafa la sortida del rellotge del microcontrolador (període de quatre microsegons), el divideix per un factor d'escala (1 en el nostre cas) 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 = INTIO67, FCMEN = OFF, IESO = OFF				// CONFIG1H
#pragma config PWRT = OFF, BOREN = SBORDIS, BORV = 30				// CONFIG2L
#pragma config WDTEN = OFF, WDTPS = 32768					// CONFIG2H
#pragma config MCLRE = OFF, LPT1OSC = OFF, PBADEN = ON, CCP2MX = PORTC		// CONFIG3H
#pragma config STVREN = ON, LVP = OFF, XINST = OFF				// CONFIG4L
#pragma config CP0 = OFF, CP1 = OFF, CP2 = OFF, CP3 = OFF			// CONFIG5L
#pragma config CPB = OFF, CPD = OFF						// CONFIG5H
#pragma config WRT0 = OFF, WRT1 = OFF, WRT2 = OFF, WRT3 = OFF			// CONFIG6L
#pragma config WRTB = OFF, WRTC = OFF, WRTD = OFF				// CONFIG6H
#pragma config EBTR0 = OFF, EBTR1 = OFF, EBTR2 = OFF, EBTR3 = OFF		// CONFIG7L
#pragma config EBTRB = OFF							// CONFIG7H
#include "p18f45k20.h"				// Carrega el fitxer d'adreces i paràmetres del PIC 18F45K20
#define Polsador PORTBbits.RB0			// Li assigna un nom a l'adreça del polsador
#define FiTimer0 INTCONbits.TMR0IF		// 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
	TRISD = 0b00000000;    			// El port D és de sortida
	ANSELH = 0x00;            		// Les entrades AN8-12 són digitals (AN12 coincideix amb RB0)
	INTCON2bits.RBPU = 0;			// Habilita el control de resistències de pull-up al port B
	WPUBbits.WPUB0 = 1;			// Activa la resistència de pull-up a RB0
	TRISBbits.TRISB0 = 1;      		// RB0 és entrada
						// Configuració del Timer 0
	FiTimer0 = 0;       			// Aquest bit es posarà a 1 quan el temporitzador acabi
						// cal desactivar-lo des del programa
	T0CON = 0b00001000;       		// El timer 0 és de 16 bits i compta temps sense pre-escalat
						// o sigui, l'escalat equival a 1/1
	TMR0H = 0;                   		// Posem el comptador a 0, primer el registre H
	TMR0L = 0;				// i després el registre L
	T0CONbits.TMR0ON = 1;          		// Fem que Timer 0 comenci a comptar
	while (1)				// Inici del bucle de programa
	{
		LATD = Valor;			// Copiem el valor al port (als LED)
		if (Adreta == 0)
			Valor = (Valor << 1)|(Valor >> 7);	// Desplacem els bits a l'esquerra
		if (Adreta == 1)
			Valor = (Valor >> 1)|(Valor << 7);	// Desplacem els bits a la dreta
		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
	}
}

La rotació es fa cada 65536 cicles de 4 μs per tant cada 0,26 s. Dit d'una altra manera, es desplacen aproximadament quatre posicions cada segon. Podem posar una pre-escala per aconseguir valors més lents:

#pragma config FOSC = INTIO67, FCMEN = OFF, IESO = OFF				// CONFIG1H
#pragma config PWRT = OFF, BOREN = SBORDIS, BORV = 30				// CONFIG2L
#pragma config WDTEN = OFF, WDTPS = 32768					// CONFIG2H
#pragma config MCLRE = OFF, LPT1OSC = OFF, PBADEN = ON, CCP2MX = PORTC		// CONFIG3H
#pragma config STVREN = ON, LVP = OFF, XINST = OFF				// CONFIG4L
#pragma config CP0 = OFF, CP1 = OFF, CP2 = OFF, CP3 = OFF			// CONFIG5L
#pragma config CPB = OFF, CPD = OFF						// CONFIG5H
#pragma config WRT0 = OFF, WRT1 = OFF, WRT2 = OFF, WRT3 = OFF			// CONFIG6L
#pragma config WRTB = OFF, WRTC = OFF, WRTD = OFF				// CONFIG6H
#pragma config EBTR0 = OFF, EBTR1 = OFF, EBTR2 = OFF, EBTR3 = OFF		// CONFIG7L
#pragma config EBTRB = OFF							// CONFIG7H
#include "p18f45k20.h"				// Carrega el fitxer d'adreces i paràmetres del PIC 18F45K20
#define Polsador PORTBbits.RB0			// Li assigna un nom a l'adreça del polsador
#define FiTimer0 INTCONbits.TMR0IF		// 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
	TRISD = 0b00000000;    			// El port D és de sortida
	ANSELH = 0x00;         			// Les entrades AN8-12 són digitals (AN12 coincideix amb RB0)
	INTCON2bits.RBPU = 0;			// Habilita el control de resistències de pull-up al port B
	WPUBbits.WPUB0 = 1;			// Activa la resistència de pull-up a RB0
	TRISBbits.TRISB0 = 1;      		// RB0 és entrada
						// Configuració del Timer 0
	FiTimer0 = 0;       			// Aquest bit es posarà a 1 quan el temporitzador acabi
						// cal desactivar-lo des del programa
	T0CON = 0b00000001;			// El timer 0 és de 16 bits i compta temps amb pre-escalat 1/4
	TMR0H = 0;                    		// Posem el comptador a 0, primer el registre H
	TMR0L = 0;				// i després el registre L
	T0CONbits.TMR0ON = 1;           	// Fem que Timer 0 comenci a comptar
	while (1)				// Inici del bucle de programa
	{
		LATD = Valor;			// Copiem el valor al port (als LED)
		if (Adreta == 0)
			Valor = (Valor << 1)|(Valor >> 7);		// Desplacem els bits a l'esquerra
		if (Adreta == 1)
			Valor = (Valor >> 1)|(Valor << 7);		// Desplacem els bits a la dreta
		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.

També podem inicialitzar el comptador amb un valor per comptar el temps desitjat. Si mantenim el pre-escalat 1/4 vol dir que cada increment del comptador són 16 μs. Si volem que el moviment sigui cada 0,6 s (és a dir cada 600 000 μs) ens caldrà comptar fins 600 000 / 16 = 37500. Per posar aquest valor, farem:

	TMR0 = 65536 - 37500 = 28036
	TMR0H = TMR0/256 = 28036/256 = 109
	TMR0L = TMR0 - (256 * TMR0H) = 28036 - (256 * 109) = 132

que és el que hi ha al programa següent:

#pragma config FOSC = INTIO67, FCMEN = OFF, IESO = OFF				// CONFIG1H
#pragma config PWRT = OFF, BOREN = SBORDIS, BORV = 30				// CONFIG2L
#pragma config WDTEN = OFF, WDTPS = 32768					// CONFIG2H
#pragma config MCLRE = OFF, LPT1OSC = OFF, PBADEN = ON, CCP2MX = PORTC		// CONFIG3H
#pragma config STVREN = ON, LVP = OFF, XINST = OFF				// CONFIG4L
#pragma config CP0 = OFF, CP1 = OFF, CP2 = OFF, CP3 = OFF			// CONFIG5L
#pragma config CPB = OFF, CPD = OFF						// CONFIG5H
#pragma config WRT0 = OFF, WRT1 = OFF, WRT2 = OFF, WRT3 = OFF			// CONFIG6L
#pragma config WRTB = OFF, WRTC = OFF, WRTD = OFF				// CONFIG6H
#pragma config EBTR0 = OFF, EBTR1 = OFF, EBTR2 = OFF, EBTR3 = OFF		// CONFIG7L
#pragma config EBTRB = OFF							// CONFIG7H
#include "p18f45k20.h"				// Carrega el fitxer d'adreces i paràmetres del PIC 18F45K20
#define Polsador PORTBbits.RB0			// Li assigna un nom a l'adreça del polsador
#define FiTimer0 INTCONbits.TMR0IF		// 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
	TRISD = 0b00000000;     		// El port D és de sortida
	ANSELH = 0x00;             		// Les entrades AN8-12 són digitals (AN12 coincideix amb RB0)
	INTCON2bits.RBPU = 0;			// Habilita el control de resistències de pull-up al port B
	WPUBbits.WPUB0 = 1;			// Activa la resistència de pull-up a RB0
	TRISBbits.TRISB0 = 1;       		// RB0 és entrada
						// Configuració del Timer 0
	FiTimer0 = 0;       			// Aquest bit es posarà a 1 quan el temporitzador acabi
						// cal desactivar-lo des del programa
	T0CON = 0b00000001;    		     	// El timer 0 és de 16 bits i compta temps amb pre-escalat de 1/4
	TMR0H = 109;                   		// Fem la precàrrega, primer el registre H
	TMR0L = 132;				// i després el registre L
	T0CONbits.TMR0ON = 1;          		// Fem que Timer 0 comenci a comptar
	while (1)				// Inici del bucle de programa
	{
		LATD = Valor;			// Copiem el valor al port (als LED)
		if (Adreta == 0)
			Valor = (Valor << 1)|(Valor >> 7);		// Desplacem els bits a l'esquerra
		if (Adreta == 1)
			Valor = (Valor >> 1)|(Valor << 7);		// Desplacem els bits a la dreta
		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
		TMR0H = 109;                   	// I fem la precàrrega, primer el registre H
		TMR0L = 132;			// i després el registre L
	}
}

 

 

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