目录

1602 LCD

1602LCD 是工业上常用的模块, 在工厂交通运输设备上经常能见到. 驱动芯片为 HD44780, 1602LCD 的字符显示为两行, 每行16个字符, 字符基于5×8的像素矩阵

PIN脚功能

Pin Name Function
1 Ground 地 (0V)
2 Vcc 供电 5V (4.7V – 5.3V), 注意不能用3.3V供电
3 Vo / VEE 对比度调节. 连接一个可变电阻, 过高无法分辨显示的字符, 过低字符太淡无显示
4 RS 寄存器选择(Register Select), 低电平为命令寄存器, 高电平为数据寄存器
5 Read/write 读写选择, 低电平写入, 高电平读取
6 Enable EN 闲时处于低电平, 当需要执行指令前几个毫秒将EN拉高, 执行完再拉低
7~14 DB0~DB7 8-bit 数据pin
15 Led+ LED 背光电源
16 Led- LED 背光接地

RS (Register Select)

1602LCD有两组寄存器, 命令寄存器和数据寄存器, RS用于数据和命令寄存器的切换

实际使用时, 需要配合 EN 和 R/W

  • 在 EN = 1, R/W = 0, RS = 1 时, 往数据寄存器写入的字符会用于展示.
  • EN = 1, R/W = 0, RS = 0 时, 往命令寄存器写入, 用于发送指令, 例如: 初始化, 清空屏幕, 设置光标位置, 控制显示等

指令编码

以下是各指令位的说明

/*-------------------------------------------------------------
* Instruction D7 D6 D5 D4 D3 D2 D1 D0
* ==============================================
* Display clear 0 0 0 0 0 0 0 1
* Cursor home 0 0 0 0 0 0 1 *
* Entry Mode Set 0 0 0 0 0 1 I/D S
* Display On/Off 0 0 0 0 1 D C B
* Curs/Disp shift 0 0 0 1 S/C R/L * *
* Function Set 0 0 1 DL N F * *
* CG RAM addr set 0 1 ---------Acg---------
* DD RAM addr set 1 -------------Add---------
*
* Meaning:
* * - nonvalid bit
* Acg - CG RAM address (CHARACTER GENERATOR)
* Add - DD RAM address (DATA DISPLAY)
* AC - adress counter
*
* I/D - 1-increment, 0-decrement
* S - 1-display shift, 0-no display shift
* D - 1-display ON, 0-display OFF
* C - 1-cursor ON, 0-cursor OFF
* B - 1-blink ON, 0-blink OFF
* S/C - 1-display shift, 0-cursor movement
* R/L - 1-right shift, 0-left shift
* DL - 1-8 bits data transfer, 0-4 bits data transfer
* N - 1-1/16 duty, 0-1/8 or 1/11 duty
* F - 1-5x10 dot matrix, 0-5x7 dot matrix
* BF - 1-internal operation in progress, 0-display ready
*
\**************************************************************/

配合 EN = 1, R/W = 0, RS = 0 时, 往命令寄存器写入, 可以执行以下指令

No. Hex Binary 命令说明
1 01 0000 0001 清除显示
2 02 0000 001x 光标回原位
3 04 0000 0100 向左移动光标(两个bit分别控制方向左右, 光标还是屏幕)
4 06 0000 0110 向右移动光标
5 05 0000 0101 向右移显示
6 07 0000 0111 向左移动显示
7 08 0000 1000 显示关闭, 光标关闭(三个bit分别控制屏幕显示, 光标显示, 光标闪烁)
8 0A 0000 1010 显示关闭, 光标打开
9 0C 0000 1100 显示打开, 光标关闭
10 0E 0000 1110 显示打开, 光标闪烁
11 0F 0000 1111 显示打开, 光标闪烁
12 10 0001 00xx 将光标位置向左移动(两个bit分别控制光标还是屏幕, 左移还是右移)
13 14 0001 01xx 将光标位置向右移动
14 18 0001 10xx 将整个显示屏向左移动
15 1C 0001 11xx 将整个显示屏向右移动
16 28 0010 10xx 4位, 2行, 5x8矩阵(三个bit分别控制4位还是8位,一行还是两行,5x10还是5x8)
17 20 0010 00xx 4位, 1行, 5x8矩阵
18 38 0011 10xx 8位, 2行, 5×8
19 4x 01xx xxxx 设置 CGRAM 地址, 后面6个bit是地址, 在这个指令之后发送或接收数据
20 8x 1xxx xxxx 设置 DDRAM 地址, 后面7个bit是地址, 在这个指令之后发送或接收数据
21 80 1000 0000 将光标强制移动到开头(第一行)
22 C0 1100 0000 将光标强制移动到开头(第二行)

显示自定义字符

自定义字符要在 CG-RAM 中设置. CG-RAM地址从 0x40 开始, 大小为 64 byte, 可以创建8个字符, 每个字符8个byte. 在这些地址创建字符后, 就可以在LCD中显示.

CG-RAM 地址和命令

No. Addr. Command
0 0x40 0
1 0x48 1
2 0x56 2
3 0x64 3
4 0x72 4
5 0x80 5
6 0x88 6
7 0x96 7

上面的表中可以看到每个字符的起始地址及其打印命令, 例如第一个字符的地址是 [0x40, 0x47], 使用命令0可以输出这个字符, 第二个字符的地址[0x48, 0x55], 使用命令1输出.

自定义字符时, 每个字符是5x8的点阵, 5是列数, 8是行数. 对应字母b的点阵可以表示为

char b[7] = {0x10,0x10,0x16,0x19,0x11,0x11,0x1E};

将其发送到对应的地址就可以创建字符.

I2C 接口 PCF8574 扩展板

因为1602LCD本身刷新率不高, 为节省IO, 可以通过 PCF8574 扩展模块, 将I2C协议转为并口输出. 1602屏直连MCU, 需要至少7个IO(RS, R/W, EN, 4位对应4根数据线)才能驱动起来, 使用 PCF8574 模块只需要2个IO口.

PCF8574 是一个IIC协议的IO口扩展芯片, 包含一个8位准双向口, 一个总线接口, 还有三条地址线. 每个IO口可以单独的分配为输入或者输出. 作为输入时, 可以用于监控中断或者键盘. 作为输出时, 可以用于驱动LED. 可以通过单独的寄存器读取输入端口状态或者配置输出端口状态. PCF8574 的三个地址管脚, 可以分配8个地址, 也就是同一个系统中可以最多存在8个这样的模块.

PCF8574 电流消耗很低, 并且输出锁存, 具有大电流驱动能力, 可直接驱动LED. 还带一个中断接线, 可以作为MCU的外部中断. 通过中断通知MCU 是否有数据输入, 因此 PCF8574 也可以作为一个单被控器.

通过 PCF8574 控制 1602LCD, 可以将命令发送到 I2C 接口, PCF8574 的输出与 1602LCD 的连接为

[tu]

VSS =  Ground
VDD = Connects to VCC on the I2C header
VO = Display contrast. Connects to the potentiometer on the module
RS = P0 on PCF8574
RW = P1 on PCF8574
E = P2 on PCF8574
D0 – D3 no connects
D4 = P4 on PCF8574
D5 = P5 on PCF8574
D6 = P6 on PCF8574
D7 = P7 on PCF8574
A = Backlight Anode. Typically connects to 5V.
K = Backlight Cathode. Connects to ground

基于 PY32F0 的演示

硬件

  • 已焊接 PCF8574 扩展模块的 1602LCD
  • 基于 PY32F0 系列的开发板
  • USB2TTL 用于观察地址输出

接线

大多数 PY32F0 都有 PF1/PF0, 可以通过复用将I2C接口换成其他的pin脚.

注意 PCF8574+1602LCD 供电电压为5V, 3.3V供电无法驱动字符显示. 如果 PY32F0 使用 3.3V 供电, 则需要另接5V电源, 与 PY32F0 共地即可.

PY32          PCF8574 1602 LCD       USB2TTL
PF1/PA9 SCL
PF0/PA10 SDA
VCC -> 5V
GND GND -> GND GND
PA2 RX
PA3 TX

软件

以下的实现基于LL库, 完整的示例代码位于

https://github.com/IOsetting/py32f0-template/tree/main/Examples/LL/I2C/PCF8574_1602LCD

指令和地址的宏定义

/* I2C address
* - 7 bit slave address, left aligned, bits 7:1 are used, LSB bit is not used
* - 0x4E or 0x7E
*/
#define LCD1602_I2C_ADDR 0x7E
/* Delay in millisecond */
#define LCD1602_DELAY 5
/* Register selection */
#define PIN_RS (1 << 0)
/* Read/Write */
#define PIN_RW (1 << 1)
/* Chip enable */
#define PIN_EN (1 << 2)
/* Back light - might not be available on some PCF8574 modules */
#define BACKLIGHT (1 << 3) /* Clear display */
#define LCD1602_CMD_CLEAR_DISPLAY 0b00000001
/* Move cursor home */
#define LCD1602_CMD_HOME 0b00000010 // Entry Mode, Set cursor/display moving direction
#define LCD1602_CMD_DIRECTION_RIGHT 0b00000110
#define LCD1602_CMD_DIRECTION_LEFT 0b00000100
#define LCD1602_CMD_DIRECTION_RIGHT_SHIFT 0b00000111
#define LCD1602_CMD_DIRECTION_LEFT_SHIFT 0b00000101
// Display mode
#define LCD1602_CMD_MODE_OFF 0b00001000
#define LCD1602_CMD_MODE_ON_CURSOR_OFF 0b00001100
#define LCD1602_CMD_MODE_ON_CURSOR_ON 0b00001110
#define LCD1602_CMD_MODE_ON_CURSOR_BLNK 0b00001111
// Cursor/Display Shift
#define LCD1602_CMD_CURSOR_MOVE_LEFT 0b00010000
#define LCD1602_CMD_CURSOR_MOVE_RIGHT 0b00010100
#define LCD1602_CMD_DISPLAY_SHIFT_LEFT 0b00011000
#define LCD1602_CMD_DISPLAY_SHIFT_RIGHT 0b00011100 /* Function set: 4-bit, 1 row, 5X8 matrix */
#define LCD1602_CMD_FUNC_4B_1L_5X8 0b00100000
/* Function set: 4-bit, 2 row, 5X8 matrix */
#define LCD1602_CMD_FUNC_4B_2L_5X8 0b00101000
/* Function set: 8-bit, 1 row, 5X8 matrix */
#define LCD1602_CMD_FUNC_8B_1L_5X8 0b00110000
/* Function set: 8-bit, 2 row, 5X8 matrix */
#define LCD1602_CMD_FUNC_8B_2L_5X8 0b00111000
/* Set/Read CGRAM address */
#define LCD1602_CMD_CGRAM_ADDR 0b01000000
/* Set/Read DDRAM address */
#define LCD1602_CMD_DDRAM_ADDR 0b10000000 /* First row address */
#define LCD1602_DDRAM_ROW0 0b10000000
/* Second row address */
#define LCD1602_DDRAM_ROW1 0b11000000

基础方法

发送指令, 数据和文本

ErrorStatus LCD_SendInternal(uint8_t lcd_addr, uint8_t data, uint8_t flags)
{
ErrorStatus status;
for(;;)
{
status = BSP_I2C_IsDeviceReady(lcd_addr, 5000);
if(status == SUCCESS)
{
break;
}
} uint8_t up = data & 0xF0;
uint8_t lo = (data << 4) & 0xF0; uint8_t data_arr[4];
data_arr[0] = up|flags|BACKLIGHT|PIN_EN;
data_arr[1] = up|flags|BACKLIGHT;
data_arr[2] = lo|flags|BACKLIGHT|PIN_EN;
data_arr[3] = lo|flags|BACKLIGHT; status = BSP_I2C_MasterTransmit(lcd_addr, data_arr, sizeof(data_arr), 5000);
LL_mDelay(LCD1602_DELAY);
return status;
} void LCD_SendCommand(uint8_t lcd_addr, uint8_t cmd)
{
LCD_SendInternal(lcd_addr, cmd, 0);
} void LCD_SendData(uint8_t lcd_addr, uint8_t data)
{
LCD_SendInternal(lcd_addr, data, PIN_RS);
} void LCD_SendString(uint8_t lcd_addr, char *str)
{
while (*str)
{
LCD_SendData(lcd_addr, (uint8_t)(*str));
str++;
}
}

初始化设置

void LCD_Init(uint8_t lcd_addr)
{
// 4-bit mode, 2 lines, 5x8 format
LCD_SendCommand(lcd_addr, LCD1602_CMD_FUNC_4B_2L_5X8);
// display & cursor home
LCD_SendCommand(lcd_addr, LCD1602_CMD_HOME);
// display on, right shift, underline off, blink off
LCD_SendCommand(lcd_addr, LCD1602_CMD_MODE_ON_CURSOR_BLNK);
// move direction right
LCD_SendCommand(lcd_addr, LCD1602_CMD_DIRECTION_RIGHT);
// clear display (optional here)
LCD_SendCommand(lcd_addr, LCD1602_CMD_CLEAR_DISPLAY);
}

