In this article, we dive into how Serial LCD Displays can enhance embedded projects, offering improved interfaces and streamlined data visualization.
Things used in this project
Software apps and online services
1-Â STMicroelectronics STM32CubeMX
2-Â STMicroelectronics STM32CubeIDE
3-Â Proteus 8
Efficient Integration of Serial LCDs with STM32 Microcontrollers via UART Communication
Serial LCDs, also known as serially-interfaced LCDs, offer a streamlined solution for displaying information in electronic projects. With their simplified interface and versatile compatibility, they have become a staple in hobbyist and professional circuits alike. Let’s delve into the world of Serial LCDs and explore their capabilities, configurations, and applications.
Introducing Serial LCDs:
Serial LCD Displays come in various configurations, each tailored to specific needs. Among the products available are the BPK LCD Driver Board and a range of compatible Serial LCD Displays modules:
- BPK LCD Driver Board, Part Number 6-201
- Serial LCD 2×16, Part Number 6-111
- Serial LCD 2×20, Part Number 6-121
- Serial LCD 2×40, Part Number 6-131
- Serial LCD 4×20, Part Number 6-141
Compatibility and Connectivity:
The BPK Serial Driver Board serves as a bridge between LCD modules and microcontrollers, converting standard parallel interfaces to a manageable serial interface. Compatible with Hitachi 44780 controllers or equivalents, it supports up to 80 on-screen characters. However, it’s worth noting that it’s not suitable for 4×40 displays. Connecting the BPK Board to LCDs is a straightforward process, requiring careful consideration of pin arrangements, especially for backlit LCDs. The board ensures compatibility with both non-backlit and backlit displays, making it adaptable to various setups.
Programming and Operation:
Programming Serial LCDs involves sending text serially at either 2400 or 9600 baud, adhering to specific formatting requirements. Preceding instruction commands with the byte <254> transitions the LCD into Instruction mode temporarily. It’s important to note that LCDs require a brief settling period after power-up, and certain commands may necessitate additional pauses for optimal operation.
Furthermore, Serial LCDs seamlessly integrate with STM32 microcontrollers via UART communication, significantly enhancing their compatibility and utility. Leveraging the UART capabilities of STM32 devices facilitates effortless interfacing with Serial LCD modules, empowering developers to enhance the display capabilities of their applications.
To commence this project, we will initiate the configuration of UART (Universal Asynchronous Receiver-Transmitter), a pivotal step in establishing communication between the microcontroller and the Serial LCD. Subsequently, we will embark on the development of a dedicated driver module, denoted as ‘LCD_UART’, meticulously crafted to facilitate seamless interaction between the microcontroller and the Serial LCD module.
STM32CubeMX Configuration:
- Open CubeMX & Create New Project Choose The Target MCUÂ STM32F103C6Â & Double-Click Its Name
- Go To The Clock Configuration & Set The System Clock To 8MHz
Configuration for theÂ
UART
 Mode:
