0
\$\begingroup\$

I have a DEM 16217 SYH-PY 2x16 character LCD and I have problems initializing it.

I'm using AVR Studio 4. The 8 datalines are connected to port A of the microcontroller while the 3 control lines are connected to port E. Enable is PE2, R/W is PE1 and S is PE0. Port A connections are DBn to PORTAn. As far as I can see from the datasheet, no instructions seem to take more than 2 ms. For some reason, busy flag check isn't working correctly, so I used 2 ms delay instead.

At first, I wanted to have an LED blink after each step, but it turned out to be much better to have output at a serial port.

Here's my code:

#include <avr/io.h>
#include<util/delay.h>
#include "LED.h"
#include "Terminal.h"

void Screen_Execute(void)
{
    _delay_us(2);
    PORTE=PORTE | 4;
    _delay_us(2);
    PORTE=PORTE ^4;
    _delay_us(2);
    //_delay_us(2);

}

void Screen_busy(void)
{
    _delay_ms(2);
    //is the screen busy?   
    //PORTE=PORTE | 2;
    //DDRA=0x7F;
    //Screen_Execute();
    //while ((PINA & 128))
    //{
        //Screen_Execute();
        //BLINK_LED(500);
    //}// wait until zero
    //DDRA=0xFF;
    //PORTE=PORTE ^ 2;
    //Screen_Execute();
    //no longer busy
}




void Screen_init(void)
{

    //BLINK_LED(1000);
    SEND_STRING("Starting initialization\r\n",0);
    DDRE=0xFF;
    PORTE=0x00;
    DDRA=0xFF;
    PORTA=0x30;
    _delay_ms(250);
    _delay_ms(1000);
    SEND_STRING("Step 1 executing.\r\n",0);

    Screen_Execute();//voltage stabilized
    _delay_ms(5);//first output complete
    SEND_STRING("Step 1 complete.\r\n",0);


    //PORTA=0x30;
    //Screen_Execute();//second time
    //_delay_us(110);//end 

    //PORTA=0x30;//third time
    //Screen_Execute();

    SEND_STRING("Step 2 start.\r\n",0);
    //BLINK_LED(1000);
    Screen_busy();
    PORTA=0x38;//two lines, 8 bits, 5*7 characters
    SEND_STRING("Step 2 execute.\r\n",0);
    Screen_Execute();
    SEND_STRING("Step 2 complete.\r\n",0);

    SEND_STRING("Step 3 start.\r\n",0);
    //BLINK_LED(1000);
    Screen_busy();
    PORTA=0x08;//screen off
    SEND_STRING("Step 3 execute.\r\n",0);
    Screen_Execute();
    SEND_STRING("Step 3 complete.\r\n",0);


    SEND_STRING("Step 4 start.\r\n",0);
    //BLINK_LED(1000);
    Screen_busy();
    PORTA=0x14;//cursor goes to home and screen is cleared
    SEND_STRING("Step 4 execute.\r\n",0);
    Screen_Execute();
    SEND_STRING("Step 4 complete.\r\n",0);

    //Screen_busy();
    //PORTA=0x04;//
    //Screen_Execute();//end of init
    //Screen_busy();
    SEND_STRING("Step 5 start.\r\n",0);
    //BLINK_LED(1000);
    PORTA=0x0F;
    Screen_Execute();//cursor blinks, screen works
    SEND_STRING("Step 5 execute.\r\n",0);
    Screen_busy();
    SEND_STRING("Step 5 complete.\r\n",0);
}

My problem is that after initialization, cursor appears on a random position on the screen.

When I try to do initialization as described in the documentation, by sending the PORTA=0x30; line 3 times, it doesn't work. Also, if I try to use tighter timing, it again doesn't work.

\$\endgroup\$
  • \$\begingroup\$ do you have RS and R/W hooked up and have selected the correct settings for these pins? Edit- never mind its there \$\endgroup\$ – jsolarski Feb 15 '11 at 2:44
  • \$\begingroup\$ @jsolarski Yes, all lines are connected and I can output text, but it starts writing on random position. \$\endgroup\$ – AndrejaKo Feb 15 '11 at 8:36
  • \$\begingroup\$ have you tried setting the cursor to the return home command after it initializes? It sounds like it starts at a random address in the memory. And could you point me to which page has the initialization info? \$\endgroup\$ – jsolarski Feb 15 '11 at 14:11
  • 1
    \$\begingroup\$ @jsolarski Looks like they removed the page with the links, but the documents are instruction initialization, INITIALIZATION, TIMING, SOFTWARE_EXAMPLE. \$\endgroup\$ – AndrejaKo Feb 15 '11 at 20:43
2
\$\begingroup\$

I like the way you do serial port debugging, and the comments at each stage.

