TODOPIC

Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: marcoscab1166 en 18 de Julio de 2017, 13:29:27

Título: Libreria para Max6675 en CCS
Publicado por: marcoscab1166 en 18 de Julio de 2017, 13:29:27
Hola, estoy buscando si alguno tiene una libreria para este integrado, que pueda utilizar con el pic 16F873A.

Este integrado se maneja con SPI, y yo mucho no conozco del tema. Lo que necesito es poder extraer la temperatura leida y pasarla a Celsius, para poder utilizarla junto con otros valores que maneja el programa.

Aca les dejo un codigo que encontre en la web, es el mas difundido, pero algunos dicen que no funciona. Ademas segun entiendo extrae la temperatura en caracteres, y yo la necesito en forma numerica. Si alguno me puede dar una pista de como adaptarlo, o si tienen algo similar se los re agradeceria.

Código: [Seleccionar]

/**************************************************************************************
*   max6675.c - communicates with a MAX6675 thermcouple interface chip                *
*   Copyright Jimbob's Ma 2006                                                        *
*                                                                                     *
*   This program is free software; you can redistribute it and/or                     *
*   modify it under the terms of the GNU General Public License                       *
*   as published by the Free Software Foundation version 2                            *
*   of the License.                                                                   *
*                                                                                     *
*   This program is distributed in the hope that it will be useful,                   *
*   but WITHOUT ANY WARRANTY; without even the implied warranty of                    *
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                     *
*   GNU General Public License for more details.                                      *
*                                                                                     *
*   You should have received a copy of the GNU General Public License                 *
*   along with this program; if not, write to the Free Software                       *
*   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.   *
**************************************************************************************/

/*
This is a diver for the MAX6675 K-type thermocouple interface chip. It implements an SPI
bus without the need for dedicated hardware (aka a bit-banged interface). The result from
toFloat_TC() is the temperature in degrees celcius of the thermocouple tip. The rest should
be self-evident. Have a look at the end of the file for example usage.
*/

#ifndef TC_CLK
   #define TC_CLK               PIN_B1            //edit these pins as necessary
#endif

#ifndef TC_CS
   #define TC_CS               PIN_B2
#endif

#ifndef TC_DATA
   #define TC_DATA               PIN_B3
#endif


int1 thermocouple_error;         //a handy dandy global error flag to tell you if a thermocouple is connected or not

void init_TC(void)
{
   output_low(TC_CLK);
   output_low(TC_DATA);
   output_high(TC_CS);            //if we idle high, the chip keeps doing conversions. Change this if you like
}

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_us(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);
      output_low(TC_CLK);
   }

   thermocouple_error=bit_test(data,2);      //this is the thermocouple status bit
       
   output_high(TC_CS);
   return(data);
}

int16 sortout(int16 raw)
{
    return(0x0FFF & (raw>>3));      //returns only the bits converning temperature
}

float toFloat_TC(int16 tmp)
{
   return((float)tmp/4.0);      //adjusts data to floating point format, and accounts for the decimal point
}

float do_everything(void)
{
   init_TC();
   delay_ms(200);               //200ms is a long time to be doing nothing. use a timer interrupt to avoid wasting time here
   return(toFloat_TC(sortout(read_TC())));
}


/*

//example program

#define TC_CLK               PIN_B2
#define TC_CS               PIN_B2
#define TC_DATA               PIN_B1

#include "max6675.c"

void main()
{
   char msg[32];
   delay_ms(50);      //allow oscillator to stabilise

   while(1){
      delay_ms(800);
      sprintf(msg,"%01.2f%cC\r\n",do_everything(),0xB0);
       
      if(thermocouple_error)
         printf("Thermocouple not connected\r\n");   
      else
         printf("%s",msg);
   }
}

*/
Título: Re:Libreria para Max6675 en CCS
Publicado por: KILLERJC en 18 de Julio de 2017, 15:07:29
La lectura es esta:

Código: C
  1. int16 read_TC(void)               //It takes 200ms (ish) for the MAX6675 to perform a conversion
  2. {
  3.    int8 i;
  4.    int16 data;
  5.  
  6.    output_low(TC_CS);            //stop any conversion processes
  7.    delay_us(1);               //and give it some time to power up (not very much, admittedly)
  8.  
  9.    for (i=0;i<16;i++){
  10.       shift_left(&data,2,input(TC_DATA));      //reads in 2 bytes to data from the pin TC_DATA
  11.       output_high(TC_CLK);
  12.       output_low(TC_CLK);
  13.    }
  14.  
  15.    thermocouple_error=bit_test(data,2);      //this is the thermocouple status bit
  16.        
  17.    output_high(TC_CS);
  18.    return(data);
  19. }

Usa un SPI por software, asi que si lo haces por Hardware mejor.
El codigo es correcto, apenas se baja CS procede a llegar el primer bit, luego en cada pulso del reloj tenes el otro, se repite 16 veces, todo correcto hasta aca.
Devuelve el valor data que es lo leido desde el IC, los cuales son 12bits de temepratura, y  de esos 12, hay 2 que son decimales. los otros bits son de informacion.

la funcion sortout quita esos bits de informacion y deja unicamente la temperatura. Te recuerdo, aca tenes ya la temeperatura sola que son 12bits, que si quisieras tomar solamente el entero y no el decimal deberias rotarlo 2 lugares a la derecha para quitarle la coma. Y tendrias tu valor numerico entero
Y luuego lo pasa a float con la funcion toFloat_TC.

