| 
	
	|  |  |  
	
		| View previous topic :: View next topic |  
		| Author | Message |  
		| Zilog750 
 
 
 Joined: 19 Oct 2013
 Posts: 6
 
 
 
			    
 
 | 
			
				| LCD HD44780 PCF8574T i2c Driver |  
				|  Posted: Sat Oct 19, 2013 3:13 pm |   |  
				| 
 |  
				| Hello, 
 trying to control an LCD via i2c, I have this hardware
 
 * PIC16F877
 * LCD HD44780
 * Arduino-IIC-LCD GY-LCD-V1 (with PCF8574T)
 
 also I have CCS 4.108 and this library
 
 
  	  | Code: |  	  | //-----------------------------------------------------------------------------
 // Title:         lcd4_i2c.c
 // Description:   Driver for common LCD 4 row modules using I2C protocol.
 // Date:          May-2002
 // Ver.Rev.:      1.1
 // Author:        XP8100 (blixenonline@terra.es) #Based on the routines LCD.C from CCS#
 // Modified:      To HM-Baybus Project by Manuel Díaz
 //-----------------------------------------------------------------------------
 //
 // lcd_init() Must be called before any other function.
 //
 // lcd_putc(c) Will display c on the next position of the LCD.
 // The following have special meaning:
 //     f Clear display
 //
 // Go to start of second line
 //      Move back one position
 //
 //     lcd_gotoxy(x,y) Set write position on LCD (upper left is 1,1)
 //
 //-----------------------------------------------------------------------------
 // LCD pins D0-D3 are not used.
 //-----------------------------------------------------------------------------
 //
 // Commment   : Control of a compatible LCD HITACHI from a bus I2C with
 //              an EXPANDER of I/O with connection I2C. The tests of these
 //              routines have been programmed using the IC PCF8574P of Phillips.
 //              I use 4 bits mode programming. The 8 bits mode programming
 //              is possible if you uses 2 x PCF8574P.
 //
 // As defined in the following structure the pin connection is as follows:
 //
 //  PCF8574P     LCD
 //  ========     ======
 //     P0        Enable
 //     P1        RS
 //     P2        RW
 //     P3        No connect
 //     P4        D4
 //     P5        D5
 //     P6        D6
 //     P7        D7
 //
 //
 //
 // THIS DOCUMENT IS PROVIDED TO THE USER "AS IS"
 //-----------------------------------------------------------------------------
 
 #define lcd_type 2            // 0=5x7, 1=5x10, 2=2 lines
 #define lcd_line_two 0x40     // LCD RAM address for the second line
 #define lcd_line_three 0x14   // LCD Ram address for the 3 line
 #define lcd_line_four 0x54    // LCD Ram address for the 4 line
 
 #define IOE_ADDR  0x40        // I2C addr for i/o expander PCF8574P
 
 byte CONST LCD_INIT_STRING[4] = {0x20 | (lcd_type << 2), 0xc, 1, 6}; // These bytes need to be sent to the LCD to start it up.
 
 byte address; // The following are used for setting the I/O port direction register.
 
 void lcd_send_nibble( byte n, byte type ) {
 switch (type) {
 case "C" :
 i2c_write(n << 4);
 delay_cycles(1);
 i2c_write(n << 4 | 0x01);
 delay_us(2);
 i2c_write(n << 4 & 0xFE);
 break;
 case "D" :
 i2c_write(n << 4 | 0x02);
 delay_cycles(1);
 i2c_write(n << 4 | 0x03);
 delay_us(2);
 i2c_write(n << 4 & 0x02);
 break;
 }
 }
 
 void lcd_send_byte( byte n, byte type ) {
 delay_ms(1);
 lcd_send_nibble(n >> 4, type);
 lcd_send_nibble(n & 0xf, type);
 }
 
 
 void lcd_init() {
 byte i;
 i2c_start();
 i2c_write(IOE_ADDR);
 lcd_send_nibble(0, "C");
 delay_ms(15);
 for (i=1;i<=3;++i)   {
 lcd_send_nibble(3, "C");
 delay_ms(5);
 }
 lcd_send_nibble(2, "C");
 delay_ms(5);
 for (i=0;i<=3;++i)   {
 lcd_send_byte(LCD_INIT_STRING, "C");
 }
 i2c_stop();
 }
 
 void lcd_gotoxy( byte x, byte y) {
 i2c_start();
 i2c_write(IOE_ADDR);
 switch(y){
 case 1: address= 00; break;
 case 2: address= lcd_line_two; break;
 //      case 3: address= lcd_line_three; break;
 default: address= 00; break;
 //      default: address= lcd_line_four; break;
 }
 address+=x-1;
 lcd_send_byte(0x80|address, "C");
 i2c_stop();
 }
 
 void lcd_gotonl (){
 /*  switch(address){
 case 00 : address= lcd_line_two; break;
 //    case lcd_line_two : address= lcd_line_three; break;
 //    case lcd_line_three: address= lcd_line_four; break;
 default : address= 00; break;
 }*/
 address= lcd_line_two;
 lcd_send_byte(0x80|address, "C");
 }
 
 void lcd_putc( char c) {
 i2c_start();
 i2c_write(IOE_ADDR);
 switch (c) {
 case "f" : lcd_send_byte(1, "C");
 delay_ms(2);
 break;
 case "
 " : lcd_gotonl(); break;
 case "" : lcd_send_byte(0x10, "C"); break;
 default : lcd_send_byte(c, "D"); break;
 }
 i2c_stop();
 }
 
 | 
 
 And using this main code
 
 
  	  | Code: |  	  | /************************************************************/
 /*               P R E P R O C E S S O R                    */
 /************************************************************/
 
 #include <16F877.h>
 #device ADC=10
 
 /************************************************************/
 /*                      F U S E S                           */
 /************************************************************/
 
 #fuses XT,NOWDT,NOPROTECT,NOLVP,BROWNOUT
 
 /************************************************************/
 /*           O S C I L A T O R   &   D E L A Y              */
 /************************************************************/
 
 
 #use delay(clock=4000000) /* one instruction=1us? */
 
 /************************************************************/
 /*                S E T U P   R S - 2 3 2                   */
 /************************************************************/
 
 #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
 
 /************************************************************/
 /*                  S E T U P   I 2 C                       */
 /************************************************************/
 
 #use I2C(master, SCL=PIN_C3, SDA=PIN_C4)
 
 /************************************************************/
 /*                   D E F I N I T I O N S                  */
 /************************************************************/
 
 //
 
 /******************************************************************/
 /*                      I N C L U D E S                           */
 /******************************************************************/
 
 #include "lcd4_i2c.c"
 
 /************************************************************/
 /*           G L O B A L   V A R I A B L E S                */
 /************************************************************/
 
 
 /************************************************************/
 /*                 F U N C T I O N S                        */
 /************************************************************/
 
 
 /******************************************************************/
 /*             I N T E R R U P T   V E C T O R S                  */
 /******************************************************************/
 
 // NONE
 
 /******************************************************************/
 /*                      M A I N   P R O G R A M                   */
 /******************************************************************/
 
 void main()
 {
 delay_ms (200);
 output_high (PIN_B2);
 delay_ms (200);
 output_low (PIN_B2);
 delay_ms (200);
 lcd_init ();
 
 while (TRUE)
 {
 lcd_putc ("Hello");
 delay_ms (100);
 output_high (PIN_B1);
 delay_ms (100);
 output_low (PIN_B1);
 delay_ms (50);
 }
 }
 
 | 
 
 When compiling I have "Attempt to create a pointer to a constant" errors on lines like
 
 
  	  | Code: |  	  | lcd_send_nibble(0, "C"); | 
 
 and also
 
 
  	  | Code: |  	  | lcd_send_byte(LCD_INIT_STRING, "C"); | 
 
 I don't have experience on i2c nor CCS Compiler. Any idea what's is happening?
 
 Regards
 |  |  
		|  |  
		| PCM programmer 
 
 
 Joined: 06 Sep 2003
 Posts: 21708
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Sat Oct 19, 2013 5:40 pm |   |  
				| 
 |  
				| The function declaration for your nibble routine looks like this: 
  	  | Quote: |  	  | void lcd_send_nibble( byte n, byte type ) { | 
 The 2nd parameter is a byte.  But below, and in several other places, you
 are trying to give it a string:
 
  	  | Quote: |  	  | lcd_send_nibble(0, "C"); | 
 
 To give it a parameter of the letter C, then you need to put it in single
 quotes.  Example:
 
  	  | Code: |  	  | lcd_send_nibble(0, 'C'); | 
 Also change your switch-case statement to put the characters in single
 quotes.  This will give you a byte instead of a string.
 |  |  
		|  |  
		| Zilog750 
 
 
 Joined: 19 Oct 2013
 Posts: 6
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Sun Oct 20, 2013 3:36 am |   |  
				| 
 |  
				| Hello, 
 changed code as this on lib
 
 
  	  | Code: |  	  | //----------------------------------------------------------------------------- // Title:         lcd4_i2c.c
 // Description:   Driver for common LCD 4 row modules using I2C protocol.
 // Date:          May-2002
 // Ver.Rev.:      1.1
 // Author:        XP8100 (blixenonline@terra.es) #Based on the routines LCD.C from CCS#
 // Modified:      To HM-Baybus Project by Manuel Díaz
 //-----------------------------------------------------------------------------
 //
 // lcd_init() Must be called before any other function.
 //
 // lcd_putc(c) Will display c on the next position of the LCD.
 // The following have special meaning:
 //     f Clear display
 //
 // Go to start of second line
 //      Move back one position
 //
 //     lcd_gotoxy(x,y) Set write position on LCD (upper left is 1,1)
 //
 //-----------------------------------------------------------------------------
 // LCD pins D0-D3 are not used.
 //-----------------------------------------------------------------------------
 //
 // Commment   : Control of a compatible LCD HITACHI from a bus I2C with
 //              an EXPANDER of I/O with connection I2C. The tests of these
 //              routines have been programmed using the IC PCF8574P of Phillips.
 //              I use 4 bits mode programming. The 8 bits mode programming
 //              is possible if you uses 2 x PCF8574P.
 //
 // As defined in the following structure the pin connection is as follows:
 //
 //  PCF8574P     LCD
 //  ========     ======
 //     P0        Enable
 //     P1        RS
 //     P2        RW
 //     P3        No connect
 //     P4        D4
 //     P5        D5
 //     P6        D6
 //     P7        D7
 //
 //
 //
 // THIS DOCUMENT IS PROVIDED TO THE USER "AS IS"
 //-----------------------------------------------------------------------------
 
 #define lcd_type 2            // 0=5x7, 1=5x10, 2=2 lines
 #define lcd_line_two 0x40     // LCD RAM address for the second line
 #define lcd_line_three 0x14   // LCD Ram address for the 3 line
 #define lcd_line_four 0x54    // LCD Ram address for the 4 line
 
 #define IOE_ADDR  0x40        // I2C addr for i/o expander PCF8574P
 
 byte CONST LCD_INIT_STRING[4] = {0x20 | (lcd_type << 2), 0xc, 1, 6}; // These bytes need to be sent to the LCD to start it up.
 
 byte address; // The following are used for setting the I/O port direction register.
 
 void lcd_send_nibble( byte n, byte type )
 {
 switch (type)
 {
 case 'C' :
 i2c_write(n << 4);
 delay_cycles(1);
 i2c_write(n << 4 | 0x01);
 delay_us(2);
 i2c_write(n << 4 & 0xFE);
 break;
 case 'D' :
 i2c_write(n << 4 | 0x02);
 delay_cycles(1);
 i2c_write(n << 4 | 0x03);
 delay_us(2);
 i2c_write(n << 4 & 0x02);
 break;
 }
 }
 
 void lcd_send_byte( byte n, byte type )
 {
 delay_ms(1);
 lcd_send_nibble(n >> 4, type);
 lcd_send_nibble(n & 0xf, type);
 delay_ms (1);
 }
 
 void lcd_init()
 {
 byte i;
 i2c_start();
 i2c_write(IOE_ADDR);
 lcd_send_nibble(0, 'C');
 delay_ms(15);
 
 for (i=1;i<=3;++i)
 {
 lcd_send_nibble(3, 'C');
 delay_ms(5);
 }
 
 lcd_send_nibble(2, 'C');
 delay_ms(5);
 
 for (i=0;i<=3;++i)
 {
 lcd_send_byte(LCD_INIT_STRING[i], 'C');
 }
 i2c_stop();
 }
 
 void lcd_gotoxy( byte x, byte y)
 {
 i2c_start();
 i2c_write(IOE_ADDR);
 
 switch(y)
 {
 case 1: address= 00; break;
 case 2: address= lcd_line_two; break;
 //      case 3: address= lcd_line_three; break;
 default: address= 00; break;
 //      default: address= lcd_line_four; break;
 }
 
 address+=x-1;
 lcd_send_byte(0x80|address, 'C');
 i2c_stop();
 }
 
 void lcd_gotonl ()
 {
 /*  switch(address){
 case 00 : address= lcd_line_two; break;
 //    case lcd_line_two : address= lcd_line_three; break;
 //    case lcd_line_three: address= lcd_line_four; break;
 default : address= 00; break;
 }*/
 address= lcd_line_two;
 lcd_send_byte(0x80|address, 'C');
 }
 
 void lcd_putc( char c)
 {
 i2c_start();
 i2c_write(IOE_ADDR);
 
 switch (c)
 {
 case "f" : lcd_send_byte(1, 'C');
 delay_ms(2);
 break;
 case "
 " : lcd_gotonl(); break;
 case "" : lcd_send_byte(0x10, 'C'); break;
 default : lcd_send_byte(c, 'D'); break;
 }
 
 i2c_stop();
 }
 | 
 
 Intersed some wait time on
 
 
  	  | Code: |  	  | void lcd_send_byte( byte n, byte type ) {
 delay_ms(1);
 lcd_send_nibble(n >> 4, type);
 lcd_send_nibble(n & 0xf, type);
 delay_ms (1);
 }
 
 | 
 
 And some array addressing at lcd_init()
 
  	  | Code: |  	  | for (i=0;i<=3;++i) {
 lcd_send_byte(LCD_INIT_STRING[i], 'C');
 }
 | 
 
 And main code is more or less equal
 
 
  	  | Code: |  	  | /************************************************************/ /*               P R E P R O C E S S O R                    */
 /************************************************************/
 
 #include <16F877.h>
 #device ADC=10
 
 /************************************************************/
 /*                      F U S E S                           */
 /************************************************************/
 
 #fuses XT,NOWDT,NOPROTECT,NOLVP,BROWNOUT
 
 /************************************************************/
 /*           O S C I L A T O R   &   D E L A Y              */
 /************************************************************/
 
 
 #use delay(clock=4000000) /* one instruction=1us? */
 
 /************************************************************/
 /*                S E T U P   R S - 2 3 2                   */
 /************************************************************/
 
 #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
 
 /************************************************************/
 /*                  S E T U P   I 2 C                       */
 /************************************************************/
 
 #use I2C(master, SCL=PIN_C3, SDA=PIN_C4)
 
 /************************************************************/
 /*                   D E F I N I T I O N S                  */
 /************************************************************/
 
 //
 
 /******************************************************************/
 /*                      I N C L U D E S                           */
 /******************************************************************/
 
 #include "lcd4_i2c.c"
 
 /************************************************************/
 /*           G L O B A L   V A R I A B L E S                */
 /************************************************************/
 
 
 /************************************************************/
 /*                 F U N C T I O N S                        */
 /************************************************************/
 
 
 /******************************************************************/
 /*             I N T E R R U P T   V E C T O R S                  */
 /******************************************************************/
 
 // NONE
 
 /******************************************************************/
 /*                      M A I N   P R O G R A M                   */
 /******************************************************************/
 
 void main()
 {
 lcd_init ();
 
 delay_ms (200);
 output_high (PIN_B2);
 delay_ms (200);
 output_low (PIN_B2);
 delay_ms (200);
 
 while (TRUE)
 {
 lcd_putc ("Hello");
 delay_ms(100);
 }
 }
 | 
 
 At this point I can see PCF8574 working with an oscilloscope but nothing happens on LCD. Any Idea or have someone a working lib for this?
 
 Thanks
 |  |  
		|  |  
		| Ttelmah 
 
 
 Joined: 11 Mar 2010
 Posts: 19966
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Sun Oct 20, 2013 12:23 pm |   |  
				| 
 |  
				| The driver does work.... 
 Reason's it won't.
 
 Using D0 to D3 instead of D4 to D7 on the LCD.
 Not having a suitable Vo on the LCD.
 Then just general connection problems.
 You need about 500mSec delay _before_ lcd_init.
 
 LCD's generally need about 60 to 100mSec after their supply goes 'good', before they will work. Many types don't see their supply as 'good', till a long time after the PIC. Hence 00 to 500mSec delay is needed before sending anything.
 
 If you want an alternative look at the flex_lcd driver in the code forum, which is slightly more generic, and often works easier.
 
 Best Wishes
 |  |  
		|  |  
		| PCM programmer 
 
 
 Joined: 06 Sep 2003
 Posts: 21708
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Sun Oct 20, 2013 1:14 pm |   |  
				| 
 |  
				| Post a link to the webpage for the LCD that you bought so we can look at the specs and documentation for the LCD.
 |  |  
		|  |  
		| younder 
 
 
 Joined: 24 Jan 2013
 Posts: 53
 Location: Brazil
 
 
			    
 
 |  |  
		|  |  
		| younder 
 
 
 Joined: 24 Jan 2013
 Posts: 53
 Location: Brazil
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Thu Nov 14, 2013 6:58 pm |   |  
				| 
 |  
				| I just found out that: 
 For PCF8574A the addressing is:
 
 Jp3	Jp2	Jp1
 A2	A1	A0	Dec	Hex
 L	L	L	56	0x38
 L	L	H	57	0x39
 L	H	L	64	0x40
 L	H	H	74	0x4A
 H	L	L	75	0x4B
 H	L	H	76	0x4C
 H	H	L	77	0x4D
 H	H	H	78	0x4E
 
 For PCF8574 the addressing is:
 
 Jp3	Jp2	Jp1
 A2	A1	A0	Dec	Hex
 L	L	L	32	0x20
 L	L	H	33	0x21
 L	H	L	34	0x22
 L	H	H	35	0x23
 H	L	L	36	0x24
 H	L	H	37	0x25
 H	H	L	38	0x26
 H	H	H	39	0x27
 _________________
 Hugo Silva
 |  |  
		|  |  
		| PCM programmer 
 
 
 Joined: 06 Sep 2003
 Posts: 21708
 
 
 
			    
 
 |  |  
		|  |  
		| younder 
 
 
 Joined: 24 Jan 2013
 Posts: 53
 Location: Brazil
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Thu Nov 14, 2013 10:38 pm |   |  
				| 
 |  
				| Thanks PCM Programmer... The Address is 0x4e... but the driver in this thread still not working... I could make the lcd work only through another 16x4 driver...but my display is 16x2...maybe it is the reason that I got a bug in the backlight.. it turns it off when I send the command ON. I'll post the driver code below: 
  	  | Code: |  	  | //////////////////////////////////////////////////////////////////////////////
 // This is the simple CCS program for I2C (PCF8574T) lcd module
 // Auther: Pumrin S.
 // Pin map:
 // PCF8574T > 20x4 LCD
 //   P0     >   RS
 //   P1     >   R/W
 //   P2     >   E
 //   P3     >   NC
 //   P4     >   D4
 //   P5     >   D5
 //   P6     >   D6
 //   P7     >   D7
 // Note: The SCL and SDA pins should be pull-up resister allway.
 //////////////////////////////////////////////////////////////////////////////
 #include <18f4550.h>
 #device ICD = TRUE
 #device ADC=10
 #use delay (clock=48000000)
 #use i2c(Master,Fast=100000, sda=PIN_D6, scl=PIN_D7,force_sw)
 #include <lcd20x4.h>
 #fuses HSPLL,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,USBDIV,PLL5,CPUDIV1,DEBUG,ICSP1 // configura fuses
 
 #define LCDADDR        0x70 // default slave address
 #define ON             0x08
 #define OFF            0x00
 
 #define LCD_SET_BIT(x)    fetch_data(x)
 
 byte LCD_ADDR=0x4E; //0X4e I2C slave address for Funduino LCD module
 
 //Transmittion data
 void transceiver(unsigned char data)
 {
 i2c_start();
 i2c_write(LCD_ADDR); //the slave addresse
 i2c_write(data);
 i2c_stop();
 }
 
 //Clocking the LCD's enable pin during transmit data
 void fetch_data(unsigned char data)
 {
 data=data|0b00000100;//set pin E is a 1
 transceiver(data);
 delay_ms(1);
 data=data-4;//toggle E back to 0
 transceiver(data);
 delay_ms(1);
 
 }
 
 void lcd_init()
 {
 
 //Request works on the command by set the RS = 0 R/W = 0 write
 LCD_SET_BIT(0x00);
 LCD_SET_BIT(0x10);
 LCD_SET_BIT(0x00);
 LCD_SET_BIT(0x00);
 LCD_SET_BIT(0x10);
 //First state in 8 bit mode
 LCD_SET_BIT(0x30);
 LCD_SET_BIT(0x30);
 //Then set to 4-bit mode
 LCD_SET_BIT(0x30);
 LCD_SET_BIT(0x20);
 //mode 4 bits, 2 lines, characters 5 x 7 (28 h)
 LCD_SET_BIT(0x20);
 LCD_SET_BIT(0x80);
 //no need cursor on (0Ch)
 LCD_SET_BIT(0x00);
 LCD_SET_BIT(0xC0);
 //the cursor moves to the left (06 h)
 LCD_SET_BIT(0x00);
 LCD_SET_BIT(0x60);
 //clears the display
 LCD_SET_BIT(0x00);
 LCD_SET_BIT(0x10);
 }
 
 void lcd_clear()
 {
 LCD_SET_BIT(0x00);
 LCD_SET_BIT(0x10);
 }
 
 // Need the backlight lid.
 void lcd_backlight(byte state)
 {
 LCD_SET_BIT(0x00);
 LCD_SET_BIT(state);
 }
 
 //Display the character on LCD screen.
 void display(char in_data)
 {
 char data;
 data=in_data&0xF0;
 data=data+1; //set RS pin to 1
 fetch_data(data);
 data=in_data&0x0F;
 data=data<<4;
 data=data+1; //set RS pin to 1
 fetch_data(data);
 
 }
 
 //Make the x/y pointer
 void lcd_goto_xy(byte x, byte y)
 {
 byte ptr1, ptr2;
 
 fetch_data(0x10);
 fetch_data(0x00);
 
 switch(y)
 {
 case 1:
 ptr1=line_1[x]&0xF0;// stamp the high bit
 ptr2=line_1[x]&0x0F;// stamp the low bit
 
 break;
 
 case 2:
 ptr1=line_2[x]&0xF0;
 ptr2=line_2[x]&0x0F;
 
 break;
 
 case 3:
 ptr1=line_3[x]&0xF0;
 ptr2=line_3[x]&0x0F;
 
 break;
 
 case 4:
 ptr1=line_4[x]&0xF0;
 ptr2=line_4[x]&0x0F;
 
 break;
 
 default:
 fetch_data(0x80);
 fetch_data(0x00);
 break;
 
 }
 ptr2=ptr2<<4;
 fetch_data(ptr1);
 fetch_data(ptr2);
 }
 
 void main()
 {
 lcd_init();
 while (TRUE)
 {
 
 lcd_goto_xy(0,1);
 display("ABCDEFGHIJKLMNOP");
 //lcd_backlight(ON);
 delay_ms(1000);
 lcd_goto_xy(0,2);
 display("1234567890123456");
 //lcd_backlight(ON);     If I declare here, it clears the display
 delay_ms(1000);
 
 output_high(PIN_D2);
 delay_ms(100);
 output_low(PIN_D2);
 delay_ms(100);
 }
 
 }
 
 | 
 
 lcd20x4.h
 
 
  	  | Code: |  	  | //*** START LCD Command ***
 #define  LCD_CLEAR_SCREEN   0B00000001
 #define  LCD_RETURN_HOME    0B00000010
 
 //Entry mode set (BIT2=1)
 #define  LCD_ENTRY_MODE     0B00000100
 #define  INCREMENTS_LCD     0B00000010
 #define  DECREMENTS_LCD     0B00000000
 #define  NO_SCROLL_LCD      0B00000000
 #define  SCROLL_LCD         0B00000001
 
 //Display ON/OFF (BIT3=1)
 #define  DISPLAY_LCD        0B00001000
 #define  LCD_ON             0B00000100
 #define  LCD_OFF            0B00000000
 #define  LCD_CURSOR_ON      0B00000010
 #define  LCD_CURSOR_OFF     0B00000000
 #define  LCD_BLINK_ON       0B00000001
 #define  LCD_BLINK_OFF      0B00000000
 
 //Scroll Display/Shift Cursor (BIT4=1)
 #define  LCD_SCROLL_SHIFT   0B00010000
 #define  LCD_SHIFT_CURSOR   0B00000000
 #define  LCD_SHIFT_DISPLAY  0B00001000
 #define  LCD_SHIFT_LEFT     0B00000000
 #define  LCD_SHIFT_RIGHT    0B00000100
 
 //Function set (BIT5=1)
 #define  LCD_FUNCTION_SET   0B00100000
 #define  LCD4BIT_MODE       0B00000000
 #define  LCD8BIT_MODE       0B00010000
 #define  LCD_LINE1          0B00000000
 #define  LCD_LINE2          0B00001000
 #define  LCD_FONT_5X7       0B00000000
 #define  LCD_FONT_5X10      0B00000100
 
 //Move To CGRAM Address (BIT6=1)
 #define  LCD_CGRAM_ADDRESS  0B01000000
 
 //Move To DDRAM Address (BIT7=1)
 #define  LCD_DDRAM_ADDRESS  0B10000000
 
 //*** END LCD Command ***
 
 // Prepare x,y address byte
 //line1=80h, line2=C0h line3=94h, line4=D4h
 //   1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20
 //1 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93
 //2 C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3
 //3 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7
 //4 D4 D5 D6 D7 D8 D9 DA DB DC DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8
 
 byte line_1[20]={0x80,0x81,0x82,0x83,0x84,
 0x85,0x86,0x87,0x88,0x89,
 0x8A,0x8B,0x8C,0x8D,0x8E,
 0x8F,0x90,0x91,0x92,0x93};
 byte line_2[20]={0xC0,0xC1,0xC2,0xC3,0xC4,
 0xC5,0xC6,0xC7,0xC8,0xC9,
 0xCA,0xCB,0xCC,0xCD,0xCE,
 0xCF,0xD0,0xD1,0xD2,0xD3};
 byte line_3[20]={0x94,0x95,0x96,0x97,0x98,
 0x99,0x9A,0x9B,0x9C,0x9D,
 0x9E,0x9F,0xA0,0xA1,0xA2,
 0xA3,0xA4,0xA5,0xA6,0xA7};
 byte line_4[20]={0xD4,0xD5,0xD6,0xD7,0xD8,
 0xD9,0xDA,0xDB,0xDC,0xDE,
 0xDF,0xE0,0xE1,0xE2,0xE3,
 0xE4,0xE5,0xE6,0xE7,0xE8};
 
 | 
 _________________
 Hugo Silva
 |  |  
		|  |  
		| younder 
 
 
 Joined: 24 Jan 2013
 Posts: 53
 Location: Brazil
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Sat Nov 16, 2013 5:39 pm |   |  
				| 
 |  
				| Hi Folks Again 
 The issue with the driver shared by Zilog750 (in my case) was the PCF8574T i2c interface Pins, which does not match the ones declared in that driver. Can anyone explain how to change it in the driver? the code seems to be a bit complex to me,,, and would really appreciate if someone can explain how the driver is accessing these pins... is there a better way to do that?
 
 I want to change it from:
 
 //  PCF8574P     LCD
 //  ========     ======
 //     P0        Enable
 //     P1        RS
 //     P2        RW
 //     P3        No connect
 //     P4        D4
 //     P5        D5
 //     P6        D6
 //     P7        D7
 
 To:
 
 //  PCF8574P     LCD
 //  ========     ======
 //   P0     >   RS
 //   P1     >   R/W
 //   P2     >   Enable
 //   P3     >   No connect
 //   P4     >   D4
 //   P5     >   D5
 //   P6     >   D6
 //   P7     >   D7
 
 Driver:
 
  	  | Code: |  	  | //-----------------------------------------------------------------------------
 // Title:         lcd4_i2c.c
 // Description:   Driver for common LCD 4 row modules using I2C protocol.
 // Date:          May-2002
 // Ver.Rev.:      1.1
 // Author:        XP8100 (blixenonline@terra.es) #Based on the routines LCD.C from CCS#
 // Modified:      To HM-Baybus Project by Manuel Díaz
 //-----------------------------------------------------------------------------
 //
 // lcd_init() Must be called before any other function.
 //
 // lcd_putc(c) Will display c on the next position of the LCD.
 // The following have special meaning:
 //     f Clear display
 //
 // Go to start of second line
 //      Move back one position
 //
 //     lcd_gotoxy(x,y) Set write position on LCD (upper left is 1,1)
 //
 //-----------------------------------------------------------------------------
 // LCD pins D0-D3 are not used.
 //-----------------------------------------------------------------------------
 //
 // Comment    : Control of a compatible LCD HITACHI from a bus I2C with
 //              an EXPANDER of I/O with connection I2C. The tests of these
 //              routines have been programmed using the IC PCF8574P of Phillips.
 //              I use 4 bits mode programming. The 8 bits mode programming
 //              is possible if you uses 2 x PCF8574P.
 //
 // As defined in the following structure the pin connection is as follows:
 //
 //  PCF8574P     LCD
 //  ========     ======
 //     P0        Enable
 //     P1        RS
 //     P2        RW
 //     P3        No connect
 //     P4        D4
 //     P5        D5
 //     P6        D6
 //     P7        D7
 //
 //
 //
 // THIS DOCUMENT IS PROVIDED TO THE USER "AS IS"
 //-----------------------------------------------------------------------------
 
 #define lcd_type 2            // 0=5x7, 1=5x10, 2=2 lines
 #define lcd_line_two 0x40     // LCD RAM address for the second line
 #define lcd_line_three 0x14   // LCD Ram address for the 3 line
 #define lcd_line_four 0x54    // LCD Ram address for the 4 line
 
 #define IOE_ADDR  0x40        // I2C addr for i/o expander PCF8574P
 
 byte CONST LCD_INIT_STRING[4] = {0x20 | (lcd_type << 2), 0xc, 1, 6}; // These bytes need to be sent to the LCD to start it up.
 
 byte address; // The following are used for setting the I/O port direction register.
 
 void lcd_send_nibble( byte n, byte type )
 {
 switch (type)
 {
 case 'C' :
 i2c_write(n << 4);
 delay_cycles(1);
 i2c_write(n << 4 | 0x01);
 delay_us(2);
 i2c_write(n << 4 & 0xFE);
 break;
 case 'D' :
 i2c_write(n << 4 | 0x02);
 delay_cycles(1);
 i2c_write(n << 4 | 0x03);
 delay_us(2);
 i2c_write(n << 4 & 0x02);
 break;
 }
 }
 
 void lcd_send_byte( byte n, byte type )
 {
 delay_ms(1);
 lcd_send_nibble(n >> 4, type);
 lcd_send_nibble(n & 0xf, type);
 delay_ms (1);
 }
 
 void lcd_init()
 {
 byte i;
 i2c_start();
 i2c_write(IOE_ADDR);
 lcd_send_nibble(0, 'C');
 delay_ms(15);
 
 for (i=1;i<=3;++i)
 {
 lcd_send_nibble(3, 'C');
 delay_ms(5);
 }
 
 lcd_send_nibble(2, 'C');
 delay_ms(5);
 
 for (i=0;i<=3;++i)
 {
 lcd_send_byte(LCD_INIT_STRING[i], 'C');
 }
 i2c_stop();
 }
 
 void lcd_gotoxy( byte x, byte y)
 {
 i2c_start();
 i2c_write(IOE_ADDR);
 
 switch(y)
 {
 case 1: address= 00; break;
 case 2: address= lcd_line_two; break;
 //      case 3: address= lcd_line_three; break;
 default: address= 00; break;
 //      default: address= lcd_line_four; break;
 }
 
 address+=x-1;
 lcd_send_byte(0x80|address, 'C');
 i2c_stop();
 }
 
 void lcd_gotonl ()
 {
 /*  switch(address){
 case 00 : address= lcd_line_two; break;
 //    case lcd_line_two : address= lcd_line_three; break;
 //    case lcd_line_three: address= lcd_line_four; break;
 default : address= 00; break;
 }*/
 address= lcd_line_two;
 lcd_send_byte(0x80|address, 'C');
 }
 
 void lcd_putc( char c)
 {
 i2c_start();
 i2c_write(IOE_ADDR);
 
 switch (c)
 {
 case "f" : lcd_send_byte(1, 'C');
 delay_ms(2);
 break;
 case "
 " : lcd_gotonl(); break;
 case "" : lcd_send_byte(0x10, 'C'); break;
 default : lcd_send_byte(c, 'D'); break;
 }
 
 i2c_stop();
 }
 
 | 
 
 Thanks!!
 _________________
 Hugo Silva
 |  |  
		|  |  
		| PCM programmer 
 
 
 Joined: 06 Sep 2003
 Posts: 21708
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Sun Nov 17, 2013 1:27 am |   |  
				| 
 |  
				|  	  | Quote: |  	  | I would really appreciate if someone can explain how the driver is
 accessing these pins.
 
 | 
 It's done with the numbers shown in bold below.  My advice is to change
 those numbers from hex format (0x) to binary format (0b prefix).  Then
 compare the values in bits 0 to 2, to the pin table for pins P0, P1 and P2
 given below.  You will see a correspondence.
 
  	  | Quote: |  	  | //  PCF8574P     LCD
 //  ========     ======
 //     P0        Enable
 //     P1        RS
 //     P2        RW
 //     P3        No connect
 //     P4        D4
 //     P5        D5
 //     P6        D6
 //     P7        D7
 
 
 switch (type)
 {
 case 'C' :
 i2c_write(n << 4);
 delay_cycles(1);
 i2c_write(n << 4 | 0x01);
 delay_us(2);
 i2c_write(n << 4 & 0xFE);
 break;
 
 case 'D' :
 i2c_write(n << 4 | 0x02);
 delay_cycles(1);
 i2c_write(n << 4 | 0x03);
 delay_us(2);
 i2c_write(n << 4 & 0x02);
 break;
 }
 | 
 |  |  
		|  |  
		| Ttelmah 
 
 
 Joined: 11 Mar 2010
 Posts: 19966
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Sun Nov 17, 2013 2:14 am |   |  
				| 
 |  
				| Or of course, use the names... 
  	  | Code: |  	  | / PCF8574P LCD
 // ======== ======
 // P0 Enable
 // P1 RS
 // P2 RW
 // P3 No connect
 // P4 D4
 // P5 D5
 // P6 D6
 // P7 D7
 #define ENABLE 1
 #define RS 2
 #define NOT ~
 #define n_shifted n<<4
 
 switch (type)
 {
 case 'C' :
 i2c_write(n_shifted);
 delay_cycles(1);
 i2c_write(n_shifted | ENABLE);
 delay_us(2);
 i2c_write(n_shifted & NOT ENABLE);
 break;
 
 case 'D' :
 i2c_write(n_shifted | 0xRS);
 delay_cycles(1);
 i2c_write(n_shifted | RS | ENABLE);
 delay_us(2);
 i2c_write(n_shifted & RS);
 break;
 }
 
 | 
 This way the names reflect what pins you are operating.
 
 Best Wishes
 |  |  
		|  |  
		| younder 
 
 
 Joined: 24 Jan 2013
 Posts: 53
 Location: Brazil
 
 
			    
 
 | 
			
				| Working Driver!!! |  
				|  Posted: Sun Nov 17, 2013 5:59 pm |   |  
				| 
 |  
				| Thanks for the tips Ttelmah!!! 
 Both Drivers are working now... but I've modified and recompiled a third one... I will share it here for anyone who needs in future...after all.. I owe a lot to this forum...
 
 It can control any compatible LCD HITACHI from a bus I2C with
 an PCF8574T I/O expander.
 
 The Driver worked with 2x16, 2x20 and 4x20 lcd modules.
 
 I renamed it for "i2c_Flex_LCD.h"
 
 Driver code:
 
  	  | Code: |  	  | //-----------------------------------------------------------------------------
 // Title:         i2c_Flex_LCD
 // Description:   Driver for common LCD with 1/2/3 or 4 row modules using PCF8574T interface board with I2C protocol.
 // Date:          Nov-2013
 // Ver.Rev.:      1.0
 // Author:        Hugo Silva (sergio-hugo@bol.com.br) #Based on the routines of 20X4_LCD_I2C_DRIVER.h from Pumrin S.
 //-----------------------------------------------------------------------------
 //
 // lcd_init() Must be called before any other function.
 //
 // lcd_putc(c) Will display c on the next position of the LCD.
 //
 //     \f Clear LCD dispay
 //     \1 Set write position on LCD Line 1
 //     \2 Set write position on LCD Line 2
 //     \3 Set write position on LCD Line 3
 //     \4 Set write position on LCD Line 4
 //
 //     lcd_gotoxy(x,y) Set write position on LCD (upper left is 1,1)
 //
 //-----------------------------------------------------------------------------
 // LCD pins D0-D3 are not used.
 //-----------------------------------------------------------------------------
 //
 // Commment   : Control of a compatible LCD HITACHI from a bus I2C with
 //              an EXPANDER of I/O with connection I2C. The tests of these
 //              routines have been programmed using the IC PCF8574T of Phillips.
 //              I used 4 bits mode programming. The 8 bits mode programming
 //              is possible if you use 2 x PCF8574T.
 //
 // As defined in the following structure the pin connection is as follows:
 //
 //  PCF8574P     LCD
 //  ========     ======
 //     P0        RS
 //     P1        RW
 //     P2        Enable
 //     P3        Led Backlight
 //     P4        D4
 //     P5        D5
 //     P6        D6
 //     P7        D7
 //
 //  The SCL and SDA pins should be pull-up resistor as shown below:
 //
 //             +5v
 //               |
 //               <
 //               > 4.7K
 //               <
 //To PIC         |          To i2c slave
 //pin xx ------------------ SDA pin
 //(SDA)
 //              +5v
 //               |
 //               <
 //               > 4.7K
 //               <
 //To PIC         |          To i2c slave
 //pin xx ------------------ SCL pin
 //(SCL)
 //
 //To PIC                    To i2c slave
 //Vss pin ----------------- Vss or ground pin
 //                |
 //              -----
 //               ---  Ground
 //                -
 //
 // THIS DOCUMENT IS PROVIDED TO THE USER "AS IS"
 //-----------------------------------------------------------------------------
 
 #define LCD_ADDR       0x4E //I2C slave address for LCD module
 
 #define ON             1
 #define OFF            0
 #define RS             0b00000001  //P0 - PCF8574T Pin connected to RS
 #define RW             0b00000010  //P1 - PCF8574T Pin connected to RW
 #define EN             0b00000100  //P2 - PCF8574T Pin connected to EN
 #define BACKLIGHT_LED  0b00001000  //P3 - PCF8574T Pin connected to BACKLIGHT LED
 
 #define lcd_line_one   0x80   // LCD RAM address for line 1
 #define lcd_line_two   0xC0   // LCD RAM address for line 2
 #define lcd_line_three 0x94   // LCD RAM address for line 3
 #define lcd_line_four  0xD4   // LCD RAM address for line 4
 
 byte address;
 int1 lcd_backlight=ON;
 
 void i2c_send_nibble(unsigned char data)
 {
 i2c_start();
 delay_us(20);
 i2c_write(LCD_ADDR); //the slave addresse
 delay_us(20);
 i2c_write(data);
 delay_us(20);
 i2c_stop();
 delay_us(20);
 }
 
 void lcd_send_byte(unsigned char data)
 {
 if (lcd_backlight) data=data|EN|BACKLIGHT_LED; else data=data|EN; //set pin EN
 i2c_send_nibble(data);
 data=data-4;       //toggle EN back to 0
 i2c_send_nibble(data);
 }
 
 void lcd_clear()
 {
 lcd_send_byte(0x00);
 lcd_send_byte(0x10);
 delay_ms(2);
 }
 
 void lcd_init()
 {
 delay_ms(200); //LCD power up delay
 
 //Request works on the command by set the RS = 0 R/W = 0 write
 lcd_send_byte(0x00);
 lcd_send_byte(0x10);
 lcd_send_byte(0x00);
 lcd_send_byte(0x00);
 lcd_send_byte(0x10);
 //First state in 8 bit mode
 lcd_send_byte(0x30);
 lcd_send_byte(0x30);
 //Then set to 4-bit mode
 lcd_send_byte(0x30);
 lcd_send_byte(0x20);
 //mode 4 bits, 2 lines, characters 5 x 7 (28 h)
 lcd_send_byte(0x20);
 lcd_send_byte(0x80);
 //no need cursor on (0Ch)
 lcd_send_byte(0x00);
 lcd_send_byte(0xC0);
 //the cursor moves to the left (06 h)
 lcd_send_byte(0x00);
 lcd_send_byte(0x60);
 //clears the display
 lcd_clear();
 }
 
 void lcd_gotoxy( byte x, byte y)
 {
 static char data;
 
 switch(y)
 {
 case 1:  address= lcd_line_one;     break;
 case 2:  address= lcd_line_two;     break;
 case 3:  address= lcd_line_three;   break;
 case 4:  address= lcd_line_four;    break;
 default: address= lcd_line_one;     break;
 }
 
 address+=x-1;
 data=address&0xF0;
 lcd_send_byte(data);
 data=address&0x0F;
 data=data<<4;
 lcd_send_byte(data);
 }
 
 //Display the character on LCD screen.
 void LCD_PUTC(char in_data)
 {
 char data;
 switch(in_data)
 {
 case '\f': lcd_clear()    ;  break;
 case '\1': lcd_gotoxy(1,1);  break;
 case '\2': lcd_gotoxy(1,2);  break;
 case '\3': lcd_gotoxy(1,3);  break;
 case '\4': lcd_gotoxy(1,4);  break;
 
 default:
 data=in_data&0xF0;
 data=data|RS; //set RS pin to 1
 lcd_send_byte(data);
 data=in_data&0x0F;
 data=data<<4;
 data=data|RS; //set RS pin to 1
 lcd_send_byte(data);
 break;
 }
 }
 
 | 
 
 Main code:
 
  	  | Code: |  	  | #include <18f4550.h>
 #device ICD = TRUE
 #device ADC=10
 #use delay (clock=48000000)
 #use i2c(Master,Fast=100000, sda=PIN_D6, scl=PIN_D7,force_sw)
 #include <i2c_Flex_LCD.h>
 #fuses HSPLL,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,USBDIV,PLL5,CPUDIV1,DEBUG,ICSP1 // configura fuses
 
 void main()
 {
 Char string="Test";
 int16 test=1;
 
 lcd_init();
 lcd_backlight=ON;
 
 while (TRUE)
 {
 test=test+1;
 
 lcd_clear();  //Clear Display
 printf(LCD_PUTC,"\1%s","LCD Line 1");  //Print on LCD line 1
 delay_ms(1000);
 
 printf(LCD_PUTC,"\2%s","LCD Line 2");  //Print on LCD line 2
 delay_ms(1000);
 
 printf(LCD_PUTC,"\f\1%s","LCD Line 1"); //Clear display, print again on Line 1
 delay_ms(1000);
 
 printf(LCD_PUTC,"\f\2%s","LCD Line 2"); //Clear display, print again on Line 2
 delay_ms(1000);
 
 lcd_backlight=OFF;
 printf(LCD_PUTC,"\f\1%s\2%s","LCD BackLight","     OFF      "); //Clear display, print again on Line 1
 delay_ms(1000);
 
 lcd_backlight=ON;
 printf(LCD_PUTC,"\f\1%s\2%s","LCD BackLight","     ON      "); //Clear display, print again on Line 2
 delay_ms(1000);
 }
 }
 
 | 
 
 Thanks guys for all support!
 BR
 Hugo
 _________________
 Hugo Silva
 |  |  
		|  |  
		| dyeatman 
 
 
 Joined: 06 Sep 2003
 Posts: 1968
 Location: Norman, OK
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Sun Nov 17, 2013 7:30 pm |   |  
				| 
 |  
				| Why not add it to the Code Library? _________________
 Google and Forum Search are some of your best tools!!!!
 |  |  
		|  |  
		| Ttelmah 
 
 
 Joined: 11 Mar 2010
 Posts: 19966
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Mon Nov 18, 2013 1:22 am |   |  
				| 
 |  
				| As a minor 'consider this', why not change the init to something like: 
  	  | Code: |  	  | void lcd_init(void)
 {
 delay_ms(200); //LCD power up delay
 cont int8 init_data[] = {0x0,0x10,0x0,0x0,0x10, \
 0x30,0x30, \ //8bit mode
 0x30,0x20, \ //4bit mode
 0x20,0x80, \ //2lines 5*7
 0x00,0xC0, \ //No cursor
 0x00,0x60 };
 int8 ctr;
 //Request works on the command by set the RS = 0 R/W = 0 write
 for (ctr=0;ctr<sizeof(init_data;ctr++)
 lcd_send_byte(ctr); //send initialisation
 //clears the display
 lcd_clear();
 }
 
 | 
 When you are using the same command fifteen times, it may well be a case of 'better to loop'.
   
 Best Wishes
 |  |  
		|  |  
		|  |  
  
	| 
 
 | You cannot post new topics in this forum You cannot reply to topics in this forum
 You cannot edit your posts in this forum
 You cannot delete your posts in this forum
 You cannot vote in polls in this forum
 
 |  
 Powered by phpBB © 2001, 2005 phpBB Group
 
 |