It appears that your display, like every other small character LCD display I've ever held in my hands, uses the Hitachi 44780 interface standard. May I ask why you aren't using some pre-tested off-the-shelf LCD library code?

Would something like the following work for you?

// WARNING: untested code. And therefore riddled with bugs.
#define SCREEN_ENABLE 4
#define SCREEN_READ 2
#define SCREEN_RS 1
// LCD #defines copied from http://techref.massmind.org/techref/io/lcd/44780.htm
#define LCDClearDisplay 1
#define LCDCursorHome   2
#define LCDOff      8   ;0x08 turn the display (and the cursor) off.
#define LCDOn       12  ;0x0C Turn on the display, but without a cursor
#define LCDCursorOn 14  ;0x0E Turn on the cursor (as an underline) as well as the display
#define LCDCursorBlink  15  ;0x0F Turn on a blinking block cursor as well as the display
#define LCDCursorLeft   16  ;0x10 Move the cursor left by one character
#define LCDCursorRight  20  ;0x14 Move the cursor right one letter
#define LCDShiftLeft    24  ;0x18 Shift the entire display left one character
#define LCDShiftRight   30  ;0x1C Shift the entire display right one character
#define LCDGoto     128 ;0x80 Add the location of the character position 
                ;   to which you wish to move the cursor

void screen_enable(void){
    _delay_us(2);
    PORTE |= SCREEN_ENABLE;
    _delay_us(2); // must be at least 140 ns
}
void screen_disable(void){
    PORTE &= ~SCREEN_ENABLE;
    _delay_us(2);
}
void Screen_Execute(void)
{
    screen_enable();
    screen_disable();
}

/** wait until screen is no longer busy */
void screen_busywait(void)
{
    char busy = 0x80;
    DDRA=0x00; // all inputs, to avoid fighting the screen outputs
    while(busy){
        // read busy flag
        PORTE |= SCREEN_READ; // read
        PORTE &= ~SCREEN_RS; // instruction: read busy flag and address
        screen_enable();
        // read busy bit while the Enable bit is high
        busy = PINA & 0x80;
        screen_disable;
        //BLINK_LED(500);
    }// wait until no longer busy

    // switch to "normal" "MCU writes to display" mode.
    PORTE &= ~SCREEN_READ; // write
    DDRA=0xFF;
}

void screen_send_instruction( char instruction ){
    PORTA=instruction;
    PORTE=0x00 + SCREEN_RS; // RS high: instruction
    DDRE=0xFF;
    DDRA=0xFF;
    Screen_Execute();
};

void Screen_init(void)
{    
    //BLINK_LED(1000);
    SEND_STRING("Starting initialization\r\n",0);
    // see http://techref.massmind.org/techref/io/lcd/44780.htm

    _delay_ms(15);
    SEND_STRING("Step 1 executing.\r\n",0);
    screen_send_instruction( 0x30 );
    _delay_ms(250);
    SEND_STRING("Step 1 complete.\r\n",0);

    screen_send_instruction( 0x30 );//second time
    _delay_ms(5);
    screen_send_instruction( 0x30 );//third time
    _delay_ms(1);

    SEND_STRING("Step 2 start.\r\n",0);
    screen_send_instruction( 0x38 ); // 8 bit interface, 2 line display, normal font
    SEND_STRING("Step 2 complete.\r\n",0);

    SEND_STRING("Step 3 start.\r\n",0);
    //BLINK_LED(1000);
    screen_busywait();
    screen_send_instruction( LCDOff );//screen off
    SEND_STRING("Step 3 complete.\r\n",0);

    screen_busywait();
    screen_send_instruction( 0x06 );// Entry mode: increment

    screen_busywait();
    screen_send_instruction( LCDClearDisplay );//cursor goes to home and screen is cleared

    screen_busywait();
    screen_send_instruction( LCDCursorOn );//screen on and underline cursor on.

    SEND_STRING("Step 4 start.\r\n",0);
    //BLINK_LED(1000);
    screen_busywait();
    screen_send_instruction( 0x14 );//Move the cursor right one letter (why????)
    SEND_STRING("Step 4 complete.\r\n",0);

    SEND_STRING("Step 5 start.\r\n",0);
    //BLINK_LED(1000);
    screen_busywait();
    screen_send_instruction( LCDCursorBlink );//Turn on a blinking block cursor as well as the display
    SEND_STRING("Step 5 complete.\r\n",0);
}

p.s.: Rather than use 11 pins of your MCU to control the display, some people sacrifice a little speed to gain back some of those pins: some control the LCD display with 7 pins of the MCU in 4-bit mode, others control their LCD display with 1 pin of the MCU.

\$\endgroup\$
  • \$\begingroup\$ The reason is that I'm not using prebuilt library is that the main goal of my device is to learn how to control an LCD. I'll check the code and report back with results. \$\endgroup\$ – AndrejaKo Mar 11 '11 at 19:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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