Revivo el tema después de mucho tiempo. Disculparán que no haya podido seguir con el tema, pero por cuestiones personales y de trabajo había tenido muy poco tiempo para dedicárselo a mis proyectos de hobby. Seguramente sabrán que llevar a cabo un proyecto al mismo tiempo que se documenta todo demanda mucho tiempo. En fin... como les comento, no he tenido oportunidad de avanzar así que comenzaré donde se quedó este asunto.
Interfaz Termopar/Microcontrolador.El circuito integrado MAX6675 de Maxim/Dallas Semiconductor es un convertidor analógico a digital para termopares tipo K. Bueno, la verdad es que este circuito tras su apariencia inocente con un encapsulado SOIC de 8 pines, esconde mucho más que un ADC y nos ahorrará bastante espacio al momento de diseñar un circuito impreso.

Dentro de este pequeño circuito se encuentra la electrónica necesaria para amplificar, compensar y convertir a digital el voltaje generado por el termopar, lo que hace muy sencilla la tarea de conectar un termopar a un microcontrolador. El único “pero” es que este circuito solo se consigue en encapsulado SOIC, por lo que no es tan fácil usarlo en el protoboard y hará falta adquirir o fabricar un adaptador para poder experimentar.
Existen muchos sensores de temperatura en el mercado, sin embargo las soluciones basadas en silicio, como el LM35 por citar un ejemplo que sea familiar, están normalmente limitados a un rango de temperatura por debajo de los 150 grados centígrados. Lo que los deja fuera de consideración cuando debemos monitorear algún proceso con temperaturas superiores, afortunadamente los termopares vienen a salvar el día, permitiéndonos mediciones en un rango más amplio, usualmente de varias centenas de grados centígrados y sin un costo excesivo.
Características del MAX6675Hay algunas características importantes que se deben tomar en cuenta antes de usar este circuito, a continuación las más importantes:
- Interfaz compatible con SPI solo de lectura.
- Resolución de 12 bits, 0.25 grados centígrados.
- Medición hasta 1024 grados centígrados.
- Alimentación de 3.3 a 5 volts.
- Frecuencia de reloj SPI máxima Fscl 4.3 Mhz.
- Tiempo de conversión 0.17 s máximo 0.22 segundos.
- Consumo máximo de 1.5 mA.
Existen más, pero creo que aquí esta lo más importante, para más detalles habrá que consultar la hoja de datos que proporciona el fabricante. A continuación tenemos el diagrama a bloques que encontramos en la hoja de datos para darnos una idea de como esta constituido este pequeño integrado.
Formato de Salida.El MAX6675 se conecta con un microcontrolador mediante una interfaz de 3 lineas compatible con el estándar SPI. El formato en el que el MAX6675 envía datos al microcontrolador es el siguiente.

