Stm32CubeMX+Proteus仿真入门
本章节资料下载链接:
我用夸克网盘给你分享了「第6章 LCD1602显示」,点击链接或复制整段内容,打开「夸克APP」即可获取。
/35953M6B5J😕
链接:https://pan.quark.cn/s/af25a9f00a50
第 六 章
1. 液晶LCD1602显示
1.1. LCD1602介绍
LCD1602字符型液晶显示模块是专门用于显示字母、数字元、符号等的点阵型液晶显示模块。
实物图如下:

引脚说明

仿真图:
型号为LM016L,仿真的引脚比实物少BL1和BL2引脚,显示功能一致,注意仿真的VEE引脚接了滑动变阻器,但不能调整显示亮度。实物是可以通过这个引脚配合滑动变阻器做亮度调整的。

基本指令:

基本操作时序:
1.读状态:输入:RS=L,RW=H,E=H 输出:D0-D7=状态字
2.写指令:输入:RS=L,RW=L,D0-D7=指令码 E=高脉冲 输出:无
3.读数据:输入:RS=H,RW=H,E=H 输出:D0-D7=数据
4.写数据:输入:RS=H,RE=L,D0-D7=数据,E=高脉冲 输出:无
对应时序图如下:

常用初始化指令:
初始化:
发送指令0x38 //八位数据接口,两行显示,57点阵
发送指令0x0C //显示开,光标关,闪烁关
发送指令0x06 //数据读写操作后,光标自动加一,画面不动
发送指令0x01 //清屏
显示字符:
发送指令0x80|AC //设置光标位置
发送数据 //发送要显示的字符数据
发送数据 //发送要显示的字符数据
LCD1602代码需知:
字符:根据一定规则建立的数字到字符的映射(ASCII码表)
例如:0x21='!',0x41='A',0x00='0'
定义方法:char x='A';(等效于char x=0x41;)
字符数组:存储字符变量的一个数组
定义方法:char y[]={'A', 'B', 'C'};
(等效于char y[]={0x41,0x42,0x43}; )
字符串:在字符数组后加一个字符串结束标志,本质上是字符数组
定义方法:char z[]="ABC";(等效于char z[]={'A', 'B', 'C', '0'};)
LCD1602部分不解释具体原理,直接上代码。
1.2. 硬件设计
如图:

LCD_RS,LCD_RW,LCD_EN分别接到stm32的PB3-PB5,LCD_D0-LCD_D7分别接到PA0-PA7引脚,引脚均设置为推挽输出。
1.3. 工程代码配置
新建两个文件命名为lcd1602.c和lcd1602.h并添加到工程文件。具体操作方法按照9.3的进行。
stm32cubemx工程配置:
和第十章的一样即可,用Part01_LEDBIT复制修改命名为Part03_LCD1602,PA0-PA7选择输出模式分别取别名为LED0-LED7,PB3-PB5输出模式,分别取别名为LSC,LSB,LSA

