![单片机原理及应用](https://wfqqreader-1252317822.image.myqcloud.com/cover/422/40778422/b_40778422.jpg)
3.2 使用并行接口点亮数码管
课件 使用并行接口点亮数码管
![](https://epubservercos.yuewen.com/8F2AFE/21182127901950806/epubprivate/OEBPS/Images/img00059001.jpg?sign=1738891213-6JnpeqHxo80uvyFLBw4mJqdVRD52HSm2-0-828ec5d8564110130435b23987936c53)
视频 使用并行接口点亮数码管
![](https://epubservercos.yuewen.com/8F2AFE/21182127901950806/epubprivate/OEBPS/Images/img00059002.jpg?sign=1738891213-oHliOxS4F2g7D9qtLBG5TIuYYZ7xFn6u-0-f24bd9977313ac77431cbe0c38c41efa)
并行接口传输的特点就是数据同时发送,同时到达。单片机可以通过并行接口驱动数码管、LCD显示模块等设备,将其运行状态显示出来,更好地方便用户使用。
1.七段数码管
七段数码管也有人称其为八段数码管,它是由8个发光二极管组成的,其中7个长条形的发光二极管排列成中文“日”字形状,另一个小圆点在右下角作为小数点使用。其结构示意图如图3-5所示。这种组合可以显示0~9十个数字以及部分英文字母。
![](https://epubservercos.yuewen.com/8F2AFE/21182127901950806/epubprivate/OEBPS/Images/img00059003.jpg?sign=1738891213-vgLjG199OKcpFla1yFIQROjliKVXiJDl-0-80e350c40be9d0d274141838b9fca341)
图3-5 七段数码管
数码管由多段发光二极管彼此相连构成,这些二极管的连接方式有两种:一种是共阴极连接方式,即各发光二极管的所有阴极连接在一起共同接地,此时当某个发光二极管的阳极为高电平时,该发光二极管会点亮;另一种是共阳极连接方式,与共阴极数码管的连接方式正好相反,是所有发光二极管的阳极连接在一起共同接电源,此时当某个发光二极管的阴极为低电平时,该发光二极管会点亮。共阴极、共阳极数码管的内部电路原理图如图3-6所示。
![](https://epubservercos.yuewen.com/8F2AFE/21182127901950806/epubprivate/OEBPS/Images/img00060001.jpg?sign=1738891213-fZGCEDQEUCvHxhQe0vvjLnYRuc3yfAbc-0-f0e97fa708b303e14a6f9f7580166f18)
图3-6 数码管的内部电路原理图
使用数码管时,只需要将单片机的任一并行接口的8个引脚与数码管引脚一一对应(并行接口的0号引脚对应数码管的a段,1号引脚对应b段,以此类推)相连即可。通过并行接口输出数据即可达到控制数码管显示内容的目的,如图3-7所示。
![](https://epubservercos.yuewen.com/8F2AFE/21182127901950806/epubprivate/OEBPS/Images/img00060002.jpg?sign=1738891213-KFqGLhj1Qw3hONBiLWX0w4NTFq8AxWzr-0-27edd65043c60bee24e0adcc66ab7a1a)
图3-7 使用P1口点亮一个数码管
通常将控制数码管显示内容的8位字节数据称为段选码。不同的段选码对应不同的数码显示。共阳极数码管与共阴极数码管的段选码正好互补,见表3-2。
表3-2 七段数码管的段选码
![](https://epubservercos.yuewen.com/8F2AFE/21182127901950806/epubprivate/OEBPS/Images/img00061001.jpg?sign=1738891213-r7Yi7OA21eiTnYlyhR9TLOiFGOqkdcyg-0-6f74fcf1b2ddc2d7d87755d2c8042892)
注:表中字符都不带小数点,故未涉及dp段状态,与其对应引脚也未连接。
【课堂练习】通过P1口控制一个数码管显示数字5。电路原理图见图3-7。
【分析】图3-7中所用的数码管公共端接地即为共阴极数码管。查表3-2可知,欲显示数字5,其段选码(共阴码)为1101101(即6DH)。通过P1口输出1101101就可控制该数码管点亮。由此编写出以下显示数字5的驱动程序。
![](https://epubservercos.yuewen.com/8F2AFE/21182127901950806/epubprivate/OEBPS/Images/img00061002.jpg?sign=1738891213-ju1PfvfzZjlD7pEF7sjhzgChLxvAcbNF-0-ff8f6b39eac6dc0f2fc8ab55c7466be7)
图3-7中为数码管连接了一个排阻,这其中的道理与点亮一个发光二极管时,需要串联一个限流电阻用以保护发光二极管一样。排阻是一排电阻的简称,实质上就是多个电阻。Proteus中排阻有两种:一种是带有公共端的,名称为RESPACK;另一种是不带公共端的,名称为RX8。Proteus中七段数码管的英文名称为7SEG,共阳极为AN,共阴极为CAT。
将上述程序编译后,导入单片机,单击“仿真运行”按钮,即可观察到数码管点亮。
2.精确调整的延时函数
课件 使用单片机控制数码管显示输出数字
![](https://epubservercos.yuewen.com/8F2AFE/21182127901950806/epubprivate/OEBPS/Images/img00061003.jpg?sign=1738891213-n3AfMzJ4vEUPDq5ZeryrbXMioT4BdqRz-0-8217ba8a002c8ea79ff2c5f6942ffa09)
视频 使用单片机控制数码管显示输出数字
![](https://epubservercos.yuewen.com/8F2AFE/21182127901950806/epubprivate/OEBPS/Images/img00061004.jpg?sign=1738891213-b4Eo4Bx5WyCCBYj0zZl7f20zGG8372MH-0-d3802dc86c210e61a01de9e139d98605)
上例只是实现了一个数字的显示,如果要让数码管从0显示到9,且每隔50ms就变换一个数字又该怎么编写程序呢?
将上面课堂练习的代码简单修改,在显示每个数字后添加一个延时函数,就能简单实现每隔50ms变换一个数字的效果。
![](https://epubservercos.yuewen.com/8F2AFE/21182127901950806/epubprivate/OEBPS/Images/img00062001.jpg?sign=1738891213-gGPKS4SOEQrDO9WUM95YT0EbJhnaaBRJ-0-51448c98f86dc12540f4f8ee9ca60743)
这里涉及延时函数实现50ms时间间隔问题。延时函数的实质就是利用单片机每条指令执行的时长固定,且严格按时序执行的特点,让它执行一些毫无意义的语句来耗费一点CPU的时间,以达到延缓系统运行的目的。要实现精确定时,必须依据振荡频率计算出机器周期的时长。
下面就介绍如何来精确地设定延时函数。
首先打开Keil,新建一个工程,选择单片机为AT89C51,晶振频率为12MHz,如图3-8所示。
![](https://epubservercos.yuewen.com/8F2AFE/21182127901950806/epubprivate/OEBPS/Images/img00062002.jpg?sign=1738891213-ZbmlGWe7n9lY3d5TdgWmbDLtw7Sa0Bfm-0-4fcef634e63eb2dff601522fd57b243a)
图3-8 设定单片机的主频为12MHz
延时函数的代码如下所示:
![](https://epubservercos.yuewen.com/8F2AFE/21182127901950806/epubprivate/OEBPS/Images/img00062003.jpg?sign=1738891213-mLlFstc7wlSsyKLVLqpcRjRdvpkeDOu4-0-37ee8196c834d29de969550f2d492b25)
在这个延时函数中,会接收一个参数x,它就是要延时的时长,这个函数执行一次大约为0.988ms,十分接近1ms可以近似当作1ms,那么当x为50时,就相当于停顿了50ms。delay()函数的一次执行时间与晶振的频率是密切相关的。晶振的频率越高,delay()的一次执行时间就越短。
那么又是如何知道这个函数执行一次用了0.988ms呢?原来可以通过Keil的调试运行来观察程序的执行时间。当程序编写完成后,单击工具栏上的按钮,会出现程序调试窗口,如图3-9所示。
![](https://epubservercos.yuewen.com/8F2AFE/21182127901950806/epubprivate/OEBPS/Images/img00063002.jpg?sign=1738891213-oOzuLWwNEyNhEVKnoeZj9GRXUdB1Dwty-0-4f9d71f844ee74e14948e2132f5b3a15)
图3-9 程序调试窗口
工具栏上的和
分别表示单步执行和跳过函数继续执行。配合这两个工具按钮以及屏幕左侧的寄存器栏中的系统运行时间,就可以计算得出执行一次延时函数所需要的时间了。
进入设计程序后,先单击按钮,进行单步运行,当程序运行到delay(1)时,记下此时系统运行已经耗用的时间为0.0039100s,接着再单击
按钮,即已经执行一次delay(1),再记录一下此时系统的时间为0.00137900s,二者之差为0.988ms。这就是延时函数执行一次所用的时间。
在上述延时函数中,主要通过两个循环来实现延时,内层循环[for(z=120;z>0;z--);]是整个延时函数的关键,它运行的时间就是执行一次延时的耗时量,通过调整z的初始值,使其无限接近1ms。外层循环就是延时的倍数,与内层循环的时间量相乘,就是延时的时间。所以,上面延时函数执行一次约为0.988ms,欲延时50ms,就需要循环50÷0.988≈50,即这个循环执行50次就接近延时50ms。通过这个计算就可以编写精确的延时函数了。
下面,请读者思考一下,当系统晶振分别为6MHz、12MHz时,延时1ms需要设定的循环次数该是多少?
3.C51的数组及应用
【课堂练习】将设定好的延时函数添加到程序,并实现由9到0的数码倒计时显示,每个数字间隔50ms。
【分析】仍以图3-8所示电路原理图为例,通过前面的介绍,可以很快地写出如下代码:
……
![](https://epubservercos.yuewen.com/8F2AFE/21182127901950806/epubprivate/OEBPS/Images/img00064001.jpg?sign=1738891213-f1OJ8mxRuHisi134q9aaBvaC2VbgXBlZ-0-65e9b199ef58b3a19e6fa2ead6291807)
观察上述代码,可以看出代码的规律很明显,都是通过P1口显示一个数字(只是方框内数字不同)然后再延时,但这样写的代码冗长易错,工作量也大;应用C51提供的数组结合循环语句则可以有效地减少代码,使程序可读性更强,代码更为精练。
C51中数组是同一数据类型数据的集合。利用数组可以一次性定义多个变量,对这些变量可以采用“数组名[下标]”的方式读取。将数组与循环相结合,利用循环变量当作数组的下标,就可以在循环当中,遍历到每一个数组值了。利用这个思路,将段选码定义为数组,程序执行时,只需要让P1口按顺序读取数组元素就能达到预期目标了。
定义数组的语法格式:
![](https://epubservercos.yuewen.com/8F2AFE/21182127901950806/epubprivate/OEBPS/Images/img00064002.jpg?sign=1738891213-u51YfWhJNeRN5g8Q29DtnlVXY5Zu8sx6-0-34bc3727c7a62ce0ce91550a4a27e9c2)
注意:定义数组时使用code关键字表示将该数组存放在程序存储器空间,因此带有code的数组元素值不可改变。如数组值在运行中会改变,则不要加code关键字。
数组的调用方法:
![](https://epubservercos.yuewen.com/8F2AFE/21182127901950806/epubprivate/OEBPS/Images/img00064003.jpg?sign=1738891213-93pc2ET5JnINBiKjIRm7Fms5bSrYoVda-0-5224b1331ef50d9ba0489b638e303363)
尤其需要特别提醒的是,C51中数组的下标都是从0开始计数的。如定义一个数组table,含有10个数字,则命令写为:
ucharcode table[10]={0x6f,0x7f,0x07,0x7d,0x6d,0x66,0x4f,0x5b,0x06,0x3f};
上面数组中起始的数组元素是table[0],其内容为0x6f;结束的元素是table[9],其内容是0x3f,千万注意上面定义的数组中并不存在table[10]这个元素。
结合for循环,上面的倒计时程序就可简化为如下片段:
![](https://epubservercos.yuewen.com/8F2AFE/21182127901950806/epubprivate/OEBPS/Images/img00064004.jpg?sign=1738891213-QlmCYWLl7jcduB0YAWBxdCUWdiTRJFZF-0-65ad33f2dcee59dbf31884f4a3f187bc)
通过上述代码可以看见,数组配合循环语句后,极大地简化了代码,程序的结构也更加清晰,同时还避免了重复书写过多相同结构代码带来的错误,提高了编程效率。这种应用方法值得读者反复练习,并加以熟练运用。