每日一言
你读过的书、走过的路、流过的汗,终将成就独一无二的你。
硬件:LCD1602液晶显示
非标协议外设
概述
LCD1602(Liquid Crystal Display)是一种工业字符型液晶,能够同时显示 16×02 即 32 字符(16列两行)
那我们会发现明明就是屏幕上面只有32个位置来存放字符啊,那为什么要8位呢,明明5位就好啦(2的5次方等于32),因为其实这个他是可以移位的,就是其实不止我们看到的屏幕那么大的地方可以存放数据,后面还有看解释:
- 容量:80 字节(地址范围 0x00~0x4F),但仅前 32 字节对应屏幕可见位置。
- 映射关系:
屏幕位置 | 地址范围 | 实际显示区域 |
第一行 | 0x00~0x27 | 0x00~0x0F(前 16 字节) |
第二行 | 0x40~0x67 | 0x40~0x4F(前 16 字节) |
LCD1602 的 8 位数据线(D0~D7)中,每一位都独立代表 1 个二进制数据位,共同组成 8 位数据(即 1 字节),用于传输指令或显示内容
反正就用8位数据线(代表8位数据)(当然也有4位的,4位就是每次每次传输的字节是8位的一半)
我们的接线
因为写入显示地址是要求最高位D7恒定位高电平
所以要在05这个位置写入字符的话,那其实这个位置的地址为0x85(0x80+0x05)也就是0x80+5 1000 0101
看时序图
写操作(我们的地址和内容其实都是写的操作,写到LCD1602里面)
RS为1的时候为内容
RS为0的时候是地址/指令
这个8位数据线就很像SBUF的作用,因为这个LCD1602是没有SBUF的所以我们要等于是做了一个这样的功能,用这个8位数据线,每一条数据线代表一个位,
BF为忙标志位 1代表忙 0代表不忙
LCD1602 的状态寄存器(用于读取忙标志 BF)和数据寄存器(用于写入显示数据)是两个独立的寄存器,它们的最高位功能不同,不会相互影响。
BF 的自动变化:
当 LCD 执行内部操作(如清屏、初始化)时,硬件自动将 BF 置 1,表示忙碌。
操作完成后,硬件自动将 BF 置 0,表示空闲。
MCU 只需循环读取 BF,无需手动修改它。
精髓所在!!!
LCD1602 的初始化操作与忙信号检测是紧密关联的逻辑流程。初始化过程中需要执行清屏、显示模式设置等指令,这些操作需要一定时间完成,在此期间 LCD 处于 “忙碌” 状态(忙信号有效)。而忙信号检测的作用正是确认 LCD 是否已完成初始化及相关操作 —— 只有当检测到忙信号变为 “不忙” 时,才能确保后续的数据写入或指令发送能被正确执行。简而言之,初始化操作会触发 LCD 的忙碌状态,而忙信号检测则是判断初始化是否完成的关键依据,二者通过 “操作耗时→状态检测→后续执行” 的逻辑链条实现联动,以保证 LCD 显示控制的准确性和稳定性。
案例1:LCD实现显示一个字符C
代码解释
前期工作:我们先将RS RW 还有E 还有8位数据位都先做好工作
这边我们 将8位数据位用P0组来表示,因为刚好我的P0组够用这个8根数据线
然后我们用宏定义 #define dataBuffer P0 这样来表示 ,因为我们的数据就是存放在这个dataBuffer里面的,然后这个P0组所有的数据都汇聚到这边,所以dataBuffer 就好像是一个SBUF的作用 ,也是后面的写操作要将指令写到这个dataBuffer里面做铺垫
要将写内容和写指令的代码写出来,这边我们将它们封装成了两个函数data_Write_cmd 和data_Write_data
data_Write_cmd 将指令写到LCD1602的函数
这个函数我们通过手册知道写指令的操作需要将RS置为低电平,因为我们需要选择指令寄存器,RW呗是要一直为低电平因为RW为低电平就是写的操作
后面就要看时序图,和参数了
我们根据时序图写E和数据的写入,和变化
数据在E变高电平之前就进行了数据的写入,那么dataBuffer = cmd这个指令就要在E = 1之前写出来,后面就是我们根据参数,来给时间,那么这边他的单位是ns,我们单片机给一个_nop_()就够了,1个nop代表1us,
所以我们根据他的最低时间来穿插nop()函数
这个函数我们通过手册知道写内容的操作需要将RS置为高电平,因为我们需要选择数据寄存器,RW呗是要一直为低电平因为RW为低电平就是写的操作
写内容和写指令,都是写的操作,所以时序图是一样的,只是RS不同,也就是寄存器不同需要选择对应的寄存器,所以改一下RS为高电平就好了
随后我们根据手册知道,还需要进行LCD初始化(这个是初始化的代码,和命令和意图)
又随后我们还需要进行忙信号的检测
那么忙信号,就是我们进行初始化,的那些操作所需要耗费的时间,在进行初始化的时候,忙信号就会为1,初始化结束的时候,不忙就会为0 ..
我们来写忙信号封装的函数
通过手册得知,这边说明一下
重点看这个
LCD1602 的指令寄存器(用于读取忙标志 BF)指令寄存器,读的操作 所以是RS = 0; RW = 1;
那么我们肯定知道我们去读取忙信号是读的操作
检测BF的话其实就是检测bit7为1,那么就是先检测bit7是否为1,为1的时候说明还在初始化(还忙),那么我们就让他卡在循环那,不断检测,直到bit7为0,说明忙信号为0(不忙了),不忙了我们才让他出不断检测忙信号的循环。说明这样的话我们需要将检测忙信号做一个while循环就像这样:
什么意思呢?就是刚开始就是忙的嘛所以我们先设置tmp和dataBuffer=0x80,为什么都设置0x80呢? 1、让强制进入检测忙信号的循环 2、因为我们检测忙信号,只是检测最高位bit7的位置是否是1,所以dataBuffer设置为0x80,然后这个dataBuffer他是总线嘛,是传输数据的,当不忙的时候,指令寄存器就会传输数据为0x某某,那么bit7就不会等于1等于0了,那么随之改变的tmp也会改变,那么tmp & 0x80就会等于0了(按位与是有0为0,全1为1),然后就跳出循环了,那么我们的写操作就可以开始进行了(不管是写指令还是写内容都要先开始检测忙信号,不检测的话会导致数据丢失)
所以现在我们确认好根据时序图来写代码
最后main函数里面:
1定义一个位置和定义一个内容
2调用初始化函数,在调用3写指令函数4写内容函数
案例2:LCD实现显示一句话
字符串的话也是一样的,基本上大差不差
在原来代码上面添加这些代码
要说的点在
这个地址哈0x80+6 那么这个就是很多工业的液晶显示的习惯就是 基址+移动
比如想显示在第一行 基址(0x80+0x00)+移动(6) 向右边偏移6个位置,如果不习惯的话也可以直接写成0x86
所以这个0x80+col 是0x80+6的这个写法不用太计较
先写地址,写完地址后写入内容,我们输入一句话(字符数组,在其他语言里叫做字符串)肯定是用指针啊,用指针遍历是我们的经典做法
每一行有每一行的地址的写法,所以我们用switch