当前课程知识点:ARM微控制器与嵌入式系统 > 第五章 ARM微控制器的各种外设 > E4 实验四 数码管显示编程实操 > E4 实验四 数码管显示编程实操
各位同学大家好
我是清华大学工程物理系的曾鸣老师
欢迎大家继续回到我们
ARM微控制器与嵌入式系统的MOOC课堂
那么在这节课呢
我们来带着大家进行第四次的实验
我们前面已经做了三次实验
分别完成了IO 按键 串行通讯
以及时钟中断等等这样一些功能
那么在这次实验里呢
我们并不会去应用一个新学的知识
其实都是在基于
已经学过的知识里头的一个应用
但我们要挑战一个特别好玩的功能
就是来把我们这个板子上
第一类的显示模块给用起来
我们这个板子的正面的这个显示模块呢
是可以抠下来的
我们可以看到在我们的套件里
有彩色的LCD屏
有数码的OLED显示屏
其实还有一个最最小
最最简单的这个7段的数码管
一共是6个数字
大家可以把它换到自己的板子上
来进行我们这样一次的实验
那么每次实验的时候
都会说一说我们涉及到的知识在哪里
特别在芯片手册上在哪里
那么要把这样的一个数码管点亮
其实并不难
我们可能涉及到知识
最最主要的其实还是IO
当然我们也会灵活的使用时钟中断的知识
那么IO的知识大家都很熟悉了
在KL25这个芯片的芯片手册的
第四章和第四十一章讲IO的部分
那么如果大家用到SysTick最简单的
是这个时钟中断的
它在我们的ARM Cortex M0的芯片手册上
第四章第四节
大家自己可以找到
一定要记住我们做实验
碰到任何问题的时候
慢慢的学习养成查阅芯片手册的习惯
那么我们完成今天的实验任务呢
就像我所说的要把这样一个
由数码管构成的
六个数字的显示屏给点亮
那么如果我们看一看这个模组
就会发现这六个数字分成了两块
每一块上面有三个数字
而每一个数字都是一个八字形的
一个基本的数字单元
这每个单元每一个笔横竖呢
感觉上都是可以单独发亮的
其实大家都见过对吧
那么我们实际从电路的原理上来讲
都知道这每一个笔划
包括这个小数点
每一个数字刚好是7段数码加一个小数点
一共是8个LED需要点亮
那么一个模组三个数字
三八二十四
我们要点亮24个LED呢
其实就会涉及到因为要用掉24个IO引脚
这显然对于一个封装比较小巧
或者体积比较有限的
微控制器来讲是不可以接受的
成本太高了
那么实际上
我们再点这样一类数码管的时候
工业界对它所采用的设计
是像这张电路原理图所示
这八个LED是并列在一起形成一个模组
它们的阴极都短接到了一个引脚上共用
我们称为共阴极的接法
它们的阳极
每个引脚是独立的
所以呢
在实际接到电路的时候
就是如这张图所示
一个模组的三个数字每个数字的对应笔划
也就是这八个LED所有的阳极
对应同一个笔划的阳极都接在一起
出来用8个IO进行控制
而每一个数字的阴极
控制每一个数字是否亮的这个总的阴极
分别独立的引出来
可以在我们电路图里使用三个mos管
分别控制它的开关
所以如果我们从定性的角度
从语言来描述这个电路的功能
就是实际上我们用三乘以八的IO组合
来控制了24个LED的亮面
那么用八个LED来控制
在这样一个独立的数字上
哪些笔划亮
哪些笔划不亮 对吧
这个很直观
然后用下面三个引脚
分别控制哪一个数字的阴极电路是导通的
换言之这八个笔划控制
在哪一个数字上被点亮
而哪一个数字不能被点亮的
这样 实现了一个对数字的选择
加上对八个笔划的这个控制
实现这个数字的显示
这是电路的原理图
那么如果我们把我们这个开发板上
这个显示屏的所有电路原理图拿出来看
就会发现
整个屏幕六个数字实际上是两个模组
他们连在一起
你会发现这两个模组一共六个数字的
所有这八个笔划 这八个IO
都是短接在一起
由一组IO来控制
就是PORTB的0到7
然后每一个数字下面通过MOS管
都有一个总开关
所以有六个独立的IO
PORTD上的六个IO
分别每一个IO控制每一个数字是否导通
也就是它的阴极电路是否导通
是否能够点亮
所以我们可以通过对PORTB的编程
选择显示的内容
通过对PORTD的编程
选择这个显示的内容
在哪一位数字上实现显示
这就是电路的这个原理图
所以在做本次的实验之前
我带着大家读了读图
日后大家会慢慢锻炼
从电路图当中抽象出
电路的连接和逻辑关系
乃至知道自己该如何编写程序
这样一种能力
那么图读完了
把任务给出来
看看大家来怎么实现它
我们的任务一其实非常简单
就是选中我们这六个数字当中的最后一个
大家待会看看电路图
最后一个它的这个阴极
是哪个引脚来对应控制
然后我们使之显示某一个
我们自己想要的数字
比如1 比如2 比如3 比如4 对吧
那么我们读电路图的时候
我们知道这里头有两个关键点
一个是整个这个最后一个数字
这个阴极共用这个阴极
这个引脚得导通
另外就是这个数字的这八个笔画
对应的PORTB0到7的这八个IO
它的高低电平
它的点亮关系能使这上面的字
显示我们要的那个数
那这个问题如果倒过来问
我问问大家
那大家有没有办法或者能不能花点时间
自己分析一下
PORTB这个IO模块这个寄存器
赋什么值的时候
这个数字屏上分别显示0、1、2、3、4
一直到9这十个数字
大家把它给画一画
分析分析
然后这个值写成16进制码
做赋值语句的时候分别是什么
然后大家把这件事情做完了以后
有没有点什么感觉
如果有了点这种感觉
我们再往下看
我们的程序应该怎么编写
那么这个第四次实验第一次任务呢
我会给大家一点例程
其实这个例程非常简单
如果还有困难同学
你可以停下来在这儿看一看代码
但是我觉得更鼓励大家自己编出来
因为IO编程已经非常熟悉了
就是那三个步骤
把我们用到的PORTB和PORTD的时钟打开
把PORTB和PORTD对应的引脚指定为当IO用
然后通过IO的寄存器编程
设定好PORTB和PORTD的这些引脚是输出
然后给这些引脚输出的电平赋上初值
该为高电平导通的就导通
该为低电平为零的就为零
赋好初值
完成了整个这个屏幕的初始化
希望这个屏幕初始化完了以后
是关闭的 是黑着的状态 对吧
然后接着呢我们要写代码
对于这个电路图和这个屏幕的关系
想办法把上面对应的LED点亮
得到我们要要的数字
那么大家可能会有很多的写法
大家最直观的写法就是
曾老师说了显示一个数
我想要显示数字比如2
那我就上面这几笔得点亮
我就一句一句的赋值
把这IO点亮
这个任务我就完成了
这是一次性完成这个任务的方法
作为实验我希望大家能够多想一想的是
比如说我们想好了PORTB赋哪些值
对应0、1、2、3、4
那我们做一个像这样的宏定义
比如说我#define LED_0
#define LED_1
这个宏是我们将要赋给PORTB的值
使屏幕刚好对应显示0或者1
那是不是日后我们再来给PORTB赋值
让它显示对应数字的时候
我的代码就不再是这个PORTB的PDOR寄存器
等于一个奇怪的16进制数
而是直接等于一个LED_0、LED_1这样的宏
就可以了
那么带来的好处
一个是我的代码
是不是就变得就更可读
因为我看代码的时候
我就更容易知道我这句话
是为了让屏幕显示个0还是显示个1
那第二个好处呢
是不是大家有没有领会到这件事情
其实是针对我们这个电路设计
针对我们这个屏幕完成了一次
显示到数据的编码
我们对应的这个宏定义的后面这16进制数
就是对应人类看到0、1、2、3、4的
这个信息的一次编码
其实它在本质上
跟我们所用的ASCII码是一致的
如果大家领会到这个程度
那可能对于这个部分的理解
和日后的编程又会略有提高
那么与之类似的
我们对于这些引脚
某一个管子
某一个数字的选通
也可以通过一些宏的方式来加以定义
而至于宏的定义本来就非常的灵活
千差万别
每个同学都有自己最习惯 最漂亮的写法
甚至还有同学会用数组
会用指针这都是可以的
所以我在这里给的是一点点提示
希望大家领会的是这个显示的值
和编码之间的关系
以及如何用代码更干净更漂亮的实现它
我倒是鼓励大家不照我这个写
能够写出很漂亮的代码来
好 做完了实验任务一
我们在六个数字的
最后一个数字的位置上
显示了一个我们想要的数字
那有的同学是用笨办法做的
说老师我就是一个个IO点
点出了我的数字
那现在挑战来了
你还是得绕回相对聪明的办法
为什么呢
因为现在这个任务是希望大家
不是点亮最后一个数字
而是在这六个数字的屏幕上面
依次点亮每一个位数
每个数码管
然后分别让它从最低位到最高位
显示123456
然后中间有一个时间间隔
我给大家一点提示
你可以用delay函数
当然你可以用SysTick来做
第一次做你可以在main函数里头
用delay函数来做
那什么意思呢
如果我用人类的语言
来给大家描述这个程序执行的流程
大家注意听
回头你要用代码写出来
我选通最低的那个数字让它显示个1
然后我delay一段时间
我把它关掉
我选通第二位的数字让它显示个2
然后我再delay一段时间
我再把它关掉
然后再选择第三位数字这个数码管
让它显示一个3
于是我们依次选中每一位数
然后在它上面显示不同的数字
所以这个任务实际上
是把任务1所完成的事情串起来
加上delay函数做出一个程序的流程
如果大家成功的做成了实验1
又听明白了
我刚才对于这样一个流程的分析
大家可以尝试用代码
把它写出来 这就是任务二
那么高级一点的同学
你可以尝试用时钟中断来把它写出来
那么任务二我就不给代码了
我们的实验已经到第四次了
慢慢的大家听到任务要自己做
自己实现
它并不是那么困难
那么如果任务二做成了的同学
我们再来看看任务三
任务三是这样的
它非常的简单
几乎没有重新编程的任务
把任务二当中的delay函数
一点一点的尝试着把它改短
改的这个时间间隔越短
那么我问一问大家你会看到什么现象
然后我们现在不用实际的做
就在这里直接讲的话
如果时间足够短
短到什么程度
有的同学反映很快
说短到视觉暂留
对 短到这个时间间隔少于几十个毫秒
我们人肉眼看到这个切换一次的时间
小于这个每秒24帧
这个视觉暂留的时候
我们会看到什么现象
我们会看到这个屏幕上
越闪越快 越闪越快
到最后就稳定住不闪了
你是看到这个屏幕同时显示的数字
就是6、5、4、3、2、1
每个数码管同时都是亮的
而且稳定的显示着各自不同的数值
这个时候
可能有些同学在这个实验一开始的时候
心理有个疑问
说老师你这个屏幕设计的很弱啊
这个都没动脑筋啊
你这个电路这么设计
六个数字的8个IO都串联到一起了
都并联到一起了
然后每个数字单独一个选通
那你怎么能控制这个屏幕上显示多位数呢
你亮我不亮 我亮你不亮
我亮的数跟你亮的数不一样
你这个电路不干活啊
到了任务3的时候大家应该领会这件事
我们在绝大多数电子产品
看到这种数码管
你看到一个多位的数比如3576的时候
它并不是在真正计算机意义上的
同时显示这四个数字
而是以非常快的速度
分别切换每一位数字显示各自的值
而当整个切换的速度
超过人类视觉暂留的时候
你看到的是一个屏幕稳定的显示多位数
这就是任务三
那么如果大家前面
按我的要求在IO的实验
做过一点点呼吸灯
做过一点多彩的颜色灯的时候
你其实应该对这件事情非常有感觉
这就是从计算机视角做人机交互的时候
做显示一个重要的概念
包括我们日后做点阵屏
做彩色液晶屏
这个大家包括玩游戏
你一秒钟能切换多少帧
会对你造成一种动画的稳定的效果
那么这个任务的拔高
就是大家不用delay函数
用我们前面学过的SysTick
时钟中断来做这件事
把我们对于屏幕的显示
放到时钟中断里去做
你能不能做
那么大家可以试一试
那么本次实验的最后一个任务是什么呢
就是又要跟我们之前学过的
某一个任务关联起来
就是大家用串口接收来自于
我们计算机的超级终端发来的字符
那么这个时候我们不接收别的字符
只接收我们在超级终端里
从键盘上发的0到9的数字键
那么收到的是什么
我考大家一下
收到的是0或者9吗
收到的是0X00到0X09吗
不是的 大家要注意
收到的是0和到9的ASCII码的字符
你要做个减法把它换回值 对吧
那么拿到这个值以后
每当键盘上敲了一个新的数
就在我们刚才这个多位的数码管的最低位
显示新收到的这个数
把这上面原有的数顺便往左移一位
大家听明白这个意思没有
就是最终的效果是屏幕上是黑的
我在键盘上按了一下1
这个我的电路板上最低位就是1
我在按了一下6
然后我电路板上1挪到10位
个数显示6
我再按了一下5
我的屏幕上显示的是165
顺着1、6往左移
5出现在个位
所以大家想想这件事情要怎么实现
单就显示而言
其实我们前面已经做了 对吧
我们可以通过一个比较快的速度的刷新
在屏幕上显示我们要的值
大家核心的问题
一个是如何从串口接收出去
这在串口通讯的实验里大家也做过
第二个问题是如何把串口通讯的数据
倒腾到我们要显示的内容里来
这是不是很多同学卡住的
这个时候给大家提示
你可以用一个全局变量
或者用一个全局变量的数组
来保存你应该在屏幕上显示的内容
然后你通过串口的接收
来更新这个全局变量的值
而在你的另外的for循环的delay循环里
或者在你的SysTick时钟中断里
根据这个全局变量的值
来决定屏幕上对应每个管子
应该把哪个值显示上去
如果把这件事情要做的漂亮
一方面大家可能要把这个值之间
从ASCII码到数值
数值到我们应该给PORTB赋的那个值
那个宏定义 那个我们自己的编码
做一个很漂亮的关联起来
用代码实现的干干净净的
第二个问题
如果大家是挑战用SysTick来做这件事
你会有个非常强烈的感觉是
Sys Tick是main之外的一个中断
我们用了一个数据结构 一个全局变量
在上面保留要显示的内容
而他在SysTick的后台
不断把内容更新的值刷到屏幕上
而他不用关心这个值是否被更新了
什么时候被更新了
他只是不停去刷这个显示
这是我们做显示的时候
经常会有的一个概念
于是前台通过串口通讯
对于要显示内容的更新
可能在for循环里
在串口通讯里在前面做
而根据这个值不停的把内容刷到屏幕上
保证显示的内容是不停的更新的
在后台
用我们的时钟中断来做
于是把这样两个
看上去编程很麻烦的任务
分成了两个相对独立的单元
如果大家在最后第四个任务里
领会了这件事
日后大家要做个复杂的大作业
或者是写个趣味小程序小游戏
我相信就逐渐上路了
这就是这一次实验
给大家的最后一个任务与挑战
大家玩一玩看看吧
那么本次实验的内容呢
大概就是这些
往后做大家会慢慢发现
把我们所在实验里涉及到的知识
一点点串起来
我们就能慢慢做一些
比较难和比较复杂的任务了
-1.1 课程概览
--1.1 课程概览
-1.2 如何学好嵌入式系统
-2.1 计算机的基本概念、发展历史
-2.2 从晶体管到CPU
-2.3 概念CPU、微控制器MCU和嵌入式系统
-2.4 八卦计算机史
-2.5 不同领域、不同系列的嵌入式系统
-2.6 ARM历史与MKL25Z128 MCU
--2.6 ARM历史与MKL25Z128 MCU【习题】
-3.1 CPU的基本结构和运行机制
-3.2.1 堆栈的概念
--3.2.1 堆栈的概念【习题】
-3.2.2 堆栈的概念-头脑体操
-3.3.1 ARM的体系结构
--3.3.1 ARM的体系结构【习题】
-3.3.2 ARM的体系结构-头脑体操
-3.4.1 中断的概念和机制
-3.4.2 中断子程的概念和编程
-3.5 复位、时钟、存储器和总线
--3.5 复位、时钟、存储器和总线【习题】
-3.6 小结:MCU的总体结构和程序运行机制
--3.6 小结:MCU的总体结构和程序运行机制【习题】
-4.1 第一种外设:IO
-4.2 IO外设的编程实操-点亮LED
-4.3 IO外设的进阶知识
-4.4 嵌入式开发的基本概念与工具链
-4.5 嵌入式开发的进阶知识
-4.6 嵌入式开发中的C语言(上)
--4.6 嵌入式开发中的C语言(上)【习题】
-4.7 嵌入式开发中的C语言(下)
--4.7 嵌入式开发中的C语言(下)【习题】
-E0.1 实验零 开发板的初步认识与工具链的安装
-E0.2 实验零 体验一个例程的编译与下载
-E0.3 实验零 编写第一个程序:点亮核心板LED
-E1 实验一 点灯秘籍
-5.1 ARM微控制器外设学习概述
-5.2.1 ARM微控制器外设:通讯
-5.2.2 ARM微控制器外设:异步串行通讯UART的原理(上)
--5.2.2 ARM微控制器外设:异步串行通讯UART的原理(上)
--5.2.2 ARM微控制器外设:异步串行通讯UART的原理(上)【习题】
-5.2.3 ARM微控制器外设:异步串行通讯UART的原理(下)
--5.2.3 ARM微控制器的外设:异步串行通讯UART的原理(下)
--5.2.3 ARM微控制器外设:异步串行通讯UART的原理(下)【习题】
-5.2.4 ARM微控制器外设:RS-232串口与USB虚拟串口
--5.2.4 ARM微控制器外设:RS-232串口与USB虚拟串口
-5.2.5 ARM微控制器外设:UART的寄存器编程(上)
--5.2.5 ARM微控制器外设:UART的寄存器编程(上)
-5.2.6 ARM微控制器外设:UART的寄存器编程(下)
--5.2.6 ARM微控制器外设:UART的寄存器编程(下)
--5.2.6 ARM微控制器外设:UART的寄存器编程(下)【习题】
-E2 实验二 UART编程实操
-5.3.1 ARM微控制器外设:IO的中断编程(上)
-5.3.2 ARM微控制器外设:IO的中断编程(下)
-5.4.1 ARM微控制器外设:定时器的原理
-5.4.2 ARM微控制器外设:定时器的编程
--5.4.2 ARM微控制器外设:定时器的编程【习题】
-E3 实验三 定时器中断编程实操
-5.5.1 ARM微控制器外设:PWM的原理
-5.5.2 ARM微控制器外设:PWM寄存器与编程
-5.5.3 ARM微控制器外设:PWM编程实例—电子音乐
--5.5.3 ARM微控制器外设:PWM编程实例—电子音乐
-E4 实验四 数码管显示编程实操
-5.6.1 ARM微控制器外设:SPI通讯简介
--5.6.1 ARM微控制器外设:SPI通讯简介【习题】
-5.6.2 ARM微控制器外设:SPI寄存器与编程
-5.6.3 ARM微控制器外设:SPI编程实例—OLED显示屏驱动
--5.6.3 ARM微控制器外设:SPI编程实例—OLED显示屏驱动
-5.7.1 ARM微控制器外设:I2C通讯简介
-5.7.2 ARM微控制器外设:I2C的通讯协议
-5.7.3 ARM微控制器外设:I2C寄存器与编程
--5.7.3 ARM微控制器外设:I2C寄存器与编程【习题】
-5.7.4 ARM微控制器外设:I2C编程实例—加速度传感器
--5.7.4 ARM微控制器外设:I2C编程实例—加速度传感器
-5.8.1 ARM微控制器外设:ADC简介
-5.8.2 ARM微控制器外设:ADC基础
-5.8.3 ARM微控制器外设:ADC寄存器与编程
-E5 实验五 ADC编程实操
-E6 挑战实验
--E6 挑战实验
-6.1 嵌入式系统的接口与设计
-6.2 嵌入式系统的实例