功能操作

清除屏幕

LCD_SendCommand(LCD1602_I2C_ADDR, LCD1602_CMD_CLEAR_DISPLAY);

移动光标, 输出文字

// move cursor to 0,0
LCD_SendCommand(LCD1602_I2C_ADDR, LCD1602_DDRAM_ROW0|0);
LCD_SendString(LCD1602_I2C_ADDR, " Using 1602 LCD");
// move cursor to 1,0
LCD_SendCommand(LCD1602_I2C_ADDR, LCD1602_DDRAM_ROW1|0);
LCD_SendString(LCD1602_I2C_ADDR, " over I2C bus");

通过 CGRAM 设置 自定义字符

// CGRAM test
for (i = 0; i < 8; i++)
{
LCD_SetCGRAM(LCD1602_I2C_ADDR, i, &cgrom[i * 8]);
}

展示自定义字符

for (i = 0; i < 8; i++)
{
LCD_SendData(LCD1602_I2C_ADDR, i);
LL_mDelay(200);
}

显示整体左右平移

// Shift display test
LCD_SendCommand(LCD1602_I2C_ADDR, LCD1602_CMD_CLEAR_DISPLAY);
LL_mDelay(500);
LCD_SendCommand(LCD1602_I2C_ADDR, LCD1602_DDRAM_ROW0|9);
LCD_SendString(LCD1602_I2C_ADDR, "Shift");
LCD_SendCommand(LCD1602_I2C_ADDR, LCD1602_DDRAM_ROW1|8);
LCD_SendString(LCD1602_I2C_ADDR, "<<<->>>");
LL_mDelay(500);
for (i = 0; i < 8; i++)
{
LCD_SendCommand(LCD1602_I2C_ADDR, LCD1602_CMD_DISPLAY_SHIFT_LEFT);
LL_mDelay(200);
}
LL_mDelay(500);
for (i = 0; i < 8; i++)
{
LCD_SendCommand(LCD1602_I2C_ADDR, LCD1602_CMD_DISPLAY_SHIFT_RIGHT);
LL_mDelay(200);
}

左右移动光标

// Move cursor test
for (i = 0; i < 11; i++)
{
LCD_SendCommand(LCD1602_I2C_ADDR, LCD1602_CMD_CURSOR_MOVE_LEFT);
LL_mDelay(200);
}
LL_mDelay(500);
for (i = 0; i < 12; i++)
{
LCD_SendCommand(LCD1602_I2C_ADDR, LCD1602_CMD_CURSOR_MOVE_RIGHT);
LL_mDelay(200);
}

常见问题

1. 屏幕不显示

不显示的原因有很多, 如果确认代码和接线无误, 可能的原因有

  1. 检查1602LCD的供电电压是不是5V, 在3.3V下无法驱动, 只有背光没有字符
  2. 检查I2C地址是否正确. 查看串口扫描到的实际的设备I2C地址, 是否和程序中的地址一致, 通常情况下, PCF8574T 的地址是 0x4E, PCF8574AT 的地址是 0x7E

2. 字符显示乱码

对于部分屏幕, 启动时需要等待较长的延时, 如果等待时间不足, 会导致输出乱码, 在上电后过几秒再按 PY32F0 的 RESET 键重启, 就能恢复正常显示. 在代码中需要增加延时时间.

参考