En fin, llamar a la funcion do_everything y te devuelve un valro float con la temeperatura.
Título: Re:Libreria para Max6675 en CCS
Publicado por: marcoscab1166 en 18 de Julio de 2017, 15:42:34
Genial, entonces si quiero leer la temperatura bastaria con esto?

float temp;

temp=do_everything();

Y ya tendria la temperatura en celcius?
Título: Re:Libreria para Max6675 en CCS
Publicado por: KILLERJC en 18 de Julio de 2017, 16:25:52
Exacto

Deberias leer tambien el datasheet para compensar la temperatura.
Título: Re:Libreria para Max6675 en CCS
Publicado por: marcoscab1166 en 19 de Julio de 2017, 14:10:15
Bueno estuve intentando pero no logro sacar nada de lectura. Para hacerlo con el hardware SPI del PIC como seria?
Título: Re:Libreria para Max6675 en CCS
Publicado por: KILLERJC en 19 de Julio de 2017, 14:15:48
Una cosa mas, si estas usando un cristal de 10Mhz o mas cambia esto:

Código: C
  1. for (i=0;i<16;i++){
  2.       shift_left(&data,2,input(TC_DATA));      //reads in 2 bytes to data from the pin TC_DATA
  3.       output_high(TC_CLK);
  4.       output_low(TC_CLK);
  5.    }

por

Código: C
  1. for (i=0;i<16;i++){
  2.       shift_left(&data,2,input(TC_DATA));      //reads in 2 bytes to data from the pin TC_DATA
  3.       output_high(TC_CLK);
  4.       delay_us(1);
  5.       output_low(TC_CLK);
  6.    }

Respecto a como hacerlo por hardware, unicamente lo se hacer por XC8, no uso CCS, asi que no te podria ayudar con eso.
Título: Re:Libreria para Max6675 en CCS
Publicado por: marcoscab1166 en 19 de Julio de 2017, 16:26:03
Bueno, cambie esas lineas, pero sigo sin conseguir resultados favorables. El primer problema es que si bien ahora al menos lee algo, el valor no corresponde al de la termocupla. Ademas, en algunas temperaturas tira el error de que no hay termocupla, cuando si hay.
En fin, estuve pensando en cambiar a un amplificador operacional, el LM358. Con ese consigo una lectura aceptable con las termocuplas tipo J. Pero el problema es que yo necesito que reconosca cuando no hay termocupla conectada. Alguna idea para eso?
Título: Re:Libreria para Max6675 en CCS
Publicado por: KILLERJC en 19 de Julio de 2017, 16:59:53
Que estes leyendo quiere decir que al menos la parte digital esta bien.

Aumentaria un poco el delay, ya que el tiempo de conversion va de 180 a 220ms. Y al bajar el CS simplemente corta la conversion
Los terminales son los correctos? Alumel en T+ y Chromel en T-
T- esta conectado a GND?
¿Capacitor de bypass?
¿Cable largo?
¿Dispositivos cerca que generen reuido ?
Título: Re:Libreria para Max6675 en CCS
Publicado por: jorge luis en 06 de Diciembre de 2017, 17:32:26
Hola, necesito su ayuda, estoy intentado leer la temperatura de un termopar con un MAX6675 y un PIC16F877A a 10MHz, en la simulación logro capturar datos, en la programación realice una condición de que si el cable del termopar esta abierto en el LCD debe salir el mensaje "TERMOPAR ABIERTO"(cuando el bit 2 del registro leído esta en 1) pero me encuentro con 3 problemas:

1)  Al momento de variar la temperatura en el termopar a pesar de estar conectado, el mensaje se sobreescribe sobre la temperatura leída y esto continua mientras voy haciendo la variación.
2) Entre el MAX y el PIC puse un switch para hacer pruebas de abrir el circuito, al abrir el switch debería mostrarse el mensaje "TERMOPAR ABIERTO" pero ésto no sucede y se sigue mostrando el valor de temperatura y si vario el valor en el termopar en el lcd se observa tambien la variación cuando deberia estar mostrandose el mensaje.
3) El valor de temperatura que indica en el termopar no coincide con el valor calculado por el pic, el calculo en el pic lo estoy haciendo multiplicando el valor de los 12bits*0.25 (ésto lo saque del calculo de la libreria que se usa en arduino para el MAX6675).

Ojala puedan ayudarme, les agradezco por su tiempo. Adjunto el programa en CCS v5.070, circuito en proteus 8.6 y el datasheet del MAX6675.
Título: Re:Libreria para Max6675 en CCS
Publicado por: M16A14 en 07 de Marzo de 2020, 02:01:58
Hola,

Tengo un inconveniente, estoy utilizando el max6675  con el pic16f877a. Cuando simulo el programa no tengo ningun inconveniente, pero cuando lo pongo en mi montaje, en la lcd me sale el mensaje de error. Agradeceria indicar como puedo solucionar esto.

este es el programa que estoy utilizando

#INCLUDE <16f877a.h>
#fuses HS,NOWDT, NOLVP, XT, NOPROTECT ,NOBROWNOUT ,NOPUT ,NOLVP//hs,noput
#USE DELAY(CLOCK=4000000)

#define TC_CLK     PIN_C3 
#define TC_CS      PIN_C0
#define TC_DATA    PIN_C4
#INCLUDE <LCD.C>
#include "MAX.c"

void main()
{
 LCD_INIT();       //Inicializa el LCD
 LCD_PUTC("\f");   //Borrar el contenido del LCD
 char msg[32];
 delay_ms(50);      //allow oscillator to stabilise 
 
 while(1){
    delay_ms(800);
    LCD_PUTC("\f");
    sprintf(msg,"%1.1f%cC\r\n",do_everything(),0xB0);
    printf(LCD_PUTC,"Temp = %s",msg);
    delay_ms(1000);
   

}
}

