前言
时不可以苟遇,道不可以虚行。
一、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、生成代码
三、编写代码
#include "LCD1602.h"
LCD_Init();
LCD_Puts(0,0,"I am successful.");
#ifndef __LCD1602_H_
#define __LCD1602_H_
#include "main.h"
#define _LCD_COLS 16
#define _LCD_ROWS 2
#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)
#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)
#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
#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
#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;
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));
}
void LCD_Delay_ms(uint8_t ms)
{
HAL_Delay(ms);
}
void LCD_Init(void)
{
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;
LCD_Cmd(LCD_FUNCTIONSET | LCD_Opts.DisplayFunction);
LCD_Opts.DisplayControl = LCD_DISPLAYON;
LCD_DisplayOn();
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);
}
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;
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);
}
四、结果
|