STM32 CubeIDE 4线驱动LCD1602
1、LCD1602简介
LCD1602是指显示的内容为16X2,即可以显示两行,每行16个字符液晶模块(显示字符和数字),能显示的字符数是32,LCD1602内置了字库。带ASCII码字库,不能显示中文。
1.1、引脚介绍
LCD1602有16条引脚,还有14条引脚的,与16脚的相比缺少了背光电源A(15脚)和地线K(16脚)。
1.2 、LCD1602 基本时序操作
RS:RS为寄存器选择,高电平1选择数据寄存器,低电平0时选择指令寄存器。
R/W:R/W为读写信号线,高电平1时进行读操作,低电平0时进行写操作
EN:EN端为使能端,写操作时,下降沿使能。读操作时,E高电平有效
读状态。输入RS=0,RW=1,E=高脉冲。输出:D0—D7为状态字。
读数据。输入RS=1,RW=1,E=高脉冲。输出:D0—D7为数据。
写命令。输入RS=0,RW=0,E=高脉冲。输出:无。
写数据。输入RS=1,RW=0,E=高脉冲。输出:无。
2、LCD1602 显示
使用高4位数据线的接法,即4线并行模式(不同于8线并行模式操作),D0~D3这4个口悬空,据传输只需要通过D4-D7。翻译移植项目,来源https://controllerstech.com/interface-lcd-16x2-with-stm32-without-i2c/
LCD1602与STM32引脚连接:
LCD1602 | MCU |
---|---|
D4 | PA4 |
D5 | PA5 |
D6 | PA6 |
D7 | PA7 |
RS | PA1 |
RW | PA2 |
EN | PA3 |
2.1 、建立工程文件
打开调试引脚
开启外部时钟:
配置时钟树:
开启定时器1,定时间仅仅就为了定时,可以任意选择:
选择管脚:
2.2、程序移植
创建文件 LCD1602.c 和LCD1602.h 头文件。
LCD1602.h 头文件内容
#ifndef INC_LCD1602_H_
#define INC_LCD1602_H_
void lcd_init (void); // initialize lcd
void lcd_send_cmd (char cmd); // send command to the lcd
void lcd_send_data (char data); // send data to the lcd
void lcd_send_string (char *str); // send string to the lcd
void lcd_put_cur(int row, int col); // put cursor at the entered position row (0 or 1), col (0-15);
void lcd_clear (void);
LCD1602.c 文件内容:
#include <LCD1602.h>
#include "stm32f1xx_hal.h"
/*********** Define the LCD PINS below ****************/
#define RS_Pin GPIO_PIN_1
#define RS_GPIO_Port GPIOA
#define RW_Pin GPIO_PIN_2
#define RW_GPIO_Port GPIOA
#define EN_Pin GPIO_PIN_3
#define EN_GPIO_Port GPIOA
#define D4_Pin GPIO_PIN_4
#define D4_GPIO_Port GPIOA
#define D5_Pin GPIO_PIN_5
#define D5_GPIO_Port GPIOA
#define D6_Pin GPIO_PIN_6
#define D6_GPIO_Port GPIOA
#define D7_Pin GPIO_PIN_7
#define D7_GPIO_Port GPIOA
/****************** define the timer handler below **************/
#define timer htim1
extern TIM_HandleTypeDef timer;
void delay (uint16_t us)
{
__HAL_TIM_SET_COUNTER(&timer, 0);
while (__HAL_TIM_GET_COUNTER(&timer) < us);
}
/****************************************************************************************************************************************************************/
void send_to_lcd (char data, int rs)
{
HAL_GPIO_WritePin(RS_GPIO_Port, RS_Pin, rs); // rs = 1 for data, rs=0 for command
/* write the data to the respective pin */
HAL_GPIO_WritePin(D7_GPIO_Port, D7_Pin, ((data>>3)&0x01));
HAL_GPIO_WritePin(D6_GPIO_Port, D6_Pin, ((data>>2)&0x01));
HAL_GPIO_WritePin(D5_GPIO_Port, D5_Pin, ((data>>1)&0x01));
HAL_GPIO_WritePin(D4_GPIO_Port, D4_Pin, ((data>>0)&0x01));
/* Toggle EN PIN to send the data
* if the HCLK > 100 MHz, use the 20 us delay
* if the LCD still doesn't work, increase the delay to 50, 80 or 100..
*/
HAL_GPIO_WritePin(EN_GPIO_Port, EN_Pin, 1);
delay (20);
HAL_GPIO_WritePin(EN_GPIO_Port, EN_Pin, 0);
delay (20);
}
void lcd_send_cmd (char cmd)
{
char datatosend;
/* send upper nibble first */
datatosend = ((cmd>>4)&0x0f);
send_to_lcd(datatosend,0); // RS must be 0 while sending command
/* send Lower Nibble */
datatosend = ((cmd)&0x0f);
send_to_lcd(datatosend, 0);
}
void lcd_send_data (char data)
{
char datatosend;
/* send higher nibble */
datatosend = ((data>>4)&0x0f);
send_to_lcd(datatosend, 1); // rs =1 for sending data
/* send Lower nibble */
datatosend = ((data)&0x0f);
send_to_lcd(datatosend, 1);
}
void lcd_clear (void)
{
lcd_send_cmd(0x01);
HAL_Delay(2);
}
void lcd_put_cur(int row, int col)
{
switch (row)
{
case 0:
col |= 0x80;
break;
case 1:
col |= 0xC0;
break;
}
lcd_send_cmd (col);
}
void lcd_init (void)
{
// 4 bit initialisation
HAL_Delay(50); // wait for >40ms
lcd_send_cmd (0x30);
HAL_Delay(5); // wait for >4.1ms
lcd_send_cmd (0x30);
HAL_Delay(1); // wait for >100us
lcd_send_cmd (0x30);
HAL_Delay(10);
lcd_send_cmd (0x20); // 4bit mode
HAL_Delay(10);
// dislay initialisation
lcd_send_cmd (0x28); // Function set --> DL=0 (4 bit mode), N = 1 (2 line display) F = 0 (5x8 characters)
HAL_Delay(1);
lcd_send_cmd (0x08); //Display on/off control --> D=0,C=0, B=0 ---> display off
HAL_Delay(1);
lcd_send_cmd (0x01); // clear display
HAL_Delay(1);
HAL_Delay(1);
lcd_send_cmd (0x06); //Entry mode set --> I/D = 1 (increment cursor) & S = 0 (no shift)
HAL_Delay(1);
lcd_send_cmd (0x0C); //Display on/off control --> D = 1, C and B = 0. (Cursor and blink, last two bits)
}
void lcd_send_string (char *str)
{
while (*str) lcd_send_data (*str++);
}
在main.c 文件里面添加修改:
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "LCD1602.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
int row=0;
int col=0;
/* USER CODE END PTD */
开启定时器LCD初始化:
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start(&htim1);//开启定时器
lcd_init ();
lcd_put_cur(0, 0);
lcd_send_string("HELLO ");
lcd_send_string("WORLD ");
lcd_send_string("FROM");
lcd_put_cur(1, 0);
lcd_send_string("CONTROLLERS TECH");
HAL_Delay(3000);
lcd_clear();
/* USER CODE END 2 */
循环输出字符:
/* Infinite loop */
/* USER CODE BEGIN WHILE */
//循环输出字符
while (1)
{
for (int i=0;i<128;i++)
{
lcd_put_cur(row, col);
lcd_send_data(i+48);
col++;
if (col > 15) {
row++; col = 0;}
if (row > 1) row=0;
HAL_Delay(250);
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
2.3、可能出现的错误
在使用的过程中要注意一点,看自己手里的LCD1602是仅仅5V驱动还是支持3.3V驱动。背光,根据自己的需求选择合适的电压,背光可以接电位器调节,或者使用STM32 DAC产生电压进行控制。