LCD1602.C代码内容为
#include "system.h"
#include "lcd1602.h"
//D0-D7设定方向:I-输入;O-输出
void DataDir(char dir)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
HAL_GPIO_WritePin(GPIOA, LED0_Pin|LED1_Pin|LED2_Pin|LED3_Pin|LED4_Pin|LED5_Pin|LED6_Pin|LED7_Pin, GPIO_PIN_SET);
GPIO_InitStruct.Pin = LED0_Pin|LED1_Pin|LED2_Pin|LED3_Pin|LED4_Pin|LED5_Pin|LED6_Pin|LED7_Pin;
GPIO_InitStruct.Pull = GPIO_PULLUP;
if(dir == 'I')
{
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
}
else if(dir == 'O')
{
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
}
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
//D0-D7读数据
uint8_t ReadData(void)
{
uint8_t dat=0;
//DataDir('I');
if(HAL_GPIO_ReadPin(GPIOA, LED0_Pin)==GPIO_PIN_SET) dat|=0x01;
if(HAL_GPIO_ReadPin(GPIOA, LED1_Pin)==GPIO_PIN_SET) dat|=0x02;
if(HAL_GPIO_ReadPin(GPIOA, LED2_Pin)==GPIO_PIN_SET) dat|=0x04;
if(HAL_GPIO_ReadPin(GPIOA, LED3_Pin)==GPIO_PIN_SET) dat|=0x08;
if(HAL_GPIO_ReadPin(GPIOA, LED4_Pin)==GPIO_PIN_SET) dat|=0x10;
if(HAL_GPIO_ReadPin(GPIOA, LED5_Pin)==GPIO_PIN_SET) dat|=0x20;
if(HAL_GPIO_ReadPin(GPIOA, LED6_Pin)==GPIO_PIN_SET) dat|=0x40;
if(HAL_GPIO_ReadPin(GPIOA, LED7_Pin)==GPIO_PIN_SET) dat|=0x80;
return dat;
}
//D0-D7写数据
void WriteData(uint8_t dat)
{
uint16_t Set_Pins = 0, Rst_Pins = 0;
//DataDir('O');
if(dat & 0x01) Set_Pins |= LED0_Pin;
else Rst_Pins |= LED0_Pin;
if(dat & 0x02) Set_Pins |= LED1_Pin;
else Rst_Pins |= LED1_Pin;
if(dat & 0x04) Set_Pins |= LED2_Pin;
else Rst_Pins |= LED2_Pin;
if(dat & 0x08) Set_Pins |= LED3_Pin;
else Rst_Pins |= LED3_Pin;
if(dat & 0x10) Set_Pins |= LED4_Pin;
else Rst_Pins |= LED4_Pin;
if(dat & 0x20) Set_Pins |= LED5_Pin;
else Rst_Pins |= LED5_Pin;
if(dat & 0x40) Set_Pins |= LED6_Pin;
else Rst_Pins |= LED6_Pin;
if(dat & 0x80) Set_Pins |= LED7_Pin;
else Rst_Pins |= LED7_Pin;
HAL_GPIO_WritePin(GPIOA, Set_Pins, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, Rst_Pins, GPIO_PIN_RESET);
}
//LCD忙等待
void LCD_Busy_Wait(void)
{
uint8_t status;
DataDir('I');
RS_InstructionR();
RW_Read();
do
{
E_Set();
__NOP();
status = ReadData();
E_Rst();
}
while(status & 0x80);
}
//写LCD指令
void LCD_Write_Cmd(uint8_t cmd)
{
DataDir('O');
WriteData(cmd);
RS_InstructionR();
RW_Write();
E_Rst();
RS_InstructionR();
RW_Write();
E_Set();
__NOP();
E_Rst();
LCD_Busy_Wait();
}
//写LCD数据寄存器
void LCD_Write_Data(uint8_t dat)
{
DataDir('O');
WriteData(dat);
RS_DataR();
RW_Write();
E_Set();
__NOP();
E_Rst();
LCD_Busy_Wait();
}
//LCD初始化
void LCD_Init(void)
{
LCD_Write_Cmd(0x38);
HAL_Delay(2);
LCD_Write_Cmd(0x01);
HAL_Delay(2);
LCD_Write_Cmd(0x06);
HAL_Delay(2);
LCD_Write_Cmd(0x0c);
HAL_Delay(2);
}
//在x行(0-1),y列(0-15)显示字符串
void LCD_ShowString(uint8_t x, uint8_t y, char str)
{
// LCD_Write_Cmd(0x01); //清屏 会有抖动现象
uint8_t i=0;
//设置显示起始位置
if(x == 0)
LCD_Write_Cmd(0x80|y);
else if(x == 1)
LCD_Write_Cmd(0xc0|y);
//输出字符串
for(i=0; i<16 && str[i]!='0'; i++)
{
LCD_Write_Data(str[i]);
HAL_Delay(2);
}
}
void LCD_ShowChar(uint8_t x, uint8_t y,uint8_t dat)
{
//设置显示起始位置
if(x == 0)
LCD_Write_Cmd(0x80|y);
else if(x == 1)
LCD_Write_Cmd(0xc0|y);
LCD_Write_Data(dat);
}
//在x行(0-1),y列(0-15)显示数字
void LCD_ShowNum(uint8_t x, uint8_t y,uint8_t num)
{
//设置显示起始位置
if(x == 0)
LCD_Write_Cmd(0x80|y);
else if(x == 1)
LCD_Write_Cmd(0xc0|y);
LCD_ShowChar(x,y,num+'0');
}
LCD1602.h代码如下
c
#ifndef INC_LCD1602_H_
#define INC_LCD1602_H_
#include "system.h"
#include "gpio.h"
#include "stdint.h"
//位带定义
#define LCD_RS PBout(3)
#define LCD_RW PBout(4)
#define LCD_EN PBout(5)
//选择数据寄存器
#define RS_DataR() LCD_RS=1
#define RS_InstructionR() LCD_RS=0
//选择指令寄存器
//读操作
#define RW_Read() LCD_RW=1
//写操作
#define RW_Write() LCD_RW=0
//Enable操作:高电平-读取信息;下降沿-执行指令
#define E_Set() LCD_EN=1
#define E_Rst() LCD_EN=0
void DataDir(char dir);
uint8_t ReadData(void);
void WriteData(uint8_t dat);
void LCD_Busy_Wait(void);
void LCD_Write_Cmd(uint8_t cmd);
void LCD_Write_Data(uint8_t dat);
void LCD_Init(void);
void LCD_ShowString(uint8_t x, uint8_t y, char str);
void LCD_ShowChar(uint8_t x, uint8_t y,uint8_t dat);
void LCD_ShowNum(uint8_t x, uint8_t y,uint8_t num);
#endif
主函数增加

/ USER CODE BEGIN 1 /和 / USER CODE END 1 /增加

USER CODE BEGIN 2和USER CODE END 2之家增加LCD1602初始化


USER CODE BEGIN WHILE和 USER CODE END WHILE增加


/ USER CODE BEGIN 3 / 和 / USER CODE END 3 /


编译0错误警告不影响
"Jsmcu_P03_LCD1602Jsmcu_P03_LCD1602.axf" - 0 Error(s), 8 Warning(s).
实验现象:
