Problema con comunicacion i2c y lcd

Buenas, estoy haciendo un pequeño proyecto personal de un reloj despertador. Para ello utilizo un PIC16F887, un RTC: DS3232, y una pantalla LCD 16x2. Como no he logrado que cuente he reducido lo mas que he podido el código para encontrar el error. Este código que muestro aqui lo que busco que haga es simplemente escribir en el registro de segundos del RTC un valor "20" y luego leerlo y mostrarlo en la pantalla LCD. El problema es que en la simulación de proteos el LCD solo muestra "00" y nunca logra mostrar el "20" que yo estoy buscando que muestre. Obviamente puedo hacer que muestre 20 colocando ese valor directamente desde el PIC pero el punto es lograr que muestre ese valor utilizando la comunicación i2c que es lo que creo que esta fallando. A continuación les dejo el código y el esquema del proteus

C:
#include <pruebai2c.h>
#fuses XT,NOWDT,NOPROTECT,NOLVP
#use I2C(master, SDA=PIN_C4, SCL=PIN_C3, FAST)

#define LCD_ENABLE_PIN  PIN_D0                                  
#define LCD_RS_PIN      PIN_D1                                  
#define LCD_RW_PIN      PIN_D2                                  
#define LCD_DATA4       PIN_D4                              
#define LCD_DATA5       PIN_D5                                  
#define LCD_DATA6       PIN_D6                                
#define LCD_DATA7       PIN_D7

#include "DS3232DEF.c"
#include <lcd.c>


void main()
{
   delay_ms(1000);
   lcd_init();
   lcd_putc('\f');
   seconds=20;
   set_time();
   delay_ms(200);
   get_time();
   printf(lcd_putc, "%02u", seconds);
   delay_ms(1000);
}

C:
#include <stdint.h>

uint8_t seconds;
//uint8_t set_time;

//////////////////////////////////////

// functions //

uint8_t bcd_to_decimal(uint8_t number);
uint8_t decimal_to_bcd(uint8_t number);

//////////////////////////////////////
//////////////////////////////////////
//////////////////////////////////////

// converts BCD to decimal //

uint8_t bcd_to_decimal(uint8_t number)
{
  return ( (number >> 4) * 10 + (number & 0x0F) );
}

// converts decimal to BCD //

uint8_t decimal_to_bcd(uint8_t number)
{
  return ( ((number / 10) << 4) + (number % 10) );
}

///////////////////////////////////////
///////////////////////////////////////
///////////////////////////////////////

// sets time and date //
void set_time()
{
seconds = decimal_to_bcd(seconds);

// write data to the RTC chip //
  i2c_start();
  i2c_write(0xD0);              //mando la direccion donde se encuentra el esclavo (ds3232)
  i2c_write(0x00);              //me posiciono en el registro del ds3232 correspondiente a los segundos
  i2c_write(seconds);           //cargo la informacion de la variable segundos, en el registro correspondiente a los segundos del ds3232, luego de haber hecho la conversion de decimal a bcd
  i2c_stop();                   //se finaliza la comunicacion con el ds3232, se supone que mi informacion que tenia en la variable segundos ya se ha cargado en el registro correspondiente a los segundos del DS
}
 


// reads time and date //
void get_time()
{
  i2c_start();
  i2c_write(0xD0);              //mando la direccion donde se encuentra el esclavo (ds3232)
  i2c_write(0x00);              //me posiciono en el registro del ds3232 correspondiente a los segundos
  i2c_start();    //reinicio, desconozco el proposito de este paso
  i2c_write(0xD0 | 0x01);       //realizo un OR para colocar el bit 0, correspondiente a la direccion del esclavo, en 1. Esto indica que voy a proceder a leer informacion, es decir que el esclavo me va a mandar informacion al maestro. Si solo coloco 0xD0 el maestro es el que envia informacion al esclavo.
  seconds = i2c_read(0);        //cargo mi variable "seconds" con el valor que tiene el registros de segundos del ds3232 al momento de realizar la lectura.
  i2c_stop();                   //se finaliza la comunicacion con el ds3232, se supone que ahora tengo cargado en mi variable "seconds" los valores que se encontraban en el registro de segundos del RS3232.
 
  // convert BCD to decimal //
  seconds = bcd_to_decimal(seconds);    //con la comunicacion anterior cargamos el valor del registro de segundos del RS3232 en nuestra variable "seconds" pero ese valor se encuentra en BCD y debemos transformarlo a Decimales por eso realizamos este paso.(si mal no recuerdo esto es para mostrar de manera adecuada los valores en el lcd)
 
}


