Author Topic: LCD 16x2 command sequence issue  (Read 5478 times)

0 Members and 1 Guest are viewing this topic.

Online DTJTopic starter

  • Super Contributor
  • ***
  • Posts: 1016
  • Country: au
LCD 16x2 command sequence issue
« on: November 14, 2014, 08:10:11 am »
Hi I've got a problem talking to a Winstar 1602 LCD that's beating me.

My string write function works ok.
The cursor location code works - I can change the command value and place the cursor anywhere I want.
The cursor home code works.


However if I move the cursor to a position just prior to the string write it crashes - just leaves cursor flashing, no string written.

Poking around with the debugger and CRO it looks like the LCD gets stuck in the busy mode when trying to write the string after the cursor position command - hence the flashing cursor left on the screen.


Why does the cursor position command cause this to happen? Am I misusing it?

I need to be able to position the cursor and then write a string so I can write to line 2 of the display.

Any advice welcome!



This Code WORKS - the string is written to line 1 of LCD
=======================================================

//set cursor to line position 1
DATA_PORT = 0x80; //Send 0x80 | 0x00 = 0x80 sets cursor to line 1 pos 0x00
RS_PIN=0;   //sending cmd
RW_PIN=0;   //write to lcd
StrobeE_PIN();   //load command into LCD


//   cursor home
DATA_PORT = 0b00000011; //Send 0x03 sets cursor to home
RS_PIN=0;   //sending cmd
RW_PIN=0;   //write to lcd
StrobeE_PIN();   //load command into LCD


LCD_string(str1_splash);      //write string ==> LCD




This Code DOES NOT WORK - the cursor just blinks at home position
The order of cursor home & cursor to line 1 position 1 code sections are swapped.
===============================================================

//   cursor home as inline code
DATA_PORT = 0b00000011; //Send 0x03 sets cursor to home
RS_PIN=0;   //sending cmd
RW_PIN=0;   //write to lcd
StrobeE_PIN();   //load command into LCD


//set cursor to line position 1
DATA_PORT = 0x80; //Send 0x80 | 0x00 = 0x80 sets cursor to line 1 pos 0x00
RS_PIN=0;   //sending cmd
RW_PIN=0;   //write to lcd
StrobeE_PIN();   //load command into LCD


LCD_string(str1_splash);      //write string ==> LCD







 

Online DTJTopic starter

  • Super Contributor
  • ***
  • Posts: 1016
  • Country: au
Re: LCD 16x2 command sequence issue
« Reply #1 on: November 14, 2014, 11:39:12 am »
I just discovered something else...


If I write a single ASCII character to the LCD >>AFTER<< the "set cursor to line code", then the next "string write" works ok.

So writing a single character to the LCD seems to correct or reset the condition that the "set cursor to line code" is creating.
The single character write is the same function called by the string write code.

Apologies in advance for the grungie code.... :)

String write code
=============

void LCD_string(char *buffer)
{
        while(*buffer)                  // Write data to LCD up to null
        {
        while(LCD_busy());                // Wait while LCD is busy
   LCD_char(*buffer);                // Write character to LCD
        buffer++;                               // Increment buffer
        }
        return;
}


Single Character write code
===================

void LCD_char(char char2LCD)
{
RS_PIN=1;                       //sending data
RW_PIN=0;                       //write to lcd
DATA_PORT = char2LCD;       //character = LCD data port
StrobeE_PIN();
RS_PIN=0;                       //restore RS_PIN to low state
}                                       // end of LCD_char()

 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: LCD 16x2 command sequence issue
« Reply #2 on: November 14, 2014, 11:47:35 am »
I would suggest that you read the datasheet and compare it, both in terms of data sent and timing, vs. your code.

The issues are fairly obvious.
================================
https://dannyelectronics.wordpress.com/
 

Offline mikerj

  • Super Contributor
  • ***
  • Posts: 3438
  • Country: gb
Re: LCD 16x2 command sequence issue
« Reply #3 on: November 14, 2014, 11:52:38 am »
Where is the code for either reading back the busy flag before (or after) and operation, or alternatively the delays to wait for the maximum specified time for any given operation?
 

Online DTJTopic starter

  • Super Contributor
  • ***
  • Posts: 1016
  • Country: au
Re: LCD 16x2 command sequence issue
« Reply #4 on: November 14, 2014, 12:03:45 pm »

Hi Mikerj - when I write a character I don't check for busy flag - it works ok without delays at the moment.


Hi Dannyf - I'm obviously having problems spotting the obvious. Any clues?  ;)

Thanks guys.

Single character write code;
====================


void LCD_char(char char2LCD)
{
RS_PIN=1;                            //sending data
RW_PIN=0;                            //write to lcd
DATA_PORT = char2LCD;     //character = LCD data port
StrobeE_PIN();
RS_PIN=0;                           //restore RS_PIN to low state
}                                           // end of LCD_char()



When writing the string, the busy flag is checked prior to writing to the lcd;
=====================================================

void LCD_string(char *buffer)
{
        while(*buffer)                       // Write data to LCD up to null
        {
         while(LCD_busy());      // Wait while LCD is busy
   LCD_char(*buffer);
        buffer++;       // Increment buffer
        }
        return;
}


This is my busy flag code;
==================