- Enable USART1 Module (Asynchronous Mode)
- Set the USART1 communication parameters (baud rate =Â 115200, parity=NON, stop bits =1, and word length =8bits)
- Generate The Initialization Code & Open The Project In CubeIDE
STM32CubeIDE Configuration:
- Write The Application Layer Code
- Serial-LCD.h & Serial-LCD.c
- main.c
/* * Serial-LCD.h * Author: Marwen Maghrebi */ #ifndef INC_SERIAL_LCD_H_ #define INC_SERIAL_LCD_H_ #include "main.h" #include <stdio.h> #include <string.h> extern UART_HandleTypeDef huart1; // Function prototypes void Delay_10ms(void); void Delay_500ms(void); void LCD_UART_Transmit(uint8_t *pData, uint16_t Size); void LCD_sendCommand(uint8_t command); void LCD_sendData(uint8_t data); void LCD_setCursor(uint8_t row, uint8_t col); void LCD_scroll_left(uint8_t num_chars); void LCD_scroll_right(uint8_t num_chars); void LCD_home(); void LCD_blinking_cursor_ON(); void LCD_blinking_cursor_OFF(); void LCD_clearScreen(void); void Move_cursor_left(uint8_t num_chars); void Move_cursor_right(uint8_t num_chars); void LCD_underline_cursor_ON(); void LCD_Blank(); void LCD_print(const char *str); void LCD_printInt(int value); void LCD_printFloat(float value, int decimalPlaces); #endif /* INC_SERIAL_LCD_H_ */
/* * Serial-LCD.c * Author: Marwen Maghrebi */ #include"Serial-LCD.h" //wait for LCD to power up void Delay_500ms(void) { HAL_Delay(500); } //wait for the clear commande to settle void Delay_10ms(void) { HAL_Delay(10); } // Transmit data via UART void LCD_UART_Transmit(uint8_t *pData, uint16_t Size) { HAL_UART_Transmit(&huart1, pData, Size, HAL_MAX_DELAY); } // Send command to the LCD void LCD_sendCommand(uint8_t command) { LCD_UART_Transmit(&command, 1); } // Send data to the LCD void LCD_sendData(uint8_t data) { LCD_UART_Transmit(&data, 1); } // Set cursor position on the LCD !! void LCD_setCursor(uint8_t row, uint8_t col) { LCD_sendCommand(0xFE); // Command to set the cursor position LCD_sendCommand(0x80 + (row * 0x40) + col); // Calculate position based on row and column } // Scroll LCD content left void LCD_scroll_left(uint8_t num_chars) { for (uint8_t i = 0; i < num_chars; i++) { LCD_sendCommand(0xFE); // Command to set the cursor position LCD_sendCommand(0x18); // Command to scroll one character to the left HAL_Delay(100); } } // Scroll LCD content right void LCD_scroll_right(uint8_t num_chars) { for (uint8_t i = 0; i < num_chars; i++) { LCD_sendCommand(0xFE); // Command to set the cursor position LCD_sendCommand(0x1C); // Command to scroll one character to the right HAL_Delay(100); } } // Return cursor to the home position void LCD_home() { LCD_sendCommand(0xFE); // Command to clear the screen LCD_sendCommand(0x00); } // Enable blinking cursor void LCD_blinking_cursor_ON() { LCD_sendCommand(0xFE); // Command to clear the screen LCD_sendCommand(0x0D); } // Disable blinking cursor void LCD_blinking_cursor_OFF() { LCD_sendCommand(0xFE); // Command to clear the screen LCD_sendCommand(0x0C); } // Clear the LCD screen void LCD_clearScreen(void) { LCD_sendCommand(0xFE); // Command to clear the screen LCD_sendCommand(0x01); } // Move cursor left by num_chars characters void Move_cursor_left(uint8_t num_chars) { for (uint8_t i = 0; i < num_chars; i++) { LCD_sendCommand(0xFE); // Command to clear the screen LCD_sendCommand(0x10); HAL_Delay(100); } } // Move cursor right by num_chars characters void Move_cursor_right(uint8_t num_chars) { for (uint8_t i = 0; i < num_chars; i++) { LCD_sendCommand(0xFE); // Command to clear the screen LCD_sendCommand(0x14); HAL_Delay(100); } } // Enable underline cursor void LCD_underline_cursor_ON() { LCD_sendCommand(0xFE); // Command to clear the screen LCD_sendCommand(0x0E); } // Turn off cursor and blinking void LCD_Blank() { LCD_sendCommand(0xFE); // Command to clear the screen LCD_sendCommand(0x08); } // Print a string to the LCD void LCD_print(const char *str) { while (*str) { LCD_sendData(*str++); } } // Print an integer to the LCD void LCD_printInt(int value) { char buffer[20]; // Adjust the buffer size based on your needs sprintf(buffer, "%d", value); LCD_print(buffer); } // Print a floating-point number to the LCD with given decimal places void LCD_printFloat(float value, int decimalPlaces) { char buffer[20]; sprintf(buffer, "%.*f", decimalPlaces, value); // code to display the buffer on the LCD4 LCD_print(buffer); }
/* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include"Serial-LCD.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ UART_HandleTypeDef huart1; /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_USART1_UART_Init(void); /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_USART1_UART_Init(); /* USER CODE BEGIN 2 */ Delay_500ms(); // Wait for LCD to power up /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ LCD_clearScreen(); Delay_10ms(); // Enable blinking cursor LCD_blinking_cursor_ON(); Delay_10ms(); // Move cursor left and right Move_cursor_left(50); Move_cursor_right(50); Delay_10ms(); // Enable underline cursor LCD_underline_cursor_ON(); Delay_10ms(); // Disable blinking cursor LCD_blinking_cursor_OFF(); Delay_10ms(); // Clear the screen LCD_clearScreen(); Delay_10ms(); // Print messages with scrolling effect LCD_setCursor(0, 0); LCD_print("THE EMBEDDED THINGS!"); LCD_setCursor(1, 0); LCD_print("FOR MORE VIDEOS"); LCD_setCursor(2, 0); LCD_print("LIKE & SUBSCRIBE"); LCD_setCursor(3, 0); LCD_print("THANK YOU ^_^"); LCD_scroll_left(20); Delay_10ms(); LCD_scroll_right(20); // Clear the screen LCD_clearScreen(); Delay_10ms(); // Print integer and float values int x = 200; float y = 10.23; LCD_setCursor(0, 0); LCD_print("INTEGER VAL: "); LCD_setCursor(0, 12); LCD_printInt(x); LCD_setCursor(1, 0); LCD_print("FLOAT VAL:"); LCD_setCursor(1,12); LCD_printFloat(y, 2); Delay_10ms(); } /* USER CODE END 3 */ }
Proteus Configuration :
- Open Proteus & Create New Project and click next
- Click on Pick Device
- Search for STM32F103C6 &Â MILFORD-2X20-BKP &Â MILFORD-4X20-BKP &Â MILFORD-2X16-BKP
- Click on Terminal Mode then choose (DEFAULT & POWER &GROUND)
- finally make the circuit below and start the simulation
That’s all!
If you have any questions or suggestions don’t hesitate to leave a comment below