持续关注阿杰在线更新保姆式蓝桥杯笔记~~坚持日更
目录
问:数码管动态扫描如何实现?(即需要什么步骤)
答:
- 给对应的IO口赋值,位选编码选择哪一位亮
- 消隐,避免上一次IO口确定的段码对本次段码产生影响
- 给选中的数码管段选赋值,让其显示对应的数字或字母
- 适当延时使其稳定(延时不易过长)--》选用定时器实现
静态显示
静态显示的特点是每个数码管的段选必须接一个8位数据线来保持显示的字形码。当送入一次字形码后,显示字形可一直保持,直到送入新字形码为止。这种方法的优点是占用CPU时间少,显示便于检测可控制。缺点是硬件电路比较复杂,成本较高。
动态显示
将所有的数码管的段选线并接在一起,用一个IO接口控制,公共端并不是直接接地(共阴极)或者电源(共阳极),而是通过相应的IO接口控制。以阴极为例假设4个数码管工作过程为:每个数码管的公共端与一根IO相连,第一步使最右边一个数码管的公共端为0,其余数码管公共端为1,同时在IO上 发送右边第一个数码管的字段码,这时候只有右边的第一个数码管显示,其余不显示;第二部使右边第二个数码管的公共端为0,其余的公共端为1,同时在上发送右边第二个数码管的字段码,这时候,只有右边第二个数码管显示,其余不显示,以此类推,直到最后一个,这样子4个数码管轮流显示相应的信息,一遍显示完毕,隔一段时间,又这样循环显示。从计算机角度,每个数码管隔一段时间才显示一次,但是由于人的视觉暂留效应,只要隔离时间足够短,循环的周期足够长,每秒达到24次以上,看起来数码管就一直稳定显示了,这就是动态显示原理。
一、数码管的原理介绍
数码管的原理图如图3-1,本质就是把8段LED小灯组合在一起。
数码管可以分为共阴极和共阳极,内部结构如下图3-2所示:
共阴极数码管,即把8只LED灯的阴极连接在一起,由阳极来控制单个小灯的亮灭(1亮0灭);
共阳数码管就是阳极连接在一起,通过阴极来控制小灯的亮灭(1灭0亮)。
code关键字:C51单片机中,使用关键字unsigned char或者 unsigned int定义的变量都是放在单片机的RAM中,这些变量的值可以通过程序改变。而在定义时使用code修饰的变量是存储到存储空间FLASH里的,这样可以大大的节省的RAM的空间,但是这些变量的值在程序中不可以修改,所以我们在定义一些程序中不需要修改的变量时,可以使用code关键字,例如上面提到的数码管的真值的定义:unsigned char code LEDchar[]={};
二、数码管的动态显示
原理分析
动态数码管,即同时有多个数码管显示数字,实际上是轮流点亮各个数码管(同一时刻只有一个数码管被点亮),利用人眼的视觉暂留现象(余晖效应),使我们看到多个数码管同时点亮的效果。就像我们看到的电影也是由一帧一帧的画面组成的,但因为速度足够快,我们看到它就是动态的。刷新时间小于10毫秒时,对于人眼来说就是无闪烁的。
- CT107D开发板为例(共阳极数码管),原理图如下:
三、代码区
**main.c文件**
#include "dsp_init.h"
#include "timer.h"
#include "dsp_seg.h"
#include "STDIO.H"
//全局变量
unsigned char disp_data = 123;//待显示的数据
unsigned char seg_string[10];//给小数点和结束符保留了2个空间的字符串数组
unsigned char seg_buf[8];//段码数组和数码管一一对应
unsigned char pos = 0;//数码管要显示的位置
void main()
{
Cls_peripheral();//关闭外设
Timer1Init();//定时器1被征用到数码管显示1ms一次的控制。
EA = 1;//打开总中断
sprintf(seg_string," %4u",(unsigned int)disp_data);
//将待显示的数据打印到seg_string字符串数组,
即将disp_data数据放到seg_string字符串数组中去
Seg_Tran(seg_string,seg_buf);
//将seg_string的各个位转换为数码管段码,存储到seg_buf数组中。
while(1);
}
//-----------------------------------------------
/* Timer1_interrupt routine */
void tm1_isr() interrupt 3
{
Seg_Disp(seg_buf, pos);
pos++;
if(pos == 8) pos = 0;
}
//-----------------------------------------------
**dsp_seg.c文件**
//函数名:“字符串”到“数码管段码”的转换函数
//入口参数:seg_string(10个字节)待转换的字符串;将转换完的段码存到seg_buf(8个字节)里
//返回值:无
//函数功能:将seg_string的各个位转换为数码管段码,存储到seg_buf数组中。
void Seg_Tran(unsigned char *seg_string, unsigned char *seg_buf)
{
unsigned char i=0;//buf[i],i=0~7
unsigned char j=0;//seg_string[j],j=0~10
unsigned char temp;//字符串转换为段码的中间存储变量
for(i=0;i<=7;i++,j++)
{
switch(seg_string[j])
{
case '0': temp = ~0x3F; break;
case '1': temp = ~0x06; break;
case '2': temp = ~0x5B; break;
case '3': temp = ~0x4F; break;
case '4': temp = ~0x66; break;
case '5': temp = ~0x6D; break;
case '6': temp = ~0x7D; break;
case '7': temp = ~0x07; break;
case '8': temp = ~0x7F; break;
case '9': temp = ~0x6F; break;
case 'A': temp = ~0x77; break;
case 'B': temp = ~0x7C; break;
case 'C': temp = ~0x39; break;
case 'D': temp = ~0x5E; break;
case 'E': temp = ~0x79; break;
case 'F': temp = ~0x71; break;
case '-': temp = 0xbf; break;
case ' ': temp = 0xff; break;
default : temp = 0xff; break;
}
if(seg_string[j+1] == '.')//如果字符串里边出现了‘.’,要把刚刚出炉的temp值改变。
{
temp &= 0x7f;//把dp位点亮
j++;//跳过带'.'的位置
}
seg_buf[i] = temp;//将转换后的段码值传递给Buf存储。
}
}
//函数名:将“段码数组”的第N位显示。
//入口参数:seg_buf(8个字节)是转换完的段码; pos待显示的seg_buf第pos位。
//返回值:无
//函数功能:将seg_buf的第pos位显示在数码管的第pos位
void Seg_Disp(unsigned char *seg_buf,unsigned char pos)
{
P0 = 1<<pos;//位码送入
P2 = P2 & 0x1f | 0xc0;// 0xC0,选通Y6,也就是位码的锁存器,将数据透传过去
P2 &= 0x1f;//将打开的锁存器关闭,使任何一个锁存器都不打开
P0 = 0xff;//清空屏幕 段码--》消隐
P2 = P2 & 0x1f | 0xe0;// 0xE0,选通Y7,也就是段码的锁存器,将数据透传过去
P2 &= 0x1f;//将打开的锁存器关闭,使任何一个锁存器都不打开
P0 = seg_buf[pos];//段码送入
P2 = P2 & 0x1f | 0xe0;// 0xE0,选通Y7,也就是段码的锁存器,将数据透传过去
P2 &= 0x1f;//将打开的锁存器关闭,使任何一个锁存器都不打开
}
巧:
问:段码需要自己背吗?
答:不需要,可借助STC-ISP。
如图所示: