【Proteus】:LCD1602仿真实验基于STM32CubeMX
LCD1602是一种工业字符型液晶,能够同时显示16x02即32个字符。LCD1602液晶显示原理: LCD1602液晶显示的原理是利用液晶的物理特性,通过电压对其显示区域进行控制,有电就有显示,这样即可以显示出图形。1602液晶也叫1602字符型液晶,它是一种专门用来显示字母、数字、符号等的点阵型液晶模块。LCD1602则是指显示内容为16 * 2,即可以显示两行、每行可以显示 16 个字符的液
·
前言
时不可以苟遇,道不可以虚行。
一、LCD1602介绍
LCD1602
是一种工业字符型液晶,能够同时显示16x02
即32
个字符。LCD1602液晶显示原理: LCD1602液晶显示的原理是利用液晶的物理特性,通过电压对其显示区域进行控制,有电就有显示,这样即可以显示出图形。1602液晶也叫1602字符型液晶,它是一种专门用来显示字母、数字、符号等的点阵型液晶模块。LCD1602
则是指显示内容为16 * 2
,即可以显示两行、每行可以显示 16 个字符的液晶模块。
1、引脚说明:
- 下图是在 proteus 中的 LCD1602 屏幕的样子,少了两个背光引脚:
引脚 | 功能 |
---|---|
VSS | 地电源 |
VDD | 接 5 V 电源 |
VEE/VL | 液晶显示器对比度调整端,接正电源时对比度最弱,接地时对比度最高,对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度。 |
RS | 指令/数据选择信号,高电平时选择数据寄存器、低电平时选择指令寄存器 |
RW | 读写信号线,高电平时进行读操作,低电平时进行写操作 |
E | 使能端,当E端由高电平跳变成低电平时,液晶模块执行命令 |
D0~D7 | 双向数据线,传输信息 |
BLA | 背光源正极 |
BLK | 背光源负极 |
2、指令集
二、工程建立
准备:
- proteus 软件:proteus 8.13
- STM32CubeMX 软件:6.5
- Keil MDK
1、新建仿真工程
- 所需元器件查找:
元器件 | 符号 |
---|---|
LCD1602 | LM016L |
电位器(滑动变阻器) | POT |
STM32单片机 | STM32F103R6 |
- 仿真连线如下图所示:
- 供电网配置:
2、STM32cubemx新建工程
1、 选择芯片型号:
2、时钟配置
3、引脚输出配置
4、生成代码
三、编写代码
- 在 main.c 中:
/* USER CODE BEGIN Includes */
#include "LCD1602.h"
/* USER CODE END Includes */
/* USER CODE BEGIN 2 */
LCD_Init();
LCD_Puts(0,0,"I am successful.");
/* USER CODE END 2 */
- LCD1602.h:
#ifndef __LCD1602_H_
#define __LCD1602_H_
#include "main.h"
#define _LCD_COLS 16
#define _LCD_ROWS 2
/***** GPIOB3 H:data;L:command ******/
#define LCD1602_RS_DATA HAL_GPIO_WritePin(GPIOB,GPIO_PIN_3,GPIO_PIN_SET)
#define LCD1602_RS_CMD HAL_GPIO_WritePin(GPIOB,GPIO_PIN_3,GPIO_PIN_RESET)
/***** GPIOB4 H:read;L:write ******/
#define LCD1602_RW_READ HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4,GPIO_PIN_SET)
#define LCD1602_RW_WRITE HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4,GPIO_PIN_RESET)
/***** GPIOB5 ******/
#define LCD1602_E_HIGH HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_SET)
#define LCD1602_E_LOW HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_RESET)
#define LCD1602_DATA(x) GPIOB->ODR=(GPIOB->ODR & 0x00ff) | (x<<8)
/* 指令集 */
#define LCD_CLEARDISPLAY 0x01 //清屏指令
#define LCD_RETURNHOME 0x02 //地址计数器 AC=0;(此时地址为 0x80) 光标归原点,但是 DDRAM 中断内容不变
#define LCD_ENTRYMODESET 0x04 //输入模式设置
#define LCD_DISPLAYCONTROL 0x08 //只开显示
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x20
#define LCD_SETCGRAMADDR 0x40
#define LCD_SETDDRAMADDR 0x80
/* 显示入口模式的标志 */
#define LCD_ENTRYRIGHT 0x00
#define LCD_ENTRYLEFT 0x02
#define LCD_ENTRYSHIFTINCREMENT 0x01
#define LCD_ENTRYSHIFTDECREMENT 0x00
/* 开关控制标志 */
#define LCD_DISPLAYON 0x04
#define LCD_CURSORON 0x02
#define LCD_BLINKON 0x01
#define LCD_DISPLAYMOVE 0x08
#define LCD_CURSORMOVE 0x00
#define LCD_MOVERIGHT 0x04
#define LCD_MOVELEFT 0x00
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_2LINE 0x08
#define LCD_1LINE 0x00
#define LCD_5x10DOTS 0x04
#define LCD_5x8DOTS 0x00
typedef struct {
uint8_t DisplayControl;
uint8_t DisplayFunction;
uint8_t DisplayMode;
uint8_t currentX;
uint8_t currentY;
} LCD_Options_t;
void LCD_Init(void); //屏幕初始化
void LCD_DisplayOn(void);
void LCD_DisplayOff(void);
void LCD_Clear(void); //清屏
void LCD_Puts(uint8_t x, uint8_t y, char* str); //显示字符串
void LCD_BlinkOn(void);
void LCD_BlinkOff(void);
void LCD_CursorOn(void);
void LCD_CursorOff(void);
void LCD_ScrollLeft(void);
void LCD_ScrollRight(void);
void LCD_CreateChar(uint8_t location, uint8_t* data);
void LCD_PutCustom(uint8_t x, uint8_t y, uint8_t location);
void LCD_Put(uint8_t Data);
#endif
- LCD1602.c:
#incldue “LCD1602.h”
static void LCD_Cmd(uint8_t cmd);
static void LCD_Data(uint8_t data);
static void LCD_CursorSet(uint8_t col, uint8_t row);
static void LCD_EnBlink(void);
static LCD_Options_t LCD_Opts;
//us级Delay
void LCD_Delay_us(uint16_t us)
{
uint32_t Div = (SysTick->LOAD+1)/1000;
uint32_t StartMicros = HAL_GetTick()*1000 + (1000- SysTick->VAL/Div);
while((HAL_GetTick()*1000 + (1000-SysTick->VAL/Div)-StartMicros < us));
}
//ms级Delay
void LCD_Delay_ms(uint8_t ms)
{
HAL_Delay(ms);
}
//LCD初始化
void LCD_Init(void)
{
/* Set cursor pointer to beginning for LCD */
LCD_Opts.currentX = 0;
LCD_Opts.currentY = 0;
LCD_Opts.DisplayFunction = LCD_8BITMODE | LCD_5x8DOTS | LCD_1LINE;
if (_LCD_ROWS > 1)
LCD_Opts.DisplayFunction |= LCD_2LINE;
/* Set # lines, font size,8BITMODE,etc. */
LCD_Cmd(LCD_FUNCTIONSET | LCD_Opts.DisplayFunction);
/* Turn the display on with no cursor or blinking default */
LCD_Opts.DisplayControl = LCD_DISPLAYON;
LCD_DisplayOn();
/* Default font directions 文字不动,地址自动+1*/
LCD_Opts.DisplayMode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
LCD_Cmd(LCD_ENTRYMODESET | LCD_Opts.DisplayMode);
LCD_Clear();
LCD_Delay_ms(5);
}
//清屏
void LCD_Clear(void)
{
LCD_Cmd(LCD_CLEARDISPLAY);
LCD_Delay_ms(5);
}
//显示一个string,支持换行
void LCD_Puts(uint8_t x, uint8_t y, char* str)
{
LCD_CursorSet(x, y);
while (*str) {
if (LCD_Opts.currentX >= _LCD_COLS)/*移动到下一行*/ {
LCD_Opts.currentX = 0;
LCD_Opts.currentY++;
LCD_CursorSet(LCD_Opts.currentX, LCD_Opts.currentY);
}
if (*str == '\n') /*换行,列对其*/{
LCD_Opts.currentY++;
LCD_CursorSet(LCD_Opts.currentX, LCD_Opts.currentY);
} else if (*str == '\r') /*回车,换行回行首*/{
LCD_CursorSet(0, LCD_Opts.currentY);
} else {
LCD_Data(*str);
LCD_Opts.currentX++;
}
str++;
}
}
void LCD_DisplayOn(void)
{
LCD_Opts.DisplayControl |= LCD_DISPLAYON;
LCD_Cmd(LCD_DISPLAYCONTROL | LCD_Opts.DisplayControl);
}
void LCD_DisplayOff(void)
{
LCD_Opts.DisplayControl &= ~LCD_DISPLAYON;
LCD_Cmd(LCD_DISPLAYCONTROL | LCD_Opts.DisplayControl);
}
void LCD_BlinkOn(void)
{
LCD_Opts.DisplayControl |= LCD_BLINKON;
LCD_Cmd(LCD_DISPLAYCONTROL | LCD_Opts.DisplayControl);
}
void LCD_BlinkOff(void)
{
LCD_Opts.DisplayControl &= ~LCD_BLINKON;
LCD_Cmd(LCD_DISPLAYCONTROL | LCD_Opts.DisplayControl);
}
void LCD_CursorOn(void)
{
LCD_Opts.DisplayControl |= LCD_CURSORON;
LCD_Cmd(LCD_DISPLAYCONTROL | LCD_Opts.DisplayControl);
}
void LCD_CursorOff(void)
{
LCD_Opts.DisplayControl &= ~LCD_CURSORON;
LCD_Cmd(LCD_DISPLAYCONTROL | LCD_Opts.DisplayControl);
}
void LCD_ScrollLeft(void)
{
LCD_Cmd(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
}
void LCD_ScrollRight(void)
{
LCD_Cmd(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
}
void LCD_CreateChar(uint8_t location, uint8_t *data)
{
uint8_t i;
/* We have 8 locations available for custom characters */
location &= 0x07;
LCD_Cmd(LCD_SETCGRAMADDR | (location << 3));
for (i = 0; i < 8; i++) {
LCD_Data(data[i]);
}
}
void LCD_PutCustom(uint8_t x, uint8_t y, uint8_t location)
{
LCD_CursorSet(x, y);
LCD_Data(location);
}
static void LCD_EnBlink(void)
{
LCD1602_E_HIGH;
LCD_Delay_us(50);
LCD1602_E_LOW;
LCD_Delay_us(50);
}
static void LCD_Cmd(uint8_t cmd)
{
LCD1602_RS_CMD;
LCD1602_RW_WRITE;
LCD1602_DATA(cmd);
LCD_EnBlink();
}
static void LCD_Data(uint8_t data)
{
LCD1602_RS_DATA;
LCD1602_RW_WRITE;
LCD1602_DATA(data);
LCD_EnBlink();
}
static void LCD_CursorSet(uint8_t col, uint8_t row)
{
uint8_t row_offsets[] = {0x00, 0x40, 0x14, 0x54};
if (row >= _LCD_ROWS)
row = 0;
LCD_Opts.currentX = col;
LCD_Opts.currentY = row;
LCD_Cmd(LCD_SETDDRAMADDR | (col + row_offsets[row]));
}
void LCD_Put(uint8_t Data)
{
LCD_Data(Data);
}
四、结果
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
已为社区贡献7条内容
所有评论(0)