wangine
Joined: 07 Jul 2009 Posts: 98 Location: Curtea de Arges, Romania
|
20x2 LCD driver (chinese type) |
Posted: Fri Nov 20, 2015 10:47 am |
|
|
This driver is based on PCM_p modified driver
https://www.ccsinfo.com/forum/viewtopic.php?t=24661
and an original driver based on a 32 bit ARM controller (i say chinese because the top comment with all description is in chinese and even with google translate i didn't understand too much). The driver has separate functions for all commands (except 2), i didn't find it yet. The controller for LCD is a ST7066u with modified character page. Also the datasheet don't exist. I left the original PCM_p driver intact, without any modifications, i just put the rest of the functions on the bottom, in that you way can call _LCD_putc() and lcd_putc() in same driver, difference is on _LCD_puts()
Code: |
// Flex_LCD420.c
// These pins are for my Microchip PicDem2-Plus board,
// which I used to test this driver.
// An external 20x4 LCD is connected to these pins.
// Change these pins to match your own board's connections.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Clear and home
#define LCD_CLR_DISP 0x01 // Clear screen, home cursor, unshift display
#define LCD_RETURN_HOME 0x02 // Home cursor, unshift display
// commands
// Display on/off, cursor on/off, blinking char at cursor position
#define LCD_DISP_OFF 0x08 // Display off
#define LCD_DISP_ON 0x0C // Display on, cursor off
#define LCD_DISP_ON_BLINK 0x0D // Display on, cursor off, blink char
#define LCD_DISP_ON_CURSOR 0x0E // Display on, cursor on
#define LCD_DISP_ON_CURSOR_BLINK 0x0F // Display on, cursor on, blink char
// Move cursor/shift display
#define LCD_MOVE_CURSOR_LEFT 0x10 // Move cursor left (decrement)
#define LCD_MOVE_CURSOR_RIGHT 0x14 // Move cursor right (increment)
#define LCD_MOVE_DISP_LEFT 0x18 // Shift display left
#define LCD_MOVE_DISP_RIGHT 0x1C // Shift display right
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#define LCD_DB4 PIN_D4
#define LCD_DB5 PIN_D5
#define LCD_DB6 PIN_D6
#define LCD_DB7 PIN_D7
#define LCD_RS PIN_D1
#define LCD_RW PIN_D2
#define LCD_E PIN_D3
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#define USE_RW_PIN 1
// These are the line addresses for most 4x20 LCDs.
#define LCD_LINE_1_ADDRESS 0x00
#define LCD_LINE_2_ADDRESS 0x40
///#define LCD_LINE_3_ADDRESS 0x14
///#define LCD_LINE_4_ADDRESS 0x54
// These are the line addresses for LCD's which use
// the Hitachi HD66712U controller chip.
//#define LCD_LINE_1_ADDRESS 0x00
//#define LCD_LINE_2_ADDRESS 0x20
//#define LCD_LINE_3_ADDRESS 0x40
//#define LCD_LINE_4_ADDRESS 0x60
//========================================
/* Local variables */
static unsigned int _lcd_ptr;
/* 8 user defined characters to be loaded into CGRAM (used for bar graph) */
static const unsigned char UserFont[8][8] = {
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
{ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10 },
{ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18 },
{ 0x1C,0x1C,0x1C,0x1C,0x1C,0x1C,0x1C,0x1C },
{ 0x1E,0x1E,0x1E,0x1E,0x1E,0x1E,0x1E,0x1E },
{ 0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F },
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }
};
//========================================
#define lcd_type 2 // 0=5x7, 1=5x10, 2=2 lines(or more)
int8 lcd_line;
int8 const LCD_INIT_STRING[4] =
{
0x20 | (lcd_type << 2), // Set mode: 4-bit, 2+ lines, 5x8 dots
0xc, // Display on
1, // Clear display
6 // Increment cursor
};
//-------------------------------------
void lcd_send_nibble(int8 nibble)
{
// Note: !! converts an integer expression
// to a boolean (1 or 0).
output_bit(LCD_DB4, !!(nibble & 1));
output_bit(LCD_DB5, !!(nibble & 2));
output_bit(LCD_DB6, !!(nibble & 4));
output_bit(LCD_DB7, !!(nibble & 8));
delay_cycles(1);
output_high(LCD_E);
delay_us(2);
output_low(LCD_E);
}
//-----------------------------------
// This sub-routine is only called by lcd_read_byte().
// It's not a stand-alone routine. For example, the
// R/W signal is set high by lcd_read_byte() before
// this routine is called.
#ifdef USE_RW_PIN
int8 lcd_read_nibble(void)
{
int8 retval;
// Create bit variables so that we can easily set
// individual bits in the retval variable.
#bit retval_0 = retval.0
#bit retval_1 = retval.1
#bit retval_2 = retval.2
#bit retval_3 = retval.3
retval = 0;
output_high(LCD_E);
delay_us(1);
retval_0 = input(LCD_DB4);
retval_1 = input(LCD_DB5);
retval_2 = input(LCD_DB6);
retval_3 = input(LCD_DB7);
output_low(LCD_E);
delay_us(1);
return(retval);
}
#endif
//---------------------------------------
// Read a byte from the LCD and return it.
#ifdef USE_RW_PIN
int8 lcd_read_byte(void) // lcd_rd_stat()
{
int8 low;
int8 high;
output_high(LCD_RW);
delay_cycles(1);
high = lcd_read_nibble();
delay_us(26); //**************
low = lcd_read_nibble();
return( (high<<4) | low);
}
#endif
//----------------------------------------
// Send a byte to the LCD.
void lcd_send_byte(int8 address, int8 n)
{
output_low(LCD_RS);
#ifdef USE_RW_PIN
while(bit_test(lcd_read_byte(),7)) ;
#else
delay_us(60);
#endif
if(address)
output_high(LCD_RS);
else
output_low(LCD_RS);
delay_us(3); //*********
#ifdef USE_RW_PIN
output_low(LCD_RW);
delay_cycles(1);
#endif
output_low(LCD_E);
lcd_send_nibble(n >> 4);
////delay_us(60); //*****
lcd_send_nibble(n & 0xf);
}
//----------------------------
void lcd_init(void)
{
int8 i;
lcd_line = 1;
output_low(LCD_RS);
#ifdef USE_RW_PIN
output_low(LCD_RW);
#endif
output_low(LCD_E);
// Some LCDs require 15 ms minimum delay after
// power-up. Others require 30 ms. I'm going
// to set it to 35 ms, so it should work with
// all of them.
delay_ms(50);
for(i=0 ;i < 3; i++)
{
lcd_send_nibble(0x03);
delay_ms(5); // delay_ms(5);
}
lcd_send_nibble(0x02);
for(i=0; i < sizeof(LCD_INIT_STRING); i++)
{
lcd_send_byte(0, LCD_INIT_STRING[i]);
// If the R/W signal is not used, then
// the busy bit can't be polled. One of
// the init commands takes longer than
// the hard-coded delay of 50 us, so in
// that case, lets just do a 5 ms delay
// after all four of them.
#ifndef USE_RW_PIN
delay_ms(5); // delay_ms(5);
#endif
}
}
//----------------------------
void lcd_gotoxy(int8 x, int8 y)
{
int8 address;
switch(y)
{
case 1:
address = LCD_LINE_1_ADDRESS;
break;
case 2:
address = LCD_LINE_2_ADDRESS;
break;
// case 3:
// address = LCD_LINE_3_ADDRESS;
// break;
//
// case 4:
// address = LCD_LINE_4_ADDRESS;
// break;
default:
address = LCD_LINE_1_ADDRESS;
break;
}
address += x-1;
lcd_send_byte(0, 0x80 | address);
}
//-----------------------------
void lcd_scroll_right(void)
{
lcd_send_byte(0, 0x1E);
}
//-------------------------
void lcd_scroll_left(void)
{
lcd_send_byte(0, 0x18);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void lcd_putc(char c)
{
switch(c)
{
case '\f':
lcd_send_byte(0,1);
lcd_line = 1;
delay_ms(2);
break;
case '\n':
lcd_gotoxy(1, ++lcd_line);
break;
case '\b':
lcd_send_byte(0,0x10);
break;
default:
lcd_send_byte(1,c);
break;
}
}
//------------------------------
#ifdef USE_RW_PIN
char lcd_getc(int8 x, int8 y)
{
char value;
lcd_gotoxy(x,y);
// Wait until busy flag is low.
while(bit_test(lcd_read_byte(),7));
output_high(LCD_RS);
value = lcd_read_byte();
output_low(LCD_RS);
return(value);
}
#endif
//// continue CORTEX curiozitate
/*--------------------------- lcd_wr_cmd ------------------------------------*/
static void _lcd_wr_cmd (unsigned int c) {
/* Write command to LCD controller. */
output_low(LCD_RS);
#ifdef USE_RW_PIN
while(bit_test(lcd_read_byte(),7)) ;
#else
delay_us(60);
#endif
output_low(LCD_RS);
delay_us(3); //*********
#ifdef USE_RW_PIN
output_low(LCD_RW);
delay_cycles(1);
#endif
output_low(LCD_E);
lcd_send_nibble(c >> 4);
////delay_us(60); //*****
lcd_send_nibble(c & 0xf);
}
/*--------------------------- lcd_wr_data -----------------------------------*/
static void _lcd_wr_data (unsigned int d) {
/* Write data to LCD controller. */
output_low(LCD_RS);
#ifdef USE_RW_PIN
while(bit_test(lcd_read_byte(),7)) ;
#else
delay_us(60);
#endif
output_high(LCD_RS);
delay_us(3); //*********
#ifdef USE_RW_PIN
output_low(LCD_RW);
delay_cycles(1);
#endif
output_low(LCD_E);
lcd_send_nibble(d >> 4);
////delay_us(60); //*****
lcd_send_nibble(d & 0xf);
}
/*--------------------------- LCD_load --------------------------------------*/
void _LCD_load (unsigned char *fp, unsigned int cnt) {
/* Load user-specific characters into CGRAM */
unsigned int8 i;
_lcd_wr_cmd (0x40); /* Set CGRAM address counter to 0 */
for (i = 0; i < cnt; i++, fp++) {
_lcd_wr_data (*fp);
}
}
/*--------------------------- LCD_gotoxy ------------------------------------*/
void _LCD_gotoxy (unsigned int x, unsigned int y) {
/* Set cursor position on LCD display. Left corner: 1,1, right: 20,2 */
unsigned int c;
c = --x;
if (--y) {
c |= 0x40;
}
_lcd_wr_cmd (c | 0x80);
_lcd_ptr = y*16 + x;
}
/*--------------------------- LCD_cls ---------------------------------------*/
void _LCD_cls (void) {
/* Clear LCD display, move cursor to home position. */
_lcd_wr_cmd (0x01);
_LCD_gotoxy (1,1);
}
/*--------------------------- LCD_cursor_off------------------------------------*/
void _LCD_cur_off (void) {
/* Switch off LCD cursor. */
_lcd_wr_cmd (0x0c);
}
/*--------------------------- LCD_cursor_on------------------------------------*/
void _LCD_cur_on (void) {
/* Switch on LCD cursor. */
_lcd_wr_cmd (LCD_DISP_ON_CURSOR);
}
/*--------------------------- LCD_on ------ ---------------------------------*/
void _LCD_on (void) {
/* Switch on LCD and enable cursor. */
_lcd_wr_cmd (0x0e);
}
/*--------------------------- LCD_putc --------------------------------------*/
void _LCD_putc (unsigned char c) {
/* Print a character to LCD at current cursor position. */
if (_lcd_ptr == 20) {
_lcd_wr_cmd (0xc0);
}
_lcd_wr_data (c);
_lcd_ptr++;
}
/*--------------------------- LCD_puts --------------------------------------*/
void _LCD_puts (unsigned char *sp) {
/* Print a string to LCD display. */
while (*sp) {
_LCD_putc (*sp++);
}
}
/*--------------------------- LCD_bargraph ----------------------------------*/
void _LCD_bargraph (unsigned int8 val, unsigned int8 size) {
/* Print a bargraph to LCD display. */
/* - val: value 0..100 % */
/* - size: size of bargraph 1..16 */
unsigned int i;
val = val * size / 20; /* Display matrix 5 x 8 pixels */
for (i = 0; i < size; i++) {
if (val > 5) {
_LCD_putc (5);
val -= 5;
}
else {
_LCD_putc (val);
break;
}
}
} |
|
|