普冉PY32系列(六) 通过I2C接口驱动PCF8574扩展的1602LCD的更多相关文章

  1. 普冉PY32系列(一) PY32F0系列32位Cortex M0+ MCU简介

    目录 普冉PY32系列(一) PY32F0系列32位Cortex M0+ MCU简介 普冉PY32系列(二) Ubuntu GCC Toolchain和VSCode开发环境 PY32F0系列上市其实相 ...

  2. 普冉PY32系列(二) Ubuntu GCC Toolchain和VSCode开发环境

    目录 普冉PY32系列(一) PY32F0系列32位Cortex M0+ MCU简介 普冉PY32系列(二) Ubuntu GCC Toolchain和VSCode开发环境 以下介绍PY32F0系列在 ...

  3. 普冉PY32系列(三) PY32F002A资源实测 - 这个型号不简单

    目录 普冉PY32系列(一) PY32F0系列32位Cortex M0+ MCU简介 普冉PY32系列(二) Ubuntu GCC Toolchain和VSCode开发环境 普冉PY32系列(三) P ...

  4. SpringCloud系列六:Feign接口转换调用服务(Feign 基本使用、Feign 相关配置)

    1.概念:Feign 接口服务 2.具体内容 现在为止所进行的所有的 Rest 服务调用实际上都会出现一个非常尴尬的局面,例如:以如下代码为例: Dept dept = this.restTempla ...

  5. C51 I2C接口驱动,IO口模拟I2C(主+从)

    Master.asm ;/*------------------------------------------------------------------*/ ;/* --- STC MCU I ...

  6. SQL Server 2008空间数据应用系列六:基于SQLCRL的空间数据可编程性

    原文:SQL Server 2008空间数据应用系列六:基于SQLCRL的空间数据可编程性 友情提示,您阅读本篇博文的先决条件如下: 1.本文示例基于Microsoft SQL Server 2008 ...

  7. java基础解析系列(六)---深入注解原理及使用

    java基础解析系列(六)---注解原理及使用 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析系列(二)---Integer ja ...

  8. java基础解析系列(六)---注解原理及使用

    java基础解析系列(六)---注解原理及使用 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析系列(二)---Integer缓存及 ...

  9. 【C++自我精讲】基础系列六 PIMPL模式

    [C++自我精讲]基础系列六 PIMPL模式 0 前言 很实用的一种基础模式. 1 PIMPL解释 PIMPL(Private Implementation 或 Pointer to Implemen ...

  10. Netty4.x中文教程系列(六) 从头开始Bootstrap

    Netty4.x中文教程系列(六) 从头开始Bootstrap 其实自从中文教程系列(五)一直不知道自己到底想些什么.加上忙着工作上出现了一些问题.本来想就这么放弃维护了.没想到有朋友和我说百度搜索推 ...

随机推荐

  1. Qt的三套无边框窗体的方案:可按比例拖拽窗体大小的无边框窗口和几个常见的无边框实例

    一.可按比例拖拽窗体大小的无边框窗口 前几天接到一个需求,就是视频广播的窗体画面要可以拖拽,修改成了可以拖拽全屏的窗口之后,又有一个问题:视频画面也被拉伸了. 由于视频画面是有比例的,所以我们最好也能 ...

  2. 记一次 .NET 某工控MES程序 崩溃分析

    一:背景 1.讲故事 前几天有位朋友找到我,说他的程序出现了偶发性崩溃,已经抓到了dump文件,Windows事件日志显示的崩溃点在 clr.dll 中,让我帮忙看下是怎么回事,那到底怎么回事呢? 上 ...

  3. 高可用系列文章之三 - NGINX 高可用实施方案

    前文链接 高可用系列文章之一 - 概述 - 东风微鸣技术博客 (ewhisper.cn) 高可用系列文章之二 - 传统分层架构技术方案 - 东风微鸣技术博客 (ewhisper.cn) 四 NGINX ...

  4. 【Spring专题】「开发指南」夯实实战基础功底之解读logback-spring.xml文件的详解实现

    logback的maven配置 <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j- ...

  5. uniapp 微信小程序 改变头部的信号、时间、电池显示颜色

    修改前 修改后 修改方法:"navigationBarTextStyle":"white"

  6. Mybatis-plus实现数据库的增删改查操作

    目录 1.MybatisPlus简介 2.MybatisPlus注解介绍 3.常用方法 4.SpringBoot整合MybatisPlus实现增删改查的一个简单Demo 5.参考资料 1.Mybati ...

  7. C/S UDP通信实践踩坑记录与对于ICMP的进一步认识

    背景 最近有个业务场景需要服务端(简称S)与客户端(简称C)设计一套基于UDP的通信协议--要求尽可能快的前提下可容忍一定丢包率,得以比较深入地学习和了解UDP通信和实践,在开发调试期间先后碰到了C端 ...

  8. ArcGIS Python判断数据是否存在

    判断是程序编写的一个基本的操作,也是增强程序稳定性的重要方式.在ArcPy处理数据时,要保证数据存在才能做后续的操作,为源GIS提示使用arcpy自带的Exists函数可判断要素类.表.数据集.sha ...

  9. S2-008

    漏洞名称 S2-008(CVE-2012-0392) 远程代码执行漏洞 利用条件 Struts 2.0.0 - Struts 2.3.17 漏洞原理 S2-008 涉及多个漏洞,Cookie 拦截器错 ...

  10. [Leetcode]设计循环队列

    题目   代码 class MyCircularQueue { public: /** Initialize your data structure here. Set the size of the ...