前言

时不可以苟遇,道不可以虚行。


一、LCD1602介绍

  • LCD1602 是一种工业字符型液晶,能够同时显示 16x0232 个字符。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、新建仿真工程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 所需元器件查找:
元器件符号
LCD1602LM016L
电位器(滑动变阻器)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);
}

四、结果

在这里插入图片描述

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