Imprimir

Bus I2C: Sensor de Temperatura MCP9800 con PIC16F628A y LCD

Escrito por Raúl Alvarez.

 

Sensor de temperatura con el MCP9800El protocolo de bus serial I2C puede parecer complicado de implementar para quienes nunca han usado previamente buses seriales, y en verdad lo es, si se trata de manejar el protocolo al nivel más bajo de la especificación. Sin embargo, el uso de librerías de alto nivel que se encarguen de ocultar las complejidades de bajo nivel en la implementación de protocolo I2C, permiten a un "principiante" lograr de manera más sencilla e inmediata la implementación de una aplicación simple con un dispositivo que se comunica mediante este bus serial.

En este tutorial implementamos un termómetro digital con pantalla LCD haciendo uso del sensor MCP9800 de Microchip que se comunica mediante I2C, un microcontrolador PIC16F628A y una pantalla universal de cristal líquido (LCD) de 16x2 (16 columnas por 2 filas). El software se ha desarrollado en lenguaje C para el compilador PICC de Hi-Tech haciendo uso de las libreríasy ejemplos provistos por este último, tanto para la interfaz con el LCD como para la interfaz serial con el sensor de temperatura.

ACTUALIZACION 05-10-13: hemos actualizado el código y el proyecto MPLAB está disponible para su descarga.

Video Demostrativo


Tecnologia Bolivia -  

Contenido del Video

  • Demostración del circuito funcionando (sensor MCP9800 + PIC + LCD 16x2).
  • Conceptos teóricos básicos del funcionamiento del sensor.
  • Conceptos básicos del protocolo I2C.
  • Diagrama del circuito.
  • Algoritmo general para la interfaz con el sensor.

Descargas

Proyecto MPLAB X. El proyecto ya está compilado y el código listo para ser grabado al microcontrolador, para recompilarlo es necesario tener el compilador Hi-Tech (Microchip) PICC v9.81 o superior.

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

Circuito armado en Breadboard

Sensor serial I2C de temperatura

Descripción de los Componentes Principales

Microcontrolador PIC16F628A

  Microcontrolador PIC16F628A
  PIC16F628A
