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 Timer1 que és un comptador de 16 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 el registre TMR1 (bytes TMR1L i TMR1H). Quan aquest registre arriba a zero s'activa un bit en un altre registre.
En aquest exemple cada cop que Timer1 acabi de comptar farem rodar els bits de la variable Valor i en copiarem el resultat sobre els LED. Li hem posat un prescalador de 8, de manera que s'incrementa cada 8 μs i ha de comptar 65536; per tant, fara una rotació cada 0,52 s.
#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 FiTimer1 PIR1bits.TMR1IF // Li assigna un nom al bit que indica el final del Timer 1 #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 1
FiTimer1 = 0; // Aquest bit es posarà a 1 quan el temporitzador acabi
// cal desactivar-lo des del programa
T1CON = 0b00110001; // Configuració de Timer1
// 11 - Factor d'escala de 8
// I el posem en marxa
while(1){ // Inici del bucle de programa
PORTC = Valor; // Copiem el valor al port (als LED)
if(FiTimer1 == 1){ // Si ha acabat el temporitzador
FiTimer1 = 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 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, 4 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 FiTimer1 PIR1bits.TMR1IF // Li assigna un nom al bit que indica el final del Timer 1 #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 1
FiTimer1 = 0; // Aquest bit es posarà a 1 quan el temporitzador acabi
// cal desactivar-lo des del programa
T1CON = 0b00110001; // Configuració de Timer1
// 11 - Factor d'escala de 8
// I el posem en marxa
while (1){ // Inici del bucle de programa
if(FiTimer1 == 1){ // Si ha acabat el temporitzador
FiTimer1 = 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 dos segons (de fet, cada 2,1 s).
També podem inicialitzar el comptador amb un valor per comptar el temps desitjat. Si mantenim el pre-escalat de 8 vol dir que cada increment del comptador són 8 μ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 /8 = 6250. Per posar aquest valor, farem:
TMR1 = 65536 - 6250 = 59286 TMR1H = 59286 / 256 = 231 TMR1L = 59286 % 256 = 150
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 #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 FiTimer1 PIR1bits.TMR1IF // Li assigna un nom al bit que indica el final del Timer 1 #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 1
FiTimer1 = 0; // Aquest bit es posarà a 1 quan el temporitzador acabi
// cal desactivar-lo des del programa
TMR1H = 231; // Inicialitza el Timer1
TMR1L = 150;
T1CON = 0b00110001; // Configuració de Timer1
// 11 - Factor d'escala de 8
// I el posem en marxa
while (1){ // Inici del bucle de programa
if(FiTimer1 == 1){ // Si ha acabat el temporitzador
T1CONbits.TMR1ON = 0; // Atura momentàniament el Timer1
TMR1H = 231; // Inicialitza el Timer1
TMR1L = 150;
T1CONbits.TMR1ON = 1; // Torna a engegar el Timer1
Compta++; // Incrementa Compta
FiTimer1 = 0; // Tornem a posar el bit a zero
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
}
}
}
// 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
}
}
}

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