
LCD1602是工业字符液晶,可以同时显示16x02或32个字符。LCD1602液晶显示的原理是利用液晶的物理特性,通过电压来控制其显示区域,即可以显示图形。在本章中,我们将讨论LCD1602液晶屏驱动程序的设计与实现。
1、功能概述LCD1602液晶又叫1602字符液晶,是一种仅用于显示字母、数字和符号的点阵液晶模块。LCD1602中的存储器一般有三种:CGROM、CGRAM和DDRAM。其中DDRAM(显示数据RAM)是显示数据RAM,用来寄存要显示的字符码。共80字节,地址与屏幕的对应关系如下所示:
LCD1602使用三条控制线:EN、RW和RS。其中EN的作用实际上是中线的作用,RW和RS表示读写的方向和内容。在读取数据(或忙标志)期间,EN线必须保持高电平;在写指令(或数据)的过程中,必须在EN线上发送正脉冲。RW和RS的组合有四种情况,分别对应四种运算:
(1)、RS=0和RW=0——表示向LCD写入指令。
(2),RS=0和RW=1——表示读取繁忙标志。
(3) RS=1、RW=0——表示向LCD写入数据。
(4) RS=1、RW=1——表示从LCD读取数据。
LCD1602使用指令代码来区分不同的操作。主要有两种:一种是初始化配置的指令码;第二个是数据控制的指令代码。LCD初始化配置的第一种指令代码,基本上是在系统启动时,对LCD1602进行一次性配置。第二类数据操作的指令代码主要用于设置数据指针的位置,实现和明确真实信息等。这两种类型的脚本在使用上并没有太大的区别,后面我们会详细解释。
2、驱动程序设计与实现我们已经了解了LCD1602的基本情况。接下来,我们将介绍LCD1602的基本知识,并设计LCD602的驱动程序。
2.1、对象定义我们需要在使用对象之前获取它。同样,如果我们想要LCD1602液晶屏,首先需要定义LCD1602液晶屏的对象。
2.1.1、对象的抽象我们需要先分析一下LCD1602液晶屏对象的基本特征。一般来说,一个对象至少包含两个特征:属性和操作。接下来我们就从这两个方面来思考一下LCD1602液晶屏的对象。
先考虑属性。作为属性,它们必须用于识别或记录对象的特征。让我们考虑一下LCD1602的物体属性。对于LCD1602显示屏,其主要功能是显示信息。为了识别当前状态,我们将状态寄存器的值作为对象的属性。
然后我们还需要考虑LCD1602液晶屏对象的操作。首先我们需要控制LCD1602的三个控制引脚来实现对LCD1602的控制,但是这些控制引脚的操作与具体的操作平台有关,所以我们把它们作为对象的操作。同样,我们还需要向LCD1602发送命令和数据,并从LCD1602获取消息,而读取和发送依赖于具体的操作平台,所以我们把它们视为LCD1602的两个操作。我们在操作LCD1602时,不可避免的要控制时序,所以需要有延时操作,但是我们都知道演示操作依赖于具体的软硬件平台,所以我们把延时处理函数作为对象操作。
根据以上对LCD1602液晶显示器的分析,我们可以将LCD1602液晶显示器的对象类型定义如下:
typedef struct LCD 1602对象{ uint8 _ tstatusLCD1602PinSetType * PinHandlevoid(*SendByte)(uint8_t数据);uint 8 _ t(* GetByte)(void);void(* dela Yus)(volatile uint 32 _ t period);//微秒延迟函数void(* delay mes)(volatile uint 32 _ ttime);//毫秒延时函数} LCD1602ObjectType2.1.2、对象初始化我们知道一个对象不能只通过声明来使用,需要先对其进行初始化,所以这里考虑LCD1602液晶屏对象的初始化函数。一般来说,初始化函数需要处理几个问题。首先,检查输入参数是否合理;二是给对象的属性赋初值;第三是对对象进行必要的初始化配置。基于此,我们设计LCD1602液晶屏对象的初始化函数如下:
Void LCD 1602初始化(LCD 1602对象类型* LCD,//LCD 1602对象指针LCD1602PinSetType *PinHandle,//控制引脚操作函数指针数组LCD1602SendByteType sendByte,//发送一个字节函数指针LCD1602GetByteType getByte,//读取一个字节函数指针LCD1602DelayType delayus,//微秒延迟函数指针LCD1602DelayType delayms //毫秒延迟函数指针)} LCD-pin handle=pin handle;LCD-send byte=send byte;LCD-get byte=get byte;LCD-dela Yus=dela Yus;LCD-delay ms=delay ms;LCD-Delayus(15);WriteCommandToLCD1602(lcd,0x 38);LCD-delay ms(5);WriteCommandToLCD1602(lcd,0x 38);LCD-delay ms(5);WriteCommandToLCD1602(lcd,0x 38);LCD-delay ms(10);WriteCommandToLCD1602(lcd,0x 38);//显示模式设置LCD-delay ms(10);WriteCommandToLCD1602(lcd,0x 08);//显示关闭LCD-delay ms(10);WriteCommandToLCD1602(lcd,0x 01);//显示清晰的LCD-delay ms(10);WriteCommandToLCD1602(lcd,0x 06);//显示光标移动位置的LCD-delay ms(10);WriteCommandToLCD1602(lcd,0x0C);//显示on和光标设置lcd-PinHandle[LCD1602_EN](低);LCD-status=readstatusfromlcd 1602(LCD);}2.2、对象操作我们已经完成了LCD1602的对象类型定义和对象初始化函数的设计。但是我们的主要目标是获取对象的信息,然后还要实现对LCD1602的各种操作。
2.2.1、数据读取操作我们需要从LCD1602液晶显示器中获取某些数据,包括读取状态信息和数据信息。唯一不同的是RS控制引脚的电平,其他操作相同。读取数据的时序图如下:
根据我们前面的描述和上面的序列图,我们可以实现如下获取状态信息和数据的操作功能:
static uint 8 _ t readstatusfromlcd 1602(LCD 1602对象类型* LCD){ uint 8 _ t status;lcd-PinHandle[LCD1602_RS](低);lcd-PinHandle[LCD1602_RW](高);lcd-PinHandle[LCD1602_EN](高);LCD-Delayus(20);status=LCD-get byte();lcd-PinHandle[LCD1602_EN](低);LCD-Delayus(5);退货状态;}static uent 8 _ t readdatafromlcd 1602(LCD 1602对象类型* LCD){ uint 8 _ tdata;lcd-PinHandle[LCD1602_RS](高);lcd-PinHandle[LCD1602_RW](高);lcd-PinHandle[LCD1602_EN](高);LCD-Delayus(20);data=LCD-get byte();lcd-PinHandle[LCD1602_EN](低);LCD-Delayus(5);返回数据;}2.2.2、写入数据操作如果我们想要显示我们想要的信息,我们需要将命令和数据发送到LCD1602显示屏。发送数据和发送命令的区别只是RS控制引脚的操作级别,具体操作顺序如下:
Static Void Write command CD 1602(LCD 1602对象类型* LCD,uint 8 _ t command){ LCD-pin handle[LCD 1602 _ RS](低);lcd-PinHandle[LCD1602_RW](低);lcd-SendByte(命令);lcd-PinHandle[LCD1602_EN](高);LCD-Delayus(20);lcd-PinHandle[LCD1602_EN](低);LCD-Delayus(5);}静态void写入数据CD 1602 (LCD 1602对象类型* LCD,uint 8 _ tdata){ LCD-pin handle[LCD 1602 _ RS](高);lcd-PinHandle[LCD1602_RW](低);lcd-SendByte(数据);lcd-PinHandle[LCD1602_EN](高);LCD-Delayus(20);lcd-PinHandle[LCD1602_EN](低);LCD-Delayus(5);}3、驱动我们已经实现了LCD1602的LCD驱动,接下来需要设计一个简单的应用来验证这个驱动设计是否正确。
3.1、使用基于对象的操作来声明和初始化对象,我们需要先获取这个对象,所以我们需要使用之前定义的LCD1602 LCD对象类型来声明一个LCD1602 LCD对象变量。具体操作格式如下:
LCD 1602对象型液晶显示器;
声明这个对象变量不能立即使用,我们还需要用驱动中定义的初始化函数初始化这个变量。该初始化功能所需的输入参数如下:
Ldc1602对象类型* LCD,//LC1602对象指针LCD1602PinSetType *PinHandle,///控制引脚操作函数指针数组LCD1602SendByteType sendByte,///发送一个字节函数指针LCD1602GetByteType getByte,//读取一个字节函数指针LCD1602DelayType delayus,//微秒延迟函数指针LCD1602DelayType delayms //毫秒延迟函数指针我们已经定义了这些参数和对象变量。主要是我们需要定义几个函数,并以函数指针为参数。这些功能的类型如下:
TypeDefvoid(* LCD 1602 pinsettype)(uint 8 _ tvalue);typedefvoid(* LCD 1602 sendbytetype)(uint 8 _ tdata);typedefint 8 _ t(* LCD 1602 getbytetype)(void);TypeDefvoid (* LCD1602延迟类型)(volatile uint 32 _ t time);对于这些功能,我们可以根据风格来定义,具体操作可能与使用的硬件平台有关。控制管脚的运算功能实际上有三个,组成一个函数指针数组,分别对应RS、RW、EN控制管脚。具体功能定义如下:
LCD1602PinSetType引脚集[3]={RsPinOperation,RwPinOperation,EnPinOperation };static void rspinoperation(uint 8 _ tvalue){ Hal _ gpio _ write pin(gpio id,gpio _ pin _ 7,(gpio _ pinstate)值);}static void rwpinoperation(uint 8 _ tvalue){ Hal _ gpio _ write pin(gpio id,gpio _ pin _ 8,(gpio _ pinstate)值);}static void enpinoperation(uint 8 _ tvalue){ Hal _ gpio _ write pin(gpio id,gpio _ pin _ 9,(gpio _ pinstate)值);}static uint 8 _ t readbytefromld(void){ uint 8 _ t data=0;data=(uint 8 _ t)(gpio d-IDR);返回数据;}static void writed byte tolcd(uint 8 _ tdata){ uint 16 _ tvalue=gpio d-ODR;value=(value0x ff 00)| | data;gpio d-ODR=值;我们可以采用多种方法来实现延时功能。我们用的是STM32平台和HAL库,所以毫秒延时函数可以直接用HAL_Delay()函数。微秒延迟函数采用了我们写的delayus,所以我们可以如下调用初始化函数:
LCD 1602初始化(LCD,//LCD 1602对象指针pinSets,//控制引脚操作函数指针数组WriteByteToLCD,//发送一个字节函数指针ReadByteFromLCD,//读取一个字节函数指针Delayus,//微秒延迟函数指针HAL_Delay //毫秒延迟函数指针);3.2、对对象进行操作时,我们定义了对象变量,并用初始化函数对其进行了初始化。然后我们会考虑操纵这个对象来获取我们想要的数据。我们已经获取了驱动程序中的数据,并将其转换为转换值的比例值。接下来,我们使用这个驱动程序来开发我们的应用程序示例。
Void LCD 1602显示(Void){ float temp=20.5;浮点pres=101.35浮动米虎=34.6;LCD1602DisplayClear(lcd,LCD1602_AllLine),Lcd1602ContentDisplay(lcd,0x80,' T%0.1fC,P%0.1fKPa,H%0.1f%% 'temp,pres,米虎);Lcd 1602内容显示(LCD,0xC0,' T%0.1fC,P%0.1fKPa,H%0.1f%% 'temp,pres,米虎);我们将清除监视器,然后在每一行显示温度、压力和湿度数据。
4、应用总结我们设计并实现了LCD1602的驱动程序,并在此基础上设计了一个简单的验证应用。我们可以正常的读写LCD1602显示屏,正确的担心LCD1602显示屏上我们想要的信息,说明我们的驱动设计没有问题。
使用驱动时有一点需要注意。因为在初始化函数中,时间函数指针数组用于控制管脚的操作,但是数组元素的顺序不是任意的,而是必须与枚举类型LCD1602PinType中定义的顺序一致才能正确操作。









