3.2 使用并行接口点亮数码管
课件 使用并行接口点亮数码管
视频 使用并行接口点亮数码管
并行接口传输的特点就是数据同时发送,同时到达。单片机可以通过并行接口驱动数码管、LCD显示模块等设备,将其运行状态显示出来,更好地方便用户使用。
1.七段数码管
七段数码管也有人称其为八段数码管,它是由8个发光二极管组成的,其中7个长条形的发光二极管排列成中文“日”字形状,另一个小圆点在右下角作为小数点使用。其结构示意图如图3-5所示。这种组合可以显示0~9十个数字以及部分英文字母。
图3-5 七段数码管
数码管由多段发光二极管彼此相连构成,这些二极管的连接方式有两种:一种是共阴极连接方式,即各发光二极管的所有阴极连接在一起共同接地,此时当某个发光二极管的阳极为高电平时,该发光二极管会点亮;另一种是共阳极连接方式,与共阴极数码管的连接方式正好相反,是所有发光二极管的阳极连接在一起共同接电源,此时当某个发光二极管的阴极为低电平时,该发光二极管会点亮。共阴极、共阳极数码管的内部电路原理图如图3-6所示。
图3-6 数码管的内部电路原理图
使用数码管时,只需要将单片机的任一并行接口的8个引脚与数码管引脚一一对应(并行接口的0号引脚对应数码管的a段,1号引脚对应b段,以此类推)相连即可。通过并行接口输出数据即可达到控制数码管显示内容的目的,如图3-7所示。
图3-7 使用P1口点亮一个数码管
通常将控制数码管显示内容的8位字节数据称为段选码。不同的段选码对应不同的数码显示。共阳极数码管与共阴极数码管的段选码正好互补,见表3-2。
表3-2 七段数码管的段选码
注:表中字符都不带小数点,故未涉及dp段状态,与其对应引脚也未连接。
【课堂练习】通过P1口控制一个数码管显示数字5。电路原理图见图3-7。
【分析】图3-7中所用的数码管公共端接地即为共阴极数码管。查表3-2可知,欲显示数字5,其段选码(共阴码)为1101101(即6DH)。通过P1口输出1101101就可控制该数码管点亮。由此编写出以下显示数字5的驱动程序。
图3-7中为数码管连接了一个排阻,这其中的道理与点亮一个发光二极管时,需要串联一个限流电阻用以保护发光二极管一样。排阻是一排电阻的简称,实质上就是多个电阻。Proteus中排阻有两种:一种是带有公共端的,名称为RESPACK;另一种是不带公共端的,名称为RX8。Proteus中七段数码管的英文名称为7SEG,共阳极为AN,共阴极为CAT。
将上述程序编译后,导入单片机,单击“仿真运行”按钮,即可观察到数码管点亮。
2.精确调整的延时函数
课件 使用单片机控制数码管显示输出数字
视频 使用单片机控制数码管显示输出数字
上例只是实现了一个数字的显示,如果要让数码管从0显示到9,且每隔50ms就变换一个数字又该怎么编写程序呢?
将上面课堂练习的代码简单修改,在显示每个数字后添加一个延时函数,就能简单实现每隔50ms变换一个数字的效果。
这里涉及延时函数实现50ms时间间隔问题。延时函数的实质就是利用单片机每条指令执行的时长固定,且严格按时序执行的特点,让它执行一些毫无意义的语句来耗费一点CPU的时间,以达到延缓系统运行的目的。要实现精确定时,必须依据振荡频率计算出机器周期的时长。
下面就介绍如何来精确地设定延时函数。
首先打开Keil,新建一个工程,选择单片机为AT89C51,晶振频率为12MHz,如图3-8所示。
图3-8 设定单片机的主频为12MHz
延时函数的代码如下所示:
在这个延时函数中,会接收一个参数x,它就是要延时的时长,这个函数执行一次大约为0.988ms,十分接近1ms可以近似当作1ms,那么当x为50时,就相当于停顿了50ms。delay()函数的一次执行时间与晶振的频率是密切相关的。晶振的频率越高,delay()的一次执行时间就越短。
那么又是如何知道这个函数执行一次用了0.988ms呢?原来可以通过Keil的调试运行来观察程序的执行时间。当程序编写完成后,单击工具栏上的按钮,会出现程序调试窗口,如图3-9所示。
图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所示电路原理图为例,通过前面的介绍,可以很快地写出如下代码:
……
观察上述代码,可以看出代码的规律很明显,都是通过P1口显示一个数字(只是方框内数字不同)然后再延时,但这样写的代码冗长易错,工作量也大;应用C51提供的数组结合循环语句则可以有效地减少代码,使程序可读性更强,代码更为精练。
C51中数组是同一数据类型数据的集合。利用数组可以一次性定义多个变量,对这些变量可以采用“数组名[下标]”的方式读取。将数组与循环相结合,利用循环变量当作数组的下标,就可以在循环当中,遍历到每一个数组值了。利用这个思路,将段选码定义为数组,程序执行时,只需要让P1口按顺序读取数组元素就能达到预期目标了。
定义数组的语法格式:
注意:定义数组时使用code关键字表示将该数组存放在程序存储器空间,因此带有code的数组元素值不可改变。如数组值在运行中会改变,则不要加code关键字。
数组的调用方法:
尤其需要特别提醒的是,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循环,上面的倒计时程序就可简化为如下片段:
通过上述代码可以看见,数组配合循环语句后,极大地简化了代码,程序的结构也更加清晰,同时还避免了重复书写过多相同结构代码带来的错误,提高了编程效率。这种应用方法值得读者反复练习,并加以熟练运用。