大家好,我是老耿,高职青椒一枚,一直从事单片机、嵌入式、物联网等课程的教学。 对于高职的学生层次,同行应该都懂的,老师在课堂上教学几乎是没什么成就感的。正因如此,才有了借助 CSDN 平台寻求认同感和成就感 的想法。在这里,我准备陆续把自己花了很多心思的教学设计分享出来,主要面向广大师生朋友,单片机老鸟就略过吧。欢迎点赞+关注,各位的支持是本人持续输出的动力,多谢多谢!
前边我们讲解了LED、按键和蜂鸣器的应用,这三类器件本身工作原理十分简单,因此我们的重点是放在STM32的GPIO上面。这一章我们来学习一下开发板配套的那块厚厚的液晶屏------LCD1602,聚焦的是这个器件本身的特点和工作时序。 因此,我们需要熟读它的数据手册,因为手册里告诉了编程的要点、参数、时序等。阅读器件手册是做单片机和嵌入式开发必备的基本能力, 我们就从这一章开始锻炼起来吧。为了不让篇幅太长,本章打算分四个部分来讲解,本文是第四部分。
【学习目标】
- 了解LCD1602的工作原理
- 掌握LCD1602的工作时序
- 领悟软件模拟时序的思路和方法
四、字符跳动显示实验
我们在前面的液晶指令描述中可以看到,LCD1602还支持光标和屏幕移动,下面我们就通过两个实验来感受一下动态显示的效果。
4.1 任务描述
这个实验是让字符串里的每个字符逐个跳出来显示,我们将实验的动态效果分解在图18中,中间部分做了一些省略。
图18 字符跳动显示效果
4.2 工程源码剖析
对于底层的 lcd1602.c 和 lcd1602.h 驱动文件来说,我们尽量不去改动。控制字符跳出的代码在主程序里实现,见如下代码清单16。
cpp
/**
******************************************************
* 代码清单16:main.c
* 项 目:LCD1602液晶显示
* 任务描述:字符跳到显示
* 实验平台:OneNET STM32开发板V3.2
* 作 者:老耿
* 日 期:yyyy/mm/dd
******************************************************
**/
//-----------------------------------------------------
// 必要的头文件
//-----------------------------------------------------
#include "delay.h"
#include "lcd1602.h"
int main()
{
u8 i; //控制列坐标的变量
u8 *p; //指向字符串的指针
delay_init(); //Systick初始化,用于普通的延时
Lcd1602_Init(); //LCD1602初始化
while(1)
{
i = 2; //列坐标初值
p = "STM32 Board"; //指向待显示的字符串
Lcd1602_Clear(2); //每次开始显示前先清屏
Lcd1602_ShowStr(0, 3, "KylinV3.2"); //首行静态显示
delay_ms(250); //停留一下进入下面的字符跳出效果
/* ------------ 以下是控制字符逐个跳出的循环 -------------*/
while(*p) //只要不是结束字符就循环,即while(*p!='\0')
{
Lcd1602_ShowChar(1, i, *p); //第二行指定位置显示一个字符
i++; //下一列
p++; //下一个字符
delay_ms(250); //每个字符跳出的间隔
}
delay_ms(250); //跳完停留一下
}
}
五、液晶滚动显示实验
5.1 任务描述
这个实验是让整个屏幕画面整体向左或向右滚动显示,我们将实验动态效果分解在图19中,中间部分做了一些省略。
图19 液晶滚动显示效果
5.2 工程源码剖析
同理,还是只修改主程序里的控制代码,见如下代码清单17。
cpp
/**
******************************************************
* 代码清单17:main.c
* 项 目:LCD1602液晶显示
* 任务描述:滚动显示
* 实验平台:OneNET STM32开发板V3.2
* 作 者:老耿
* 日 期:yyyy/mm/dd
******************************************************
**/
//-----------------------------------------------------
// 必要的头文件
//-----------------------------------------------------
#include "delay.h"
#include "lcd1602.h"
int main()
{
delay_init(); //Systick初始化,用于普通的延时
Lcd1602_Init(); //LCD1602初始化
Lcd1602_ShowStr(0, 3, "KylinV3.2");
Lcd1602_ShowStr(1, 2, "STM32 Board");
while(1)
{
Lcd1602_WriteCmd(0x18); //画面整体左移一个字符位置
//Lcd1602_WriteCmd(0x1C); //画面整体右移一个字符位置
delay_ms(250);
}
}
六、液晶显示功能的扩展
在上面的实验中,我们通过 Lcd1602_ShowStr() 函数实现了字符串信息的显示。但不知你是否考虑过,倘若显示的内容不是字符的类型,比如传感器采集温湿度值、ADC采集的电压值等,这些数据都是浮点类型的,也想通过液晶显示出来,该如何处理呢?
针对以上问题,我们补充一个显示函数 Lcd1602_Printf(),来实现多种数据类型的显示, 就像使用 printf() 函数那样,可以通过%d、%f、%s这样的形式来指定显示内容的数据类型。该函数用到了C语言中解决变参问题的操作方式,想详细了解这部分知识的同学请自行搜索查阅,这里不展开。源码见如下代码清单18。
cpp
/*
************************************************************
* 代码清单18: Lcd1602_Printf()函数
* 函数功能: 设置LCD1602显示的内容
* 入口参数: x和y:显示的起始坐标(同上)
* fmt:不定长参
* 返回参数: 无
* 说明:
************************************************************
*/
void Lcd1602_Printf(u8 x, u8 y, char *fmt, ...)
{
u8 LcdPrintfBuf[33]; //"打印"字符的缓冲区
va_list ap; //定义一个可变参数列表
u8 *ptr = LcdPrintfBuf; //指向缓冲区的指针
va_start(ap, fmt); //获取可变参数列表第一个参数的地址
vsprintf((char *)LcdPrintfBuf, fmt, ap); //把可变参数列表内容格式化成字符串存入缓冲区
va_end(ap); //清空可变参数列表
Lcd1602_SetCursor(x, y); //设置显示位置
while(*ptr) //循环显示缓冲区里的每个字符
{
Lcd1602_WriteData(*ptr);
ptr++;
}
}
有了这个函数,我们就可以在主程序中像使用 printf() 函数那样在液晶屏上"打印"需要的内容了,代码清单19给了一个简单示例。
cpp
/**
******************************************************
* 代码清单18:main.c
* 项 目:LCD1602液晶显示
* 任务描述:用液晶"打印"函数来显示
* 实验平台:OneNET STM32开发板V3.2
* 作 者:老耿
* 日 期:yyyy/mm/dd
******************************************************
**/
//-----------------------------------------------------
// 必要的头文件
//-----------------------------------------------------
#include "delay.h"
#include "lcd1602.h"
int main()
{
char *str = "Kylin STM32"; //字符串类型
float ver = 3.2; //浮点类型
delay_init(); //Systick初始化,用于普通的延时
Lcd1602_Init(); //LCD1602初始化
Lcd1602_Printf(0, 0, "%s", str);
Lcd1602_Printf(1, 0, "version:%.1f", ver);
while(1);
}
可以看到,带变参的 Lcd1602_Printf() 函数更灵活通用,使我们不必再纠结显示内容究竟是什么数据类型,这是它的优势。那有没有劣势呢?当然有了,在显示同样内容的情况下,使用Lcd1602_Printf() 函数比用 Lcd1602_ShowStr() 函数编译出来的代码量大了不是一点儿,如图20所示。
图20 编译的代码量对比
(第四部分完,共四部分)