More Pages

Saturday, April 23, 2016

ARM Cortex-M3 (STM32F103) Tutorial - LCD 16x2 Library

In this tutorial, I will share about LCD 16x2 library. With this library, you can easily use LCD 16x2 with STM32F103 microcontroller. This library contain 2 file: lcd16x2.h and lcd16x2.c files. If you want to know the more detail how the LCD 16x2 works, you can see this tutorial.


In this library, we can configure GPIO for the LCD 16x2 on lcd16x2.h file. This definitions on lcd16x2.h contains GPIO configuration for LCD 16x2:
// LCD control lines (must be on the same port) 
#define LCD16X2_RCC_GPIO_CONTROL   RCC_APB2Periph_GPIOB
#define LCD16X2_GPIO_CONTROL       GPIOB
#define LCD16X2_GPIO_RS            GPIOB
#define LCD16X2_GPIO_RW            GPIOB
#define LCD16X2_GPIO_EN            GPIOB
// LCD data lines (must be on the same port)
#define LCD16X2_RCC_GPIO_DATA      RCC_APB2Periph_GPIOA
#define LCD16X2_GPIO_DATA          GPIOA
#define LCD16X2_GPIO_D4            GPIOA
#define LCD16X2_GPIO_D5            GPIOA
#define LCD16X2_GPIO_D6            GPIOA
#define LCD16X2_GPIO_D7            GPIOA
// Pin definition
#define LCD16X2_PIN_RS             GPIO_Pin_12
#define LCD16X2_PIN_RW             GPIO_Pin_13
#define LCD16X2_PIN_EN             GPIO_Pin_14
#define LCD16X2_PIN_D4             GPIO_Pin_8     // 4-bit mode LSB
#define LCD16X2_PIN_D5             GPIO_Pin_9
#define LCD16X2_PIN_D6             GPIO_Pin_10
#define LCD16X2_PIN_D7             GPIO_Pin_11    // 4-bit mode MSB
In this definitions, you can configure GPIO for LCD control lines (RS, RW, EN) and LCD data lines (D4-D7). This library only support 4-bit data mode.

To use this library, in the main.c file, you must call lcd16x2_init() function. There are 5 parameter for this function that can be used, depending on what type of cursor you want to use:
  • LCD16X2_DISPLAY_OFF_CURSOR_OFF_BLINK_OFF
  • LCD16X2_DISPLAY_ON_CURSOR_OFF_BLINK_OFF
  • LCD16X2_DISPLAY_ON_CURSOR_OFF_BLINK_ON
  • LCD16X2_DISPLAY_ON_CURSOR_ON_BLINK_OFF
  • LCD16X2_DISPLAY_ON_CURSOR_ON_BLINK_ON
This library is also support custom character display. This code is an example for use the library for displaying a string and also custom character:
#include "stm32f10x.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
#include "delay.h"
#include "lcd16x2.h"

// Custom char data (battery symbol)
uint8_t custom_char[] = { 0x0E, 0x1B, 0x11, 0x11, 0x11, 0x11, 0x1F, 0x1F };

int main(void)
{
    // Delay initialization
    DelayInit();

    // LCD initialization
    lcd16x2_init(LCD16X2_DISPLAY_ON_CURSOR_OFF_BLINK_OFF);

    // Create custom char
    lcd16x2_create_custom_char(0, custom_char);

    while (1)
    {
        // Display custom char
        lcd16x2_put_custom_char(0, 0, 0);
        lcd16x2_puts(" Battery Low");
        DelayMs(500);
        // Clear display
        lcd16x2_clrscr();
        DelayMs(500);
    }
}
The result will be like this:


You can download the library and example code from my repository.