(Ver este producto en
nuestra
Tienda Virtual

Las características del El PIC16F628A más relevantes al proyecto son las siguientes:

  • Microcontrolador de 8 bits
  • Oscilador interno de 4 MHz calibrado en fábrica a +/-1%
  • 16 pines de E/S con control individual de dirección
  • Tres módulos temporizadores
  • Memoria flash de 2K, RAM de 224 bytes y EEPROM de 128 bytes.

En este proyecto el PIC se ha programado para trabajar con su oscilador interno de 4 MHz, minimizando así el conteo de componentes externos. Debido a que el microcontrolador no cuenta con un módulo de comunicación serial I2C, la comunicación se realizará mediante el método "bit banging" por software; para ello, el compilador PICC de Hi Tech provee librerías ejemplo, las cuales se han usado para la realización de dicha comunicación.

Pantalla de Cristal Líquido (LCD)

Diplay de cristal líquido LCD

 

Pantalla LCD
(Ver este producto en nuestra
Tienda Virtual
)
 

El LCD es un display alfanumérico genérico de interfaz paralela. Utiliza básicamente 3 líneas para control y 8 líneas para datos, aunque también puede funcionar con solamente 4 líneas de datos. Se ha escogido esta última modalidad a fin de ahorrar las 4 líneas adicionales. La comunicación del PIC con el LCD es manejada totalmente por una librería correspondiente incluida también en los archivos de ejemplo del compilador PICC.

 

 

Sensor de Temperatura con Conexión Serial I2C

  Sensor de temperatura MCP9800 con salida serial I2C
  Sensor de Temperatura MCP9800
(Ver este producto en nuestra
Tienda Virtual
)

El sensor MCP9800 de Microchip es un sensor de bajo costo, bajo consumo de potencia y alta resolución que puede ser usado en aplicaciones de propósito general y en sistemas complejos (servidores, computadoras, equipos de comunicaciones, equipo de oficina y otros). Sus características más sobresalientes son las siguientes:

  • Exactitud máxima de +/- 0.5ºC con 12 bits de resolución
  • Resolución seleccionable por el usuario: 9-12 bits
  • Voltaje de operación: 2.7V a 5.5V
  • Interfaz de 2 hilos: I2C/SMBus Compatible
  • Bajo consumo de corriente.

Diagrama del Circuito

Sensor Serial I2C de Temperatura con PIC16F6248A  y LCD

Sección LCD del Circuito

El LCD maneja su interfaz de comunicación mediante tres líneas de control:

  • RS: Selector de Registro (Register Select) conectado en este caso al pin RA3 del PIC. Con un "0" lógico en este pin, el LCD espera recibir un comando, y con un "1" lógico espera recibir un dato.
  • R/W: Lectura/Escritura (Read/Write). Conectado al pin RA2, con un 1 lógico el LCD se habilita para lectura y con un 0 lógico, para escritura.
  • E: Habilitación (Enable). Conectado al pin RA1. Habilita al LCD para reconocer los comandos y datos enviados y/o solicitados.

Dado que el LCD posee dos modos de funcionamiento: con bus de datos de 8 bits y con bus de datos de 4 bits, se ha escogido este último para minimizar el tamaño del circuito. Los pines RB3-RB0 del PIC se han conectado respectivamente a los pines D7-D4 del LCD, esto último según especifica el manual para el modo de funcionamiento con bus de datos de 4 bits.

Básicamente se puede usar casi cualquier grupo de pines, tanto del puerto A como del puerto B para la interconexión con el LCD, siempre que todas las lineas de control estén conectadas a un puerto y las lineas de datos conectados a otro puerto distinto (no ubicar lineas de control y datos en el mismo puerto), de otro modo las librerías para la comunicación con el LCD podrían no funcionar correctamente.

Sección Microcontrolador

Como ya se explicó anteriormente, el circuito del PIC se simplifica grandemente con el uso de su reloj interno, obviando así componentes externos para el circuito de reloj. El circuito es muy simple como se puede apreciar en la figura. 

Sección Sensor de Temperatura

Sensor I2C MCP9800 de MicrochipEl sensor de temperatura trabaja solamente en modo Esclavo, por lo cual el PIC debe trabajar en en modo Maestro (Para más detalles ver las especificaciones oficiales del protocolo I2C). El bus serial maneja dos líneas/señales:

  • SDA: Datos Seriales (Serial Data), a través de la cual el Esclavo manda y recibe los datos requeridos por el dispositivo Maestro.
  • SCL: Reloj Serial (Serial Clock), a trevés de la cual recibe del Maestro la señal de reloj necesaria para la sincronización de la comunicación.

Adicionalmente este sensor posee una salida ALERT (alerta) la cual provee una señal de salida cuando la temperatura sobrepasa un valor programado por el usuario. No hacemos uso de esta característica en el presente tutorial, pero es también de muy fácil implementación.

Sensor de temperatura MCP9800

Preparación del Sensor

El sensor viene en un empaque SOT-32 y es muy pequeño; para poder usarlo en el breadboard tuvimos que prepararlo convenientemente:


  1. Pegamos el sensor en un pequeño pedazo de cartón con un pegamento de carpintería. Se puede usar cualquier pegamento que pegue plástico y metal, pero que sea no conductivo.
  2. Pegamos alambres de extensión alineándolos con las terminales del chip.
  3. Después de dejar secar el pegamento por un tiempo, soldamos cuidadosamente las uniones entre los alambres de extensión y las terminales.
  4. Doblamos los alambres y ya está listo para conectarse al breadboard.

Breve Definición del Protocolo I2C

El protocolo de bus está definido de la siguiente manera:

  • Master (Maestro): Dispositivo que controla el bus serial, usualmente un microcontrolador.
  • Slave (Esclavo): El dispositivo direccionado por el maestro (el MCP9800 en este caso).
  • Transmitter (Transmisor): Dispositivo que envía datos al bus.
  • Receiver (Receptor): Dispositivo que recibe datos del bus.
  • Start (Inicio): Una señal única enviada por el Maestro para iniciar la interconexión serial con un Esclavo.
  • Stop (Terminación): Una señal única enviada por el Maestro para terminar la interconexión serial con un Esclavo.
  • Read/Write (Lectura/Escritura): Una lectura o escritura realizada a los registros internos del MCP9800.
  • ACK: El receptor Reconoce (Acknowledge = Reconocimiento) la recepción de cada byte mediante consulta repetitiva (polling) del bus.
  • NAK: El receptor No Reconoce (Not-Acknowledge = No reconoce), o libera el bus para mostrar la condición EOD (End of Data = Fin de Datos).
  • Busy (Ocupado): La comunicación no es posible debido a que el bus está en uso (Se pueden conectar varios dispositivos al mismo bus).
  • Not Busy (No Ocupado): El bus está en estado pasivo, ambas líneas SDA y SCL permanecen altas.
  • Data Valid (Dato Válido): SDA debe permanecer estable antes de que SCL suba (1 lógico), a fin de que un bit de datos sea considerado válido. Durante trasnferencias normales de datos, SDA solo cambia de estado cuando SCL está bajo (0 lógico).

Para una información más detallada del protocolo consultar la Hoja de Datos del sensor MCP9800 y las especificaciones oficiales del protocolo I2C.

Listado del Programa

/* *******************************************************************************
 * Sensor Serial de Temperatura MCP9800 I2C con PIC16F628A y LCD 16x2
 * 
 * Recibe la lectura de temperatura del sensor MCP9800 (Microchip)
 * mediante I2C y lo visualiza en un LCD genérico de 16x2.
 * Hace uso de las librerías y código ejemplo provistos por el compilador
 * PICC de Hi-Tech.
 * 
 * Hardware:    PIC16F628A, MCP9800, LCD 16x2 genérico.
 * Funciones:   Software ejemplo para el sensor digital de temperatura MCP9800
 * Compilador:  Microchip Hi-Tech PICC v9.83
 * Version:     1.1 (26 de Septiembre de 2013)
 * Autor:       Raul Alvarez Torrico (www.TecBolivia.com)
 * 
 * Descargado de www.TecBolivia.com - Ingresa al sitio para más ejemplos similares.
**********************************************************************************/

#include <htc.h>    // Libreria del compilador PICC de Hi-Tech
#include <stdlib.h> // Necesario para la función itoa()
#include "lcd.h"    // Librería para comunicación con el LCD incluida con el compilador PICC
#include "i2c.h"    // Librería para comunicación I2C incluida con el compilador PICC

/* Palabra de configuracion para el PIC16F628A para versiones del compilador PICC desde
   la Version 9.81 en adelante */
__CONFIG(CPD_OFF & CP_OFF & LVP_OFF & BOREN_ON & MCLRE_ON & PWRTE_ON & WDTE_OFF & FOSC_INTOSCIO);

/* Todas las definiciones para el PIC16F628A están ubicadas en el archivo:
   (Directorio Archivos de Programa)\HI-TECH Software\PICC\9.xx\include\pic16f628a.h
*/

/* Declaracion de variables */
// Estas variables auxiliares son usadas solo para depuracion, almacenan algunos
// valores binarios retornados por el MCP9800 para ser visualizados en pantalla
char aux, aux2, aux3, aux4;

/* Declaracion de funciones*/
void mostrar_temp (signed char * msb, char * lsb, char pos);

void main(void)
{
    /* La parte entera de la lectura viene en complemento a 2, por lo cual
    es necesaria una variable con signo */
    signed char byteMSB = 0;
    char byteLSB = 0;

    CMCON = 0x07;    // Configurar Puerto A como E/S digital

    /* Habilitar Pull-ups en el Puerto B, de este modo se obvian las resistencias
     * de Pull-up en las líneas SDA y SCL para la comunicación I2C */
    nRBPU = 0;    // Habilitar pull-ups en el Puerto B
    
    lcd_init();    // Función de inicializacion del LCD

    /* En nuestro caso la direccion de escritura es 0x90 y 0x91 para lectura, pero
     * podemos usar la misma direccion 0x90 para ambas operaciones porque la
     * función i2c_SendAddress() se encarga de fijar el bit R/W a 0 o 1 lógico,
     * segun se use i2cWriteTo() o i2c_ReadFrom() */

    /* Escribir nuevo CONFIG */
    do {
        /* NOTA: las siguientes funciones retornan FALSE si el I2C esclavo (en
         este caso el MCP9800) ha reconocido las transmisiones realizadas */
        aux = i2c_WriteTo(0x90);    // Direccion de escritura 10010000
        aux2 = i2c_PutByte(0x01);    // Puntero al registro CONFIG
        aux3 = i2c_PutByte(0x40);    // Configurar 0100 0000 (11 bits o 0.125°C de resolución)

        i2c_Stop();     // Detener comunicacion I2C
    // Si la configuracion ha sido exitosa, podemos seguir adelante y asumir que
    // la comunicacion con el I2C esclavo es correcta
    } while (aux != FALSE && aux2 != FALSE && aux3 != FALSE);

    /* Leer el nuevo CONFIG escrito. Esto no es estrictamente necesario, solo lo
     * incluimos como ejemplo por si acaso se necesite leer el CONFIG */
    i2c_ReadFrom(0x91);    // Direccion de lectura 10010001
    aux4 = i2c_GetByte(I2C_LAST); // Leer configuración escrita a la variable auxiliar
    i2c_Stop();     // Detener comunicacion I2C

    while (1)   // Ciclo infinito
    {
        i2c_WriteTo(0x90);  // Direccion de escritura 10010000
        i2c_PutByte(0x00);  // Puntero al registro TA
        i2c_ReadFrom(0x91); // Direccion de lectura 10010001
        byteMSB = i2c_GetByte(I2C_MORE);    // Leer 1 byte, hay más por leer
        byteLSB = i2c_GetByte(I2C_LAST);    // Leer el último byte
        i2c_Stop();     // Detener comunicacion I2C

        /* Conversión de la parte decimal a un entero sin el "0." */
        byteLSB = (100*byteLSB)/256;

        /* OJO: byteMSB leido es un numero en formato de complemento a 2
         Por simplicidad estamos asumiendo temperaturas positivas, lo cual
         quiere decir que el bit de signo (bit 7) de byteMSB es '0'. Con temperaturas
         negativas este bit se pone a '1' y hay que hacer primeramente la conversion
         del numero negativo que esta en complemento a 2 para tener el valor correcto */

        /* Mostrar la temperatura en el LCD */
        mostrar_temp(&byteMSB, &byteLSB, 0);

        // Retardo para disminuir la frecuencia de las lecturas
        __delay_ms(500);
    }
}

/*******************************************************************************
*                     MUESTRA LA TEMPERATURA EN EL LCD
*
* Descripción   :    Muestra en el LCD los caracteres correspondientes a la
*                    temperatura.
* Argumentos    :    signed char * msb    puntero al byte del entero
*                    char * lsb    puntero al byte del decimal
*                    char fila  la fila para la escritura de la temperatura
* Retorna       :    Nada
* Notas         :    El byte MSB viene como numero en complemento a 2 (con signo)
*                    y el byte LSB viene como entero sin el "0."
********************************************************************************/
void mostrar_temp (signed char * msb, char * lsb, char pos)
{
    char buf[5];    // Buffer temporal para conversión entero a cadena de caracteres

    lcd_goto(pos);    // Posicionar el cursor del LCD en la fila correspondiente
    lcd_puts("Temp:");
    itoa(buf, *msb, 10);    // Convertir byte MSB (complemento a 2) a cadena de caracteres
    lcd_puts(buf);          // Manda la parte entera a LCD
    lcd_putch('.');         // Manda el punto decimal

    itoa(buf, (*lsb), 10);  // Convertir byte LSB a cadena de caracteres
    lcd_puts(buf);          // Mandar la parte decimal a LCD
    lcd_goto(0x0A);         // Posicionar el cursor en el 11 caracter
    lcd_puts(" C ");
}



Descripción de las Partes Más Relevantes del Código

     CMCON = 0x07;    // Configurar Puerto A como E/S digital

    /* Habilitar Pull-ups en el Puerto B, de este modo se obvian las resistencias
     * de Pull-up en las líneas SDA y SCL para la comunicación I2C */
    nRBPU = 0;    // Habilitar pull-ups en el Puerto B

El Puerto A del PIC16F628A se configura como entradas análogas por defecto después de un reset; es necesario especificar su configuración como puerto digital.

Importante: Si no se habilitan los pull-ups de los pines SDA y SCL configurados en el Puerto B, se debe añadir dos resistencias pull-up a ambas líneas del bus, las cuales son requeridas para el funcionamiento del protocolo I2C.

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

     /* Escribir nuevo CONFIG */
    do {
        /* NOTA: las siguientes funciones retornan FALSE si el I2C esclavo (en
         este caso el MCP9800) ha reconocido las transmisiones realizadas */
        aux = i2c_WriteTo(0x90);    // Direccion de escritura 10010000
        aux2 = i2c_PutByte(0x01);    // Puntero al registro CONFIG
        aux3 = i2c_PutByte(0x40);    // Configurar 0100 0000 (11 bits o 0.125°C de resolución)

        i2c_Stop();     // Detener comunicacion I2C
    // Si la configuracion ha sido exitosa, podemos seguir adelante y asumir que
    // la comunicacion con el I2C esclavo es correcta
    } while (aux != FALSE && aux2 != FALSE && aux3 != FALSE);

Con el segmento de código anterior se realiza la configuración del MPC9800 en cuatro pasos:

1. Mandar la dirección de escritura al MCP9800 para ser reconocida por el mismo.
Los 7 bits más significativos de la dirección son fijos y vienen predeterminados de fábrica (ver Hoja de Datos del MCP9800). El bit menos significativo en la dirección es el bit R/W (lectura/escritura). Con un 0 lógico en este bit, se especifica que se quiere escribir en los registros internos del sensor, y con un 1 lógico se especifica que se quiere leer de los mismos.

2. Mandar el puntero al registro interno del MCP9800
El sensor posee 4 registros internos direccionable mediante un puntero de 8 bits, en el cual se usan efectivamente los 2 bits menos significativos y los 6 bits restantes deben estar a 0 lógico. Los registros y sus punteros son los siguientes:

  • Registro TA (Temperatura Ambiente, solo lectura): Provee el dato de la temperatura ambiente en un formato de 9 hasta 12 bits programable por el usuario. La temperatura se la obtiene en dos lecturas sucesivas de 8 bits. Puntero de acceso: 0000 0000
  • Registro CONFIG (Configuración, lectura/escritura): Permite la configuración para el funcionamiento del sensor para, por ejemplo: ciclo de trabajo del sensor, señal ALERT de salida, desactivación del sensor y resolución de bits. En este tutorial solamente estamos configurando la resolución de bits, sin embargo el resto de las funciones pueden ser configuradas de la misma manera (ver Hoja de Datos de sensor).
  • Registro THYST (Histéresis de Temperatura, lectura/escritura): Registro de 16 bits que permite la configuración de una determinada histéresis para el límite de temperatura TSET (ver más abajo). Para ello se puede escribir en este registro un valor de temperatura límite mímina de 9 bits en formato de complemento a 2.
  • Registro TSET (Límite de temperatura, lectura/escritura): Registro de 16 bits que permite la configuración de un determinado valor máximo límite de la temperatura. Si este límite es sobrepasado, una señal ALERT (pin 3 del MCP9800) es enviada afuera. Este límite de temperatura máxima se la programa con un dato de 9 bits en formato de complemento a 2.

3. Mandar la palabra de configuración
Los bits 5-6 del registro CONFIG definen la resolución de bits según la siguiente tabla:

00 = 9 bit o 0.5°C (Por defecto)
01 = 10 bit o 0.25°C
10 = 11 bit o 0.125°C
11 = 12 bit o 0.0625°C

En el código, con el byte: 0010 0000  (0x40) estamos configurando al sensor para que trabaje con 11 bits o 0.125°C de resolución.

Algon muy importante que tomar en cuenta es que la mayoría de las rutinas I2C que viene con el compilador PICC de Hi-Tech (en este caso se ha usado la versión 9.7) retonan FALSE para una comunicación exitosa y TRUE si se ha verificado algún error. de ahí que en el bloque "while" evaluamos "aux != FALSE" como condición para seguir intentando una configuración exitosa.

4. Terminación la comunicación con i2c_Stop()
----------------------------------------------------------

     while (1)   // Ciclo infinito
    {
        i2c_WriteTo(0x90);  // Direccion de escritura 10010000
        i2c_PutByte(0x00);  // Puntero al registro TA
        i2c_ReadFrom(0x91); // Direccion de lectura 10010001
        byteMSB = i2c_GetByte(I2C_MORE);    // Leer 1 byte, hay más por leer
        byteLSB = i2c_GetByte(I2C_LAST);    // Leer el último byte
        i2c_Stop();     // Detener comunicacion I2C

        /* Conversión de la parte decimal a un entero sin el "0." */
        byteLSB = (100*byteLSB)/256;

        /* OJO: byteMSB leido es un numero en formato de complemento a 2
         Por simplicidad estamos asumiendo temperaturas positivas, lo cual
         quiere decir que el bit de signo (bit 7) de byteMSB es '0'. Con temperaturas
         negativas este bit se pone a '1' y hay que hacer primeramente la conversion
         del numero negativo que esta en complemento a 2 para tener el valor correcto */

        /* Mostrar la temperatura en el LCD */
        mostrar_temp(&byteMSB, &byteLSB, 0);

        // Retardo para disminuir la frecuencia de las lecturas
        __delay_ms(500);
    }

Para leer la temperatura seguimos seis pasos:

  1. Mandamos la dirección de escritura del sensor (0x90) indicando que deseamos escribir a sus registros internos.
  2. Mandamos (escribimos) el puntero al registro TA (0x00) que almacena los datos de lectura de la temperatura ambiente.
  3. Mandamos la dirección de lectura del sensor (0x91) indicando que deseamos leer de su registro interno TA (temperatura ambiente).
  4. Leemos el Byte Más Significativo (MSB) que contiene los enteros.
  5. Leemos el Byte Menos Significativo (LSB) que contiene los decimales.
  6. Terminamos la comunicación con i2c_Stop()

Para obtener la parte decimal del código binario leído, la hoja de datos especifica que se debe utilizar la fórmula:

                                 TA  = Code x 2-4

                                                                 Donde:
                                                                 TA = Temperatura Ambiente (°C)
                                                                 Code = Salida del MCP9800 en decimal

Nota: usamos 2-4 en la fórmula si solo tomamos los 4 bits más significativos del byte. En nuestro caso llega a ser: byteLSB = byteLSB*(2-8) debido a que el número se encuentra almacenado en formato de 8 bits, a pesar de que los  4 bits menos significativos no se usan y permanecen siempre en 0.

Como paso adicional, multiplicamos el número por 100 para eliminar el punto decimal. De ese modo podremos escribir la parte decimal de la temperatura como si fuera un número entero.

Conclusión

Termómetro digital con sensor MCP9800 I2CObviamente que, a la larga, se hace necesario un entendimiento más profundo, de más bajo nivel, de dicho protocolos; si se quiere implementar aplicaciones propias desde "cero" o probar otros dispositivos I2C, ya que aún con el uso de librerías siempre se habrá la necesidad de escribir y probar por uno mismo nuevo código de aplicación, es así que, mientras más uno conozca del funcionamiento intrínseco de los protocolos, más fácil se hace desarrollar nuevas aplicaciones.


Para quienes no usaron antes I2C, el uso de librerías y proyectos de ejemplo hace más gratificante y menos traumático el uso del protocolo, abriendo un nuevo mundo de posibilidades para nuevos proyectos usando sensores, memorias, pantallas LCD con bus serial, convertidores ADC y otros dispositivos I2C.

¿Ya estás pensando en cual será tu nuevo proyecto con el bus serial I2C?

Raúl Alvarez Torrico
www.TecBolivia.com

Suscríbete a Nuestro Boletín de Noticias

Y te notificaremos de la publicación de otros artículos similares.

Pregunta anti spam. Ingresa abajo las últimas 4 letras de: asteroide
Nombre:
Email:

Productos Relacionados en Nuestra Tienda Virtual

Sensor de Temperatura MCP9800A con Bus Serial I2C

MCP9800A0T_4bc0e564a2fbb.jpg

Detalles del Producto

$us 3.52

Sensor de Temperatura con Salida Digital de 1 Hilo - DS18B20

Sensor_de_Temper_4e134fee405a1.jpg

Detalles del Producto

$us 1.50

Sensor Infrarrojo de Temperatura MLX90614

Sensor_Infrarroj_4eef4c45703b5.jpg

Detalles del Producto

$us 11.50

Microcontrolador PIC16F628A-I/P

PIC16F628A_I_P_4bc0e0aa3b224.jpg

Detalles del Producto

$us 3.60

PIC16F876A-I/SP

PIC16F876A_I_SP_4bc0dcd33f116.jpg

Detalles del Producto

$us 9.50