Monday, June 24, 2013

An AVR Atmega library for HD44780 based lcd connected through i2c

This library implements a driver for HD44780 lcd connected through PCF8574 port expander.
Data is transmitted using only 2 wire over i2c with the PCF8574.


Lcd driver is based upon Peter Fleury's lcd driver.
Setup parameters can be found in file lcdpcf8574.h and pcf8574.h
This library was developed on Eclipse, built with avr-gcc on Atmega8 @ 1MHz.




Issues fix:

  • If you have problem making this library works with Arduino Uno and QAPASS LCD with Funduino I2C interface, please read the comment above "Matt Alizadeh June 1, 2018 at 2:56 PM"  by Matt Alizadeh


Changelog
  • 02: added CGRAM, custom char functions by Péter Papp
  • 01: first release

Code

Notes
  • read risk disclaimer
  • excuse my bad english

192 comments:

  1. Hello Davide.

    I have a problem I want to use this code with the atmega328.
    But I can't get it working I get error afther errror and when I fix one error I get an other, I struggling for almost 3 day's so it's time to ask for help.
    Can you help me converting this code so it work with a atmega328? I would really appreciate it thank you.

    Best regards Tom
    E-mail: tomklijn@outlook.com

    ReplyDelete
    Replies
    1. to me, it compiles and works on atmega328p without any compiling error.
      check you wiring, check you fuses, check you cpu frequency, try debug using uart.

      Delete
  2. Hi David,
    I am using atmega168 and avr studio I am new to this stuff and my screen is just showing one solid block of squares in one line only. Do I need to set the port and pin numbers for TWI in some file. I saw that none of the headers files set the port numbers.
    Appreciate your help,
    Thanks

    ReplyDelete
    Replies
    1. yes, you have to setup pin number in file: lcdpcf8574.h

      Delete
    2. I apologoze for bothering you again, but figure out that pin numbers are hardwired so we do not need to use them, but you are running it a 4Mhz frequency, I am trying to so it at 8Mhz, in what places should I change the code. Also I used the meter to check ao,a1,a2 and all three report avoltage of 4.9v. this means they are tied high, so my address will be 0x27, correct? I am using PCF8574T. The program is hanging somewhere in lcd_init. Any help will be appreciated.

      Delete
    3. i'm running it at 1Mhz, but i've run it at 8Mhz on other project only changing the i2c speed.
      the only problem i've encountered during my experiments, is when pin connection are wrong.
      debug using logic analizer on the pcf8574 lines, or simply using uart output to check where it stucks.

      Delete
    4. Well, we have to use a multimeter to match the LCD pins to the PCF8574T pins, on our board they were totally different. After setting the pins correctly in LCDPCF8574.h file, the code worked like a charm
      Thanks for all the help.

      Delete
    5. I also get solid block of squares in one line only but I can't get this even to compile... i keep getting some compile errors about LCD_DISP_ON_BLINK and 2, or 3 other lines.
      To be clear i really don't understand all this stuff what it mean and avr studio is quite strange to me, but even i know that my pin connections are different I could fix that later based on Your previous advice for lcdpcf8574.h.
      For now i don't know how to get compile ok. My mcu is Atmega168 @8MHz internall. I'm trying to get this to work just to know does my pcf8574t chip is still live at all because i'm also trying to controll lcd on such was using some other programming method.

      Please sir i need help. For You it's maybe 5minutes of work, can you provide me with hex file just to burn it to my mcu?

      pcf8574 adress is 0x20, and my connection is like this
      http://mmdolze.users.sourceforge.net/images/myLoS-i2c.png but my and my backlight is npn transistor so turned on is PCF_P7=1
      i use atmega168

      Delete
    6. Hello,
      try Eclipse with avrgcc and AVR plugin, it's very simple to use it and compile it with Eclipse avr plugin.
      Or you can write your own makefile. There are a few tutorial out there.
      Yes, i could compile it for you, but every time you have to make a change, you have to ask me to compile, and it could not bring anything to your knowledge :)

      Delete
    7. i really don't know how to do anything of that. Write my own makefile? hah, good one... :) I don't know even #C at all. That's why I'm using Flowcode, programming mcu by putting blocks around but there are also some tricky issues about i2c LCD that gives me a headache and matrix multimedia support sucks.
      Actually I'm medical worker and electronics is just my hobby, complete noob :)
      I don't think that i will need that hex more than one (this) time, simply to check my hardware to know am I doing something wrong in Flowcode or my PCF8574 chip is simply dead for some reason and that's why I don't get normal result on LCD. that's all


      at least i would be happy with zip that include avr studio solution and all those .c and .h included so I can look around and try to understand what is what and how things should be done.

      Delete
    8. Ok. For neebie you should consider working with Arduino, which is really simple! Just import that code in your avr studio project. Keep in mind that you will have to change some registers in order to make this works on mega16. Give it a try to arduino, the LCD i2c library is really simple.

      Delete
    9. i don't have arduino and as far as i saw how it works it also need some knowledge about #C... also arduino IDE won't work on my laptop, i don't know why and i don't care, i will not use it.
      and i did tried already to import code in avr studio, as I said before i get build errors. registers to change?! i don't know how to do that

      never mind. i will continue my fight with Flowcode. thanks

      Delete
    10. Ali, could you please post your pin configuration?
      I have the PCF8574T too.
      Thanks!

      Delete
  3. Hi David,

    Nice work, but I'm having trouble getting it to work.

    I'm using a 20x4 LCD from YwRobot, which comes with a PCF8574. I have it connected to analog pins 4 (SDA) and 5 (SCL) on an ATmega328P. I have made the following connections, which I believe are correct: DATA0 = 4, DATA1 = 5, DATA2 = 6, DATA3 = 7, RS = 0, RW = 1, EN = 2. The backlight seems to just be connected to Vcc (which pin should I set it to?).

    I am not sure what address to use. I've tried both 0x20 and 0x27 (this worked when I used the LCD with an Arduino library some time ago).

    Any idea what the problem might be?

    ReplyDelete
    Replies
    1. hello,
      at first try with a 16x2 LCD, HD44780, pretty standard and a cheap PCF8574 board-
      Then when you are shure it works, test it with your hardware.
      Anyway, pin numbers are in file: lcdpcf8574.h

      Delete
    2. I don't have one :( My LCD is a HD44780 though. I have set the pin numbers in lcdpcf8574.h.

      Delete
  4. Davide, thank you for your library!
    The pins for PCF8574T I2C LCD adapter (bought from Ebay):

    #define LCD_DATA0_PIN 4
    #define LCD_DATA1_PIN 5
    #define LCD_DATA2_PIN 6
    #define LCD_DATA3_PIN 7
    #define LCD_RS_PIN 0
    #define LCD_RW_PIN 1
    #define LCD_E_PIN 2
    #define LCD_LED_PIN 3

    ReplyDelete
    Replies
    1. Thank you for sharing your feedback!

      Delete
    2. and address into 0x27
      #define PCF8574_ADDRBASE (0x27) //device base address

      Delete
    3. Maciej, this has just saved me after a day of debugging thanks for posting. I have the same setting requirements.

      Delete
  5. Looking for an assembly version of this, is there a way to concert the c to assembly? I can read assembly but not c well. Thanks. Even compile it with avr studio and send me the hex and I will decompile it.

    Thanks

    ReplyDelete
    Replies
    1. Hello, I can send you a compiled hex or the compiler lss avrgcc file, which contains the assembly. Keep in mind that it will be assembly code from the compiler, so it can not be so "clean". Anyway, just send me an email, or give me your address and i will reply with the code.

      Delete
    2. admin at tipsntricks dot ca

      Delete
  6. Hello,
    I used this library to run PCF8574T on ATmega16A. I got cheap ebay display with I2C backpack ( PCF8574T) module. I changed pins in .h file and communication works ok (Im able to write something on display), but there is no backlight. The thing is that there is backlight for some ms, but when display init method starts, it turns off backlight somehow and I cant figure out why. Its some kind of invert mode I think.

    If you got any ideas, please share. Thanks,

    ReplyDelete
    Replies
    1. The setup pin for the lcd light is LCD_LED_PIN (lcdpcf8574.h). The function to light up and down is lcd_led. In normal mode lcd_led(1) will turn the led on, lcd_led(0) off, in inverted mode, it works inverted, so 1 to off, o to on.
      It your board works and it's all connected properly, this is the way it should work.
      It could also be your hardware that is damaged.
      You can double check your wiring, and try different pins.

      Delete
    2. Problem solved! Thank you very much!

      Delete
    3. Thank you for your feedback ;)

      Delete
    4. This comment has been removed by the author.

      Delete
  7. im using this files with ATmega32. i have this module
    http://www.ebay.com/itm/310565362720?_trksid=p2059210.m2749.l2649&ssPageName=STRK%3AMEBIDX%3AIT
    i had already used the based libraries about lcd 2x16 and works fine. so i dont have edit my code as it use same functions.

    i've change the
    F_CPU with my xtal freq.
    also i change the adress to 0x27 (A0,A1,A2 = 4.8V)
    and finally change pins several times with different combination.

    i had build circuit with module and lcd on breadboard and connections with wires. to make sure that pins corresponding right.

    nothing works :(

    ReplyDelete
    Replies
    1. Check your hardware with other libraries, or with Arduino. So you will be sure that your hardware works, and what the pin of your hardware are.
      You could also check where your code stops working, using a serial debugger.

      Delete
    2. thanks for reply.
      i can't use debugger now. im trying to add i2c in an already working circuit with FTDI and atmega32. my uart its reserved from ftdi chip

      Delete
    3. my hardware works perfectly. checked with arduino hardware, arduino ide and arduino libraries.

      Delete
    4. So, it could be the I2C library, you have to check the bus using a logic analizer, or debug in other way to check where your code stop working.
      The code was tested using avrgcc.

      Delete
    5. This comment has been removed by the author.

      Delete
    6. 1- gnd
      2- vcc-
      3- contrast-
      4- rs- pcf0
      5- rw- pcf1
      6- e- pcf2
      7- db0-
      8- db1-
      9- db2-
      10- db3-
      11- db4- pcf4
      12- db5- pcf5
      13- db6- pcf6
      14- db7- pcf7
      15- +led- led_jumper
      16- -led- led_jumper

      Delete
  8. i tried define:
    #define LCD_DATA0_PIN 4
    #define LCD_DATA1_PIN 5
    #define LCD_DATA2_PIN 6
    #define LCD_DATA3_PIN 7
    #define LCD_RS_PIN 0
    #define LCD_RW_PIN 1
    #define LCD_E_PIN 2
    #define LCD_LED_PIN 3
    but nothing works :(

    ReplyDelete
    Replies
    1. Check if your I2C works, check the output of your PCF8574 with a multimeter.
      Hack the code to test every pin output using pcf8574_setoutputpin funcion.

      Delete
    2. thanks for advice davide. i will...

      Delete
    3. It works!
      There was connection error on breadboard!
      Works perfectly...!
      thank you Davide!

      Delete
  9. I have another problem.
    i had made a project with atmega32 which communicates with pc via ft232rl.
    pc sends data through ftdi (uart) to atmega32 and while sends data, the mcu interrupted.
    the atmega32 while its not in interrupt routine, it running a code which measuring a distance with HCSR04.
    now, while i running the pc program for sending data to mcu, my main routine stop to work and in lcd i see only data from pc and not from ultrasonic sensor.
    it working without i2c.

    ReplyDelete
    Replies
    1. Try to put a watchdog, to test if the mcu restart.

      Delete
    2. I mean.. if the mcu restarts when the data is sent. Then, debug your HCSR04 routine.
      Start at small steps, try at first with a simple ADC read routine, then attach your distance sensor code.

      Delete
  10. Hello everyone,

    I had a problem with compilation that code . Something like " Poisoned SIG_USART_DATA nad SIG_USART_RECV . So I found and changed that uasrt.h file and uart.c file into almost the same ( now SIG_USART_DATA is UART_UDRE_vect for example ) the rest is same. Compillation is without any problems, but nothing appeared on my LCD :( I have been trying to resolve that problem for 8 hours. I am using pcf8574T and I changed pins :(

    Do you know what should I do?

    I would add that I am using that set http://www.ebay.com/itm/Arduino-IIC-I2C-TWI-162-1602-16X2-Serial-Blue-LCD-Module-Display-Screen-/190573003243 and ATMEGA8 .

    ReplyDelete
    Replies
    1. I took that new files ( uart.h and uart.c ) from that site http://mmdolze.users.sourceforge.net/use-a-lcd-with-twi.html

      Delete
    2. Uart is there just for debug purpose. You could also remove that, or use anyother library. What i can say is that on HD44780 based LCD wiring is really important. So double chek it. Also, you could use a logic analyzer to debug the pcl8574 to lcd bus. Check that pcl8574 output works as desider, debug the output editing the code. Compile using avrgcc. Compile using your actual micro F_CPU. Check SCL_CLOCK of the twimaseter.c
      Hope this helps.

      Delete
    3. Thanks for answer, I will try to remove uart files. Can u only please tell me about configuration of pins for that: http://www.ebay.com/itm/Arduino-IIC-I2C-TWI-162-1602-16X2-Serial-Blue-LCD-Module-Display-Screen-/190573003243

      How it should looks like:

      #define LCD_DATA0_PIN 0 /**< pin for 4bit data bit 0 */
      #define LCD_DATA1_PIN 1 /**< pin for 4bit data bit 1 */
      #define LCD_DATA2_PIN 2 /**< pin for 4bit data bit 2 */
      #define LCD_DATA3_PIN 3 /**< pin for 4bit data bit 3 */
      #define LCD_RS_PIN 4 /**< pin for RS line */
      #define LCD_RW_PIN 5 /**< pin for RW line */
      #define LCD_E_PIN 6 /**< pin for Enable line */
      #define LCD_LED_PIN 7 /**< pin for Led */

      To be honest I don't get it. What are that numbers from 0-7? Are they numbers of P0-P7 ?

      Thanks for answer ;)

      Delete
    4. Hello, for that module, you have to trace out the pinout using a multimeter or whatelse.
      As example: LCD_RS_PIN -> 4 means that the pcl8574 P4 output goes to RS input pin of your 16x2 HD44780 based lcd.

      Delete
  11. This comment has been removed by the author.

    ReplyDelete
  12. Hi David
    Thank you for libraries
    Works fine in AtmelStudio6
    I added the library into a new project and wrote in Project\Properties\Toolchain\AVR/GNU C Compiler\Symbols: F_CPU = 16000000UL
    and comment string #include PCF8574_I2CFLEURYPATH in pcf8574.c
    "F_CPU = 16000000UL" for Atmega328P for other chips another frequency
    Good luck to everyone!

    ReplyDelete
  13. This comment has been removed by the author.

    ReplyDelete
  14. This comment has been removed by the author.

    ReplyDelete
  15. Hi David,

    I have a quick question. Where do I set the i2c device id in your code? The default device id 0x27 and the device id of my i2c lcd backpack is 0x3F.

    Thanks,

    -Justin

    ReplyDelete
    Replies
    1. Hello, it's in the pcf8574.h file: look at this PCF8574_ADDRBASE definition.

      Delete
  16. This comment has been removed by the author.

    ReplyDelete
  17. Hi Davide,

    I'm trying to use a LCD2004A/PCF8574T with an atmega328P but after hours of debugging I still can't get it to work.

    I already checked the pin mapping between the lcd display and the attached port expander by using a multimeter.

    See here:

    P0 -> RS
    P1 -> RW
    P2 -> E
    P3 -> not connected to any of the lcd pins
    P4 -> D4
    P5 -> D5
    P6 -> D6
    P7 -> D7

    The pin mapping and wiring shouldn't be the problem. I found out that my code hangs in the following while-loop in the i2c_start function.

    while( !(TWCR & (1<<TWINT)) );

    It seems that the TWINT flag never changes and therefore causes the program to hang in the while-loop.

    In order to ensure there's no hardware issue I tested the i2c communication with the LiquidCrystal_I2C library from the Arduino IDE and it all worked fine. I could send text to my LCD display via i2c.
    But I really want to use your code because it's completely written in C and not in C++ like the Arduino library.

    Do you have an idea why the program freezes in the following code section?

    uint8_t i2c_start(uint8_t address)
    {
    // reset TWI control register
    TWCR = 0;
    // transmit START condition
    TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
    // wait for end of transmission
    while( !(TWCR & (1<<TWINT)) ); // The program freezes at this point


    Thanks in advance.

    ReplyDelete
    Replies
    1. Hello, good explanation, and debugging! So, now I'm out of my main PC, but one first question is. Check with another SCL clock, and/or test your F_CPU settings, and you atmega fuse setting. Also, are you compiling it with avrgcc?

      Delete
    2. Hello Davide,

      thanks for your reply.

      Today I changed the SCL from 100000UL (100 KHz) to 400 KHz and 1.7 MHz, but none of these configurations worked. My F_CPU is at 16 MHz. According to the datasheet of the port expander (pcf8574) it requires an i2c SCL of 100 KHz to work properly, so I made my changes undone and set it back to 100 KHz.

      In order to program my atmega328p I'm using an Arduino Uno with the "ArduinoISP" sketch installed on it. Further I'm using avrdude to uploaded the compiled .hex file of my C program to my atmega328p with the following fuse configuration.

      lfuse: 0xe6
      hfuse: 0xd9

      This is my complete parameter chain of avrdude:
      -U lfuse:w:0xe6:m -U hfuse:w:0xd9:m -e -F -v -patmega328p -carduino -P COM3 -b19200 -D -Uflash:w:"$(ProjectDir)Debug\$(ItemFileName).hex":i -C"C:\Program Files (x86)\Arduino\hardware\tools\avr\etc\avrdude.conf"

      And yes I think I'm using avrgcc as a compiler, at least the project properties claims that.

      Do you think it might have something to do with the fuse config?

      Best regards,
      Frans

      Delete
    3. So, if you are compiling for 16Mhz ( One simple think could be check it using UART debugging ). Check the PCF8574_ADDRBASE, is that the same of the Arduino library? Try this library: http://davidegironi.blogspot.it/2013/03/pcf8574-gpio-expander-library-for-avr.html Can you pull up/down any of the GPIO pin (check it with a multimeter)?

      Delete
    4. Frans & Davide,
      I have exact same setup and same problem. 16MHz, Atmega328P Arduno Uno with Fundino I2C interface. Already confirmed that pins defined in header file are correct by connections test.
      My code can't pass that while loop in i2c_start() function.

      Do any of you know the root cause and the solution?

      I'd appreciate it a lot if you share.
      Cheers
      Matt

      Delete
    5. I forgot to mention I'm using avr-gcc and the address is 0x27 as all 3 address pins on i2c interface are connected to Vcc.
      Looking forward to hearing from you.
      Matt

      Delete
    6. This comment has been removed by the author.

      Delete
    7. Finally solved!

      The root cause of problem was that PC4 & PC5 pins were not configured as output and was not set to high initially. Here is the list of changes need to be done on original code to let Arduino Uno and QAPASS LCD with Funduino I2C interface work:
      1. PORTC PC4 and PC5 may need to be configured as output and initiated to 1 in beginning of main():
      DDRC |= _BV(DDC5) | _BV(DDC4);
      PORTC |= _BV(DDC5) | _BV(DDC4);

      2. The value of LCD_DATA0_PIN, etc might need to change based on the connections of P7-0 on PCF8574 to LCD pins. No change needed in my case.
      3. F_CPU should be defined as 16000000UL.
      4. SCL_CLOCK should be defined 100000L ( it was 10000L which was causing overflow in TWBR initialised value, i.e. 0x81 instead of 0x318)
      5. Value of PCF8574_ADDRBASE might need to change based on 3 address input bits of PCF8574 (0x27 in my case, where it was 0x20).

      These corrections solved the problem on my setup and worked OK.
      Cheers
      Matt

      Delete
    8. Thank you for sharing your solution!

      Delete
  18. This comment has been removed by the author.

    ReplyDelete
  19. Thanks for this code...works like a champ. Used the pinout posted by Andrew (April 22, 2014), device address of 0x27, F_CPU=1MHz. Hardest part for this newbie was climbing the "make" learning curve to compile the code. Once that's accomplished, life gets much easier.

    ReplyDelete
  20. This comment has been removed by the author.

    ReplyDelete
  21. This comment has been removed by the author.

    ReplyDelete
  22. This comment has been removed by the author.

    ReplyDelete
    Replies
    1. Hello. Step 1, debug your pcf8754 output. Check that the library really put a pin up and down, using the pcf8574_setoutputpinhigh function and a multimeter.

      Delete
  23. Hello,
    Great Library, but I was wondering how I set it up to control multiple displays. I have a PCF8574 connected to each display and each '8574 has a unique address.

    Any help on this would be greatly appreciated.

    JIm

    ReplyDelete
    Replies
    1. Hello, this libary was built to drive one display at time, anyway, if you want to drive more than one you can do it by changing functions in lcdpcf8574 files. You should built up an array of deviceid, then add the deviceid variable to all the funcitions. This is one way to do what you need, not the only one.

      Delete
  24. Thanks, but I guess I should have been a little more clearer in my question. I do not want to update multiple displays with the same information, but have multiple displays with different information driven off the same I2C bus, with each display being serviced individually. How does one add the Device ID to teh functions?
    Jim

    ReplyDelete
    Replies
    1. Yes, i understaind it. You have to implement multiple deviceid on the lcdpcf8574 library. This library cant at present drive one display. If you implement an array of multimple device id, you can drive many display at the same time.

      Delete
    2. I've implemented a libray based upon this, to drive up to 8 LCD display. It will be soon online.

      Delete
  25. I am guessing I would have to create multiple lines of these in the .h file:

    #define LCD_PCF8574_INIT 1 //init pcf8574

    #define LCD_PCF8574_DEVICEID 0 //device id, addr = pcf8574 base addr + LCD_PCF8574_DEVICEID

    As I see the DEVICE ID in the .c file, but I am wondering how in my main code I tell the library what display I want to talk to.

    Sorry to be a bother, but I just think I am missing one key piece to this.

    JIm

    ReplyDelete
  26. Great libraries. Got them to work with an atmega328p at 16000000Hz on 20x4 lcd. Thank you so much.

    ReplyDelete
    Replies
    1. This comment has been removed by the author.

      Delete
    2. Came up with a problem after changing 20x4 blue series lcd screen to a green lcd series screen.Screen sometimes started up perfectly other times just produced garbage. Reliability was restored by adding 20ms delays after the lcd_e_toggle function calls in lcd_write function. This would seem a rather heavy handed solution if the problem is an iniation issue. I'll keep looking.

      Delete
    3. Is your AVR using the internal oscillator, or an external crystal? Also did you set up the clock frequencies in the .H files properly?

      JIm

      Delete
    4. This comment has been removed by the author.

      Delete
    5. This comment has been removed by the author.

      Delete
    6. Thanks for your reply. External crystal at 16000000hz.
      F_CPU has been defined correctly at all appropriate locations.
      A pwm timer has been included in the code to verify clock speed.

      Delete
  27. I am unable to successfully get the libraries to work, I get many errors in the twimaster. I am trying to use an ATmega325PA 16Mhz on a (20x4). I'm assuming its a little change but I just can't figure it out. Any assistance would be greatly appreciated.

    ReplyDelete
    Replies
    1. TWXX undeclared (first use in this function)

      Delete
    2. Hello, are you compiling with avr-gcc? This project is tested for this compiler usinc Eclipse.

      Delete
    3. Dweck,
      Take a look at your threads on AVRfreaks. I just posted there that the Mega325 WILL NOT work with Davides library, nor Peter Fleury's, and I explained why too.

      I have a demo that you may have to get you going if you want it.

      Jim

      Delete
  28. I am using this library in AVR-GCC and it does work Dweck as I recommended it to you on AVRfreaks. IF you want you can ZIP up your Studio project and post it in your thread and I can take a look

    JIm

    ReplyDelete
    Replies
    1. Hello, I'm sorry but I have no time to check your project, hope you understaind. So, is that a compile error, or a runtime error?

      Delete
  29. DAvide,
    I was offering to help out Dweck as he has a thread going on AVRfreaks. I was not asking you to look at anything.

    Jim

    ReplyDelete
    Replies
    1. Ups, I'm sorry, it's my mistake part due to my bad english, and part due to the fact that usually people ask me to look at their project. Any help is apriciated. Thank you for you help James.

      Delete
    2. This comment has been removed by the author.

      Delete
  30. No Problem. Happy to help if I can

    Jim

    ReplyDelete
  31. Davide,
    Congratulations! Your code works nice. My display is 20x4 and works. But, he write the text slowly. What's happen?

    ReplyDelete
    Replies
    1. Thank you! It could be your I2C clock. Set it on twimaster.c. If you set your ATmega to run @ 8Mhz or more you could even set the clock at 100kbit/s (#define SCL_CLOCK 100000L)

      Delete
  32. The schematic shown must be for a rather old version of the I2C-to-HD44780 character LCDs. All the ones available in 2016 have been updated to have 3 address offset solder pad jumpers. Also, the LED backlight driver circuit has a 2-pin push-on jumper to cut/supply power to the backlight LED.

    Note that the series resistor to current-limit the backlight LED should be connected to the transistor's collector pin, not the emitter pin, just the same as with a NPN transistor. Emitter resistors are used exclusively to compensate for temperature drift in linear applications. There is no need for to do this for digital drive circuits.

    I have redrawn the schematic and can make it available to you, but there is no way for me to attach the file to this message.

    ReplyDelete
    Replies
    1. Hello, thank you for your suggestion. I've updated the schematics.

      Delete
  33. Hi Davide,
    I don't understand the lcd_read() function
    In particular the line:
    data = pcf8574_getoutputpin(LCD_PCF8574_DEVICEID, LCD_DATA0_PIN) << 4;
    Isn't pcf8574_getinput() supposed to be the right one to apply the <<4?
    Grazie
    Ciao

    ReplyDelete
    Replies
    1. Hello, you are right. There Peter Fleury use a trick, he read the PORT register - 2, so he read the PIN register.
      Look at the read function here: http://pastebin.com/TF0ugKNa expires in 1 month. Let me know if it works, I will update the library.

      Delete
  34. Good job , but the most popular lcd model have "0x27" adress and in "twimaster.c" "F_CPU" is 4MHz , not 1MHz. I don't know Why?

    ReplyDelete
    Replies
    1. Thank you! You have to define the F_CPU according to your crystal. Anyway the twimaster it is setup only if any F_CPU directive is used.

      Delete
  35. This comment has been removed by the author.

    ReplyDelete
  36. Hello Davide! Trying to make your library works with AT90USB647. Looks like teh I2C is working, but I get no ack from display. I tried two differente brands with no luck.

    I´m using an Agilent MSO-X2024 to inspect the protocol. I see the start, the slave addres (0x20) but no ack is sent back. This very same display works in Arduino. I adjust the speed to 100KHz. Any suggestion where to look? Thank you!

    ReplyDelete
    Replies
    1. Hello. What's your micro freq.? I suggest you to check the pcf8574_setoutput function at first, just set pin on port to see if it works. Most of the time is a pcf8574 does not works is a problem of device id or timing.

      Delete
    2. Thank you for your fast reply. Just found the problem. I´m in to it since 8AM (now 17:37PM). My problem was I have two displays with diffent addresses plus the pins were mixed up. I had a lot of problems converting to work for AT90USB647 too. Since I did not work with coding frequently, I had a rad time. But now everything is working great. Thank you for sharing the code.

      Delete
  37. This comment has been removed by the author.

    ReplyDelete
  38. i am new to atmel can you please help me how to include this library and how to use it.

    ReplyDelete
    Replies
    1. Hello, if you use Eclipe with the AVR plugin, you just have to create a new project, copy this project files in the source folder of that new project and compile it. There are many Eclipse + AVR tutorial online you can take a look at.

      Delete
  39. This comment has been removed by a blog administrator.

    ReplyDelete
  40. i was copied your code to a atmel's project. I was trying to fix bug but 4 errors i can't fix.
    https://plus.google.com/u/0/115791314223391483867/posts/cNN5UwzCGsN
    Can you help me?

    ReplyDelete
    Replies
    1. Hello, i think you are compiling twice some .c files. It is a few that i do not use ATmel Studio. You have to understaind why the Studio is trying to compling twice, or you can use Eclipse IDE + the AVR plugin, it is much more simple to me to handle a project with that IDE.

      Delete
  41. This comment has been removed by the author.

    ReplyDelete
  42. Hi mr. Davide my name is Tomislav and I have a problem. I am getting an error: Error 5 too many arguments to function 'uart_init'.
    I am working with atmega16 in AVR studio. I can not campile it.
    Tnx

    ReplyDelete
    Replies
    1. Hello, This is compiled and tested using avr-gcc. About the uart library, I use the P.Fleury one, you can get it from his website here: http://homepage.hispeed.ch/peterfleury/avr-software.html
      As a suggestion, at first try to compile the P.Fleury sample project, then when you are sure the uart lib work, shift to this one.

      Delete
  43. Hi mr. Davide Iam getting Error 2 ../pcf8574/pcf8574.h: No such file or directory. I I copied all .h files to AVR install folder but when I compiled the program it doesnt see it. Can you tell me what's the problem. Tnx in advance.

    ReplyDelete
    Replies
    1. Hello, this error means that your compiler does not found this file. Try also to reference it in your project.

      Delete
  44. Hi David,

    This is a very useful library. I missed only one fuction. This was a custom character handling, so I created the necessary functions. If you think it's useful so please add it to the source code.

    - Prototype definitions in the lcdpcf8574.h
    ___________________________________________

    /**
    @brief Clear CGRAM
    @param void
    @return none
    */
    extern void lcd_clear_CGRAM (void);


    /**
    @brief Create custom character in CGRAM
    @param charnum: Character position in CGRAM. You can define maximum 8 chars.
    @param values[]: Custom character descriptor pointer.
    @return 0 - The custom character successfully created
    @return 1 - If the charnum greater than 7. You can define maximum 8 chars.
    */
    uint8_t lcd_create_custom_char (uint8_t charnum, const uint8_t * values);

    - Implementations in the lcdpcf8574.c
    _____________________________________

    /*************************************************************************
    Clear CGRAM
    *************************************************************************/
    void lcd_clear_CGRAM() {
    register uint8_t addressCounter = 0;
    for (; addressCounter < 64; addressCounter++) {
    lcd_command((1 << LCD_CGRAM) + addressCounter);
    lcd_putc(0x00);
    }
    }


    /*************************************************************************
    Define custom character in CGRAM
    Inputs: charnum: Character position in CGRAM. You can define maximum 8 chars.
    values[]: Custom character descriptor pointer.
    Returns: 0 - The custom character successfully created
    1 - If the charnum greater than 7. You can define maximum 8 chars.
    *************************************************************************/
    uint8_t lcd_create_custom_char(uint8_t charnum, const uint8_t * values) {
    register uint8_t j = 0;
    const uint8_t *p = values;

    if (charnum > 7) {
    return 1;
    }
    lcd_command((1 << LCD_CGRAM) + charnum * 8); // set CGRAM address charnum * 8 byte
    for (; j < 8; j++) {
    lcd_putc (*(p + j)); // write 8 byte data (one character) to CGRAM
    }
    return (0);
    }

    - How to use in your project
    ____________________________

    1. Define the custom character (example the degree sign):

    const uint8_t degree[8] PROGMEM = {
    0b00001100,
    0b00010010,
    0b00010010,
    0b00001100,
    0b00000000,
    0b00000000,
    0b00000000,
    0b00000000
    };

    2. Create a custom character in the LCD CGRAM. This is the first from eight. (practically in the initialisation method):

    lcd_clear_CGRAM(); // Clear CGRAM
    uint8_t buf[8];
    for (n = 0; n < 8; n++) {
    buf[n] = pgm_read_byte_near (& degree[n]);
    }
    lcd_create_custom_char (0, buf); // Write custom char to CGRAM

    3. Show custom character in your code:

    lcd_putc(0x00);

    Best Regards
    Peter

    ReplyDelete
    Replies
    1. Hello, thank you Peter. Please check this new version. https://expirebox.com/download/c83014ec3308bbe60d009e3025eb749b.html
      I've add your name in the comment on lcdpcf8574.h. If it's all ok to you I will publish it.

      Delete
  45. Hi David,

    I checked the new version and everything is OK. Thank you for your effort.

    Best Regards
    Peter

    ReplyDelete
  46. your link i think was broke sir, can u repair it ?

    ReplyDelete
    Replies
    1. Hello, I think it was a sourceforge temporary problem. Now I can download it.

      Delete
    2. thank's sir your code work fine, but i have issue when I using usart (RX TX). if I use library lcdi2c and
      serial library together, the usart not work.

      Delete
    3. Hello, try the new P.Fleury library. The version I'm using here is the older one.

      Delete
  47. Hi Davide, How can i integrate this lib to CodeVisionAVR? Thanks

    ReplyDelete
    Replies
    1. Hello, I think the only way is to port it to CodeVisionAVR compiler.

      Delete
    2. Thanks Davide, I found a way to create lib from your C file, but so many error occurred.
      Do i need just include lcdpcf8574.h to my code or which one? Your source code which has i2cmaster.h, lcdpcf8574.h, pcf8574.h, uart.h makes me confuse.

      Delete
    3. You have at least to include and compile files in lcdpcf8574, pcf8574 and i2chw. But you can also use another i2c library, if so you can use your and not use the i2chw one. Uart library is there just for debug purpose.

      Delete
    4. Thanks Davide for your info.

      Delete
  48. When I try to compile your main.c it gives me a bunch of undefined reference errors. Any advice?

    ReplyDelete
    Replies
    1. Hello, you have to compile also libraries, adding those to your project. If you are using Eclipse IDE it really simple, you just have to add files to your project src.

      Delete
  49. I saw in your software that a UART is initialized. I also see a uart used in the main,c. Do I have to use UART anywhere. I am only interested in the LCD ans pcf8574T use.

    ReplyDelete
  50. Hi Davide.
    I'm developing a system that allows to set a square wave period, then, once setted, it drives a led with a square wave with the setted period. It also uses an I2C LCD for the user interface, that uses your library. Anyway if i set the period, the output square wave isn't consistent, with heavy random period variation.
    May your library affecting the precision of the internal timer?

    ReplyDelete
  51. Hi Davide!

    When I call lcd_getxy() function. It always return with 17 value. Why is it? You have any idea?
    Thanks
    Dani

    ReplyDelete
    Replies
    1. This function (lcd_getxy()) is not present in lcdpcf8574.h

      Delete
  52. Thanks.
    Works on Atmega16.
    My device PCF8574 need to change adres
    #define PCF8574_ADDRBASE (0x3F) //device base address
    in pcf8574.h
    If set
    #define F_CPU 8000000UL
    I2C works on 400kHz
    /* I2C clock in Hz */
    #define SCL_CLOCK 400000L

    ReplyDelete
  53. Holy cats this man is patient - I can't believe what people ask.

    Anyhow after much debugging, throwing a Saleae I was convinced the code was working. Just throwing this out there. If the code is running and you can see through Uart debugging that its not hung etc. Try this - while the code is running adjust the potentiometer at the back of your i2c display. Yes folks sometimes it can be this simple. Your welcome :)… Thanks for the awesome code...

    ReplyDelete
  54. Hi
    tnx for your library but when i tring to use it and smulate circuit in proteus,nothing happen . even atmega8 pins cant creat i2c pulses when i scoped sda and scl pins.
    can you help me ?

    ReplyDelete
    Replies
    1. Hello, check with a logic analyzer the i2c line.

      Delete
  55. This comment has been removed by a blog administrator.

    ReplyDelete
  56. thanks brother!! it worked. you are our hero!!!

    ReplyDelete
  57. This comment has been removed by the author.

    ReplyDelete
    Replies
    1. Hello MHMLD, avrdude can not find the input file "can't open input file". You can try this gui here if it helps, https://blog.adafruit.com/2013/02/19/avrdudess-a-gui-for-avrdude/. Or use Eclipse IDE with AVR plugin, that is much more simple.

      Delete
  58. Hi David. The code compiles but when i send the code to my atmega328p the output is this:

    avrdude.exe: Device signature = 0x1e950f (probably m328p)
    avrdude.exe: NOTE: "flash" memory has been specified, an erase cycle will be performed
    To disable this feature, specify the -D option.
    avrdude.exe: erasing chip
    avrdude.exe: warning: cannot set sck period. please check for usbasp firmware update.
    avrdude.exe: reading input file "C:\Users\magda\Desktop\GccLibrary1\GccLibrary1\Debug\libGccLibrary1.hex"
    avrdude.exe: can't open input file C:\Users\xxxxxx\Desktop\GccLibrary1\GccLibrary1\Debug\libGccLibrary1.hex: No such file or directory
    avrdude.exe: read from file 'C:\Users\xxxxxx\Desktop\GccLibrary1\GccLibrary1\Debug\libGccLibrary1.hex' failed

    avrdude.exe: safemode: Fuses OK (E:FF, H:D9, L:E2)

    avrdude.exe done. Thank you.

    Can you help me pls???


    ReplyDelete
  59. Hello Davide. I endend up to install the eclipse ide. But my output was this:

    aviso: ‘SIG_UART_DATA’ appears to be a misspelled signal handler, missing __vector prefix [-Wmisspelled-isr] uart.c
    aviso: ‘SIG_UART_RECV’ appears to be a misspelled signal handler, missing __vector prefix [-Wmisspelled-isr] uart.c
    aviso: #warning "Compiler optimizations disabled; functions from won't work as designed" [-Wcpp] teste_atmega line 112, external location: /usr/lib/avr/include/util/delay.h C/C++ Problem
    erro fatal: lcdpcf8574/lcdpcf8574.h: Ficheiro ou directoria inexistente main.c /teste_atmega line 18 C/C++ Problem
    erro: tentativa de usar "SIG_UART_DATA" envenenado uart.c /Teste/uart line 87 C/C++ Problem
    erro: tentativa de usar "SIG_UART_RECV" envenenado uart.c /Teste/uart line 86 C/C++ Problem
    make: *** [subdir.mk:23: main.o] Error 1 teste_atmega C/C++ Problem
    make: *** [uart/subdir.mk:20: uart/uart.o] Error 1 Teste C/C++ Problem
    nota: in expansion of macro ‘UART0_RECEIVE_INTERRUPT’ uart.c
    nota: in expansion of macro ‘UART0_TRANSMIT_INTERRUPT’ uart.c

    Can you help me??? I always used the atmel studio and I have had difficulties

    ReplyDelete
    Replies
    1. Hello MHMLB. You have to add the folders in the compile path. "Ficheiro ou directoria inexistente", your compiler can not find the lcdpcf8574.h file. Take a look here https://www.instructables.com/id/How-to-get-started-with-Eclipse-and-AVR/

      Delete
    2. Sorry for being so anoying but now the errors are those...
      #warning "Compiler optimizations disabled; functions from won't work as designed" [-Wcpp] Test line 112, external location: /usr/lib/avr/include/util/delay.h C/C++ Problem
      erro fatal: ../i2chw/i2cmaster.h: Ficheiro ou directoria inexistente pcf8574.c /Test line 25 C/C++ Problem
      make: *** [subdir.mk:32: pcf8574.o] Error 1 Test C/C++ Problem

      Can you help me pls?

      Delete
    3. You keep having the same error, you just have to add the folder as "source" in the Eclipse project.

      Delete
    4. Well the error now is in the file pcf8574.c in include PCF8574_I2CFLEURYPATH. I cant understant....sorry again for being so anoying xd

      Delete
    5. Hello MHMLB. You have specify the correct relative path of the library. It's the relative to library one.

      Delete
  60. Hey Davide, first thanks for the libary it works fine. My Question is, why i cant pull R/W directly to GND? If i do the display shows nothing.. thanks

    ReplyDelete
    Replies
    1. Hello Florian. Thank you. The Rear/Write pin put the LCD between Read/Write mode. It's just because it does not works like this, for further information you can take a look here: https://www.sparkfun.com/datasheets/LCD/HD44780.pdf as example look at "Interfacing to the MPU" figure 9.

      Delete
  61. Hey Davide, I've been using your code on an Atmega 8 with a 20x4 LCD display and it works very well. I was just wondering if there was away to speed it up so text appears instantaneously on the screen rather than scrolling across?

    ReplyDelete
    Replies
    1. Hello Ben you could try to speed up the I2C speed.

      Delete
  62. Hi Davide,I can set the output pins ok but how to read the input pins?I think I should use getinputpin()? but how to see the out put then?

    ReplyDelete
    Replies
    1. Hello, if you need you can use pcf8574_getinputpin.

      Delete
  63. Hi,

    I have problem with LCD 2004A. If I'm printing for example one char in loop it will not print anything on line4. When cursor should move to line4 it will move to line2. I did some debugging but I cant find the root cause of this issue.

    #define LCD_LINES 4 /**< number of visible lines of the display */
    #define LCD_DISP_LENGTH 20 /**< visibles characters per line of the display */

    while(1) {
    lcd_putc('A');
    _delay_ms(50);
    lcd_putc('a');
    _delay_ms(50);

    }

    ReplyDelete
    Replies
    1. Dear mba, now I do not have any 4 lines LCD to help you.
      This library it's based on the P.Fleury one, did you check it with native Fleury? http://www.peterfleury.epizy.com/avr-software.html?i=1

      Delete
    2. Thank you David. I will check it.

      Delete
    3. You should change the line LCD_DISP_LENGTH to 80 as LCD 20x4 have 80 characters. Also change the line TEXT_WRAPPING (I think, it below few lines from LCD_DISP_LENGTH) and change it to 0.

      Delete
  64. Hi Davide. so I spent 3 days searching for i2c lib for atmega16A and here I am here. it seems to work with a lot of people here but not with me . I fixed all the errors that appear and it compiled without errors on Atmel studio 7 but nothing on UART or on i2c lcd.. I am using proteus.. plz I am disparate for help

    ReplyDelete
    Replies
    1. Hello Alaa, try using avrgcc as compiler, double check you wiring, do not use simulators, use real hardware. If you have, use a logic analizer.

      Delete
  65. Hi, Did you write this library for Arduino?

    Of course, I know that Arduino has its own library, but I am more interested in your library and I really like the way letters and numbers are printed on the screen.
    Of course, it would be great if there was a way to add that to the Arduino libraries.

    Also, thank you very much for this excellent library ...

    ReplyDelete
    Replies
    1. Hello Mohammed, thank you for having appreciated my work, unluckily this is just a avrgcc library, I think you can easly move this to the Arduino framework.

      Delete
  66. Hi, great work!

    I want to know if there is a way to read with MCU what the lcd shows?

    ReplyDelete
  67. Hello Davide,
    Your library is very nice and works fine. I have one question. I am using atmega328p on aruino board and I want to use on SPI one more device (GY-906 IR temp sensor). Is it somehow possible? I tried use your example, but into while(1) loop I put my working code before lcd_puts() to read temperature from sesor via SPI. But this not works (display is not showing anything) and on first look I think, that lcd needs to be again addressed after reading temperature. Generally, how should it be done correctly? I mean communicate with lcd and another SPI device/s with your library.

    ReplyDelete
    Replies
    1. Hello, yes it's possible. You can use two SPI. At first, you should initialize SPI once. Then, I would check the GY-906 reading using something like the UART. Then I would check the lcd usage. Then, only after both works, I will put all togheter.

      Delete
    2. Hello,
      Thanks for your reply. Yes, this is exactly what i did. GY-906 with SPI works in my test project. LCD also works in test project. Now I am connecting both these parts. In my main loop i have code as shown bellow. When I comment part beggining with "i2c_start(GY905ADDR+I2C_WRITE);" and ending with "i2c_stop();", then LCD is working and writing some text from code bellow this section. But when I remove comment, display is not showing anythink. It must stuck somewhere on SPI GY-906 sesor section I uncommented. Do you have some idea? I can provide some way whole project if it can help.

      lcd_led(led); //set led
      //led = !led; //invert led for next loop

      //Start of temp sesor section
      i2c_start(GY905ADDR+I2C_WRITE);
      // RAM read from 0x07 address
      i2c_write(0x07);
      //read data
      i2c_rep_start(GY905ADDR+I2C_READ);
      data_low = i2c_readAck();
      data_high = i2c_readAck();
      pec = i2c_readNak();
      i2c_stop();

      //0.02 degrees per LSB (measurement resolution)
      float tempFactor = 0.02;
      float tempData = 0x0000;

      //Temperature conversion, MSB is error bit
      //This masks off the error bit and concatenate data
      tempData = (float)(((data_high & 0x007F) << 8) + data_low);
      tempData = (tempData * tempFactor)-0.01;

      //Convert data to Celsius
      float celsius = (tempData - 273.15);
      // Convert float to string
      sprintf(out_str, "IR Temp (C) = %.3f\r\n", celsius);
      //End of temp sensor section

      lcd_gotoxy(1, 0);
      lcd_puts(out_str);

      Delete
    3. Hello,
      So at the end I solved the problem. Code was stuck on line "i2c_write(0x07);". Problem was, that for testing GY-906 I used Peter Fleury library directly downloaded from his web page with SCL_CLOCK 100000L in twimaster.c file. Your LCD library had difference in this define, SCL_CLOCK 10000L. So I solved this by changing 10000L clock to 100000L clock in your project. Now it works, sensor and LCD, both on SPI bus. I am not sure, why you have like this, but it can be cunfusing for another peoples.

      Delete
    4. Great! Thank you for sharing, this may helps other people! Miy SCL clocl is set to 10000L cause this project is running @ 1MHz.

      Delete
  68. Hello Davide,
    Thank you for your library. It worked great with me (ATmega328P and LCD 20x4 i2c) after I change some define line in your lcdpcf8574.h file. But there is a small problem. My refresh rate is quite slow (I can see the clear progress invidually), although I increased the SCL_CLOCK up to 100000L and 400000L, my F_CPU change to 16Mhz, all defined in the main.c file in the src folder. So I wonder that maybe I can increase my screen refresh rate somehow?
    Thank you for your library. Have a nice day!

    ReplyDelete
    Replies
    1. Hello, thank you. You should try editing the lcd_write function, although I haven't noticed that slow speed, indeed I've to slow the display loop down if I do not want the screen to "flicker".

      Delete
  69. Hello David,
    The first of all - thank you so much for you library it is very useful and I appreciate your work.
    Looks like I found a bug in lcdpcf8574, the mode "LCD_WRAP_LINES" doesn't make sense for 20x4 display. Please take a look addressing of the typical LCD 20x4:
    line0: 00-13
    line1: 40-53
    line2: 14-27
    line3: 54-67

    If the "LCD_WRAP_LINES==1 && LCD_LINES==4" the following code works out:
    if( pos == LCD_START_LINE1+LCD_DISP_LENGTH ) {
    lcd_write((1<<LCD_DDRAM)+LCD_START_LINE2,0);
    }
    else if ( pos == LCD_START_LINE2+LCD_DISP_LENGTH ) {
    lcd_write((1<<LCD_DDRAM)+LCD_START_LINE3,0);
    }
    else if ( pos == LCD_START_LINE3+LCD_DISP_LENGTH ) {
    lcd_write((1<<LCD_DDRAM)+LCD_START_LINE4,0);
    }
    else if ( pos == LCD_START_LINE4+LCD_DISP_LENGTH ) {
    lcd_write((1<<LCD_DDRAM)+LCD_START_LINE1,0);
    }

    So it makes a mess, if you use position (0,2) it happens in (0,1) instead and if you use (0,3) it happens in (0,2) place instead. Because in 20x4 LCD address space is split between odd and even lines.
    So maybe disable the mode for 20x4 LCD ?

    Thank you,
    Alex

    ReplyDelete
    Replies
    1. Hello, thank you for your post. I don't have a 20x4 now. I've to think about this, first of all, have you changed the LCD_DISP_LENGTH macro from 16 to 20?

      Delete
    2. As i said I do not have a 20x4 right now. You can disable this mode just setting LCD_WRAP_LINES to 0. Anyway if it happens to me to have a 20x4 or you find a way to solve this please share this. Also consider that this library is based on the P.Fleury one (http://www.peterfleury.epizy.com/avr-software.html), there are a few post on avr-freaks about this library, I'ven't find this kind of error there. But if you find this, please tell me.

      Delete
    3. David, I'd disabled, I posted it here only to let you know that such issue exist, maybe someone reads this post and also find a solution in disabling.

      Delete