Por eso mismo te dije que ibas a tener que cambiar toda la forma de programar.
Como regla general
- Lo que ocupa demasiado tiempo, hacerlo en loop (while) del main.
- En las interrupciones, en lo posible entrar y salir.
Pero eso es por lo general. Esos son buenos lineamientos si consideras que podes llegar a tener varias interrupciones, y mucho mas cuando trabajas con comunicaciones (UART) que puedan implicar recibir muchos datos y no leerlos.
Entonces voy a explicarme un poco mas sobre tu programa:
int16 read_TC(void) //It takes 200ms (ish) for the MAX6675 to perform a conversion
{
int8 i;
int16 data;
output_low(TC_CS); //stop any conversion processes
delay_ms(1); //and give it some time to power up (not very much, admittedly)
for (i=0;i<16;i++){
shift_left(&data,2,input(TC_DATA)); //reads in 2 bytes to data from the pin TC_DATA
output_high(TC_CLK);
delay_us(100); //Descomentar si usa crystal mayor a 10MHz
output_low(TC_CLK);
delay_us(100);
}
Esa función de lectura, es lo mismo que un SPI, la diferencia es que tiene 16 bits. Que los PICs vienen fijo de 8, pero eso no quita que puedas usar el SPI dos veces y su interrupción para comunicarte. De esa forma no usas demoras.
Si comenzas a sumar delays, tenes 1ms al comienzo, luego 0.2ms por cada bit, tenes un total de 4.2ms en esa comunicación del SPI.
int16 sortout(int16 raw)
{
return(0x0FFF & (raw>>3)); //returns only the bits converning temperature
}
float toFloat_TC(int16 tmp)
{
return((((float)tmp)-48.725)/1.9835);
}
La funcion sortout, no es problema, ya que una AND y un shift no son demasiados costosos computacionalmente. Pero el toFloat_TC si, una division de flotantes no es nada "barato" y se lleva su tiempo. Y ni hablar el LCD que esta lleno de demoras tambien.
Por eso mismo no esta puesto en la interrupción.
Ahora veamos el while y el porque se suma tu demora.while(true){
aux = do_everything();
if (aux != 0){
lcd_gotoxy
(1,2); printf(lcd_putc
,"Todopic %3.2f%cC ",aux
,0xDF); }
}
Observa como funciona. Se obtiene lo que se devuelve desde do_eveything, esta funcion va a devolver 0 siempre y cuando este esperando el tiempo necesario y no tenga un resultado valido (luego del proceso de lectura)
Entonces al no tener resultado valido directamente no grafica naada en el LCD, por eso esta el if.
Ahora tenemos que tener en cuenta algunas cosas.
- Tu interrupcion lo unico que hace es contar 200ms y decir "YA TERMINE!" y para de contar
- Si lo lees tarde es tu problema. Lo lees unicamente cuando ejecutas el do_everything.
Si vos pones un delay supongamos de 500ms. entonces el timer recien habia comenzado a contar, se van a cumplir los 200ms del timer, va a decir YA TERMINE!, pero no va a pasar nada, ya que todavia faltan 300ms de ese delay que tenias. Esto suponiendo que no tenes ninguna otra instruccion antes. En este caso no se "sumaria", quedaria lo que falta, el codigo seria:
while(true){
aux = do_everything();
if (aux != 0){
lcd_gotoxy
(1,2); printf(lcd_putc
,"Todopic %3.2f%cC ",aux
,0xDF); }
delay_ms(500);
}
Ahora, que pasa si agregamos MAS instrucciones, supongamos que tengo una funciona que tarda 300ms en ejecutarse
while(true){
aux = do_everything();
if (aux != 0){
lcd_gotoxy
(1,2); printf(lcd_putc
,"Todopic %3.2f%cC ",aux
,0xDF); }
mi_funcion_que_tarda_300_ms();
delay_ms(500);
}
Ahora esos 200ms van a pasar en esa funcion nueva, pero hasta que se ejecute el do_everything de nuevo necesita 100ms mas de esa función y los 500ms del delay.
Entonces ahora vas 600ms atrasado.
-------------------------------
Que pasaría si pongo todo en la interrupción?
Y ahora tal ves los delays de 500ms de mi loop principal por ahí sean de 500, 524, 551 ms etc. Puede ser cualquier valor. Ya que segun lo que tarde la interrupcion, es lo que va cambiar mi tiempo.
Vos debes saber que mientras este en la funcion de interrupcion, todo lo demas se detiene, asi que mientras mas tiempo esté dentro de la interrupcion, mas se atrasa o cambia el comportamiento del programa principal. Hay cosas que no son importantes en tiempos, pero otros si.
Si queres paso todo el código a la interrupción, solo vas a tener que tener en cuenta eso. Y otra cosa mas estamos hablando de únicamente una sola interrupción. Ya que mientras esta encerrado en una interrupcion usualmente no puede atender otra, hasta que termina (excepciones a esto son interupciones con prioridades que tiene PIC18 en adelante)
----------------------------------------
¿Qué código usaste que te dio problemas?
Una cosa mas, muchos de las librerías están realizadas todo por software, como te dije el MAX6675 lo podes hacer con 2 interrupciones por SPI + 1 interrupcion del Timer, pero como la interrupción es demasiado dependiente del hardware, la librería haría que sea poco flexible, por eso mismo la mayoría de las librerías que vas a encontrar, especialmente las de Arduino, todos los SPI están realizados por software.
Alguna forma sencilla para reducir estos problemas es reducir y mantener unicamente un delay, por ejemplo uno de 10ms, nuestra funciona que tenia una demora de 300ms antes porque queriamos que se ejecutara cada 300ms, ahora le ponemos un contador, que cuando entre 30 veces, lo ejecute, y le quitamos esos delays.
while(true){
aux = do_everything();
if (aux != 0){
lcd_gotoxy
(1,2); printf(lcd_putc
,"Todopic %3.2f%cC ",aux
,0xDF); }
if(contador_mi_funcion++ == 30) {
mi_funcion_sin_demoras()
contador_mi funcion =0;
}
delay_ms(10);
}