How to print retrieved hours from DS1307 to LCD?

Go To Last Post
15 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have a simple project. I have an ATmega32 connected to a 16x2 LCD and a DS13027 chip. I am using 8-Bit data with the 16x2 LCD. Below is the code.

#define F_CPU 8000000UL

#define LCD_DPRT  PORTA
#define LCD_DDDR  DDRA
#define LCD_DPIN  PINA
#define LCD_CPRT  PORTB
#define LCD_CDDR  DDRB
#define LCD_CPIN  PINB
#define LCD_RS  0
#define LCD_RW  1
#define LCD_EN  2

#include <avr/io.h>
#include <util/delay.h>

void i2c_stop(void);
void i2c_write(unsigned char data);
void i2c_start(void);
void i2c_init(void);
unsigned char i2c_read(unsigned char ackVal);
void rtc_init(void);
void rtc_setTime(unsigned char deviceRegister, unsigned char value);
unsigned char *rtc_getTime(unsigned char deviceRegister);
void lcdCommand( unsigned char cmnd );
void lcdData( unsigned char data );
void lcd_init();
void lcd_gotoxy(unsigned char x, unsigned char y);
void lcd_print( const char * str );

int main(void) {

    unsigned char *hours;

    rtc_init();
    rtc_setTime(0x02, 0x22);

    hours = rtc_getTime(0x02);

    lcd_init();
    lcd_gotoxy(1,1);
    lcd_print(hours[0]);
    lcd_gotoxy(2,1);
    lcd_print(hours[1]);

    while (1);
    return 0;
}

void i2c_stop(void){
    TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
}

void i2c_write(unsigned char data){
    TWDR = data;
    TWCR = (1<<TWINT) | (1<<TWEN);
    while(!(TWCR & (1<<TWINT)));
}

void i2c_start(void){
    TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
    while(!(TWCR & (1<<TWINT)));
}

void i2c_init(void){
    TWSR = 0x00;
    TWBR = 0x47;
    TWCR = 0x04;
}

unsigned char i2c_read(unsigned char ackVal){
    TWCR = (1<<TWINT) | (1<<TWEN) | (ackVal<<TWEA);
    while( !( TWCR & (1<<TWINT)) );
    return TWDR;
}

void rtc_init(void){
    i2c_init();
    i2c_start();
    i2c_write(0xD0);
    i2c_write(0x07);
    i2c_write(0x00);
    i2c_stop();
}

void rtc_setTime(unsigned char deviceRegister, unsigned char value){
    i2c_start();
    i2c_write(0xD0);
    i2c_write(deviceRegister);
    i2c_write(value);
    i2c_stop();
}

unsigned char *rtc_getTime(unsigned char deviceRegister){

    unsigned char *data;

    i2c_start();
    i2c_write(0xD0);
    i2c_write(deviceRegister);
    i2c_stop();

    i2c_start();
    i2c_write(0xD1);
    *data = i2c_read(0);
    i2c_stop();

    return data;
}

void lcdCommand( unsigned char cmnd ){
  LCD_DPRT = cmnd;
  LCD_CPRT &= ~ (1<<LCD_RS);
  LCD_CPRT &= ~ (1<<LCD_RW);
  LCD_CPRT |= (1<<LCD_EN);
  _delay_us(1);
  LCD_CPRT &= ~ (1<<LCD_EN);
  _delay_us(100);
}

void lcdData( unsigned char data ){
  LCD_DPRT = data;
  LCD_CPRT |= (1<<LCD_RS);
  LCD_CPRT &= ~ (1<<LCD_RW);
  LCD_CPRT |= (1<<LCD_EN);
  _delay_us(1);
  LCD_CPRT &= ~ (1<<LCD_EN);
  _delay_us(100);
}

void lcd_init(){
  LCD_DDDR = 0xFF;
  LCD_CDDR = 0xFF;

  LCD_CPRT &=~(1<<LCD_EN);
  _delay_us(2000);
  lcdCommand(0x38);
  lcdCommand(0x0E);
  lcdCommand(0x01);
  _delay_us(2000);
  lcdCommand(0x06);
}

