Introducción:
Después de leer varios post aquí en el foro acerca del tema, es hora de tomar conciencia y avanzar en cuanto a la forma de programar.
cuando uno se inicia en el mundo de los pic´s y llega un ejemplo que involucra retardos, lo primero que se usa el método fácil: el método del retardo cíclico (por allí leí en un libro que lo llaman: delay loop method)
les confieso que hasta hace poco creía que los timer´s eran de poco uso, que se limitaba hacer labores de conteo externo (RTCC) y que usandolo como temporizador era innecesario debido al poco tiempo generado y que para ello estaban los codigos redundantes...
pués estaba equivocado. El hecho de que con el timer no se pueda lograr tiempos largos no quiere decir que no se usará. Una cosa que debe tener en cuenta el picmaníaco a la hora de escribir un código, es saber redistribuir los procesos en el tiempo. no importa en que intervalo de tiempo los haga, pero lo importante es que logre su cometido (pensando en asm).
Esto precisamente yo lo aplicaba en ensamblador cuando requería hacer varias cosas, pero nunca se me ocurrió aplicarlo a los retardos involucrados, por supuesto que el código parecerá complicado, pero mas eficiente en su ejecución. podemos ejecutar otros procesos en vez de estar perdiendo tiempo precioso. Esto se puede dar en varios casos, como también puede ocurrir que sea mejor aplicar el otro método. ejemplos particulares.
hasta aquí la introducción...
Después de pensar hacer un ejemplo donde se involucre un retardo grande y a la vez qu el pic ejecute otros procesos, se me ocurrió este:
- se tienen 5 led´s inicialmente apagado.
- hay 5 interruptores normalmente abiertos uno para cada led.
Sn -> Ln : para todo n perteneciente a [1,5]
Sn = interruptor (n)
Ln = Led (n)
- al presionar uno de los switche, se enciende su led coterráneo ej: S1 -> L1.
- el tiempo de encendido: 2 minutos.
- se pueden presionar otros S entre retardos.
- se repite el proceso descrito.
validación:
- si L1 está encendido cuando se presiona S1, se hará caso omiso, solo hasta que L1 <- Off.
- el debounce ó antirebote estará asegurado por una bandera (flag)
posible solución:
- para el retardo de 2 minutos: el Timer1
- se hará uso de interrupciones por desbordamiento del par TMRH:TMRL.
usando una temporización de 524,2 mS interrumpiendo ó desbordandose 229 veces tenemos ~ 120 S = 2 Minutos
para configurar el timer1, podemos usar la formula T = 65536 x 8 x 4 / 4MHZ
ó
podemos usar la herramienta
PicMultiCalc que ya nos dá el valor de acuerdo a nuestro cálculo
- para 'tratar' de optimizar el programa desde el punto de vista del C , se observa que se puede manejar las variables como un arreglo, ya que los interruptores y los pines de salida son contiguos. (mejor que mejor)
- en el bucle principal se estará preguntando por cada entrada de los Sn y a la vez el timer estará contando e interrumpiendo, en la rutina del servicio de interrupción se estará preguntando por los ~ 2 minutos necesarios para apagar el/los led(s) correspondiente(s).
esto se resuelve declarando un arreglo para los contadores de los 2 minutos y uno para la bandera.
la finalidad de las banderas es mantener la cuenta después que se activó un Sn y la de evitar reiniciar el retardo si se pulsa de nuevo Sn entre los 2 minutos
//---------------------------------------------
// manejando retardos con el timer1
// PalitroqueZ 25-Abr-07
//---------------------------------------------
#include <16F877.h>
#fuses XT,NOPROTECT,NOPUT,NOWDT,NOBROWNOUT,NOLVP,NOCPD,WRT
#use delay (clock=4000000)
#byte portb=0x6
static int contador[5]; // contadores para generar los 2 minutos
static int bandera; // flag
#define bs(x) bit_test(bandera,x) //
//*************************************************
#INT_TIMER1 // rutina de servicio de interrupcion
void mitimer(){
int k;
for(k=0;k<5;k++){ // barrido
if(contador[k]==228 && bs(k)){ // pasaron los 2 minutos?
output_bit(48+k,0); // apaga el led correspondiente
contador[k]=0; // reinicia el contador
bit_clear(bandera,k);
// libera el swuitche correspondiente
}
else{
contador[k]++;
// no llega a 2 minutos, continua la cuenta
// igual cuenta si no hay pulsacion en las Sn
}
}
}
//*************************************************
void main(){
int t;
set_tris_b(0x0);
set_tris_c(0b11111);
portb=0x0;
setup_timer_1(t1_internal | t1_div_by_8);
set_timer1(0);
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
while(1){ // bucle eterno
for(t=0;t<5;t++){ // barrido
if(input(56+t)){ // pregunta por el switche correspondiente
if(!bs(t)){ // para evitar reiniciar el temporizador en una cuenta
bit_set(bandera,t); // se activa el flag correspondiente
output_bit(48+t,1); // se activa el led correspodiente
contador[t]=0; // se resetea el contador
} //fin del if2
} // fin del if1
} // fin del for
} // fin del while
} // fin del main
como veran, estoy utilizando un timer para varios procesos, y estos procesos a su vez comparten la temporización del timer sin afectar al resto.
para aquellos que usen el Proteus, aquí va un pantallazo de simulación:
cabe destacar que fué montado,cronometrado y comprobado fisicamente con resultados satisfactorios este es un primer intento, les invito a que participen en la creación de otros ejemplos, para que así nos vayamos ejercitando y podamos dominar este método (para los que no sabemos
).