Como se puede observar, además de la palabra digital correspondiente a la temperatura tenemos un bit que nos indica si el termopar esta abierto (desconectado o roto, por ejemplo) que podemos usar para tomar acciones correctivas o informativas en el software, como disparar una alarma o mostrar un aviso. También hay una buena cantidad de bits que no tienen significado.
Sobre el software para el termoparUsaremos el módulo SPI con interrupciones del microcontrolador para comunicarnos con el MAX6675. El software que escribí, usa colas (queues) de FreeRTOS para gestionar la entrada de datos por el módulo SPI al que esta conectado el MAX6675 (I/O de datos por interrupcion), sin embargo las funciones de colas e incluso las funciones asociadas a la interrupción pueden descartarse y simplemente usar la técnica de bit polling para esperar hasta que el módulo SPI termine la transferencia, por lo tanto puede usarse este código como base para usar el MAX6675 con cualquier otro microcontrolador sin importar nuestras preferencias o requisitos de programación.
* Inicializar módulo SPI: Afortunadamente el MAX6675 no requiere de ninguna inicialización, por lo tanto lo único que hace esta función es cargar los valores iniciales en los registros del módulo SPI del PIC. Existe otra función para inicializar la cola de FreeRTOS con la que se comunicará el MAX con la aplicación (ver archivos de código fuente), la cual recomiendo llamar mientras realicemos la inicialización de los recursos del RTOS.
void vThermocoupleSPISetUp() // Setup SPI module for MAX6675 operation
{
CONF_CS_MAX6675_PORT = 1; // Initialize MAX6675 pin select status
CONF_CS_MAX6675_TRIS = 0; // Initialize MAX6675 pin TRIS register bit as output
// SPI1 module configuration
SPI1CON1 = 0x043A; // Primary prescaler 2:1, secondary 4:1 2 Mhz @ 16 MIPS
SPI1CON2 = 0x0000; // No framed SPI support
// Interrupt configuration
IFS0bits.SPI1IF = 0; // Clear interrupt flag
IEC0bits.SPI1IE = 1; // Enable SPI interrupt
SPI1STAT=0; // Clear SPI status flags
SPI1STATbits.SPIEN =1; // Enable SPI module
}
* Leyendo el resultado: Si observamos el formato de salida del MAX6675 veremos que los datos transmitidos tienen una buena cantidad de bits de relleno o sin significado, por lo que hay que eliminarlos antes de que el resultado pueda usarse para convertirse a grados centígrados. La función en C que escribí para leer el termopar retorna un unsigned int que corresponde al valor leído desde el MAX6675, NO a la temperatura en grados centígrados.
unsigned int iThermocoupleRead()
{
unsigned int iTempBuffer = 0;
CONF_CS_MAX6675_PORT = 0; // Force Chip Select to low
asm("nop");
asm("nop"); // Wait for CS to stabilize, 100 nS min( view timing diagrams )
SPI1BUF = 0xAAAA; // Transmit dummy byte to start reception
xQueueReceive( xThrmcplQueue, &iTempBuffer, portMAX_DELAY ); // The caller task is blocked until the thermocouple reading is received
iTempBuffer &= 0x7FF8; // Apply mask to leave valid data only
iTempBuffer = iTempBuffer >> 3; // align data
return iTempBuffer;
}
Rutina de interrupción: En la rutina de interrupción del modulo SPI se realiza la lectura del registro correspondiente al buffer de recepción y se envía la palabra leída a través de la cola para que sea procesada por el código de la aplicación.
void iThermocoupleISR( void )
{
portBASE_TYPE xTaskWoken; // indicates if a context switch should occur after this interrupt
unsigned int iTempBuffer = 0;
iTempBuffer = SPI1BUF;
xQueueSendToBackFromISR( xThrmcplQueue, &iTempBuffer, &xTaskWoken ); // Send received word to the queue
CONF_CS_MAX6675_PORT = 1; // return chip select to the idle state
if( xTaskWoken )
taskYIELD(); // context switch if a higher priority task is woken
return;
}
void __attribute__((interrupt, auto_psv)) _SPI1Interrupt (void)
{
iThermocoupleISR();
IFS0bits.SPI1IF = 0; // Clear interrupt flag
}
Como se puede ver realizar la medición de temperatura es bastante fácil, ni siquiera hay que preocuparse demasiado de los detalles de la conversión A/D. Lo único que se debe tomar en cuenta es que al MAX6675 le toma alrededor de 220 milisegundos como máximo completar una conversión, por lo que como máximo debemos leer el valor de la temperatura unas 4 o 5 veces por segundo. Esto será más que suficiente para la mayoría de las aplicaciones. Hay que recordar que al llamar a la función iThermocoupleIsOpen() equivale a leer la temperatura y por lo tanto además del bit de termopar abierto, vamos a leer la ultima conversión de temperatura que realizo el integrado con su reloj interno. Voy a citar la hoja de datos del integrado:
Force CS low and apply a clock signal at SCK to read the results at SO. Forcing CS low immediately stops any conversion process. Initiate a new conversion process by forcing CS high.
Por lo tanto, si llamamos a la función iThermocoupleIsOpen() e inmediatamente después llamamos a iThermocoupleRead() cualquier proceso de conversión que el MAX pudiera estar realizando entre las llamadas a dichas funciones se detendrá y las dos funciones leerán el mismo valor de temperatura, que es el correspondiente a la última conversión que se pudo completar (aunque la función iThermocoupleIsOpen no toma en cuenta el valor de temperatura, aún así tiene que leerlo). En resumen… hay que respetar el ciclo de CS para el MAX6675 y permitirle 220 milisegundos entre lecturas, de lo contrario hay que estar consientes de lo que esperamos leer:
int iDiagnosticThermocouple( xHardwareResources xHardware, void * pvActionParams )
{
char cBuffer[17];// Holds the string to be printed to the LCD
vLcdDriverCommand( lcdCLEAR, xHardware->xLcdDisplay ); // Clear LCD display
do
{
vLcdDriverCommand( lcdHOME, xHardware->xLcdDisplay ); // move pointer/cursor to address 0
if( !iThermocoupleIsOpen()) // check if thermocouple is open
vHelpersAltSprintf( cBuffer, "Probe 1: %03u%cC", iThermocoupleRead()/4, 0xDF ); // If not, read and display the current temperature
else
vHelpersAltSprintf( cBuffer, "Probe 1: Open" ); // Display thermocouple open
vLcdDriverPutStr( cBuffer, xHardware->xLcdDisplay ); // Print line to LCD
vTaskDelay(500);
}
while( xKeypadGetEvent( xHardware->xKeypad, NULL, 0) == pdFALSE );
return 0;
}
Como se puede ver en mi función de diagnostico, se llama a las dos funciones iThermocoupleIsOpen() y iThermocoupleRead() sin ningún retardo entre ellas, por lo tanto, el valor del campo temperature reading será el mismo en ambas lecturas, sin embargo, verán que respeto el tiempo mínimo de conversión cuando espero valores válidos, manteniendo la linea CS en alto por mas de 220 mS (de hecho son 500 mS). Podría hacerse en definitiva de muchas otras formas, pero esta es la que implemente yo. Ahora si no se respeta este limite, lo que pasará es que leeremos el mismo valor de temperatura SIEMPRE, ya que el MAX6675 nunca terminará la conversión.
Consideraciones finales sobre el termopar y el MAX6675Hay que recordar que el termopar opera con voltajes muy bajos que son amplificados. He notado que las mediciones son bastante sensibles a la interferencia de otros aparatos, por ejemplo, sucede que al acercar el cable de una fuente de poder conmutada de una laptop (que es de dudosa calidad y al parecer mal filtrada) la medición que realiza el MAX6675 muestra valores irreales y me causo un poco de problemas al principio, antes de darme cuenta del problema. En la hoja de datos menciona algunos consejos para mejorar la estabilidad de las mediciones entre las que se encuentran colocar capacitores bypass cerca de los pines de alimentación del MAX6675 y proveer un plano de masa adecuado en el circuito impreso.
Por otra parte quedan pendientes las consideraciones sobre la linealidad del termopar, que requiere más procesamiento de la lectura como la implementación de tablas de búsqueda o solucionar ecuaciones polinomiales de grado superior, consumiendo más recursos del microcontrolador. Afortunadamente el termopar tipo K tiene una respuesta que se aproxima a la lineal y permite una buena aproximación con el programa tal como esta, sin embargo para aplicaciones que requieren mayor precisión o un mayor rango de temperatura, no podemos saltarnos este paso.
Modificaciones/ palabras finalesTomando en cuenta las sugerencias de Bruno, he decidido incorporar dos termopares (dos MAX6675) y 2 canales de PWM independientes, por lo cual hace falta agregar unos cuantos switch-case para que el software pueda leer dos termopares independientes. Cuando suba los archivos de código fuente tendrán esos cambios incluidos.
Por otra parte quisiera comentar que he estado siguiendo el foro, a pesar de que no he participado mucho he visto varios temas relacionados que iré poniendo hasta arriba en mi mensaje original, para que queden como referencia.
Por ahora ya sabemos por donde va la jugada con los termopares y el MAX6675 y ahora ya estamos en condición de poder usar la medición de nuestro termopar como feedback para el control PID.
Continuará...