数码管基础知识
蓝桥杯板上由4位数码管构成的8位数码管,数码管内部其实是一小段LED构成的,每位数码管由8个LED构成,所以控制每一小段LED的点亮和熄灭就可以显示不同的数字或英文。
蓝桥杯板载的数码管是共阳极的数码管,每一位数码管的阳极都接在一起引出来,所以一个有8个阳极,称为位选(com),所有数码管的阴极都接在一起引出来一共8位,称为段选,所以共16个引脚 。位选就是控制哪一位数码管选通,段选就是哪一段LED选通。要想点亮数码管就需要把对应的位选置为高电平,相应的段选置为低电平。
控制流程
上面说了数码管其实就是由很多个LED构成,那么点亮数码管的流程也和点亮LED一样,先给P0送段选数据,然后选通Y7C段选锁存器,关锁存器,再给P0送位选数据,开Y6C位选锁存器,关锁存器。
P27 | P26 | P25 | 译码器输出 | 或门输出 |
1 | 0 | 1 | Y5=0 | WR=0 (IO模式) Y5C=1 |
1 | 0 | 0 | Y4=0 | Y4C=1 (LED) |
1 | 1 | 0 | Y6=0 | Y6C=1 (数码管) |
1 | 1 | 1 | Y7=0 | Y7C=1 (数码管) |
聪明的童鞋就看出来了,这样子共阳极或者共阴极接的数码管在同一时刻,只能送一次段选数据,那么这样子就不能实现每一个数码管显示不同的数字或字母,但是可以利用人的视觉残留来模拟动态显示的效果,天下武功唯快不破,只要数码管上的数据变得够快,人就看不出来,就可以达到看起来每个数码管显示的东西不一样的效果了。单个数码管显示时间推荐为1ms-2ms,并且放在中断里面操作,显示效果比较好。
我们想显示不同的数字或者字母,每一次都要去推段选信号,感觉很麻烦,但是其实蓝桥杯比赛一般是会提供段选数据对照表的(只提供数字0-9),但是也有特殊情况,所以这里有一个小妙招,就是强大的STC-ISP。
在范例程序里面里面就有,并且字母对应的段选数据也有,这样子就可以愉快的复制黏贴啦~~~~当然一些特殊的符号之类的还是需要自己推的。
但是但是但是,这个里面的是共阴极数码管,蓝桥杯板载的共阳极的数码管,所以在使用这个数组的时候捏,需要进行取反(~)操作。
程序控制
//数码管动态显示
//8个数码管依次显示数字0-8
#include <STC15F2K60S2.H>
typedef unsigned char u8;
typedef unsigned int u16;
/************* 本地常量声明 **************/
u8 code t_display[]={ //标准字库
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,
//black - H J K L N o P U t G Q r M y
0x00,0x40,0x76,0x1E,0x70,0x38,0x37,0x5C,0x73,0x3E,0x78,0x3d,0x67,0x50,0x37,0x6e,
0xBF,0x86,0xDB,0xCF,0xE6,0xED,0xFD,0x87,0xFF,0xEF,0x46}; //0. 1. 2. 3. 4. 5. 6. 7. 8. 9. -1
u8 code T_COM[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; //位码
void device_ctrl(u8 P2data,u8 P0data)
{
P0=P0data;
P2=P2data;
P2=0;
}
void system_init()
{
device_ctrl(0xa0,0); //关闭蜂鸣器,继电器
device_ctrl(0x80,0xff); //关闭LED
}
void Timer2Init(void) //1毫秒@12.000MHz
{
AUXR &= 0xFB; //定时器时钟12T模式
T2L = 0x18; //设置定时初始值
T2H = 0xFC; //设置定时初始值
AUXR |= 0x10; //定时器2开始计时
IE2 |= 0x04; //开定时器2中断
EA = 1;
}
void smg_display()
{
static u8 i=0; //定义i为静态变量是为了防止每次执行完毕后将i清0
device_ctrl(0xe0,0xff); //将所有段选置为高电平,防止在com口开启时送入前一次的段选数据,其实有没有这一步操作区别也不大
device_ctrl(0xe0,~t_display[i]); //送段选信号,记住从STC-ISP中复制来的数据一定要进行取反
device_ctrl(0xc0,T_COM[i]); //送位选信号
i++;
if(i==8) //当8个数码管数据全部送完,将i清0
i=0;
}
void main()
{
system_init();
Timer2Init();
while(1)
{
}
}
void t2int() interrupt 12
{
smg_display();
}
//数码管显示HELLO
#include <STC15F2K60S2.H>
typedef unsigned char u8;
typedef unsigned int u16;
/************* 本地常量声明 **************/
u8 code t_display[]={ //标准字库
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,
//black - H J K L N o P U t G Q r M y
0x00,0x40,0x76,0x1E,0x70,0x38,0x37,0x5C,0x73,0x3E,0x78,0x3d,0x67,0x50,0x37,0x6e,
0xBF,0x86,0xDB,0xCF,0xE6,0xED,0xFD,0x87,0xFF,0xEF,0x46}; //0. 1. 2. 3. 4. 5. 6. 7. 8. 9. -1
u8 code T_COM[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; //位码
void device_ctrl(u8 P2data,u8 P0data)
{
P0=P0data;
P2=P2data;
P2=0;
}
void system_init()
{
device_ctrl(0xa0,0); //关闭蜂鸣器,继电器
device_ctrl(0x80,0xff); //关闭LED
}
u8 smg_buf[8];
void smg_process() //利用重新定义8位数组,给数字赋值,再把数组的值给8个数码管
//可以不用去修改数码管显示函数,不想显示的时候就直接给数组对应的位赋0就可以了
{
smg_buf[0]=t_display[18];
smg_buf[1]=t_display[14];
smg_buf[2]=t_display[21];
smg_buf[3]=t_display[21];
smg_buf[4]=t_display[0];
smg_buf[5]=0x00; //蓝桥杯板载是共阳极数码管,但是我们拷贝来的对照数据是共阴极的
smg_buf[6]=0x00; //并且在显示函数里面就是进行了取反操作,所以相应的0xff取反0x00才是熄灭数码管
smg_buf[7]=0x00;
}
void Timer2Init(void) //1毫秒@12.000MHz
{
AUXR &= 0xFB; //定时器时钟12T模式
T2L = 0x18; //设置定时初始值
T2H = 0xFC; //设置定时初始值
AUXR |= 0x10; //定时器2开始计时
IE2 |= 0x04; //开定时器2中断
EA = 1;
}
void smg_display()
{
static u8 i=0; //定义i为静态变量是为了防止每次执行完毕后将i清0
device_ctrl(0xe0,0xff); //将所有段选置为高电平,防止在com口开启时送入前一次的段选数据,其实有没有这一步操作区别也不大
device_ctrl(0xe0,~smg_buf[i]); //送段选信号,记住从STC-ISP中复制来的数据一定要进行取反
device_ctrl(0xc0,T_COM[i]); //送位选信号
i++;
if(i==8) //当8个数码管数据全部送完,将i清0
i=0;
}
void main()
{
system_init();
Timer2Init();
smg_process();
while(1)
{
}
}
void t2int() interrupt 12
{
smg_display();
}