南昌做房地产用哪个网站,抖音带运营给客户带来怎么样收益,做网站工资怎么样,湖南基础建设投资集团网站大家好#xff0c;我是老耿#xff0c;高职青椒一枚#xff0c;一直从事单片机、嵌入式、物联网等课程的教学。对于高职的学生层次#xff0c;同行应该都懂的#xff0c;老师在课堂上教学几乎是没什么成就感的。正因如此#xff0c;才有了借助 CSDN 平台寻求认同感和成就… 大家好我是老耿高职青椒一枚一直从事单片机、嵌入式、物联网等课程的教学。对于高职的学生层次同行应该都懂的老师在课堂上教学几乎是没什么成就感的。正因如此才有了借助 CSDN 平台寻求认同感和成就感的想法。在这里我准备陆续把自己花了很多心思的教学设计分享出来主要面向广大师生朋友单片机老鸟就略过吧。欢迎点赞关注各位的支持是本人持续输出的动力多谢多谢 前边我们讲解了LED、按键和蜂鸣器的应用这三类器件本身工作原理十分简单因此我们的重点是放在STM32的GPIO上面。这一章我们来学习一下开发板配套的那块厚厚的液晶屏——LCD1602聚焦的是这个器件本身的特点和工作时序。因此我们需要熟读它的数据手册因为手册里告诉了编程的要点、参数、时序等。阅读器件手册是做单片机和嵌入式开发必备的基本能力我们就从这一章开始锻炼起来吧。为了不让篇幅太长本章打算分四个部分来讲解本文是第三部分。
【学习目标】
了解LCD1602的工作原理掌握LCD1602的工作时序领悟软件模拟时序的思路和方法 三、液晶静态显示实验 本章的前两个部分花了不少篇幅全方面的介绍了LCD1602以及与开发板之间的联系传递出来的无非就是一个意思——吃透数据手册。这别无他法结合参考程序反复阅读手册慢慢感悟开发经验就是这么积累起来的。学完这个入门的液晶屏后面还有更复杂的彩屏和触摸屏等着我们去学习依然是“啃”数据手册。好了下面我们就动手来写一个程序把手册里的内容转换成代码驱动LCD1602去显示我们想要的效果。
3.1 任务描述 编写LCD1602驱动代码上电之后可以在指定位置显示字符串信息实验效果如图13所示。 图13 LCD1602静态显示实验效果 3.2 工程文件清单 与之前的工程一样控制一类新的硬件就增加一对与之匹配的驱动文件即图14中的 lcd1602.c 和 lcd1602.h。 图14 LCD1602工程文件 3.3 工程源码剖析 这里为了突出源码的功能细节和排版之需对源码进行了必要的分割处理。
3.3.1 lcd1602.h源码剖析 该文件源码见代码清单4主要是LCD1602端口操作的宏定义和驱动函数的声明每个函数的功能和参数将在下面剖析 lcd1602.c 源码时解读。
//---------------------------------------------------------
// 代码清单4lcd1602.h
//---------------------------------------------------------#ifndef _LCD1602_H_
#define _LCD1602_H_
#include stm32f10x.h//---------------------------------------------------------
// 端口操作宏定义
//---------------------------------------------------------
#define RS_H GPIO_SetBits(GPIOC, GPIO_Pin_6)
#define RS_L GPIO_ResetBits(GPIOC, GPIO_Pin_6)
#define RW_H GPIO_SetBits(GPIOA, GPIO_Pin_11)
#define RW_L GPIO_ResetBits(GPIOA, GPIO_Pin_11)
#define EN_H GPIO_SetBits(GPIOB, GPIO_Pin_4)
#define EN_L GPIO_ResetBits(GPIOB, GPIO_Pin_4)
#define READ_BUSY() GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_2)//通过直接配置寄存器来改变PC2是输入还是输出
//读液晶状态时是输入写命令和写数据时是输出
//GPIOx-CRL寄存器描述见手册8.2.1小节P113
#define PC2_OUT() {GPIOC-CRL0xFFFFF0FF; GPIOC-CRL|0x00000300;}
#define PC2_IN() {GPIOC-CRL0xFFFFF0FF; GPIOC-CRL|0x00000800;}//---------------------------------------------------------
// 驱动函数声明
//---------------------------------------------------------
_Bool Lcd1602_WaitReady(void);
void Lcd1602_SendByte(u8 byte);
void Lcd1602_WriteCmd(u8 byte);
void Lcd1602_WriteData(u8 byte);
void Lcd1602_ShowChar(u8 x, u8 y, u8 ch);
void Lcd1602_ShowStr(u8 x, u8 y, u8 *str);
void Lcd1602_Clear(u8 pos);
void Lcd1602_Init(void);
void Lcd1602_Printf(u8 x, u8 y, char *fmt, ...);#endif
3.3.2 lcd1602.c源码剖析 该文件就是所有LCD1602驱动函数的定义下面就逐个进行剖析。 1) 头文件部分 首先把必要的头文件都加进来如代码清单5所示。
/************************************************************************** 代码清单5lcd1602.c的头文件* 描 述LCD1602初始化、驱动* 平 台麒麟座V3.2* 作 者老耿* 日 期2024-04-09* 固 件 库ST3.5.0* 版 本V1.0* 修改记录无************************************************************************
*///必要的头文件
#include delay.h
#include lcd1602.h//C库
#include stdarg.h
#include stdio.h 2) Lcd1602_WaitReady()函数源码 该函数就是用来检测液晶是否准备好返回1表示“忙”返回“0”表示“不忙”。详细源码见如下代码清单6。
/*
************************************************************
* 代码清单6 Lcd1602_WaitReady()函数
* 函数功能 等待液晶准备好
* 入口参数 无
* 返回参数 1忙0不忙
* 说明
************************************************************
*/
_Bool Lcd1602_WaitReady(void)
{PC2_IN(); //PC2输入模式RS_L; //拉低RSRW_H; //拉高RWEN_L; //delay_us(1); //EN高脉冲EN_H; //return (_Bool)READ_BUSY(); //返回PC2状态
} 2) Lcd1602_SendByte()函数源码 该函数把一个字节参数byte送上液晶的8位数据端口高3位送到PC2 ~ PC0低5位送上PB9 ~ PB5。送数的过程如代码清单7所示有一点曲折但各位可以从中好好体会一下C语言位操作的严谨和奇妙。
/*
************************************************************
* 代码清单7 Lcd1602_SendByte()函数
* 函数功能 向LCD1602写一个字节
* 入口参数 byte需要写入的数据
* 返回参数 无
* 说明
************************************************************
*/
void Lcd1602_SendByte(u8 byte)
{u16 value 0;value GPIO_ReadOutputData(GPIOB); //读取GPIOB的数据value ~(0x001F 5); //清除bit5~8value | ((u16)byte 0x001F) 5; //将要写入的数据取低5位并左移5位GPIO_Write(GPIOB, value); //写入GPIOBvalue GPIO_ReadOutputData(GPIOC); //读取GPIOC的数据value ~(0x0007 0); //清除bit0~2value | ((u16)byte 0x00E0) 5; //将要写入的数据取高3位并右移5位GPIO_Write(GPIOC, value); //写入GPIOCdelay_us(10);
} 首先我们得清楚要改变的只有PC2 ~ PC0、PB9 ~ PB5这8位而这两组I/O的其他位是不能变的因为其它I/O还连着别的硬件呢。所以才有了先保存这组I/O的值。接下来低5位的操作过程可以用图15来表示这几句很好的诠释了C语言常见的位操作在嵌入式层面是如何应用的希望各位能好好领悟。同理高3位送到PC2~PC0各位可以自己琢磨和推导一下。 图15 PB9~PB5的送数过程 3) Lcd1602_WriteCmd()函数源码 该函数实现写一个命令参数byte到LCD1602就是按照数据手册上写命令的时序编写的大家可以对照手册来阅读源码见如下代码清单8。
/*
************************************************************
* 代码清单8 Lcd1602_WriteCmd()函数
* 函数功能 向LCD1602写命令
* 入口参数 byte需要写入的命令
* 返回参数 无
* 说明
************************************************************
*/
void Lcd1602_WriteCmd(u8 byte)
{while(Lcd1602_WaitReady()); //等到不忙PC2_OUT(); //PC2输出模式RS_L; //拉低RSRW_L; //拉低RWLcd1602_SendByte(byte); //准备命令码EN_H; //拉高使能delay_us(20); //保持一定时间EN_L; //拉低使能delay_us(5);
} 4) Lcd1602_WriteData()函数源码 该函数与写命令函数是一个套路就是通过拉高RS改成了数据模式源码见代码清单9。
/*
************************************************************
* 代码清单9 Lcd1602_WriteData()
* 函数功能 向LCD1602写数据
* 入口参数 byte需要写入的数据
* 返回参数 无
* 说明
************************************************************
*/
void Lcd1602_WriteData(u8 byte)
{while(Lcd1602_WaitReady()); //等到不忙PC2_OUT(); //PC2输出模式RS_H; //拉高RSRW_L; //拉低RWLcd1602_SendByte(byte); //准备数据EN_H; //拉高使能delay_us(20); //保持一定时间EN_L; //拉低使能delay_us(5);
} 5) Lcd1602_SetCursor()函数源码 该函数用来设置光标的位置参数x和y是位置坐标x是行坐标0表示第一行1表示第二行y是列坐标0~15源码见如下代码清单10。
/*
************************************************************
* 代码清单10 Lcd1602_SetCursor()函数
* 函数功能 设置显示RAM地址地址即光标位置
* 入口参数 x行坐标0第一行1第二行
* y列坐标0~15
* 返回参数 无
* 说明
************************************************************
*/
void Lcd1602_SetCursor(u8 x, u8 y)
{u8 addr;if(x0) //第一行addr 0x00 y;else //第二行addr 0x40 y;Lcd1602_WriteCmd(addr|0x80); //写入地址
} 6) Lcd1602_ShowChar()函数源码 该函数用来显示单个字符参数x和y与上面一样确定在哪个位置显示ch为字符内容源码见如下代码清单11。
/*
************************************************************
* 代码清单11 Lcd1602_ShowChar()函数
* 函数功能 在液晶上显示单个字符
* 入口参数 x和y显示的坐标同上
* ch待显示的字符
* 返回参数 无
* 说明
************************************************************
*/
void Lcd1602_ShowChar(u8 x, u8 y, u8 ch)
{Lcd1602_SetCursor(x, y); //设置坐标Lcd1602_WriteData(ch); //显示字符
} 7) Lcd1602_ShowStr()函数源码 该函数用来显示字符串信息参数x和y与上面一样确定从哪个位置开始显示*str指向待显示的字符串空间源码见如下代码清单12。
/*
************************************************************
* 代码清单12 Lcd1602_ShowStr()函数
* 函数功能 在液晶上显示字符串
* 入口参数 x和y显示的起始坐标同上
* str字符串指针
* 返回参数 无
* 说明
************************************************************
*/
void Lcd1602_ShowStr(u8 x, u8 y, u8 *str)
{Lcd1602_SetCursor(x, y);//每写完一个字符光标会自动指向下一个位置while(*str) //字符串没结束就不停{Lcd1602_WriteData(*str); //写入当前字符str; //指向下一个字符}
} 8) Lcd1602_Clear()函数源码 该函数用来清屏参数pos可取值为0、1、2分别表示清除第一行、第二行和整屏源码见如下代码清单13。
/*
************************************************************
* 代码清单13 Lcd1602_Clear()函数
* 函数功能 LCD1602清除指定行
* 入口参数 pos指定的行
* 返回参数 无
* 说明 0-第一行 1-第二行 2-两行
************************************************************
*/
void Lcd1602_Clear(u8 pos)
{switch(pos){case 0:Lcd1602_ShowStr(0, 0 , );break;case 1:Lcd1602_ShowStr(1, 0 , );break; case 2:Lcd1602_WriteCmd(0x01); //清屏命令break;default:break;}
} 9) Lcd1602_Init()函数源码 该函数完成LCD1602上电之后的初始化一方面将所连接的I/O口全部初始化另一方面按照数据手册交待的复位步骤对液晶进行初始化源码见如下代码清单14。
/*
************************************************************
* 代码清单14 Lcd1602_Init()函数
* 函数功能 LCD1602初始化
* 入口参数 无
* 返回参数 无
* 说明 RW-PA11 RS-PC6 EN-PC3
* D7~D5 - PC2~PC0 D4~D0 - PB9~PB5
************************************************************
*/
void Lcd1602_Init(void)
{GPIO_InitTypeDef gpio_initstruct;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | \RCC_APB2Periph_GPIOB | \RCC_APB2Periph_GPIOC, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); //禁止JTAG功能gpio_initstruct.GPIO_Mode GPIO_Mode_Out_PP;gpio_initstruct.GPIO_Pin GPIO_Pin_4 | GPIO_Pin_5 | \GPIO_Pin_6 | GPIO_Pin_7 | \GPIO_Pin_8 | GPIO_Pin_9;gpio_initstruct.GPIO_Speed GPIO_Speed_50MHz;GPIO_Init(GPIOB, gpio_initstruct);gpio_initstruct.GPIO_Pin GPIO_Pin_11;GPIO_Init(GPIOA, gpio_initstruct);gpio_initstruct.GPIO_Pin GPIO_Pin_0 | GPIO_Pin_1 | \GPIO_Pin_2 | GPIO_Pin_6;GPIO_Init(GPIOC, gpio_initstruct);Lcd1602_WriteCmd(0x38); //16*2显示5*7点阵8位数据接口Lcd1602_WriteCmd(0x0C); //开显示光标关闭Lcd1602_WriteCmd(0x06); //字符不动光标移动Lcd1602_WriteCmd(0x01); //清屏
} LCD1602液晶手册提供了一个初始化过程由于不检测“忙”位所以程序比较复杂如图16所示。而我们编写的程序已经将检测“忙”位的功能嵌入到写操作里面了所以只用了最后4行语句就完成了同样效果更加简易方便。手册上描述的那个大家仅作了解即可。以后在别的资料里看到了与我们这类不一样的初始化也不要困惑注意跟我们这里联系和对比。 图16 数据手册上的初始化过程 3.3.3 main.c源码剖析 主程序比较简单完成初始化之后就调用显示函数在屏上指定的位置显示指定的字符串源码见如下代码清单15。
/********************************************************* 代码清单15main.c* 项 目LCD1602液晶显示* 任务描述静态显示* 实验平台OneNET STM32开发板V3.2* 作 者老耿* 日 期yyyy/mm/dd******************************************************
**///-----------------------------------------------------
// 必要的头文件
//-----------------------------------------------------
#include delay.h
#include lcd1602.hint main()
{delay_init(); //Systick初始化用于普通的延时Lcd1602_Init(); //LCD1602初始化Lcd1602_ShowStr(0, 3, KylinV3.2); //第一行第4个字符开始显示字符串Lcd1602_ShowStr(1, 2, STM32 Board); //第二行第3个字符开始显示字符串while(1);
}
3.3.4 验证与测试 程序下载前接好液晶屏和电源适配器并将电源拨动开关置于OFF处如图17所示。程序下载后电源开关拨至ON即可实现实验效果。 图17 实验效果与电源拨动开关 第三部分完共四部分