unsigned char LCD_busy(void)
{
        RW_PIN = 1;                     // Set the control bits for read
        RS_PIN = 0;
        DelayFor18TCY();
        E_PIN = 1;                      // Clock in the command
        DelayFor18TCY();
                          // 8-bit interface
        if(DATA_PORT&0x80)                      // Read bit 7 (busy bit)
        {                               // If high
                E_PIN = 0;              // Reset clock line
                RW_PIN = 0;             // Reset control line
                return 1;               // Return TRUE
        }
        else                            // Bit 7 low
        {
                E_PIN = 0;              // Reset clock line
                RW_PIN = 0;             // Reset control line
                return 0;               // Return FALSE
        }
}

 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: LCD 16x2 command sequence issue
« Reply #5 on: November 14, 2014, 12:20:54 pm »
Easy: take out the datasheet, go to the section about commands / instructions and look up the ones you are using. Compare them vs. your code.

What differences do you see?
================================
https://dannyelectronics.wordpress.com/
 

Offline DJohn

  • Regular Contributor
  • *
  • Posts: 103
  • Country: gb
Re: LCD 16x2 command sequence issue
« Reply #6 on: November 14, 2014, 12:51:03 pm »
You don't say what processor you're using, or how fast it runs.  It's possible that the code is running slowly enough that the faster commands complete before you send the next one.

Home is not one of the faster commands.  You must either delay for the recommended time (1.something ms) or (much better) poll the busy signal until it is finished.  If you try sending another command before it has finished, anything can happen.  It might work.  It might ignore you.  It might catch fire (it won't, but you wouldn't get any sympathy if it did).

These displays don't like short-cuts.  Do what the datasheet says, to the letter, and it'll work fine.
 

Online DTJTopic starter

  • Super Contributor
  • ***
  • Posts: 1016
  • Country: au
Re: LCD 16x2 command sequence issue
« Reply #7 on: November 14, 2014, 12:59:33 pm »
Hi Danny - thanks for the reply. The commands seem ok? I've compared them below.

Thanks DJohn, yes home cursor is 1.53ms. I'll have another look at the code in the morning & see if I'm catering for this.
I'm using a PIC18F25K22 @ 16MHz via the internal clock and learning C in the process.....


For set cursor to line 1, first position;
==========================
Winstar data sheet:

To position cursor;
Set DDRAM Address; Set DDRAM address in address counter; 1 AC6 AC5 AC4 AC3 AC2 AC1 AC0
For the first position, line 1 AC6....AC0 all are 0.
39?s execution time
Command = 1000 0000 = 0x80

My command:
DATA_PORT = 0x80; //Send 0x80 | 0x00 = 0x80 sets cursor to line 1 pos 0x00



For cursor home
============
Winstar data sheet:

Return Home; Set DDRAM address to “00H” from AC and return cursor to its original position if shifted. The
contents of DDRAM are not changed.
1.53ms execution time execution time
0 0 0 0 0 0 0 0 1 x

My command:
DATA_PORT = 0b00000011; //Send 0x03 sets cursor to home



 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: LCD 16x2 command sequence issue
« Reply #8 on: November 14, 2014, 02:33:31 pm »
1. The LCD is non response while in software reset under command 0x01. You have to wait for the execution to finish.

2. To relocate the sensor, or the address with 0x80 and send it as command to the LCD. Rows are represented as different starting addresses.

All from memory. Hope it helps.
================================
https://dannyelectronics.wordpress.com/
 

Offline mikerj

  • Super Contributor
  • ***
  • Posts: 3438
  • Country: gb
Re: LCD 16x2 command sequence issue
« Reply #9 on: November 14, 2014, 07:09:58 pm »

Hi Mikerj - when I write a character I don't check for busy flag - it works ok without delays at the moment.


Clearly it does not! :)

Unless your compiler is producing horrendously inefficient code, or you have an extremely low clock speed on your micro then you will either need delays or (much better) to poll the busy flag to ensure one operation completes before you send the next.
 

Offline SirNick

  • Frequent Contributor
  • **
  • Posts: 589
Re: LCD 16x2 command sequence issue
« Reply #10 on: November 14, 2014, 08:02:58 pm »
If you have access to a logic analyzer, capture the pin behavior while running your code.  Compare that with the timing diagrams in the data sheet.  Flipping pins as fast as the code can run is rarely wise unless you know for certain your micro's clock is the bottleneck.

If you DON'T have access to a logic analyzer, go buy one.  They are invaluable for solving problems like this.
 

Online DTJTopic starter

  • Super Contributor
  • ***
  • Posts: 1016
  • Country: au
Re: LCD 16x2 command sequence issue
« Reply #11 on: November 15, 2014, 11:35:54 am »

SOLVED!

I found the problem.

The LCD would stop responding after I sent it the 0x80 command to set the cursor to the first position. The LCD was then apparently stuck in the busy state.

What was happening was the LCD busy check code was faulty. I grabbed it from a Microchip example. The code did not flip the LCD data port direction from output to input in order to test the BUSY signal on D7.

For most commands D7 is not 1 so the busy check would return as "not busy". However when sending the 0x80 (1000 0000) command the D7 bit was set. This was read as the busy bit from the LCD and hence locked the code in a loop thinking the LCD was busy.

Adding a couple of lines to flip the LCD data port direction inside the busy check function fixed the problem.

Thanks for you help guys - I was about to give up and needed a push to go back and have a closer look.

SirNick, +100 on the logic analyser. They are a big help, beats dicking around with the 2 channel CRO trying to work out whats going on.

Cheers.  :)


 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf