-2

I want to display letter on specific row and column in 16x2 LCD display with 8051 MCU. For Example:

Display "R" at 2nd column in first row
Display "W" at 3rd column in second row

I use these routines for the LCD:

 #include<reg51.h>

/* Data pins connected to port P1 of 8051 */
#define  Data_Port_Pins                            (P1)
sbit    Register_Select_Pin   = P2^0;           /* Register Pin of LCD connected to Pin 0 of Port P2 */
sbit    Read_Write_Pin        = P2^1;           /* Read/Write Pin of LCD connected to Pin 1 of Port P2 */
sbit    Enable_Pin            = P2^2;           /* EN pin connected to pin 2 of port P2 */
/* Function for creating delay in milliseconds */
void Delay(unsigned int wait)
   {
      volatile unsigned i, j;
      for(i = 0; i < wait; i++)
         for(j = 0; j < 1200; j++);
   }

/* Function to send command instruction to LCD */
void LCD_Command (unsigned char command)
{
    Data_Port_Pins = command;
    Register_Select_Pin =0;
    Read_Write_Pin=0;
    Enable_Pin =1;
    Delay (2);
    Enable_Pin =0;
}
/* Function to send display data to LCD */
void LCD_Data (unsigned char Data)
{
    Data_Port_Pins = Data;
    Register_Select_Pin=1;
    Read_Write_Pin=0;
    Enable_Pin =1;
    Delay(2);
    Enable_Pin =0;
}
/* Function to prepare the LCD  and get it ready */
void LCD_Initialization()
{
    LCD_Command (0x38);
    LCD_Command (0x0e);
    LCD_Command (0x01);
    LCD_Command (0x81);
}

And this is my attempt:

Does it make any sense?

   void LCD_Position( char row, char column)
   {
    unsigned char cmd = 0x80 ;   /* Start address */

   if( row != 0 )               /*If second row selected ...*/
         {
       cmd += 0x40 ;            /*add start address of second row */
     }
         cmd += row & 0x0f ; 
         LCD_Command (cmd);

   }
ABH786
  • 33
  • 2
  • 8
  • 1
    What have you tried? At the moment it looks like you just pasted the problem that you've been given. Also, without knowing exactly what LCD you're connected to, no one here can help you. – Ross Sep 15 '17 at 13:01
  • I can write program for message display on LCD and I have been written it. and tested it with simulator its working fine. after that I tried to write program to display letter on specific row and column.. but I have no idea how to display letter on specific row and column I am using 16*2 LCD – ABH786 Sep 15 '17 at 15:41
  • 1
    In `Delay()`, declare `i` and `j` `volatile` (`volatile unsigned i, j;`) – Clifford Sep 15 '17 at 23:10
  • @Clifford nice catch but with `volatile` the number `1200` will most likely change to a lower one. – Spektre Sep 16 '17 at 09:36
  • @Spektre : Eh? `volatile` will not make the loop slower, it just prevents it from being removed altogether by optimisation; it either takes the same length of time, or no time at all. It is possible of course that an optimiser may also unroll the loop and change the delay, but that is not caused or affected by `volatile`. If a consistent and accurate delay is required, a hardware timer should be used in any case. – Clifford Sep 16 '17 at 11:33
  • Your attempt is not really an attempt at all; since you have not defined `LCD_Position()` the code serves as an illustration of what you want to do, but it is in no manner an "attempt", just a "fill-in-the-blank for me" question. – Clifford Sep 16 '17 at 11:48
  • @Clifford some compilers do weird stuff for `volatile` variables. For example in **AVR studio** 2.6 and 2.7 with **GCC** compiler. Resulting in measurably much slower access for such variables on **UC3 AVR32** chips and **C++** source (at least on certain circumstances). – Spektre Sep 16 '17 at 13:40
  • 1
    @Spektre : It may force the variable to be a memory access rather than register,bso fair point, but this method of delay is subject to all sorts of variation, and would need calibration as a result of any compile option or compiler changes. In this case the delays need only be at least as long as that specified in the datasheet, so there may already be plenty of margin. – Clifford Sep 16 '17 at 14:05
  • Blatant plagiarism! Changing the question by adding someone else's solution given in answer to the original question, passing it off as your own, and asking for comments on it is pretty poor form. Especially since this is the dumbed-down version offered only in response to your confusion over the better solution. Changing the comments is not fooling anyone. – Clifford Sep 16 '17 at 20:24

1 Answers1

0

Refer to the data sheet for the LCD device in question. For the common 1602 type module (which the initialisation sequence shown suggests is what you are using) you set the position for the next data write using the Set DDRAM address instruction.

In 2-line display mode the 1st line starts at address 0x00, and the the 2nd line starts at 0x40.

void LCD_Position( int row, int pos)
{
    LCD_Command( 0x80 |                     // Set DDRAM Address
                 (row == 0) ? 0x00 : 0x40 | // Row selector
                 (pos & 0x0f) ) ;           // Position in row
}

Given (from the data sheet):

enter image description here

The code sets DB7 to 1 (0x80)indicating the Set DDRAM Addresss instruction. The other bits are address bits, but there are more locations in the display RAM than the width of the display, so only 0x00 to 0x0f and 0x40 to 0x4f refer to visible display locations. So if the second row is selected, 0x40 is masked in ((row == 0) ? 0x00 : 0x40), then the character position is masked in ((pos & 0x0f)). Although I have used bit-wise manipulation, the expression could equally be performed arithmetically:

0x80 + (row == 0) ? 0x00 : 0x40 + (pos & 0x0f)

In both cases the & 0x0f ensures the command is not modified and that the character is placed on the display even if the position if out-of-range.

Less succinctly, but perhaps easier to follow:

// Set DDRAM Address command - start of row 0
unsigned char cmd = 0x80 ;

// If second row selected ...
if( row != 0 )  
{
    // ... add start address of second row
    cmd += 0x40 ; 
}

// Add row offset.  Masked to protect other 
// bits from change if row is out of range.
cmd += row & 0x0f ;  

// Write command
LCD_Command( cmd ) ;
Clifford
  • 88,407
  • 13
  • 85
  • 165
  • I understand address 0x00 (command 0x80) set the cursor to the beginning of the first line, and address 0x40 (command 0xC0) sets the address to the beginning of the second line. but I didn't understand how does your function work.... – ABH786 Sep 16 '17 at 07:40
  • @Parth786 : Well first of all does it work? I am just reading the data sheet and assuming that your existing `LCD_Command()` works (which in turn may rely on you fixing the `Delay()` function); I have not tested it. Second I was hoping not to have to explain things already expressed in the datasheet, and comprehension of the code is really a different question. Will update answer if it helps. – Clifford Sep 16 '17 at 10:53
  • I didn't see option to post code so I have edited post. – ABH786 Sep 16 '17 at 17:26
  • @Parth786 : SO is not a discussion forum, it is a Q&A; you ask questions, you get answers. Changing the question after the event is not good form. If particular answer is useful you accept it, you may also vote on more than one answer. You should not edit your question to add an answer that was given to you and then ask if it is a good answer! That kind of recursion will cause all sorts of confusion. You are essentially asking others to comment on my answer (and IMO the least best solution of those offered), which they can do perfectly well already by commenting, voting. – Clifford Sep 16 '17 at 20:11