MODULO II Memoria EEPROM interna del PIC. La EEPROM es una matriz de memoria permanente, separada de la RAM de datos y de la FLASH, se utiliza para almacenar variables que se desean conservar cuando el controlador se desconecte o quede sin energía. No está mapeada directamente dentro de los registros o en la memoria de programa, sino que se trata indirectamente a través de registros especiales. La EEPROM se puede leer y escribir durante la ejecución del programa. Cuatro registros se utilizan para leer y para escribir los datos en la EEPROM. • • • • EECON1 EECON2 EEDATA EEADR En la EEPROM se permite la lectura y escritura de bytes. El registro EEDATA es el encargado de manejar los datos ya sea tanto cuando se leer o se escribe y el registro EEADR lleva a cabo el direccionamiento de la localización en la EEPROM. La EEPROM es muy resistente a los ciclos de escritura/borrado. Cuando se escribe un byte automáticamente se sobreescribe el byte anterior. El tiempo de escritura se controla con un temporizador integrado en el chip, variará con la tensión y la temperatura así como de chip a chip. Como se comentó el acceso a los datos se controla con dos registros: EECON1 y EECON2. Éstos son iguales que los del acceso de control a la memoria del programa (FLASH) y se utilizan de una manera similar para los datos en la EEPROM. El registro EECON1 es el registro de control para el acceso a memoria de datos y de programa. Controlando el bit, EEPGD, se determina si el acceso es a la memoria de programa o a la memoria de datos EEPROM. Cuando está borrado, las operaciones se hacen a la memoria EERPOM. Cuando está activado, se dirige a la memoria FLASH. Controlando el bit, CFGS se determina si el acceso es a los registros de configuración o a la memoria del FLASH/EEPROM. Cuando está activado, las operaciones siguientes tienen acceso a los registros de configuración. Cuando CFGS está borrado, el bit EEPGD selecciona la FLASH o la memoria EEPROM. El bit WREN, cuando está activado, permitirá una operación de escritura. Por defecto este bit esta en cero. El bit WRERR se activa por hardware y el bit WREN se borra cuando finaliza el timer interno y se completa la operación de escritura. Durante la operación normal, el WRERR se lee como ‘1’. Esto puede indicar que ha finalizado una operación de escritura prematuramente cerca de un reset o una operación de escritura finaliza incorrectamente!!!!!. El bit de control WR inicia operaciones de escritura. Este bit no se puede borrar, sólo está activar por software y se borra por hardware al terminar la operación de escritura. Programación en XC8 Pagina 55 de 174 Se activa el flag de la interrupción EEIF (PIR2<4>) cuando la escritura se completa. Debe desactivarse por software!!!. Controlando los bits, RD y WR, comienzan las operaciones lectura y escritura, respectivamente. Estos bits se activa por software y se desactiva por hardware al terminar la operación. El bit RD no se puede activar al tener acceso a la memoria de programa (EEPGD=1). El registro EECON2 no es un registro físico. Se utiliza exclusivamente en las secuencias de escribir y borrar en la memoria. La lectura EECON2 leerá todo ceros. Un ejemplo de manejo de la EEPROM interna. /* ***************************************************************************** ** Nombre : main.c ** Descripcion : Uso de la memoria EEPROM interna del PIC ** Autor : Firtec - www.firtec.com.ar ** IDE : Microchip MPLAB-X ** Compilador : XC8 ** XTAL : 20MHZ ** ****************************************************************************/ #include <xc.h> #define _XTAL_FREQ 20000000UL #pragma config OSC=HS,PWRT=ON,MCLRE=ON,LVP=OFF,WDT=OFF #include <plib/eep.h> #include <stdio.h> #include <stdlib.h> #include "C:\ELECTRÓNICA\EJERCICIOS_XC8\lcd_xc8.c" #include "C:\ELECTRONICA\EJERCICIOS_XC8\lcd_xc8.h" unsigned int direccion; // 1024 Vectores disponibles unsigned char dato; char str_int[16]; __EEPROM_DATA(1,2,3,4,5,6,7,8); // // void main(void){ lcd_init(); lcd_gotoxy(4,1); lcd_putrs("EEPROM PIC\n"); direccion = 12; dato = 12; Programación en XC8 Macro para colocar valores por defecto si fuera necesario. (No es este el caso) // La dirección sera cero (0) // El dato a guardar 25 Pagina 56 de 174 eeprom_write (direccion, dato); // Escribe el dato en la dirección indicada Busy_eep (); // Espera que termine de escribir dato=0; sprintf(str_int,"Dato memoria:%03d ",eeprom_read(direccion)); lcd_puts(str_int); // Lee la dirección indicada while(1); // Bucle infinito } XC8 tiene dos funciones para el manejo de la EEPROM interna. • eeprom_write (unsigned char, unsigned int) Escribe un byte en una posición de memoria. • eeprom_read(unsigned int) Lee un byte desde una posición de memoria. Trabajo practico Se pide que realice un programa para el control de acceso de una puerta que cumpla con las siguientes consignas: • La apertura de la puerta se hará efectiva cuando se ingrese una clave numérica de cuatro cifras que será comparada con un número almacenado en EEPROM. • Los números de la clave serán generados con un potenciómetro colocado en un canal A/D que irán desfilando en una pantalla de uno en uno mientras el usuario mueve el potenciómetro, los números mostrados solo pueden ir de 1 a 9. • Cada vez que un número que forma la clave de cuatro cifras se hace visible en la pantalla se lo valida con el botón de usuario que oficiará como botón de “Enter”. • Para indicar que la acción ha sido válida utilizar un LED. Programación en XC8 Pagina 57 de 174 Funcionamiento de la USART En la actualidad y ante la ausencia de puertos RS232 en las computadoras, acostumbramos a trabajar con puentes USB-RS232 que solucionan muchos o todos los problemas a la hora de vincularnos con computadoras a través del viejo protocolo 232. Es interesante comentar que debido a la desaparición de estos puertos en arquitecturas de computadoras uno tiende a pensar que el puerto RS-232 está extinguido, nada mas alejado de la realidad ya que arquitecturas en 16 y 32 bits no solo incorporan uno de estos puestos sino varios. El controlador no resuelve la capa física, es decir que para implementar las comunicaciones deberemos utilizar ya sea el clásico MAX232 o los modernos puentes USB-232. Esto es particularmente interesante porque con esta tecnología podemos reutilizar los viejos programas en puertos COM que por cuestiones de licencias o complejidad son mas simples de implementar que las aplicaciones USB nativas. El ejemplo que vamos a ver recibe los datos enviados desde el teclado de una PC y los re-transmite como un eco por el mismo puerto serial. /* ***************************************************************************** ** Nombre : main.c ** Descripcion : Uso de la memoria EEPROM interna del PIC ** Autor : Firtec - www.firtec.com.ar ** IDE : Microchip MPLAB-X ** Compilador : XC8 ** XTAL : 20MHZ ** ****************************************************************************/ #include <xc.h> #include <stdio.h> #include <stdlib.h> #include <plib/usart.h> #pragma config OSC=HS,PWRT=ON,MCLRE=OFF,LVP=OFF,WDT=OFF #define _XTAL_FREQ 20000000 #include "C:\ELECTRÓNICA\EJERCICIOS_XC8\USART.X\lcd_xc8.c" #include "C:\ELECTRONICA\EJERCICIOS_XC8\USART .X\lcd_xc8.h" volatile char Data, Kbhit=0; Se discrimina el origen de la interrupción void interrupt high_isr (void) { if (PIR1bits.RCIF==1){ // Discrimina la interrupción Data=getcUSART(); // Se lee dato recibido Kbhit=1; // Indica que se ha recibido un dato PIR1bits.RCIF=0; // Borra bandera de interrupción } } Programación en XC8 Pagina 58 de 174 Función Principal void main(void){ unsigned char base =1; // Inicializa el USART y lo configura a 8N1, 9600 baud OpenUSART (USART_TX_INT_OFF & // TX sin interrupción USART_RX_INT_ON & // RX con interrupciónes USART_ASYNCH_MODE & // Modo asincrónico USART_EIGHT_BIT & // Modo alta velocidad USART_CONT_RX & // Recepción continua USART_BRGH_HIGH,129); // 9600 baudios a 20Mhz Para configurar los baudios podemos usar la herramienta Pic Baud Rate RCONbits.IPEN = 0; // Deshabilitamos prioridades INTCONbits.PEIE=1; // Habilitamos la interrupcion de perifericos lcd_init(); //Delay1KTCYx(25); lcd_putrs("USART PIC18F4620"); // Cartel inicial INTCONbits.GIE=1; //Habilita interrupción global while(1){ if(Kbhit !=0){ // Indica que hay nueos datos recibidos Kbhit = 0; // Borra la marca de ISR if(Data!=0x00){ // El dato es distinto de 0? if(Data==0x08 & base > 0){ // Backspace & base son verdaderos? base--; lcd_gotoxy(base,2); lcd_putc(" "); } else{ lcd_gotoxy(base,2); lcd_putc(Data);// Muestra el dato en pantalla putcUSART (Data); base++; } } } } } Programación en XC8 Pagina 59 de 174 Para visualizar los datos recibidos vamos a usar la aplicación terminal.exe que se encuentra entre las herramientas del curso. Se recibe el mismo dato enviado por la USART. Programación en XC8 Pagina 60 de 174 Trabajo practico Se pide que escriba un programa que envíe por el puerto serial RS-232 los datos obtenidos de un canal analógico donde se ha conectado un potenciómetro. El resultado deberá ser como el que se observa en la imagen. Programación en XC8 Pagina 61 de 174 El protocolo I2C. Diseñado por Philips, este sistema de intercambio de información a través de tan solo dos cables permite a circuitos integrados y módulos OEM interactuar entre sí a velocidades relativamente lentas. Emplea comunicación serie, utilizando un conductor para manejar el reloj y otro para intercambiar datos. Este bus se basa en tres señales: • SDA (System Data) por la cual viajan los datos entre los dispositivos. • SCL (System Clock) por la cual transitan los pulsos de reloj que sincronizan el sistema. • GND (Masa) Interconectada entre todos los dispositivos "enganchados" al bus. Las líneas SDA y SCL son del tipo drenador abierto, similares a las de colector abierto pero asociadas a un transistor de efecto de campo (ó FET). Se deben poner en estado alto (conectar a la alimentación por medio de resistores Pull-Up) para construir una estructura de bus tal que se permita conectar en paralelo múltiples entradas y salidas. En el diagrama se observa la configuración eléctrica básica del bus. Las dos líneas de comunicación disponen de niveles lógicos altos cuando están inactivas. Inicialmente el número de dispositivos que se puede conectar al bus es ilimitado, pero observe que que las líneas tienen una especificación máxima de 400pF en lo que respecta a capacidad de carga. La máxima velocidad de transmisión de datos que se puede obtener es de aproximadamente 100Kbits por segundo. Las definiciones o términos utilizados en relación con las funciones del bus I2C son las siguientes: • Maestro (Master): Dispositivo que determina la temporización y la dirección del tráfico de datos en el bus. Es el único que aplica los pulsos de reloj en la línea SCL. Cuando se conectan varios dispositivos maestros a un mismo bus la configuración obtenida se denomina "multi-maestro". • Esclavo (Slave): Cualquier dispositivo conectado al bus incapaz de generar pulsos de reloj. Programación en XC8 Pagina 62 de 174 Reciben señales de comando y de reloj proveniente del dispositivo maestro. • Bus Desocupado (Bus Free): Estado en el cual ambas líneas (SDA y SCL) están inactivas, presentando un estado lógico alto. Unicamente en este momento es cuando un dispositivo maestro puede comenzar a hacer uso del bus. • Comienzo (Start): Sucede cuando un dispositivo maestro hace ocupación del bus, generando esta condición. La línea de datos (SDA) toma un estado bajo mientras que la línea de reloj (SCL) permanece alta. • Parada (Stop): Un dispositivo maestro puede generar esta condición dejando libre el bus. La línea de datos toma un estado lógico alto mientras que la de reloj permanece también en ese estado. • Dato Válido (Valid Data): Sucede cuando un dato presente en la línea SDA es estable mientras la línea SCL está a nivel lógico alto. • Formato de Datos (Data Format): La transmisión de datos a través de este bus consta de 8 bits de datos (ó 1 byte). A cada byte le sigue un noveno pulso de reloj durante el cual el dispositivo receptor del byte debe generar un pulso de reconocimiento, conocido como ACK (del inglés Acknowledge). Esto se logra situando la línea de datos a un nivel lógico bajo mientras transcurre el noveno pulso de reloj. • Dirección (Address): Cada dispositivo diseñado para funcionar en este bus dispone de su propia y única dirección de acceso, que viene pre-establecida por el fabricante. Hay dispositivos que permiten establecer externamente parte de la dirección de acceso. Esto permite que una serie del mismo tipo de dispositivos se puedan conectar en un mismo bus sin problemas de identificación. La dirección 00 es la denominada "de acceso general", por la cual responden todos los dispositivos conectados al bus. • Lectura/Escritura (Bit R/W): Cada dispositivo dispone de una dirección de 7 bits. El octavo bit (el menos significativo ó LSB) enviado durante la operación de direccionamiento corresponde al bit que indica el tipo de operación a realizar. Si este bit es alto el dispositivo maestro lee información proveniente de un dispositivo esclavo. En cambio, si este bit fuese bajo el dispositivo maestro escribe información en un dispositivo esclavo. Funcionamiento del protocolo I2C. Como es lógico, para iniciar una comunicación entre dispositivos conectados al bus I2C se debe respetar un protocolo. Tan pronto como el bus esté libre, un dispositivo maestro puede ocuparlo generando una condición de inicio. El primer byte transmitido después de la condición de inicio contiene los siete bits que componen la dirección del dispositivo de destino seleccionado y un octavo bit correspondiente a la operación deseada (lectura o escritura). Si el dispositivo cuya dirección se apuntó en los siete bits está presente en el bus éste responde enviando el pulso de reconocimiento ó ACK. Seguidamente puede comenzar el intercambio de información entre los dispositivos. Cuando la señal R/W está previamente a nivel lógico bajo, el dispositivo maestro envía datos al dispositivo esclavo hasta que deja de recibir los pulsos de reconocimiento, o hasta que se hayan transmitido todos los datos. En el caso contrario, es decir cuando la señal R/W estaba a nivel lógico alto, el dispositivo maestro genera pulsos de reloj durante los cuales el dispositivo esclavo puede enviar datos. Luego de cada byte recibido el dispositivo maestro (que en este momento está recibiendo datos) genera un pulso de reconocimiento. Programación en XC8 Pagina 63 de 174 El dispositivo maestro puede dejar libre el bus generando una condición de parada (Stop). Si se desea seguir transmitiendo, el dispositivo maestro puede generar otra condición de inicio el lugar de una condición de parada. Esta nueva condición de inicio se denomina "inicio repetitivo" y se puede emplear para direccionar un dispositivo esclavo diferente ó para alterar el estado del bit de lectura/escritura (R/W). Memoria 24LC256. La memoria 24LC256 fabricada por Microchip tiene una capacidad de almacenamiento de 256Kbits (32 Kbytes). Sobre el mismo bus pueden conectarse hasta ocho memorias 24LC256, permitiendo alcanzar una capacidad de almacenamiento máxima de 256 Kbytes. Como en todas las memorias de la familia 24XXXXX, la dirección de identificación o byte de control comienza con 1010. Seguidamente, tres bits llamados A2, A1 y A0 permiten seleccionar una de las ocho posibles memorias conectadas en el bus. La memoria se compone de 512 páginas de 64 bytes cada una. Cuando se requiere transferir volúmenes considerables de información, la escritura de bytes resulta ser bastante ineficiente, pero la escritura por páginas mejora notablemente el rendimiento. Para Programación en XC8 Pagina 64 de 174 Memoria 24LC256 con XC8. /* *************************************************************************** ** File Name : 24LC256.c ** Version : 1.0 ** Description : Control de una memoria 24LC256 ** Memoria de 32Kx8=256Kbit 64Bytes x Paginas ** Target : 40PIN PIC18F4620 ** Compiler : Microchip XC8 ** IDE : Microchip MPLAB IDE v8.50 ** XTAL : 20MHZ ** ****************************************************/ #include <xc.h> #include <stdio.h> #include <stdlib.h> #include <plib/i2c.h> #include "24LC256.h" #pragma config OSC=HS,PWRT=ON,MCLRE=OFF,LVP=OFF,WDT=OFF #define _XTAL_FREQ 20000000 #include "C:\ELECTRÓNICA\Programas PIC\2014\EJERCICIOS_XC8\24LC256.X\lcd_xc8.c" #include "C:\ELECTRÓNICA\Programas PIC\2014\EJERCICIOS_XC8\24LC256.X\lcd_xc8.h" FUNCIÓN PRINCIPAL DEL PROGRAMA void main(void){ unsigned char dir_hi =0, dir_low= 500; unsigned char Dato=54; // Dato cualquiera a guardar en Memoria char str_int[14]; lcd_init(); OpenI2C(MASTER,SLEW_OFF); // Modo Master SSPADD = 49; // 100KHz para 20MHz Escribe_Byte(0xA0,dir_hi,dir_low,Dato); // Escribe la memoria lcd_putrs(" Memoria 24C256"); lcd_gotoxy(1,2); sprintf(str_int,"Dato memoria:%02d ",Lee_Byte(0xA0,dir_hi,dir_low)); lcd_puts(str_int); while(1); } Para el funcionamiento de este ejemplo necesitamos de dos archivos encargados de lidiar con las funciones relativas a la memoria I2C. • • 24LC256 Contiene las funciones de control de la memoria. 24LC256.H Contiene las declaraciones de estas funciones. Todo lo referente al propio bus I2C esta contenido en el archivo de cabecera i2c.h provisto por el compilador. Programación en XC8 Pagina 65 de 174 El programa ejemplo solo escribe un byte en la posición 500 y lo recupera para hacerlo visible en el LCD. Trabajo practico Escriba un código utilizando I2C2 cambiando lo pines dedicados que complete 500 vectores de la memoria con los datos de un contador. Programación en XC8 Pagina 66 de 174 RTC DS1307 (Real Time Clock). Siguiendo con los dispositivos I2C el DS1307 de Dallas Semiconductor (Maxim) es una solución muy interesante cuando necesitamos trabajar con eventos que requieren puntualidad y exactitud a lo largo del tiempo. Este pequeño circuito integrado es uno de los más populares relojes RTC del mercado por su sencillez de uso y por su confiabilidad a largo plazo. Preparado para ofrecerte la hora hasta el año 2100 con ajuste de años bisiestos. /* ***************************************************************************** ** Nombre : main_1307.c ** Descripción : Control de un DS1307 & LCD 16x2 & INT ** Target : PIC18F4620 ** Compilador : XC8 ** IDE : MPLAB ** XTAL : 20MHZ ** Autor : Firtec - www.firtec.com.ar ** ****************************************************************************/ #include <xc.h> #include <stdio.h> #include <stdlib.h> #include <plib/i2c.h> #include <plib/portb.h> #include "DS1307.h" #pragma config OSC=HS,PWRT=ON,MCLRE=OFF,LVP=OFF,WDT=OFF #define _XTAL_FREQ 20000000 #include "C:\ELECTRÓNICA\Programas PIC\2014\EJERCICIOS_XC8\DS1307.X\lcd_xc8.c" #include "C:\ELECTRÓNICA\Programas PIC\2014\EJERCICIOS_XC8\DS1307.X\lcd_xc8.h" void Ajustar_Dato(unsigned char dato); void Un_Segundo(void); // Ajusta datos del DS1307 // Prototipo de la Interrupción volatile unsigned char bandera =0; // Variable usada en la Interrupción unsigned char Unidad, Decena; // Variables del Programa #define chip 0xD0 // ID I2C de Chip para el DS1307 Rutina de Interrupción void interrupt high_isr (void) { if(INTCON3bits.INT2IF) // Pregunta por bandera de INT2 { bandera =1; // Marca para actualizar el calendario INTCON3bits.INT2IF = 0; // Limpia bandera } } FUNCIÓN PRINCIPAL DEL PROGRAMA void main(void){ PORTB=0; TRISBbits.TRISB5=0; ADCON1=0x0F; // No hay canales analógicos lcd_init(); OpenI2C(MASTER,SLEW_OFF); SSPADD = 49; Programación en XC8 // Master, 100KHz // 100KHz para 20MHz Pagina 67 de 174 __delay_us(500); ByteWriteI2C(chip,0,128); Se definen valores por defecto para el Reloj ByteWriteI2C(chip,1,0x59); // Ajusta Minutos ByteWriteI2C(chip,2,0x23); // Ajusta Hora ByteWriteI2C(chip,4,0x31); // Ajusta el Día ByteWriteI2C(chip,5,0x12); // Ajusta Mes ByteWriteI2C(chip,6,0x14); // Ajusta Año ByteWriteI2C(chip,0x07,0X90); // Registro de Control (1Hz pin 7) ByteWriteI2C(chip,0,0x50); // Ajusta Segundos OpenRB2INT(PORTB_CHANGE_INT_ON & FALLING_EDGE_INT & PORTB_PULLUPS_ON); RCONbits.IPEN=0; // No hay prioridades de interrupciones INTCONbits.GIEH = 1; // Habilitador general de interrupciones activo WriteTimer0(100); lcd_putrs("Fecha ??|??|??"); lcd_gotoxy(1,2); lcd_putrs("Hora ??|??|?? "); Bucle Infinito while(1){ if(bandera){ // Bandera puesta en la interrupción PORTBbits.RB5 = ~PORTBbits.RB5; // Cambia el estado del pin RB5 lcd_gotoxy(7,1); // Coloca el cursor en la primera línea Ajustar_Dato(ByteReadI2C(chip,4)); // Lee el Día lcd_putrs("/"); // Barra separadora xx/xx/xx Ajustar_Dato(ByteReadI2C(chip,5)); // Lee el Mes lcd_putrs("/"); lcd_putrs("20"); // Imprime 20 para leer 20xx Ajustar_Dato(ByteReadI2C(chip,6)); // Lee el Año lcd_gotoxy(6,2); // Cambia la línea en el LCD Ajustar_Dato(ByteReadI2C(chip,2)); // Lee Hora lcd_putrs(":"); // Puntos separadores xx:xx:xx Ajustar_Dato(ByteReadI2C(chip,1)); // Lee Minutos lcd_putrs(":"); Ajustar_Dato(ByteReadI2C(chip,0)); // Lee Segundos bandera =0; // Borra la bandera para el próximo segundo } Sleep(); // Espera en bajo consumo } } Ajusta los datos del RTC void Ajustar_Dato(unsigned char dato){ char cadena[4]; Unidad = (dato & 0x0F); // Mascara y prepara dato para el LCD. Decena = ((dato/16) & 0x0F); // Intercambia nibles. sprintf(cadena,"%u", Decena); lcd_puts(cadena); sprintf(cadena,"%u", Unidad); lcd_puts(cadena); } Programación en XC8 Pagina 68 de 174 Registros Internos NOTA: El DS1307 solo manejas datos BCD por lo que es necesario ajustar los binarios. Mapa de memoria Programación en XC8 Pagina 69 de 174 Circuito de la Aplicación El pin siete del DS1307 ha sido configurado a través del registro de control para genera un pulso cada segundo, este pulso se conecta al pin 35 (INT2) del controlador generando una interrupción cada segundo. Esta interrupción cambia el estado de una bandera que se utiliza como indicativo que hay valores del reloj a actualizar en pantalla. Cada vez que se actualizan los datos en pantalla se cambia de estado el LED colocado en el pin 38 para tener una indicación visual que la interrupción esta funcionado al ritmo de un segundo. Han sido necesario varios archivos de cabecera para esta aplicación. • • • plib/i2c.h plib/portb.h DS1307.h Contiene las funciones para el manejo del bus I2C Contiene las funciones para el manejo de las interrupciones INTx. Contiene las funciones para el control del RTC. La línea que configura la interrupción por el pin 35 dice lo siguiente: • • • PORTB_CHANGE_INT_ON FALLING_EDGE_INT PORTB_PULLUPS_ON) Programación en XC8 Máscara de interrupción activada. Interrupción por flanco de bajada. Las resistencias del puerto B están activadas. Pagina 70 de 174 PCF 8591. Otro dispositivo I2C interesante es el PCF 8591, un conversor analógico digital y digital analógico de 8 bits, que se conecta directamente al bus I2C del microcontrolador. En el trabajo propuesto controlaremos el PCF8591 en sus dos modos, primero lo pondremos en modo conversor analógico digital leyendo la tensión de dos potenciómetros asociados al canal 0 y 1, que estará conectado entre VCC y GND (5V y 0V). En la segunda parte del programa cambiaremos el modo de funcionamiento del PCF8591, y lo utilizamos digital analógico (DAC) sacando por el pin de salida analógica un voltaje que se corresponde con el dato enviado, por ejemplo en ese modo si enviamos el número 128 por el pin analógico leemos 2,5V aproximados al 50% de Vdd. Las dos partes del programa ejemplo son controladas por un botón colocado en RA0 (pin2). La dirección del dispositivo. Esta tiene 3 bits, con lo que podremos tener asta 8 dispositivos iguales en el bus I2C, la dirección sera la siguiente “1001xxxy” donde los 4 bits de mayor peso son fijos (0x90 es el identificador I2C para este chip), los tres siguientes bits son definidos por el programador y hacen referencia a su dirección en el bus, el bit de menor peso se utiliza para decir si el PCF8591 va a estar en modo lectura o en su defecto modo escritura, siendo el ’1′ para la lectura y el ’0′ para la escritura. El mecanismo es casi el mismo que para el acceso de una memoria I2C solo que aquí leemos en la dir 0,1,2, 3 o 4 dependiendo del canal apuntado desde el PIC. Otro punto importante que debemos conocer es la manera de configurar el byte de control del dispositivo, podemos elegir las entradas analógicas para la lectura con respecto a masa o en modos diferenciales, también podemos activar la salida analógica, en nuestro caso, utilizaremos una configuración en la cual la salida analógica está deshabilitada, y las lecturas de las entradas analógicas están tomadas respecto a masa. (Consultar la hoja de datos del dispositivo). /* **************************************************************************** ** Nombre : PCF8591.c ** Descripcion : Midiendo en dos canales del ADC y funcionamiento del DAC ** Target : PIC18F4620 ** Compilador : Microchip XC8 ** XTAL : 20MHZ ** ***************************************************************************** El pulsador colocado en RA0 controla el flujo del programa. *******************************************************************************/ #include <xc.h> #include <stdio.h> #include <stdlib.h> #include <plib/i2c.h> #pragma config OSC=HS,PWRT=ON,MCLRE=OFF,LVP=OFF,WDT=OFF #include "C:\ELECTRÓNICA\Programas PIC\2014\EJERCICIOS_XC8\PCF8591.X\lcd_xc8.c" #include "C:\ELECTRÓNICA\Programas PIC\2014\EJERCICIOS_XC8\PCF8591.X\lcd_xc8.h" #define _XTAL_FREQ 20000000 static bit bandera1 = 0; // Bandera para cambiar el canal. unsigned char bandera2 = 0; Programación en XC8 Pagina 71 de 174 char Str_float[5]; float voltaje = 0.00; // Cadena para convertir el float en ASCII. // Contenedor para guardar la medición. unsigned char Lee_Byte( unsigned char ByteControl, unsigned char Direccion){ unsigned char Valor; IdleI2C(); // El modulo esta activo? StartI2C(); // Condición de START while ( SSPCON2bits.SEN ); // Espera a que la condición de inicio termine WriteI2C( ByteControl ); WriteI2C( Direccion ); RestartI2C(); // Envía ReStart while ( SSPCON2bits.RSEN ); // Si se ha recibido el byte sigue WriteI2C( ByteControl | 0x01 ); // Cambia bit 0 de ByteControl para leer. Valor=ReadI2C(); // Realiza lectura. NotAckI2C(); // Envía NACK while ( SSPCON2bits.ACKEN ); // Espera a que de ASK termine StopI2C(); // Condición de STOP while ( SSPCON2bits.PEN ); // Espera fin de condición de stop return ( Valor ); // Retorna Lectura } FUNCIÓN PARA EL CONTROL DEL ADC void ADC(void){ switch(bandera1){ // Se discrimina en cual canal se medirá. case 0:{ // Si es "0" se lee en el canal cero. voltaje =Lee_Byte(0x90,0); // En voltaje se guarda el dato desde el A/D. __delay_ms(10); bandera1 =1; // Se cambia bandera para el siguiente canal. break; } case 1:{ voltaje =Lee_Byte(0x90,1); __delay_ms(10); bandera1 =0; break; } } voltaje = (voltaje*5.0)/256; // Se escala el valor para medir entre 0 y 5V sprintf(Str_float,"%1.2f ",voltaje); // El float es convertido a ASCII if(bandera1 ==0) // Si bandera es cero se coloca el cursor en el lugar lcd_gotoxy(4,2); // indicado junto al cartel que le corresponde. else lcd_gotoxy(13,2); // Si bandera es uno se coloca el cursor en el lugar lcd_puts(Str_float); // indicado junto al cartel que le corresponde. } FUNCIÓN VERIFICA LA PRESENCIA DEL PCF8591 void check_PCF8591(unsigned short dir){ StartI2C(); // Condición de inicio en el bus. if (WriteI2C(dir)){ // Escribe la dirección del chip en el bus. lcd_gotoxy(2,2); // Si retorna "1" no hay sensor en el bus. lcd_putrs("PCF8591 ERROR!!"); // Aviso de que no hay sensor en el BUS. while(1); // Programa termina. } else { lcd_gotoxy(3,1); lcd_putrs("Chip PCF8591"); // Cartel incial para indicar la presencia } // del chip en el bus I2C. StopI2C(); } Programación en XC8 Pagina 72 de 174 FUNCIÓN PRINCIPAL DEL PROGRAMA void main() { TRISA=0X01; ADCON1 = 0X0F; // Configura el pin 2 como entrada digital // Configura los pines del PORT A como I/O Digitales OpenI2C(MASTER,SLEW_OFF); SSPADD = 49; lcd_init(); check_PCF8591(0x90); // // // // Modo Master. 100KHz para 20MHz. Configura el LCD a valores por defecto. Verifica la presencia del chip en el BUS. While(1){ // El boton en RA0 es el encargado de cambiar al DAC o al ADC if(PORTAbits.RA0!=1 && bandera2== 1){ while(!PORTAbits.RA0); // Espera a que el botón se suelte lcd_gotoxy(1,2); lcd_putrs(" "); // Limpia la línea inferior para el ADC bandera2=0; // Coloca la bandera para que el ADC sea el modo por defecto } if(PORTAbits.RA0!=1 && bandera2== 0){ // Pasa al modo DAC while(!PORTAbits.RA0); // Espera a que el botón se suelte bandera2++; lcd_gotoxy(1,2); lcd_putrs(" Conversor DAC "); StartI2C(); WriteI2C(0x90); __delay_ms(2); WriteI2C(0x40); __delay_ms(2); WriteI2C(128); // Saca por el pin analógico 2.5V aprox. (256/2=128) StopI2C(); // Condición de STOP while ( SSPCON2bits.PEN ); // Espera que termine la condición de STOP } if(bandera2==0){ // Si bandera es 0 se activa el modo por defecto (ADC) lcd_gotoxy(1,2); // Coloca los carteles para los canales analógicos lcd_putrs("A0:"); lcd_gotoxy(10,2); lcd_putrs("A1:"); ADC(); // LLama a la función del conversor analógico } } } Programación en XC8 Pagina 73 de 174 Sensor de temperatura I2C TC4A3. El chip TC74 es un sensor de temperatura serie accesible a través del bus I2C fabricado por Microchip Technology que mide con una resolución de 1°C. La temperatura está disponible en un byte que es almacenado en un registro interno. El dato de temperatura es almacenado en formato binario con complemento a 2 y el bit más significativo es el bit de signo, que se establece en 1 para temperaturas negativas por lo tanto, la temperatura máxima positiva es de + 127 ° C (0111 1111). También existe otro registro de configuración (RWCR) que se utiliza para poner el dispositivo en bajo consumo (5µA), en este modo se detiene el convertidor A / D. /* ***************************************************************************** ** Nombre : TC74A3.c ** Descripcion : Sensor de Microchip I2C de 8 bits. (-40 a +125 grados) ** Target : PIC18F4620 ** Compilador : Microchip XC8 ** XTAL : 20MHZ ** ****************************************************************************/ #include <xc.h> #include <stdio.h> #include <stdlib.h> #include <plib/i2c.h> #pragma config OSC=HS,PWRT=ON,MCLRE=OFF,LVP=OFF,WDT=OFF #include "C:\ELECTRÓNICA\Programas PIC\2014\EJERCICIOS_XC8\TC74.X\lcd_xc8.c" #include "C:\ELECTRÓNICA\Programas PIC\2014\EJERCICIOS_XC8\TC74.X\lcd_xc8.h" #define _XTAL_FREQ 20000000 void delay(unsigned int t){ while(--t) __delay_ms(1); } unsigned short num=0; const int TC74A3 = 0x96; // Dirección I2C del sensor FUNCIÓN PARA VERIFICAR EL SENSOR void check_sensor(unsigned short dir){ StartI2C(); if (WriteI2C(dir)){ lcd_gotoxy(1,2); lcd_putrs("Sensor ERROR!!"); // Aviso de que no hay sensor en el BUS. while(1); } else { lcd_gotoxy(2,1); lcd_putrs("Sensor TC74A3"); // Cartel inicial. } StopI2C(); Programación en XC8 Pagina 74 de 174 } FUNCIÓN PARA LEER LA TEMPERTAURA unsigned short Leer_Temp(){ unsigned short dato; IdleI2C(); // Pregunta si el bus está libre. StartI2C(); // Pone la condición de inicio. IdleI2C(); // Espera que termine. WriteI2C(TC74A3); // Direcciona el sensor while(SSPCON2bits.ACKSTAT); // Espera el ACK IdleI2C(); // Espera por el bus libre. WriteI2C(0x00); // Escribe la dir 0 (registro de la temp) while(SSPCON2bits.ACKSTAT); // Espera el ACK IdleI2C(); // Espera a que el bus esté libre RestartI2C(); // Re-inicio del bus IdleI2C(); // Espera que termine WriteI2C(TC74A3+1); // Envía órden de lectura en la dir. 0 while(SSPCON2bits.ACKSTAT); // Espera por ACK dato = ReadI2C(); // Lee el registro y lo guarda en dato IdleI2C(); // Espera que termine NotAckI2C(); // No hay ACK IdleI2C(); // Espera que termine StopI2C(); // Condición de fin de transacción. return dato; // Retorna la temperatura } FUNCION PRINCIPAL DEL PROGRAMA void main() { char temperatura[] = "000"; OpenI2C(MASTER,SLEW_OFF); SSPADD = 49; // Modo Master // 100KHz para 20MHz lcd_init(); // Configura el LCD a valores por defecto. lcd_gotoxy(1,2); lcd_putrs("Grados:"); // Cartel inicial II. check_sensor(TC74A3); // Verifica la presencia del sensor en el BUS. while(1) { num = Leer_Temp(); // Lee la temperatura desde el sensor. if (num > 127) { // Verifica si la temperatura es negativa. num = ~num +1; // Ajusta la temperatura si es negativa sprintf(temperatura,"-%d ",num); // Completa el string para el LCD } else{ sprintf(temperatura,"+%d ",num); // Temperatura positiva. } lcd_gotoxy(8,2); lcd_puts(temperatura); // Muestra la temperatura. delay(500); } } Programación en XC8 Pagina 75 de 174 PCF8574. Es un expansor de puertos compatible con la mayoría de microcontroladores, permite una comunicación bidireccional, necesitando solo dos líneas a través del bus I2C. Características del módulo • Tensión de alimentación de 2.5 a 6 V CC. • Bajo consumo en standby (máximo 10 microamperios). • Conversión de datos de I2C a paralelo y viceversa. • Un Pin de interrupción de salida a drenador abierto (necesita resistencia pul-up). • Un puerto cuasi-bidireccional de ocho bits (necesitan resistencias pul-up). • Tres pines disponible para configurar por hardware la dirección del dispositivo. • Disponible en encapsulados DIP y SMD. Este módulo dispone de dos modelos (PCF8574 y PCF8574A) cuya única diferencia es su dirección. Los primeros cuatro bits vienen configurados de fábrica y los tres últimos son configurables por hardware, por lo que podemos tener 8 módulos conectados al mismo bus I2C (y si combinamos ambas versiones hasta 16). Una trama de datos en una transmisión consta de: • • • • Un bit de inicio de la comunicación. Un byte formado por siete bits que identifican la dirección del esclavo + un bit para indicar si se va hacer una lectura (R/W=1) o escritura (R/W=0) en el módulo. Los datos en sí (de transmisión o recepción); el número de bytes de datos a transmitir o recibir entre el comienzo de la comunicación y la condición de fin de transmisión (bit de parada) no está limitada. Un ACK de reconocimiento. A cada byte transmitido le sigue un bit de reconocimiento, Programación en XC8 Pagina 76 de 174 • cuando el esclavo recibe un byte este envía el ACK para indicarle al maestro que lo ha recibido correctamente, cuando la petición del maestro al esclavo es de lectura este debe de enviar un ACK al esclavo para indicarle que ha recibido el byte correctamente. Un bit de parada. La condición de parada (P) ocurre cuando la línea SDA cambia de nivel alto a bajo mientras la línea de reloj se encuentra a nivel alto y es controlada por el dispositivo maestro (en nuestro caso el microcontrolador). /******************************************************************************* * File: PCF8574.c * Author: Firtec * www.firtec.com.ar - informes@firtec.com.ar * Created on 24 de mayo de 2014 ******************************************************/ #include #include #include #include <xc.h> <stdio.h> <stdlib.h> <plib/i2c.h> #include "PCF8574.h" #pragma config OSC=HS,PWRT=ON,MCLRE=OFF,LVP=OFF,WDT=OFF #define _XTAL_FREQ 20000000 #define chip 0x40 // Valor de Chip para el PCF8574 FUNCIÓN PRINCIPAL DEL PROGRAMA void main(void){ unsigned char byte =0; PORTB=0; TRISCbits.TRISC4=1; TRISB = 0; ADCON1=0x0F; // No hay canales analógicos OpenI2C(MASTER,SLEW_OFF); // Master, 100KHz SSPADD = 49; (Fos/Fck*4)-1 donde Fos 20Mhz (20000Kc) y Fck 100Kz (20000Kc/400kc)-1 = 49 para 20Mhz y Ck I2c 100K BUCLE INFINITO while(1){ byte = ByteReadI2C(chip); // Lee el puerto del PCF8574 byte = ((byte >> 4) & 0x0f) | ((byte << 4) & 0xf0); // Swap nibles __delay_us(3000); ByteWriteI2C(chip,byte); // Escribe el puerto del PCF8574 } } Este simple programa lee cuatro bits del puerto del PCF8574 intercambia los 4 bits de menor peso con los de mayor peso y los envía nuevamente al puerto. Programación en XC8 Pagina 77 de 174 Protocolo 1-wire. Es un protocolo de comunicaciones en serie diseñado por Dallas. Está basado en un bus, un maestro y varios esclavos en una sola línea de datos en la que también se alimentan. Por supuesto, necesita una referencia a tierra común a todos los dispositivos. El bus tiene un funcionamiento bastante particular, se mantiene la señal de datos a 0 voltios durante 480 microsegundos. Se reinician todos los dispositivos conectados al bus (les retira la alimentación). Los dispositivos reiniciados indican su presencia manteniendo la señal de datos a 0 voltios durante 60 microsegundos. En la actualidad los microcontroladores PIC no tienen un puerto nativo para este protocolo de comunicaciones. Señales del Bus. Programación en XC8 Pagina 78 de 174 Envío y recepción de datos por 1-Wire. Para enviar un bit a 1 el maestro se lleva a 0 voltios la línea de datos durante 1-15 microsegundos. Para enviar un bit a 0 el maestro se lleva a 0 voltios la línea de datos durante 60 microsegundos. Los dispositivos esclavos leen el bit aproximadamente a los 30 microsegundos después del flanco de bajada de cada bit. Cuando el maestro lee los datos del dispositivo esclavo el pone 0 voltios durante 1-15 microsegundos en la línea de datos y a partir de ese momento el esclavo no hace nada (la señal pasa a vale 5 voltios) si quiere mandar un 1 lógico o mantiene la señal en 0 voltios hasta los 60 microsegundos si quiere mandar un 0 lógico. Los datos se envían o reciben en grupos de 8 bits. Para iniciar una comunicación se reinicia el bus. El protocolo puede incluir detección de errores transmitiendo códigos de detección de errores (CRC). Como en el bus puede haber muchos dispositivos el protocolo incluye el direccionamiento de los mismos empleando un código único de 64 bits de los cuales el byte más significativo indica el tipo de dispositivo, y el último es un código de detección de errores (CRC) de 8 bits. Los comandos que pueden interpretar los dispositivos esclavos dependerán de estos. Para encontrar los dispositivos presentes en el bus el maestro puede enviar un comando de enumeración que responderán todos los dispositivos. Sensor de temperatura 1-wire DS18B20. Veamos un ejemplo con un sensor de temperatura muy interesante que muestra el funcionamiento de este protocolo de comunicaciones. /* ***************************************************************************** ** File Name : DS1820.c ** Version : 1.0 ** Description : Dallas/Maxim Sensores Temp. DS1820, DS18S20 o DS18B20 ** conectado al pin 6 (RA4) (Sin Rom Code). ** Author : www.firtec.com.ar ** Target : 40PIN PIC18F4620 ** Compiler : Microchip XC8 ** IDE : Microchip MPLAB-X ** XTAL : 20MHZ ** ****************************************************************************/ #include <xc.h> #include <stdio.h> #include <stdlib.h> #pragma config OSC=HS,PWRT=ON,MCLRE=OFF,LVP=OFF,WDT=OFF #define _XTAL_FREQ 20000000 #include "C:\ELECTRÓNICA\DS1820.X\lcd_xc8.c" #include "C:\ELECTRÓNICA\DS1820.X\lcd_xc8.h" #include "1wire.h" FUNCIÓN PRINCIPAL void main(void){ float Grados; // Variable para contener el dato temperatura char TempStr[5]; lcd_init(); lcd_gotoxy(2,1); lcd_putrs("SENSOR DS18B20"); // Cartel inicial lcd_gotoxy(1,2); lcd_putrs("Temperatura: "); Programación en XC8 Pagina 79 de 174 while(1){ Medir_Temperatura(); // Inicia la conversion Grados = Leer_DS18B20(); // DS18B20 12 BITS //Grados = Leer_DS18S20(); // DS1820 10 BITS sprintf(TempStr,"%2.1f", Grados); lcd_gotoxy(13,2); // Coloca el cursor en posición lcd_puts(TempStr); } } Como se comentó anteriormente, estos microcontroladores no tienen puerto nativo para esta comunicación por lo que es necesaria construirlo por software. El archivo que contiene todo el saber de esta comunicación es 1wire.c donde encontramos funciones para leer temperatura tanto con el DS18B20 o con el veterano DS1820 a 10 bits de resolución. El contenido del archivo 1wire.c contiene la librería para el manejo de este dispositivo en XC8. /////////////////////////////////////////////////////////////////////// //// Driver para el manejo de las comunicaciones entre un pic y un //// //// dispositivo Dallas/Maxim 1-wire //// //// Los tiempos han sido calculados para un cristal de 20Mhz //// //// El pin de datos se ha dispuesto por RA4 //// //// WEB: www.firtec.com.ar //// //// mail: informes@firtec.com.ar //// /////////////////////////////////////////////////////////////////////// // NOTA: No olvidar la resistencia de 4,7K entre el pin RA4 y Vdd. /////////////////////////////////////////////////////////////////////// Programación en XC8 Pagina 80 de 174 #include <xc.h> #include <stdio.h> #include <stdlib.h> #include "1wire.h" #ifndef _XTAL_FREQ #define _XTAL_FREQ 20000000 #endif #define Pin_BAJO PORTAbits.RA4=0; TRISA = 0b00000000; #define Pin_Entrada TRISA = 0b00010001; #define Pin_Lee PORTAbits.RA4; /***************************** Reset_1Wire *****************************/ /*Esta función inicializa el buz 1wire */ /*Argumentos: ninguno */ /*Retorna: 0 si todo OK */ /***********************************************************************/ int Reset_1wire(void) { int result=1; Pin_BAJO __delay_us(500); Pin_Entrada; __delay_us(60); result = (int)Pin_Lee; __delay_us(240); return (result); } /*********************** Escribir_Bit() ******************************/ /* Esta función escribe un bit en el sensor. */ /* Argumentos: Un bit (El bit a escribir en el bus 1-wire) */ /* Retorna: nada */ /*********************************************************************/ void Escribir_Bit(int _bit) { if (_bit) { Pin_BAJO; __delay_us(6); Pin_Entrada; __delay_us(60); } else { Pin_BAJO __delay_us(60); Pin_Entrada; } __delay_us(10); } /*********************** Leer_Bit() ******************************/ /* Esta función lee un bit desde el sensor. */ /* Argumentos: ninguno */ /* Retorna: El estado del bit en el pin DQ del sensor */ /***********************************************************************/ int Leer_Bit(void) { int result=0; Pin_BAJO; __delay_us(6); Programación en XC8 Pagina 81 de 174 Pin_Entrada; __delay_us(6); result = (int)Pin_Lee; __delay_us(60); return (result); } /*********************** Escribir_Byte() ******************************/ /* Esta función escribe un byte en el sensor. */ /* Argumentos: byte (El byte a escribir en el bus 1-wire) */ /* Retorna: nada */ /***********************************************************************/ void Escribir_Byte(int data) { int loop; for (loop = 0; loop < 8; loop++) { Escribir_Bit(data & 0x01); data >>= 1; } } /*********************** leer_Byte() **********************************/ /* Esta función lee 8 bit´s desde el sensor 1-wire. */ /* Argumentos: ninguno */ /* Retorna: 8 bit´s (1-byte) los datos desde el sensor */ /***********************************************************************/ int Leer_Byte(void) { int loop, result=0; for (loop = 0; loop < 8; loop++) { result >>= 1; if (Leer_Bit()) result |= 0x80; } return result; } /*********************** Medir_Temperatura() ***************************/ /* Esta función inicia la conversión para medir la temperatura. */ /* Argumentos: ninguno */ /* Retorna: nada */ /***********************************************************************/ void Medir_Temperatura(void) { Reset_1wire(); Escribir_Byte(0xCC); Escribir_Byte(0x44); while(Leer_Bit() == 0); Reset_1wire(); } /*********************** Leer_DS18S20() ***************************/ /* Esta función lee la temperatura de un sensor DS1820. */ /* Argumentos: ninguno */ /* Retorna: La temperatura con signo */ /******************************************************************/ float Leer_DS18S20(void) { unsigned char get[10]; Programación en XC8 Pagina 82 de 174 int k, temp; float ftemp; Escribir_Byte(0xCC); Escribir_Byte(0xBE); for (k=0; k<8; k++) get[k]=Leer_Byte(); temp = get[0]; if (get[1] > 0x80) temp = temp * -1; ftemp = temp; return (ftemp/2); } /*********************** Leer_DS18B20() ***************************/ /* Esta función lee la temperatura de un sensor DS18B20. */ /* Argumentos: ninguno */ /* Retorna: La temperatura con signo */ /******************************************************************/ float Leer_DS18B20(void) { unsigned char temp1, temp2; int temp3; float result; Reset_1wire(); Escribir_Byte(0xCC); Escribir_Byte(0x44); Reset_1wire(); Escribir_Byte(0xCC); Escribir_Byte(0xBE); temp1 = Leer_Byte(); temp2 = Leer_Byte(); temp3 = (( int) (((( int )( temp2 )) << 8 ) + ((int )( temp1 )))) ; result = (float) temp3 / 16.0; return(result); } Programa en ejecución. Programación en XC8 Pagina 83 de 174 En ocasiones puede ser necesario necesitar leer el código ROM de los sensores. En el ejemplo siguiente vemos la forma de leer este código y mostrarlo en un LCD. Este número de 64 bits puede sernos útil para realizar una red de sensores e interrogarlos por su número ROM. Podríamos tener varios sensores y tratarlos por su número de “RED”. A continuación el ejemplo para leer el número de serie de casa sensor. /* ***************************************************************************** ** File Name : RomCode.c ** Author : www.firtec.com.ar ** Target : 40PIN PIC18F4620 ** Compiler : Microchip XC8 ** IDE : Microchip MPLAB-X ** XTAL : 20MHZ ** *****************************************************/ #include <xc.h> #include <stdio.h> #include <stdlib.h> #include <plib/usart.h> #include "1wire.h" #include "RomCode.h" #pragma config OSC=HS,PWRT=ON,MCLRE=OFF,LVP=OFF,WDT=OFF #define _XTAL_FREQ 20000000 #include "C:\ELECTRÓNICA\Programas PIC\DS1820_ROM.X\lcd_xc8.c" #include "C:\ELECTRÓNICA\Programas PIC\DS1820_ROM.X\lcd_xc8.h" unsigned char ROM_DATA [8]; // Array donde se guardará el codigo ROM unsigned char puntero_array = 0; void main (void) { unsigned char b; // Variable de uso multiple char a[2]; lcd_init(); // Inicializa el LCD lcd_gotoxy(1,1); lcd_putrs("CODIGO ROM 64bit"); // Cartel inicial while(OWReset()){ Programación en XC8 // Si no es cero SENSOR ERROR Pagina 84 de 174 lcd_gotoxy(1,2); lcd_putrs(" SENSOR ERROR!!"); } lcd_gotoxy(1,2); lcd_putrs(" "); // Limpia pantalla LEER_ROM(); // Se leen los 64 bit's del sensor lcd_gotoxy(1,2); for(puntero_array=0;puntero_array<8;puntero_array++){ sprintf(a,"%02X",ROM_DATA[puntero_array]); lcd_puts(a); } while(1); } Programa en ejecución. Trabajo practico En base a lo aprendido escriba un programa que envíe por el puerto USART la temperatura de un sensor DS18B20 y visualizar los datos en una la computadora. Programación en XC8 Pagina 85 de 174