void lcd_gotoxy(unsigned char x, unsigned char y){
 unsigned char firstCharAdr[]={0x80,0xC0,0x94,0xD4};//table 12-5
 lcdCommand(firstCharAdr[y-1] + x - 1);
 _delay_us(100);
}

void lcd_print( const char * str ){
  unsigned char i = 0 ;
  while(str[i]!=0)
  {
    lcdData(str[i]);
    i++ ;
  }
}

When I run this program I get the following output on the LCD.

 

  1. Why isn't the hours appearing on the LCD?
  2. How can I output the hours on the LCD (code wise)?

 

When I build the program I get the following warnings.

clock_tester.c: In function 'main':
clock_tester.c:48:15: warning: passing argument 1 of 'lcd_print' makes pointer from integer without a cast [-Wint-conversion]
     lcd_print(hours[0]);
               ^
clock_tester.c:35:6: note: expected 'const __memx char *' but argument is of type 'unsigned char'
 void lcd_print( const char * str );
      ^
clock_tester.c:50:15: warning: passing argument 1 of 'lcd_print' makes pointer from integer without a cast [-Wint-conversion]
     lcd_print(hours[1]);
               ^
clock_tester.c:35:6: note: expected 'const __memx char *' but argument is of type 'unsigned char'
 void lcd_print( const char * str );
      ^
clock_tester.c: In function 'rtc_getTime':
clock_tester.c:111:8: warning: 'data' is used uninitialized in this function [-Wuninitialized]
  *data = i2c_read(0);

 

This topic has a solution.
Last Edited: Fri. Nov 19, 2021 - 02:30 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mahmoud899 wrote:
Why isn't the hours appearing on the LCD?

 

Did you print anything on the LCD, for example "Hello World", please.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes in a separate project I tested the LCD code and it printed fine.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Are you sure the RTC works? Can you check with the scope.

I recommend this:

    i2c_write(0xD0);
    i2c_write(0x07);
    i2c_write(0x00); -> change to 0x10

This change will produce 1 Hz on the board pin marked 1 Hz.

Edit: or, marked SQW

Last Edited: Fri. Nov 19, 2021 - 07:55 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am working on Proteus Simulator. The problem isn't from the DS1307. The problem is when I invoke the rtc_getTime(unsigned char deviceRegister) function what is the type of the variable that is returned from the DS1307? For example if it is an integer and I have the data variable which is unsigned char *hours, then I think this might be the problem. I will edit the post and add the warnings from when I compile the program.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

mahmoud899 wrote:
what is the type of the variable that is returned from the DS1307

 

Hours, minutes and seconds are not just binary, they should be prepared for print, according to datasheets:

 

 

Edit: found this code:

 

   time[0] = (HOURS & 0x0f) | 0x30;                //hours(1's)
   time[1] = ((HOURS & 0x30) >> 4) | 0x30;         //hours(10's)

 

 

Last Edited: Fri. Nov 19, 2021 - 08:56 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Those warnings are almost certainly why your project doesn't work. You need to fix them.

 

You could start here:

unsigned char rtc_getTime(unsigned char deviceRegister)
{
    unsigned char data;

    i2c_start();
    i2c_write(0xD0);
    i2c_write(deviceRegister);
    i2c_stop();

    i2c_start();
    i2c_write(0xD1);
    data = i2c_read(0);
    i2c_stop();

    return data;
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How can I convert unsigned char to const char *? This is the problem. The rtc_getTime(unsigned char deviceRegister) returns unsigned char. I added the following code in the main function 

    unsigned char hour;
    unsigned char temp;
    
    rtc_init();
    rtc_setTime(0x02, 0x23);
    hour = rtc_getTime(0x02);
    temp = '0' + (hour >> 4);
    hour = '0' + (hour & 0x0F);
    
    lcd_init();
    lcd_gotoxy(1,1);
    lcd_print(temp);
    
    while(1);
    return 0;

The problem is because the temp and hour is unsigned char and the lcd_print(const char *str) takes a const char that is why it isn't printing on the LCD. How can I convert the unsigned char to const char *?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

I strongly advise you to start with proven libraries.   e.g. Codevision alcd.h and i2c.h or (GCC) Fleury lcd.h and i2cmaster.h

Use the return values from the library functions when available.

 

Of course you can probably find Codevision ds1307.h or a GCC equivalent.   But these might be "too easy"

 

Anyway,   it seems wise to use proven libraries.   Post your code.   I am happy to help with Codevision, Fleury, ... or any respected library.

 

If your teacher wants you to "write your own library code",   I don't mind showing you how to implement your own versions of Codevision, Fleury, ...

The important lesson being to design a suitable set of useful functions.    Most of which will return GOOD/BAD values.

Your teacher should have explained how foolish void functions are.

 

Seriously.    Engineering is about using appropriate tools and components.   You build a car or a bridge with ready-made bolts.   This means that you can concentrate on any "special features"

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mahmoud899 wrote:
How can I convert the unsigned char to const char *?

Eh ??

Did you actually write this code because the answer is right there in the #1 code and the snippet in #8.

 

In #8 you realize that Hour from the DS1307 is a 2-digit binary coded decimal (BCD). You correctly split this into individual digits and add the offset to convert into ASCII . Those variables are now chars and you need to print them. Your lcd_print() function internally does exactly that (it prints chars).

I really don't see why you are struggling.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

void I2C functions will fail without warning, better to use I2C functions that return a status so you know you are actually talking to the RTC chip! 

I2C will tell you if your doing it wrong, but of course, one has to actually listen to what it says......

Your code above just blindly sends data onto the bus without looking for the chip to respond with it's ACK/NAK, you must check the return status of each command sent, but void functions can't do that!!!

Use proven I2C libs as suggested above and check the status after sending the chip address to see if it ACKs before sending any more, as that must work first, or all else is for not...

Jim

 

 

Keys to wealth:

Invest for cash flow, not capital gains!

Wealth is attracted, not chased! 

Income is proportional to how many you serve!

Lets go Brandon!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

When I run the code I get the following output on the LCD:

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mahmoud899 wrote:
I am working on Proteus Simulator.

So have you used its debugging facilities to see what's going on?

  • Single-step the code, to see what's happening in the code;
  • Use the virtual test instruments to see what's happening on the external hardware.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The problem was with the lcd_print() function. It has an argument const char *str. I returned the values from the rtc_getTime( unsigned char deviceRegister) and split them into individual digits. I then created an array char hour_values[2];. Then I added in the array the split values hour_values[0] = temp; hour_values[1] = hour. Then I gave the lcd_print() function the array and it outputted the values on the LCD.

 

    char hour_values[2];
    unsigned char hour;
    unsigned char temp;
    
    rtc_init();
    rtc_setTime(0x02, 0x23);
    hour = rtc_getTime(0x02);
    temp = '0' + (hour >> 4);
    hour = '0' + (hour & 0x0F);
    
    hour_values[0] = temp;
    hour_values[1] = hour;
    
    lcd_init();
    lcd_gotoxy(1,1);
    lcd_print(hour_values);
    
    while (1);
    return 0;

 

Last Edited: Fri. Nov 19, 2021 - 02:30 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

mahmoud899 wrote:
The problem was with the lcd_print() function. It has an argument const char *str. I returned the values from the rtc_getTime( unsigned char deviceRegister) and split them into individual digits. I then created an array char hour_values[2];. Then I added in the array the split values hour_values[0] = temp; hour_values[1] = hour. Then I gave the lcd_print() function the array and it outputted the values on the LCD.

Remember that your lcd_print() is expecting a null terminated string.

So really you want

char hour_values[3];
hour_values[0] = ...;
hour_values[1] = ...;
hour_values[2] = '/0';