Captura.JPG
 

Adjuntos

  • comunicacion i2c.zip
    21.2 KB · Visitas: 1
  • 1652559257973.png
    1652559257973.png
    74.3 KB · Visitas: 8
Según el datasheet del ds3232 Vbat debe tener una batería, tal vez no memorice y por eso sea siempre el valor 00. Tampoco veo las VCC y GND de U2. No obstante no uso proteus y no se si funciona en la simulación correctamente
 
Rst debería de estar a positivo, no al aire.

En la vida real seguramente habría ruido, Proteus seguramente considere un cero, osea reseteando.
 
Según el datasheet del ds3232 Vbat debe tener una batería, tal vez no memorice y por eso sea siempre el valor 00. Tampoco veo las VCC y GND de U2. No obstante no uso proteus y no se si funciona en la simulación correctamente
Hola FelML, muchas gracias por tu respuesta. Si, debe tener la batería pero es para que siga con el conteo del tiempo después de desconectado el dispositivo. Mientras esta conectado se encuentra alimentado por Vcc y Gnd que en Proteus son pines que están conectados pero ocultos. Mi problema es que mientras esta funcionando no actualiza la informacion del registro de segundos ni tampoco la lee. De todas maneras acabo de intentar agregando la bateria a la simulacion y tampoco funciona :(.
Rst debería de estar a positivo, no al aire.

En la vida real seguramente habría ruido, Proteus seguramente considere un cero, osea reseteando.
Hola Scooter, gracias por tu respuesta. Lo conecté a positivo y tampoco funciona. No se que puede ser, yo apunto mas a que problema debe de estar en el código pero la verdad que no estoy pudiendo encontrar el/los errores. Un compañero me dijo que podría ser que este mal la dirección del esclavo pero voy a la hoja de datos del ds3232 y la dirección es esa que tengo en mi código (0:LOL:0).
 
Última edición:
Se supone que el RTC está en D0, y escribes en D0, pero lees de 00.

Creo que el i2cstart ese que no sabes para qué sirve, te sobra.
 
Última edición:
Mirar este Enlace a datasheet, el ds3232 lleva el crystal integrado.
En cuanto al software tal vez pueda ser la función or | , una sola barra en C es or lógico, y dos barras || es or bit a bit. Prueba a poner doble barra. Si estoy en lo cierto la función write escribe en la dirección 0x01 (resultado del or lógico 0xd0 y 0x01)
Si tienes dudas, prueba la función write con la dirección 0xd1 para estar seguro de que escribe la dirección del ds3232 para lectura.

Una pregunta. En la línea seconds=i2c_read(0);. ¿El parámetro 0 que significa?
 
Última edición:
Buenas, probé con lo que me dijeron y lo mismo sigue sin contar en proteus, el problema persiste, pero en el proyecto físico lo logre solucionar. Ya esta contando. Era un problema de fuente al parecer, el ds3232 estaba conectado a una fuente y el pic a otra. Desconozco si era problema de potencia de la fuente para con el ds3232 (el led de encendido del ds3232 prendía, pero quizás los valores de corriente o tensión no eran los adecuados) o si era problema de sincronización debido a que prendía primero una fuente y luego otra. Ayer por la noche conecte todo a una misma fuente que era la que estaba utilizando para encender el pic y comenzó a contar.


Respecto a la pregunta de FelML el parámetro dentro del read() es el bit ack de la comunicación (bit de reconocimiento), en este caso por ser la finalización de una lectura va el 0 que corresponde a un no ack. Es decir lee los 8 bits y al final de la cadena de bits manda un no ack indicando que finaliza la lectura. Probé lo que me dijiste de utilizar barras dobles pero no funciono, es con una sola barra, lo que si escribir la dirección 0xd1 directamente si me funcionó, muchas gracias por tu ayuda FelML, voy a continuar el proyecto sin la ayuda de la simulación directamente.


Buenas Scooter. El escribir en D0 es para avisar al pic la dirección en la que se encuentra el esclavo, una vez escrito eso recién puedo ingresar a los registros del mismo, en este caso, primero aviso la posición del esclavo (0xd0) y luego voy leo la dirección de registro del ds3232 correspondiente a los segundos (0x00) que es lo que estoy buscando leer (en el caso de la función get_time()). Respecto al segundo i2c_start() también pensé que me sobraba y he probado sacándolo pero da error, luego encontré el motivo en un libro, cito: "Existe la posibilidad de que el master, tras una transmisión/recepción, no abandone el bus y siga en comunicación con el esclavo; en esta ocasión se genera una nueva condición de start, llamada start repetida, idéntica a la anterior pero después de un pulso de reconocimiento." En este caso a ese start repetido se lo usaría para pasar de enviar información desde el pic (maestro) a recibir información desde el esclavo (ds3232). Te agradezco muchísimo la ayuda, como no logro solucionar la situación con la simulación en proteus y viendo que en el proyecto real ahora si funciona, supongo que el problema estará en el proteus que yo tengo. Voy a continuar el proyecto con pruebas sin la simulación y a ver que tal va.
 
Saludos he podido leer tu publicación de principio a fin y me gustaría aportar a tu publicación lo siguiente:
  1. Muchas veces es mejor tener algo funcional en el simulador antes de ponerse a montarlo porque te permite ahorrar dinero, pero de todas maneras felicidades que este funcionando.
  2. Hace unas semanas me puse a armar un proyecto muy parecido a lo que estás haciendo para una empresa publicitaria y te comparto las imagenes correspondientes "al desnudo"
  3. Finalmente, una de las caracteristicas que tiene este proyecto dispone son las siguientes: WDT de 2036 ms, Configurable los tiempos de encendidos y apagados, te permite configurar la hora del módulo RTC, Modo de programación/trabajo.
 

Adjuntos

  • RTC.JPG
    RTC.JPG
    197.1 KB · Visitas: 8
  • rtc PCB.jpeg
    rtc PCB.jpeg
    189.2 KB · Visitas: 8
  • pcb RCT.jpeg
    pcb RCT.jpeg
    138.3 KB · Visitas: 8
Saludos he podido leer tu publicación de principio a fin y me gustaría aportar a tu publicación lo siguiente:
  1. Muchas veces es mejor tener algo funcional en el simulador antes de ponerse a montarlo porque te permite ahorrar dinero, pero de todas maneras felicidades que este funcionando.
  2. Hace unas semanas me puse a armar un proyecto muy parecido a lo que estás haciendo para una empresa publicitaria y te comparto las imagenes correspondientes "al desnudo"
  3. Finalmente, una de las caracteristicas que tiene este proyecto dispone son las siguientes: WDT de 2036 ms, Configurable los tiempos de encendidos y apagados, te permite configurar la hora del módulo RTC, Modo de programación/trabajo.
Hola Felipe! Muchas gracias! Estoy completamente de acuerdo con vos. En este caso yo ya contaba con los materiales para armarlo por eso, luego de intentar varias veces en el simulador y no tener éxito, procedí directamente a armarlo y probarlo, también sin éxito jajaj, pero por suerte lo logre solucionar al final. Actualmente en el simulador sigue sin funcionar. Esta muy bueno el proyecto Felipe! bien prolijo todo. En mi caso pude terminar el proyecto y quedo funcionando bastante bien, no esta tan prolijo pero cumple la función jaja. Próximamente voy a estar comentando y explicando el código que hice y voy a subirlo aqui también para futuras personas que estén realizando un proyecto similar. Saludos!!
 
Arriba