esta es la libreria que utilizo


#ifndef TC_CLK
    #define TC_CLK     PIN_C3            //edit these pins as necessary
#endif

#ifndef TC_CS
    #define TC_CS      PIN_C0
#endif

#ifndef TC_DATA
    #define TC_DATA    PIN_C4
#endif

int1 thermocouple_error;         //a handy dandy global error flag to tell you if a thermocouple is connected or not
void init_TC(void)
{
   output_low(TC_CLK);
   output_low(TC_DATA);
   output_high(TC_CS);            //if we idle high, the chip keeps doing conversions. Change this if you like
   //setup_spi (SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_16);
}

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);
   }
   
   thermocouple_error=bit_test(data,2);      //this is the thermocouple status bit 
   output_high(TC_CS);
   delay_ms(1);
   return(data);
}

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);


}
float do_everything(void)
{
   init_TC();
   delay_ms(200);               //200ms is a long time to be doing nothing. use a timer interrupt to avoid wasting time here
   return(toFloat_TC(sortout(read_TC())));
}
Título: Re:Libreria para Max6675 en CCS
Publicado por: KILLERJC en 07 de Marzo de 2020, 14:45:16
Citar
en la lcd me sale el mensaje de error.

Si vos no estas enviando la palabra ERROR al LCD en tu programa, entonces es un problema con el LCD y no con el MAX6675.

Deberias revisar el datasheet del LCD para ver cuando es que da ese mensaje y porque, tal ves la libreria del LCD no este respetando algun tiempo. O enviandole algun caracter raro para el LCD.
Título: Re:Libreria para Max6675 en CCS
Publicado por: M16A14 en 07 de Marzo de 2020, 16:47:09
No, la LCD esta bien, me apare el mensaje cuando el max6675 esta desconectado.
Título: Re:Libreria para Max6675 en CCS
Publicado por: Ruco en 15 de Enero de 2021, 06:12:00
Recién estoy implementando el MAX6675 con los post de este foro. Y me esta lidiando un comentario en particular que ponen dentro de la función:

Código: C++
  1. float do_everything(void)
  2. {
  3.    init_TC();
  4.    delay_ms(200);               //200ms is a long time to be doing nothing. use a timer interrupt to avoid wasting time here
  5.    return(toFloat_TC(sortout(read_TC())));
  6. }

El comentario es //200ms is a long time to be doing nothing. use a timer interrupt to avoid wasting time here o sea que 200ms es mucho tiempo sin hacer nada. Use una interrupción del temporizador para evitar perder el tiempo aquí. En realidad me gustaria implementarlo y evitar este atasco de tiempo.

Como se podría implementar el timer1?. para que en el tiempo de los 200ms el pic este realizando algunas otras tareas en lugar de estar demorando tiempo solo aquí.


Título: Re:Libreria para Max6675 en CCS
Publicado por: KILLERJC en 15 de Enero de 2021, 11:49:25
En realidad eso significa modificar la forma en como programas. Ya que vos necesitas que siga haciendo todo lo demás y cuando llegue nuevamente a esta parte que se fije si paso el tiempo..

Dependiendo de cuanto duren las funciones read_TC, sortout y toFloat_TC vas a poder ponerlo en la interrupcion o no. Si duran muy poco, pero MUY poco. entonces en la interrupcion del timer podes hacer:

