| 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;
 }
 }
 }
 | 
 |  |