Teoría:
se me ocurrió otro ejemplo para madurar la forma de utilizar retardos y a la vez hacer otras cosas.
una situación común es utilizar funciones de inicialización empezando el main, el contador de programas (CP) entra y sale de la función y contínua normalmente.
es posible que dentro de una función de inicialización tengamos que hacer un retardo, bien aplicando lo aprendido usamos el retardo por interrupción del timer. perooo.. hay un pequeño detalle: la función se debe ejecutar una sola vez y el CP no debe entrar mas a ella. ¿como hacemos?
bien la respuesta que he estudiado es usar banderas y bucles condicionales
supongamos que tenemos la función vIniciar(), si vIniciar posee un retardo, entonces
- se debe partir el código interno exactamente donde vá el retardo.
- encerrar ambos pedazos en 2 if.
- al final del primer if, configuramos el timer para el retardo.
- ambos if serán regidos por unas banderas previamente declaradas.
- para ejecutar vIniciar una sola vez, en el bucle principal, encerramos a vIniciar dentro de un condicional guiado por otra bandera.
- así en cada pasada del bucle eterno, se preguntará por dicha bandera (llamemosla fIniciar) y NO se ejecutará mas nunca vIniciar.
Aquí va un programa de ejemplo:
/* Generando Retardos con el timer. 2 Parte
Pedro - PalitroqueZ
*/
#include <18F4550.h>
#fuses XT,NOMCLR,NOWDT,NOPROTECT,NOLVP
#fuses NODEBUG,NOPBADEN,CPUDIV1,NOVREGEN //,PLL1
#use delay(clock=4M)
int8 iBanderas; // variables globales
#bit fIniciar = iBanderas.0
#bit fDurante_Retardo = iBanderas.1
#bit fFin_Retardo = iBanderas.2
//***************************************
// servicio de interrupción
//***************************************
#int_timer0
void tmr0_isr(){
fDurante_Retardo=1;
fFin_Retardo=1;
disable_interrupts(INT_TIMER0);
// deselecciona la fuente de interrupción
// para no ejecutarla a posteriori
}
//***************************************
void vIniciar(){
if(!fDurante_Retardo){
delay_us(10); // simula tiempo de lineas de programas
fDurante_Retardo=1;
set_timer0(21); // retardo de ~ 15ms
enable_interrupts(GLOBAL);
return;
}
if(fFin_Retardo){ //la otra mitad del programa dentro de vIniciar
delay_us(80); // simula tiempo de lineas de programas despues del retardo
fIniciar=0;
disable_interrupts(INT_TIMER0);
}
}
//***************************************
// programa principal
//***************************************
void main(){
int16 t;
// ... aqui va config puertos, modulos, etc.
iBanderas=0b00000001;
//fIniciar = 1;
//fDurante_Retardo = 0;
//fFin_Retardo=0;
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_64|RTCC_8_BIT);
// configura el Timer0 base de tiempo interno, pre-escaler=1:64, contador de 8 bits
enable_interrupts(INT_TIMER0);
// selecciona la fuente de interrupción del timer0
while(1){ // bucle eterno
delay_us(80); // simula tiempo de otros procesos
if(fIniciar){ // pregunta para decidir si entrará o no a vIniciar
vIniciar();
}
for(t=0;t<65000;t++){ // simula tiempo de otros procesos
delay_cycles(1);
}
}
}
Ventajas:
- uuy muchas, principalmente se aprovecha el máximo tiempo permitido, la ejecución de multiples procesos.
- las interrupciones es lo mejor que hay.
- como quisiera que la gente de Microchip le fueran puesto interrupción a cada pin de los uCPIC
Desventajas:
- se estará preguntando si es posible la ejecución de una función en cada pasada del bucle eterno, pero si lo ven bien, no está mal perder unos cuantos ciclos, a que perder miles por un tonto retardo cíclico.
- si el CP dura mucho tiempo en volver al inicio del bucle, entonces vIniciar tomará mas tiempo en completar sus lineas de programa.
Eso depende de vIniciar. Si vIniciar requiere
al menos retardo_calculado para funcionar correctamente, entonces no habrá problemas.
por el contrario, si retardo
tiene que ser retardo_calculado y continuar las lineas faltantes inmediatamente, entonces hay que tomar medidas extremas como preguntar estrategicamente por la bandera fIniciar que rige a vIniciar. (calculando previamente los tiempos entre otros procesos para que cuadre el retardo de vIniciar)
- el programa se vuelve confuso si es largo, pero ¿quien ha dicho que lo óptimo es fácil?
corolarios de esta técnica:
- por cada retardo se usa 2 bandera + un condicional.
- se pueden reutilizar las banderas usadas en el timer.