Código: C
  1. #INT_TM0  //Ojo que asi no se llama, pero no uso CCS demasiado
  2. void intetTm0(void) {
  3.    valor = toFloat_TC(sortout(read_TC());
  4.    valorNuevo=1;
  5.    disable_interrupt(INT_TM0);
  6. }
  7.  
  8. float do_everything(void)
  9. {
  10.    if(valorNuevo) {
  11.        valorNuevo = 0;
  12.        return valor;  
  13.   } else {
  14.       init_TC();
  15.       set_timer0(xxx); //Valor al timer
  16.       clear_interrupt(INT_TM0);
  17.       enable_interrupt(INT_TM0);
  18.       return 0; //Todavia no listo
  19.   }
  20. }

-------------------------------------------------------

En el caso de que NO duren poco, por que como veo tenes varios funciones con flotantes,etc, entoces conviene que este en el main:

Código: C
  1. #INT_TM0  //Ojo que asi no se llama, pero no uso CCS demasiado
  2. void intetTm0(void) {
  3.    TiempoCumplido=1;
  4.    disable_interrupt(INT_TM0);
  5. }
  6.  
  7. float do_everything(void)
  8. {
  9.    if(TiempoCumplido) {
  10.         //Listo, valor obtenido.
  11.        TiempoCumplido = 0;
  12.        return(toFloat_TC(sortout(read_TC())));  
  13.   } else {
  14.       init_TC();
  15.       set_timer0(xxx); //Valor al timer
  16.       clear_interrupt(INT_TM0);
  17.       enable_interrupt(INT_TM0);
  18.       return 0; //Todavia no listo
  19.   }
  20. }

Obviamente TODAS las demas funciones deberian funcionar de la misma manera.. Es decir sin delays, o que sea dependiente de un solo delay y muy pequeño.
Lo cual deberias remover esos delays de 800ms, y de 1000ms, deberias cambiar a una forma que sea mas desatendida en la transmision de caracteres, y en la recepción también.
Sino por 200ms no tienen ningun sentido, cuando estas esperando 1.8s en tu while.

Por eso mismo dije que deberias cambiar toda la forma de programar.
Título: Re:Libreria para Max6675 en CCS
Publicado por: Ruco en 15 de Enero de 2021, 15:37:40
Estoy probando el codigo y no muestra la temperatura.. El valor para el desborde del timer es 3036 por que lo trabajo a 20Mhz y con 3036 alcanzo 200ms del timer.

Asi es como decis Killer JC
Código: C++
  1. short TiempoCumplido=0;
  2.          
  3.          #INT_TIMER0                                                                        //Ojo que asi no se llama, pero no uso CCS demasiado
  4.          void intetTm0(void) {
  5.          set_timer1(3036);
  6.          TiempoCumplido=1;
  7.          disable_interrupts(INT_TIMER0);
  8.          }
  9.          
  10.          float do_everything(void)
  11.          {
  12.          if(TiempoCumplido) {
  13.         //Listo, valor obtenido.
  14.          TiempoCumplido = 0;
  15.          return(toFloat_TC(sortout(read_TC())));  
  16.          } else {
  17.          init_TC();
  18.          set_timer0(3036); //Valor al timer
  19.          //clear_interrupt(INT_TIMER0);
  20.          enable_interrupts(INT_TIMER0);
  21.          return 0; //Todavia no listo
  22.          }
  23.          }


En el Main

Código: C++
  1. void main()
  2.          {
  3.          lcd_init();      
  4.          setup_timer_0(RTCC_INTERNAL|RTCC_DIV_16);                
  5.          set_timer0(3036);
  6.          enable_interrupts(INT_TIMER0);  
  7.          enable_interrupts(global);                                                       //Activamos las interrupciones globales
  8.          
  9.          while(true){
  10.          lcd_gotoxy(1,2); printf(lcd_putc,"Todopic %3.2f%cC ",do_everything(),0xDF);  
  11.          
  12.          }
  13.          }

pero no muestra nada.

Este es el resto del codigo...

Código: C++
  1. #define TC_CLK     PIN_E1
  2.          #define TC_CS      PIN_E2
  3.          #define TC_DATA    PIN_E0
  4.  
  5.          short thermocouple_error;                                              // bandera de error global para indicarle si un termopar está conectado o no
  6.  
  7.          void init_TC(void)
  8.          {
  9.          output_low(TC_CLK);
  10.          output_low(TC_DATA);
  11.          output_high(TC_CS);            //if we idle high, the chip keeps doing conversions. Change this if you like
  12.          }
  13.  
  14.          int16 read_TC(void)               //It takes 200ms (ish) for the MAX6675 to perform a conversion
  15.          {
  16.          int8 i;
  17.          int16 data;
  18.          output_low(TC_CS);            //stop any conversion processes
  19.          delay_ms(1);               //and give it some time to power up (not very much, admittedly)
  20.            
  21.          for (i=0;i<16;i++){
  22.          shift_left(&data,2,input(TC_DATA));      //reads in 2 bytes to data from the pin TC_DATA
  23.          output_high(TC_CLK);
  24.          delay_us(100); //Descomentar si usa crystal mayor a 10MHz
  25.          output_low(TC_CLK);
  26.          delay_us(100);
  27.          }
  28.            
  29.          thermocouple_error=bit_test(data,2);      //this is the thermocouple status bit
  30.          output_high(TC_CS);
  31.          return(data);
  32.          }
  33.  
  34.          int16 sortout(int16 raw)
  35.          {
  36.          return(0x0FFF & (raw>>3));      //returns only the bits converning temperature
  37.          }
  38.  
  39.          float toFloat_TC(int16 tmp)
  40.          {
  41.          return((((float)tmp)-48.725)/1.9835);
  42.          }
Título: Re:Libreria para Max6675 en CCS
Publicado por: KILLERJC en 15 de Enero de 2021, 16:03:02
Si perdon... ahí te lo corrijo.
Título: Re:Libreria para Max6675 en CCS
Publicado por: KILLERJC en 17 de Enero de 2021, 21:44:00
Código: C
  1. volatile uint8_t tcState;  // Usaria static, solo que el compilador CCS no le va a bien demasiados archivos.
  2.  
  3. #INT_TIMER0                                                                        //Ojo que asi no se llama, pero no uso CCS demasiado
  4. void intetTm0(void) {
  5.   tcInterruptTimerHandler();
  6. }
  7.  
  8.  
  9.  
  10. float do_everything(void)
  11. {
  12.   // Defino las variables
  13.   float resultado = 0;
  14.  
  15.  
  16.   switch (tcState) {
  17.     case 0:
  18.       init_TC();
  19.       set_timer0(3036); //Valor al timer
  20.       enable_interrupts(INT_TIMER0);
  21.       tcState++;
  22.       break;
  23.     case 1:
  24.       //Espero por el timer
  25.       break;
  26.     case 2:
  27.       resultado = toFloat_TC(sortout(read_TC()));
  28.       tcState = 0;
  29.       break;
  30.     default:
  31.       // Por si las dudas
  32.       tcState = 0;
  33.       break;
  34.   }
  35.  
  36.   return resultado;
  37. }
  38.  
  39. void tcInterruptTimerHandler(void) {
  40.   if(tcState==1) {
  41.     tcState++;
  42.   } else {
  43.     tcState = 0;
  44.   }
  45.   disable_interrupts(INT_TIMER0);
  46. }
  47.  
  48. void main()
  49. {
  50. lcd_init();      
  51. setup_timer_0(RTCC_INTERNAL|RTCC_DIV_16);                
  52. enable_interrupts(global);                                                       //Activamos las interrupciones globales
  53.  
  54.  while(true){
  55.    float aux;
  56.    aux = do_everything();
  57.    if (aux != 0){
  58.       lcd_gotoxy(1,2);
  59.       printf(lcd_putc,"Todopic %3.2f%cC ",aux,0xDF);  
  60.    }
  61.  }
  62. }

Solo una cosa, recorda que el codigo NO ESTA probado, simplemente lo acabo de editar en el bloc de notas y te lo estoy entregando..
Título: Re:Libreria para Max6675 en CCS
Publicado por: Ruco en 18 de Enero de 2021, 12:44:46
Grcias Killerjc. Ahora lo compilo en ccs c y pongo resultados. Gracias nuevamente por responder.
Título: Re:Libreria para Max6675 en CCS
Publicado por: Ruco en 20 de Enero de 2021, 00:07:01
KILLERJC.

Ahora pude probar el código que me colocaste en el post.  Ahora funciona..  :P

Aquí el code para 20Mhz ...

Código: C++
  1. float do_everything(void);
  2.          void tcInterruptTimerHandler(void);
  3.          
  4.          volatile int8 tcState;
  5.          float aux;
  6.                  
  7.          #INT_TIMER0                                                                      
  8.          void intetTm0(void)
  9.          {
  10.          tcInterruptTimerHandler();        
  11.          }        
  12.          
  13.          float do_everything(void)
  14.          {
  15.          float resultado = 0;
  16.  
  17.          switch(tcState)
  18.          {
  19.          case 0:
  20.                   init_TC();
  21.                   set_timer0(3036);                                  // Valor al timer
  22.                   enable_interrupts(INT_TIMER0);
  23.                   tcState++;                  
  24.                   break;
  25.          case 1:
  26.                                                                      // Espero por el timer                  
  27.                   break;
  28.                  
  29.          case 2:  
  30.                   resultado = toFloat_TC(sortout(read_TC()));
  31.                   tcState = 0;
  32.                   break;
  33.                   default:                  
  34.                   tcState = 0;                                       // Por si las dudas
  35.                   break;
  36.          }
  37.                   return resultado;
  38.          }
  39.  
  40.          void tcInterruptTimerHandler(void) {
  41.          if(tcState==1) {output_toggle(pin_b0);
  42.          tcState++;
  43.          } else {
  44.          tcState = 0;
  45.          }
  46.          disable_interrupts(INT_TIMER0);
  47.          }
  48.          
  49.          void main()
  50.          {
  51.          lcd_init();      
  52.          setup_timer_0(RTCC_INTERNAL|RTCC_DIV_16);                  
  53.          set_timer0(3036);
  54.          enable_interrupts(INT_TIMER0);  
  55.          enable_interrupts(global);                                                       //Activamos las interrupciones globales
  56.          
  57.          while(true){
  58.          aux = do_everything();
  59.          if (aux != 0){
  60.          lcd_gotoxy(1,2); printf(lcd_putc,"Todopic %3.2f%cC ",aux,0xDF);        
  61.          }
  62.          }
  63.          }

En la imagen del proteus se muestra el tiempo de los 200 ms del timer0 obtenida con un output_toggle(pin_b0); del pin_b0.

Ahora tengo una pregunta... veo que ¿si dentro del ciclo infinito while (true) { genero alguna demora con delay_ms(); ese delay_ms(x); esos X tiempo se suma a los 200 ms del timer0, eso por que?. Si supuestamente esos 200ms del timer0 son continuos y fijos.

Ahora también lo probé físico y funciona!!.


Título: Re:Libreria para Max6675 en CCS
Publicado por: KILLERJC en 20 de Enero de 2021, 12:34:01
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:

Código: C
  1. int16 read_TC(void)               //It takes 200ms (ish) for the MAX6675 to perform a conversion
  2.          {
  3.          int8 i;
  4.          int16 data;
  5.          output_low(TC_CS);            //stop any conversion processes
  6.          delay_ms(1);               //and give it some time to power up (not very much, admittedly)
  7.            
  8.          for (i=0;i<16;i++){
  9.          shift_left(&data,2,input(TC_DATA));      //reads in 2 bytes to data from the pin TC_DATA
  10.          output_high(TC_CLK);
  11.          delay_us(100); //Descomentar si usa crystal mayor a 10MHz
  12.          output_low(TC_CLK);
  13.          delay_us(100);
  14.          }

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.


Código: C
  1. int16 sortout(int16 raw)
  2.          {
  3.          return(0x0FFF & (raw>>3));      //returns only the bits converning temperature
  4.          }
  5.  
  6.          float toFloat_TC(int16 tmp)
  7.          {
  8.          return((((float)tmp)-48.725)/1.9835);
  9.          }

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.

Código: C
  1. while(true){
  2.    aux = do_everything();
  3.    if (aux != 0){
  4.       lcd_gotoxy(1,2); printf(lcd_putc,"Todopic %3.2f%cC ",aux,0xDF);        
  5.    }
  6. }

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:

Código: C
  1. while(true){
  2.    aux = do_everything();
  3.    if (aux != 0){
  4.       lcd_gotoxy(1,2); printf(lcd_putc,"Todopic %3.2f%cC ",aux,0xDF);        
  5.    }
  6.    delay_ms(500);
  7. }

Ahora, que pasa si agregamos MAS instrucciones, supongamos que tengo una funciona que tarda 300ms en ejecutarse

Código: C
  1. while(true){
  2.    aux = do_everything();
  3.    if (aux != 0){
  4.       lcd_gotoxy(1,2); printf(lcd_putc,"Todopic %3.2f%cC ",aux,0xDF);        
  5.    }
  6.    mi_funcion_que_tarda_300_ms();
  7.    delay_ms(500);
  8. }

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.

Código: C
  1. while(true){
  2.    aux = do_everything();
  3.    if (aux != 0){
  4.       lcd_gotoxy(1,2); printf(lcd_putc,"Todopic %3.2f%cC ",aux,0xDF);        
  5.    }
  6.    if(contador_mi_funcion++ == 30) {
  7.       mi_funcion_sin_demoras()
  8.       contador_mi funcion =0;
  9.     }
  10.    delay_ms(10);
  11. }
Título: Re:Libreria para Max6675 en CCS
Publicado por: Ruco en 20 de Enero de 2021, 13:31:39
Saludos Killerjc me queda claro y es exactame te a lo me referia. Los tiempos se van sumando. Cual seria la mejor solucion para optimizar el codigo y hacerlo mas efectivo sin tantas demosras en cuestion de la libreria del max6675. Olvidandonos de los delay denteo del while(true)?. Casi todo dentro del timer como mencionaste?... o hacetlo spi por harware y de igualmanera usando interrupvuon del timer?... Gracias.
Título: Re:Libreria para Max6675 en CCS
Publicado por: KILLERJC en 20 de Enero de 2021, 13:56:25
Todo va a depender de tu proyecto de las cosas que pienses en agregarle, etc, en realidad tenes que verlo como un todo.

Si no vas a usar otra interrupcion, y tampoco te importa algunos milisegundos de mas en tu programa principal, llevamos todo eso a la interrupcion.

Vos luego vas a tener que definir si lo queres ciclico, o si queres que no siempre se muestre en el LCD, etc. Como dije antes, depende de que necesitas que haga el codigo. Porque puedo programarlo de una forma, pero luego al querer agregar otra terminas con otro problema.
Título: Re:Libreria para Max6675 en CCS
Publicado por: Ruco en 20 de Enero de 2021, 14:04:33
Ok. Yo como.bien lo dices. Depende de como este  todo el cosigo a la necesidad. E aprendido mucho en este foro gracias apersonas como tu. Te agradezco tanto tu tiempo.

Solo algo mas. Como seria pasarlo lo mas posible del codigo dentro del timer?...
Título: Re:Libreria para Max6675 en CCS
Publicado por: KILLERJC en 20 de Enero de 2021, 15:48:49
Es decir hacerlo todo en la interrupcion, y el while te queda para lo que quieras.

Así como esta el código, cada 400ms tendrías una conversión, si lo queres cada 200ms hay que modificar un poco el código.

Código: C
  1. float do_everything(void);
  2.  
  3. volatile int8 tcState;
  4.                
  5. #INT_TIMER0                                                                      
  6. void intetTm0(void)
  7. {
  8.   set_timer0(3036);
  9.   do_everything();  
  10. }        
  11.        
  12. void do_everything(void)
  13. {
  14.   float resultado = 0;
  15.  
  16.   if(!tcState){
  17.     init_TC();
  18.     tcState = 1;
  19.   } else {
  20.     resultado = toFloat_TC(sortout(read_TC()));
  21.     lcd_gotoxy(1,2); printf(lcd_putc,"Todopic %3.2f%cC ",resultado,0xDF); // No es necesario imprimir todo, podes solo imprimir el numero        
  22.     tcState = 0;
  23.   }
  24. }
  25.  
  26.  
  27. void main()
  28. {
  29.   lcd_init();      
  30.   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_16);                  
  31.   set_timer0(3036);
  32.   enable_interrupts(INT_TIMER0);  
  33.   enable_interrupts(global); //Activamos las interrupciones globales
  34.  
  35.   while(true){
  36.   }
  37. }
Título: Re:Libreria para Max6675 en CCS
Publicado por: Ruco en 22 de Enero de 2021, 02:57:59
KillerJC, así como mencionas queda mejor.

Creo que así queda mejor por que realiza independientemente el proceso del MAX6675. Se puede verificar que los 400ms del sensor son tiempor constantes aunque haya retardo de 500ms en el while (true).

Código: C++
  1. void do_everything(void);
  2.          
  3.          volatile int8 tcState;
  4.          float resultado = 0;
  5.                  
  6.          #INT_TIMER0                                                                      
  7.          void intetTm0(void)
  8.          {
  9.          set_timer0(3036);
  10.          do_everything();  
  11.          }        
  12.    
  13.          void do_everything(void)
  14.          {
  15.          if(!tcState){
  16.          init_TC(); output_toggle(pin_b0);
  17.          tcState = 1;
  18.          } else {        
  19.          tcState = 0;
  20.          }
  21.          }
  22.  
  23.          void main()
  24.          {
  25.          lcd_init();      
  26.          setup_timer_0(RTCC_INTERNAL|RTCC_DIV_16);                  
  27.          set_timer0(3036);
  28.          enable_interrupts(INT_TIMER0);  
  29.          enable_interrupts(global);                                                       //Activamos las interrupciones globales
  30.          
  31.          while(true){
  32.          resultado = toFloat_TC(sortout(read_TC()));
  33.          lcd_gotoxy(1,2); printf(lcd_putc,"Todopic %3.2f%cC ",resultado,0xDF); // No es necesario imprimir todo, podes solo imprimir el numero  
  34.          output_high(pin_b1); delay_ms(500);
  35.          output_low(pin_b1);  delay_ms(500);
  36.          }
  37.          }


Si coloco:

Código: C++
  1. resultado = toFloat_TC(sortout(read_TC()));
  2.          lcd_gotoxy(1,2); printf(lcd_putc,"Todopic %3.2f%cC ",resultado,0xDF); // No es necesario imprimir todo, podes solo imprimir el numero

dentro de la función void do_everything(void) me marca unos warning que dicen... >>> Warning 216  Interrupts disabled during call to prevent re-entrancy:  (@delay_ms1).

Por eso creu que es mejor sacarlo de ahi y colocarlo en el while(true), ya que ahi esta libre de Warning.

KillerJC

Citar
Así como esta el código, cada 400ms tendrías una conversión, si lo queres cada 200ms hay que modificar un poco el código.

Mencionaste de esos 400ms que ahora los vemos en el proteus; y mencionas también que se pueden reducir a 200ms, como se haria eso?...


En la imagen los 400ms del sensor y los 500ms de un led parpadeante
Título: Re:Libreria para Max6675 en CCS
Publicado por: KILLERJC en 22 de Enero de 2021, 11:31:10
En tu codigo es como que esta todo aparte, ya no tiene sentido.
Vos tenes 2 partes a tener en cuenta y es necesario tener en claro:

init_tc() es la funcion que inicia la conversion. Espero el 200ms
read_tc() es la funcion que lee la conversion una ves que termino el tiempo.


Esas dos funciones tienen que estar separadas por 200ms, despues puede haber el tiempo que sea entre que termino read_tc y comienza el otro init_tc.

Vos estas midiendo temperatura. La temperatura normalmente no cambia RAPIDO, es un proceso lento, por lo que no tiene ningun sentido volverse loco con que si o si lo haga cada 200ms otra lectura.  Si lo haces cada 1 segundos te va a sobrar.

Citar
dentro de la función void do_everything(void) me marca unos warning que dicen... >>> Warning 216  Interrupts disabled during call to prevent re-entrancy:  (@delay_ms1).

Desactiva las interrupciones debido a que:
el LCD tarda demasiado.
el codigo de division de float tarda demasiado.
etc

Si todo ese tiempo supera los 200ms del timer, entonces nunca se ejecutaria lo del while, ya que apenas salga volveria a entrar a la interrupcion.
Por eso desabilita la interrupcion. Para prevenir la re-entrada.


Segun tu codigo cada 400ms se ejecuta init_TC
y luego de todo esto:

Código: C
  1. output_high(pin_b1); delay_ms(500);
  2.         output_low(pin_b1);  delay_ms(500);

Tenes tu conversion.. Vamos a suponerlo como que se ejecutan en paralelo, los tiempos donde se ejecutan init_tc y read_tc son estos:

0ms - Lectura (read_tc)
200ms - Inicio ( init_tc )
600ms - Inicio de vuelta
1000ms - inicio y Lectura, condicion de carrera por cual es primero.
1400ms - Inicio
1800ms - Inicio
2000ms - Lectura
2200ms - Inicio

Ves que es un desastre ?

Si lo queres "continuo", entonces dejalo como estaba... a pesar que aparezca el warning ya que como te dije: NO DEBO PONER COSAS QUE DEMOREN MUCHO EN LA INTERRUPCION!.
Pero como es una sola interrupción no nos molesta.

Y modificale esta parte del codigo


Código: C
  1. #INT_TIMER0                                                                      
  2.          void intetTm0(void)
  3.          {
  4.          do_everything();  
  5.          set_timer0(3036);
  6.          clear_interrupt(INT_TIMER0);
  7.          }

De esa forma, el init_TC no va a tener problemas, se va aejecutar y salir.
El read_tc con todo lo que trae aparejado, al salir (tarde lo que tarde) pone el timer a 200ms, y limpia el flag para que no entre de unevo si se pasaron los 200ms.

Con esto vas a lograr que:

entre el init_tc y el read_tc tengas los 200ms
Entre el final del read_tc y el nuevo init_tc vas a tener 200ms + lo que tarde lo del LCD, el float, read_tc, etc.

Ahi te vas a dar cuenta, cuanto tarda todo eso que se puso en la interrupcion.

Obviamente si observas los "500ms" de tu while, ya no son mas "500ms". Si queres precision en varias coisas, entonces todo pasaria por un timer y volveriamos al primer codigo que te pase.
Título: Re:Libreria para Max6675 en CCS
Publicado por: Ruco en 22 de Enero de 2021, 12:20:53

Gracias. Lo voy a colocar como dices
Código: C++
  1. #INT_TIMER0                                                                      
  2.          void intetTm0(void)
  3.          {
  4.          do_everything();  
  5.          set_timer0(3036);
  6.          clear_interrupt(INT_TIMER0);
  7.          }

Y aunque aparezca.el warning lo coloco dentro de la funcion.

Título: Re:Libreria para Max6675 en CCS
Publicado por: KILLERJC en 22 de Enero de 2021, 12:34:14
Usalo asi y ahora si queres pone el ouput_toggle en esa función, de esa forma vas a ver el tiempo que tarda cada cosa.

Código: C
  1. #INT_TIMER0                                                                      
  2.          void intetTm0(void)
  3.          {
  4.          output_toggle(pin_b0);
  5.          do_everything();  
  6.          set_timer0(3036);
  7.          clear_interrupt(INT_TIMER0);
  8.          }

Entonces cambia cada vez que entra.. De esa forma podes ver el tiempo...

Si lo del LCD mas todo lo demas no supera los 200ms, podes mover el set_timer antes del do_everything.

PD:
Si por las dudas... ya que odio que los compiladores te agreguen cosas por ellos solos... si no te funciona, activa las interrupciones tambien LUEGO del clear_interrupt. (solo activa la del timer 0)
Título: Re:Libreria para Max6675 en CCS
Publicado por: Ruco en 23 de Enero de 2021, 22:40:30
Todo bien, la lectura de temperatura es buena y dentro de la interrupción  :-/ .

Solo como comentario. Valdría la pena tratar de meter las  funciones return(raw & 0b0111111111111000)>>3; y return((((float)tmp)-48.725)/1.9835); en la funcion  int16 read_TC(void), para no tener tantas funciones y después unirlas o seria mejor tener solo una función?.

Me refiero a estas...

Código: C++
  1. int16 read_TC(void)               //It takes 200ms (ish) for the MAX6675 to perform a conversion
  2.          {
  3.          int8 i;
  4.          int16 data;
  5.          output_low(TC_CS);            //stop any conversion processes
  6.          [b]delay_us(1);[/b]               //and give it some time to power up (not very much, admittedly)
  7.            
  8.          for (i=0;i<16;i++){
  9.          shift_left(&data,2,input(TC_DATA));      //reads in 2 bytes to data from the pin TC_DATA
  10.          output_high(TC_CLK);
  11.          [b]delay_us(1); [/b]//Descomentar si usa crystal mayor a 10MHz
  12.          output_low(TC_CLK);
  13.          [b]delay_us(1);[/b]
  14.          }
  15.            
  16.          thermocouple_error=bit_test(data,2);      //this is the thermocouple status bit
  17.          output_high(TC_CS);
  18.          
  19.          return (data);      
  20.          }
  21.  
  22.          int16 sortout(int16 raw)
  23.          {
  24.          return(raw & 0b0111111111111000)>>3;      //returns only the bits converning temperature
  25.          }
  26.  
  27.          float toFloat_TC(int16 tmp)
  28.          {
  29.          return((((float)tmp)-48.725)/1.9835);
  30.          }

Por cierto e cambiado los tiempos  (marcados en negrita) de 1ms y de 100us a 1us todos ellos y manteniéndose la buena lectura del sensor.

KillerJC. Muy agradecido por todo,  :-/
Título: Re:Libreria para Max6675 en CCS
Publicado por: KILLERJC en 24 de Enero de 2021, 09:58:20
En la parte del SPI es decir esta:

Código: C
  1. for (i=0;i<16;i++){
  2.          shift_left(&data,2,input(TC_DATA));      //reads in 2 bytes to data from the pin TC_DATA
  3.          output_high(TC_CLK);
  4.          [b]delay_us(1); [/b]//Descomentar si usa crystal mayor a 10MHz
  5.          output_low(TC_CLK);
  6.          [b]delay_us(1);

El tamaño minimo en 1 y en 0 del clock es de 100ns segun el datasheet. Si tenes un micro PIC16/18 a 20Mhz, incluso quitando los delays, tendrias 200ns, por lo que SOBRA.
Asi que hasta 40Mhz para ser exactos con un PIC16/18 no existiria problemas y no es necesario el delay. Lo mismo ocurre con el tiempo entre la señal del CS y el comienzo del clk.

Código: C
  1. output_low(TC_CS);            //stop any conversion processes
  2.          [b]delay_us(1);[/b]               //and give it some time to power up (not very much, admittedly)

Tambien el tiempo necesario es de 100ns segun datasheet del MAX, si a 20Mhz las instrucciones tardan 200ns no tendrias problemas, ademas observa que tenes el for, el shift, etc, lo que hace mas tiempo aun. También se podría quitar este delay por completo.
O comentarlos así quedan por si las dudas


-----------------------------------------------


Citar
Valdría la pena tratar de meter las  funciones return(raw & 0b0111111111111000)>>3; y return((((float)tmp)-48.725)/1.9835); en la funcion  int16 read_TC(void), para no tener tantas funciones y después unirlas o seria mejor tener solo una función?.

Normalmente para esos casos cuando son conversiones asi tan cortas por legibilidad se prefiere que este en alguna funcion aparte. Da mas sentido a lo que se esta haciendo cuando lees el codigo.
Se suele usar el palabra "inline" para definir la funcion, de esa forma el compilador no crea una llamada, sino que solo la reemplaza en el lugar. Reduciendo el stack, etc.
Pero dependiendo del compilador, y de las optimizaciones que tengan, puede que solo lo haga "inline". Asi que vos solo te preocuparias por la legibilidad de tu codigo.

Hay compiladores que no soportan el uso de inline... Solo por las dudas lo nombro.

----------------------------------------------------------

Uno de los grandes problemas que vas a tener con CCS es la no posibilidad de crear varios archivos, por ejemplo estas funciones que son de MAX, deberian estar en un archivo aparte exclusivamente con fuciones para este, de esa forma hay menos cosas en tu archivo principal.
Título: Re:Libreria para Max6675 en CCS
Publicado por: Ruco en 24 de Enero de 2021, 11:09:36

De mi parte estoy agradecido por la ayuda que e encontrado en este foro ya que ahora funciona mucho mejor el sensor. Así que te agradezco KILLERJC por tu tiempo. Gracias.
Título: Re:Libreria para Max6675 en CCS
Publicado por: remi04 en 24 de Enero de 2021, 16:36:40
Exacto

Deberias leer tambien el datasheet para compensar la temperatura.

Entiendo que si el Max está justo a pie de conector y expuesto a la misma temperatura ambiente que la unión en el bornero se compensa solo mediante un diodo interno ¿es así?.
Título: Re:Libreria para Max6675 en CCS
Publicado por: KILLERJC en 24 de Enero de 2021, 17:03:50
Si, si está todo a temperatura ambiente se compensa solo.

Seguramente lo que quise decirle al otro usuario fue que tenga en cuenta lo de la compensación. Por eso lo envié a leer el datasheet xD