I am trying to interface a 16x4 LCD to a PIC16F877 MCU. The project is just a digital clock showing date and time from a DS1307 RTC.

The display works correctly when I use a 16x2 LCD. But if I try to print the same thing, same code in the 16x4 LCD's 3rd and 4th row, the display prints it at 4rd column instead of 1. I have displayed the working and the not working screenshots below.

Maybe it is because of using 4-bit interface instead of 8. Or maybe some other issue. Can you please guide me:

I am using MikroC Pro for PIC compiler's library LCD display. It is a 4 bit interfacing library.


enter image description here

1st 2nd row:

enter image description here

3rd 4th row:

enter image description here


// LCD module connections
sbit LCD_RS at RB2_bit;
sbit LCD_EN at RB3_bit;
sbit LCD_D4 at RB4_bit;
sbit LCD_D5 at RB5_bit;
sbit LCD_D6 at RB6_bit;
sbit LCD_D7 at RB7_bit;

sbit LCD_RS_Direction at TRISB2_bit;
sbit LCD_EN_Direction at TRISB3_bit;
sbit LCD_D4_Direction at TRISB4_bit;
sbit LCD_D5_Direction at TRISB5_bit;
sbit LCD_D6_Direction at TRISB6_bit;
sbit LCD_D7_Direction at TRISB7_bit;
// End LCD module connections

unsigned short read_ds1307(unsigned short address)
  unsigned short r_data;
  I2C1_Wr(0xD0); //address 0x68 followed by direction bit (0 for write, 1 for read) 0x68 followed by 0 --> 0xD0
  I2C1_Wr(0xD1); //0x68 followed by 1 --> 0xD1

void write_ds1307(unsigned short address,unsigned short w_data)
  I2C1_Start(); // issue I2C start signal
  //address 0x68 followed by direction bit (0 for write, 1 for read) 0x68 followed by 0 --> 0xD0
  I2C1_Wr(0xD0); // send byte via I2C (device address + W)
  I2C1_Wr(address); // send byte (address of DS1307 location)
  I2C1_Wr(w_data); // send data (data to be written)
  I2C1_Stop(); // issue I2C stop signal

unsigned char BCD2UpperCh(unsigned char bcd)
  return ((bcd >> 4) + '0');

unsigned char BCD2LowerCh(unsigned char bcd)
  return ((bcd & 0x0F) + '0');

int Binary2BCD(int a)
   int t1, t2;
   t1 = a%10;
   t1 = t1 & 0x0F;
   a = a/10;
   t2 = a%10;
   t2 = 0x0F & t2;
   t2 = t2 << 4;
   t2 = 0xF0 & t2;
   t1 = t1 | t2;
   return t1;

int BCD2Binary(int a)
   int r,t;
   t = a & 0x0F;
   r = t;
   a = 0xF0 & a;
   t = a >> 4;
   t = 0x0F & t;
   r = t*10 + r;
   return r;

int second;
int minute;
int hour;
int hr;
int day;
int dday;
int month;
int year;
int ap;

unsigned short set_count = 0;
short set;

char time[] = "00:00:00 PM";
char date[] = "00-00-00";

void main()
   I2C1_Init(100000); //DS1307 I2C is running at 100KHz

   CMCON = 0x07;   // To turn off comparators
   ADCON1 = 0x06;  // To turn off analog to digital converters

   TRISA = 0x07;
   PORTA = 0x00;

   Lcd_Init();                        // Initialize LCD
   Lcd_Cmd(_LCD_CLEAR);               // Clear display
   Lcd_Cmd(_LCD_CURSOR_OFF);          // Cursor off

      second = read_ds1307(0);
      minute = read_ds1307(1);
      hour = read_ds1307(2);
       hr = hour & 0b00111111;
       ap = hour & 0b00100000;
      dday = read_ds1307(3);
      day = read_ds1307(4);
      month = read_ds1307(5);
      year = read_ds1307(6);

      time[0] = BCD2UpperCh(hr);
      time[1] = BCD2LowerCh(hr);
      time[3] = BCD2UpperCh(minute);
      time[4] = BCD2LowerCh(minute);
      time[6] = BCD2UpperCh(second);
      time[7] = BCD2LowerCh(second);

      date[0] = BCD2UpperCh(day);
      date[1] = BCD2LowerCh(day);
      date[3] = BCD2UpperCh(month);
      date[4] = BCD2LowerCh(month);
      date[6] = BCD2UpperCh(year);
      date[7] = BCD2LowerCh(year);

         time[9] = 'P';
         time[10] = 'M';
         time[9] = 'A';
         time[10] = 'M';

      Lcd_out(3, 6, time);
      Lcd_out(4, 6, date);

  • \$\begingroup\$ Can you lose the graph paper effect? It really obscures your diagrams. \$\endgroup\$ Aug 10, 2016 at 15:49
  • \$\begingroup\$ These are screenshots from Proteus simulation software. Sorry I don't know how to remove the grid, I checked. \$\endgroup\$
    – Mohsin
    Aug 10, 2016 at 15:52
  • \$\begingroup\$ @ScottSeidman I found the solution to set the indexes in -ve to make the display work as it should. But I would really like someone to tell me the cause of this problem, if possible. \$\endgroup\$
    – Mohsin
    Aug 10, 2016 at 15:55
  • \$\begingroup\$ Mohsin, you should learn that step 1 of solving your own problems is to reduce them to simplest form. In this case, for example, your issue has nothing to do with the RTC. Therefore, before asking, you should entirely strip the RTC out of your code. Make some code that just prints something stupid like "abcdef" to the LCD. Include any code that might help us understand what's going on -- like the LCD subroutines. Also include data sheets for relevant parts, like the LCD. By the time you're done doing all this, chances are good that you've solved your own problem. \$\endgroup\$ Aug 10, 2016 at 16:07
  • \$\begingroup\$ Lastly, I'm not a huge fan of putting too much time into Proteus simulations, as in many cases the program just proves to be wrong. \$\endgroup\$ Aug 10, 2016 at 16:09

3 Answers 3


You need to set up the row and column information in your code and send it to the LCD. Generally two chips are used on the LCD board. Their instruction setup can be found on the web in pdf format. The commands set up the chip to inform it how to process the information you send. Rows are from 0 to 3, and you still have to tell it where to place your text.

  • \$\begingroup\$ Yes I am telling what row and column to print at Lcd_out(1, 1, time). The issue is, for the first two rows, the first column index is 1. For the last two rows, it is -3. That is strange. \$\endgroup\$
    – Mohsin
    Aug 10, 2016 at 16:56
  • \$\begingroup\$ Can you look and see what he numbers on the IC's on the back of your LCD board are and post them? Should be two multi legged ones. \$\endgroup\$
    – David H
    Aug 11, 2016 at 20:05

The solution is quite simple. I experienced the same problem initially. But I had to find a way around it. If you issue this command, Lcd_Out(3,1,"text"); Your text would start on column 4 of row 3. The trick is, if you want to display your first character on first column of 3rd row, you count 3places backwards. You do this by subtracting 3 from the column value as shown below: Lcd_Out(3,-3,"text"); So, if I want text to start on column 6 of the 3rd row, I simply add 5(not 6) to -3 in the command line as shown below: Lcd_Out(3,2,"text"); Remember: -3 + 5 =2. The same explanation holds for the 4th row.


It's because you have Lcd_out command just after void main:


and same code at end of

Lcd_out(3, 6, time);
Lcd_out(4, 6, date);

Simply delete the 2 just after void main, or make both lines of code the same i.e. 3,1 or 3,6.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.