23 comments:

  1. Hi, could you please tell how to use your library with hal libraries?

    ReplyDelete
    Replies
    1. About HAL:If you want to make your code professional and portable don't waste your time with the nonsense HAL.
      The SPL libraries are easy to use and there are numerous examples in the internet.
      About Erwin's library: Thank you Erwin for your great work and competence. Your library is a great example of simplicity that fulfills completely all needs of an LCD application.
      Thank you again for your competence.
      A.

      Delete
  2. Hi, good tutorial..
    I'm still very beginner in stm32, please tell me, why you did separate data pin and control pin? why not all in a GPIOA?
    Thanks.. :)

    ReplyDelete
    Replies
    1. Thank you for reading my tutorial..
      In case when GPIO pins are limited (because of the other GPIOA/B pins are used for other peripherals such TIM, UART, SPI, etc.), you can separate the GPIO pins for LCD easily.

      Delete
  3. Hi

    I dont work code
    Does it have other setting.

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

    ReplyDelete
  5. Hi Yohanes,
    Didn't you have issues with the voltage needed by the display? The displays I have need 5V and the STM32F103 needs 3.3V. I do not see a level shifter in the video clip...
    Regards,
    Wilko

    ReplyDelete
    Replies
    1. In general for a hobby project it's ok to connect the LCD at 5V to a MCU at 3.3V, but for a production design or in case your LCD didn't work with 3.3V, I recommend you to use a level shifter.

      This is because when writing to the LCD, the Voh at 3.3V maybe below the Vih at 5V (see. the datasheets for the details), so the logic high from MCU will be interpreted as undefined logic by the LCD.

      For reading the LCD, I'm not use a level shifter because I'm using the 5V tolerant input pin on STM32.

      Delete
    2. There is another way. If you put a small negative voltage on the Vo pin (voltage level for LCD driving) you can run the rest of the display on 3.3V. I made a small daughterboard connected to the back of the display that generates -2V with an oscillater made with a 74HC14, some diodes and capacitors. Now I have a 16x2 display working natively on 3.3V so no level shifters needed anymore.
      Regards,
      Wilko

      Delete
  6. Hello

    I am Coocox Coide and i get the following error when using your scripts : [cc] collect2.exe: error: ld returned 1 exit status

    I have included the last part of the compiling error below. Please can you help, note that i am a novice at this.

    [cc] C:\Users\hugan\CoIDE\workspace\hd44870_lcd/main.c:15: undefined reference to `DelayInit'
    [cc] C:\Users\hugan\CoIDE\workspace\hd44870_lcd/main.c:18: undefined reference to `lcd16x2_init'
    [cc] C:\Users\hugan\CoIDE\workspace\hd44870_lcd/main.c:21: undefined reference to `lcd16x2_create_custom_char'
    [cc] C:\Users\hugan\CoIDE\workspace\hd44870_lcd/main.c:26: undefined reference to `lcd16x2_put_custom_char'
    [cc] C:\Users\hugan\CoIDE\workspace\hd44870_lcd/main.c:27: undefined reference to `lcd16x2_puts'
    [cc] C:\Users\hugan\CoIDE\workspace\hd44870_lcd/main.c:28: undefined reference to `DelayMs'
    [cc] C:\Users\hugan\CoIDE\workspace\hd44870_lcd/main.c:30: undefined reference to `lcd16x2_clrscr'
    [cc] C:\Users\hugan\CoIDE\workspace\hd44870_lcd/main.c:31: undefined reference to `DelayMs'
    [cc] collect2.exe: error: ld returned 1 exit status

    Hugan

    ReplyDelete
    Replies
    1. I think that delay.h and lcd16x2.h files are not included into project. They should be included in your main.c code, be physically located with other .h files in project subdirectories and at least in uKeil you have to include them into project (never worked with coocox)

      Delete
    2. hi friend, i want to display message an lcd 2004 with i2c and the information on the net is too poor, you may be show us how it's it, thank you !!

      Delete
    3. awaiting same details. Anybody can help us

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

    ReplyDelete
  8. Hi
    What do we need to change if we want to move from 16x2 to 20x4 ?

    Thank you

    ReplyDelete
    Replies
    1. You should modify the library, because this library is only for 16x2 LCD. I never try 20x4 LCD, but I think the LCD internal command is the same. You can try to modify the definition for display size in .h file. You can add DDRAM address for line 3 and line 4 (see datasheet for details). Then you have to modify the 'putc', 'newline' , and 'gotoxy' funcion in .c file to add the 3rd and 4th LCD line.

      Delete
    2. Some time ago, I added this to the code. Have a look over here:
      https://drive.google.com/open?id=0B3SU-dWOSZ2URWlhOUJoMlMzaXc

      Delete
  9. can you explain how you define pin connetor (pin 9-15 from where?)

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

    ReplyDelete
  11. my codes :

    #include "stm32f10x.h"
    #include "stm32f10x_rcc.h"
    #include "stm32f10x_gpio.h"
    #include "delay.h"
    #include "lcd.h"

    uint8_t a=20;

    int main(void)
    {
    DelayInit();
    lcd16x2_init(LCD16X2_DISPLAY_ON_CURSOR_OFF_BLINK_OFF);
    lcd16x2_clrscr();

    lcd16x2_gotoxy(0, 0);
    lcd16x2_puts("HELLO ");
    lcd16x2_gotoxy(0, 1);
    lcd16x2_write_data(a);

    while (1);
    }

    there is only "HELLO " word on the screen. I can't see 20 (a=20) . "lcd16x2_write_data(a)" command is not working. what should I do?

    ReplyDelete
  12. Thank you.This code is working perfectly

    Ammasi M
    Echip Control Systems,Chennai,India
    Mobile:+91 9600289496
    Website: www.echipcontrolsystems.com

    ReplyDelete
  13. thank for your generosity

    I faced with strange problem in code , sometimes my program hangs on a loop exists in lcd16x2_wait_busy function , could you please help me ?

    ReplyDelete
  14. Do you maybe have the wiring somewhere? I want to connect 1602a to Nucleo-144 F767ZI and I'm worried about burning the board. Which connections require resistors?

    ReplyDelete