Very easy! Set address command is (0x80 | address).
Address is:
- 1st line: 0x00
- 2nd line: 0x40
- 3rd line: 1st line + char number per line (ex. 0x14 for 4x20 LCD)
- 4th line: 2nd line + char number per line (ex. 0x54 for 4x20 LCD)
Some simple code:
#define RS(n) LATB0=n
#define RW(n) LATB1=n
#define E(n) LATB2=n
#define Data(n) LATC=n
#define DATA 1
#define CMD 0
// Entry Mode Set Control Bits
#define BIT_S_AUTOSCROLL_ON (1<<0) //!< Enable autoscroll. For use with Entry Mode Set command
#define BIT_S_AUTOSCROLL_OFF 0 //!< Disable autoscroll. For use with Entry Mode Set command
#define BIT_ID_INCREMENT_CURSOR (1<<1) //!< Increment cursor position after each char. For use with Entry Mode Set command
#define BIT_ID_DECREMENT_CURSOR 0 //!< Decrement cursor position after each char. For use with Entry Mode Set command
// Display On/Off Control Bits
#define BIT_B_CURSOR_BLINK (1<<0)
#define BIT_B_CURSOR_NO_BLINK 0
#define BIT_C_CURSOR_ON (1<<1)
#define BIT_C_CURSOR_OFF 0
#define BIT_D_DISPLAY_ON (1<<2)
#define BIT_D_DISPLAY_OFF 0
// Cursor / Display Shift Control Bits
#define BIT_RL_SHIFT_RIGHT (1<<2)
#define BIT_RL_SHIFT_LEFT 0
#define BIT_SC_SHIFT_DISPLAY (1<<3) //!< Seting this bit causes a display scroll
#define BIT_SC_SHIFT_CURSOR 0 //!< Clearing this bits causes a cursor move
// Function set Control Bits
#define BIT_F_FONT_5_10 (1<<2)
#define BIT_F_FONT_5_8 0
#define BIT_N_DISP_LINES_2 (1<<3)
#define BIT_N_DISP_LINES_1 0
#define BIT_DL_DATALENGTH_8 (1<<4)
#define BIT_DL_DATALENGTH_4 0
enum enLcdCommands {
E_CLEAR_DISPLAY = 0x01,
E_RETURN_HOME = 0x02,
E_ENTRY_MODE_SET = 0x04,
E_DISPLAY_ON_OFF_CTRL = 0x08,
E_CURSOR_DISPLAY_SHIFT = 0x10,
E_FUNCTION_SET = 0x20,
E_SET_CGRAM_ADDR = 0x40,
E_SET_DDRAM_ADDR = 0x80,
};
enum enLCDCursorModes {
E_LCD_CURSOR_OFF = 0x00,
E_LCD_CURSOR_ON = 0x02,
E_LCD_CURSOR_ON_BLINK = 0x03,
};
#define LCD_LEN 16
enum enLCDLineAddr {
E_LCD_LINE_1 = 0x00,
E_LCD_LINE_2 = 0x40,
E_LCD_LINE_3 = LCD_LEN,
E_LCD_LINE_4 = 0x40 + LCD_LEN,
};
void lcd_write(uint8_t d, bool isData){
RS(isData);
Data(d);
__delay_us(5);
E(1);
__delay_us(5);
E(0);
if(!isData){
if(d==E_CLEAR_DISPLAY || d==E_RETURN_HOME){
__delay_ms(2);
}
else if (d&E_FUNCTION_SET){
__delay_us(250);
}
else{
__delay_us(100);
}
}
else{
__delay_us(100);
}
}
void lcd_init(void){
__delay_ms(100);
lcd_write(E_FUNCTION_SET | BIT_DL_DATALENGTH_8 , CMD);
__delay_ms(10);
lcd_write(E_FUNCTION_SET | BIT_DL_DATALENGTH_8 , CMD);
__delay_us(200);
lcd_write(E_FUNCTION_SET | BIT_DL_DATALENGTH_8 , CMD);
lcd_write(E_FUNCTION_SET | BIT_DL_DATALENGTH_8 | BIT_N_DISP_LINES_2 | BIT_F_FONT_5_8, CMD);
lcd_write(E_CLEAR_DISPLAY, CMD);
lcd_write(E_DISPLAY_ON_OFF_CTRL | BIT_D_DISPLAY_ON | BIT_C_CURSOR_ON | BIT_B_CURSOR_BLINK, CMD);
}
void lcd_str(char* str){
while(*str){
lcd_write(*str++, DATA);
}
}
void main(void)
{
// Initialize the device
SYSTEM_Initialize();
RW(0);
lcd_init();
// Line 1
lcd_write(E_SET_DDRAM_ADDR | E_LCD_LINE_1, CMD);
lcd_str("Line 1");
// Line 2
lcd_write(E_SET_DDRAM_ADDR | E_LCD_LINE_2, CMD);
lcd_str("Line 2");
// Line 3
lcd_write(E_SET_DDRAM_ADDR | E_LCD_LINE_3, CMD);
lcd_str("Line 3");
// Line 4
lcd_write(E_SET_DDRAM_ADDR | E_LCD_LINE_4, CMD);
lcd_str("Line 4");
while (1)
{
// Add your application code
}
}