单片机蓝桥杯——数码管

我们先来看一下蓝桥杯板中数码管部分的电路图:

        对于动态数码管的控制,是需要有段选和位选的,位选是控制数码管哪一位显示,段选是控制该位显示什么数字,由上图可知,当Y6C有效时,P0控制的是数码管的位;当Y7C有效时,可以给P0写入显示数字的段码。以下依次是数码管0~F以及熄灭的段码:

{0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8, 0x80,0x90,0x88,0x80,0xc6,0xc0,0x86,0x8e,0xff}

让8位数码管依次显示1 2 3 4 5 6 7 8

思路:先使Y6C有效,进行数码管显示位的选择;再使Y7C有效,为数码管输入段码。由于动态数码管显示依靠的是视觉暂留,所以数码管的每一位设定完成后,要加一个延时函数。延时程序的作用是保持当前显示数码管足够时间,同时稳定显示效果,以形成视觉暂留。延时时间长短视具体情况而定,一般要大于2毫秒,所有数码管一次扫描完成总时间不能大于40毫秒。这里我数码管每位显示后设置了一个2ms的延时(延时1ms显示也是正常的,但3ms的时候显示的数字会闪烁,这里大家可以自己设置不同时间看一下效果)

接下来我们通过代码来看一下具体该如何实现:

#include"reg51.h"
#include"intrins.h"
//数码管段码表
unsigned char code SMG_DuanMa[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
																 0x80,0x90,0x88,0x80,0xc6,0xc0,0x86,0x8e,0xff};
												

void Init_74HC138(unsigned char n)
{
	switch(n)
	{
		case 4://Y4有效,P0直接控制LED
			P2=(P2 & 0x1f) | 0x80;
			break;
		case 5://Y5有效,P0控制蜂鸣器、继电器
			P2=(P2 & 0x1f) | 0xa0;
			break;
		case 6://Y6有效,P0控制数码管位选
			P2=(P2 & 0x1f) | 0xc0;
			break;
		case 7://Y7有效,P0控制数码管段选
			P2=(P2 & 0x1f) | 0xe0;
			break;
	}
}
void Delay2ms()		//2ms的延时函数(视觉暂留)
{
	unsigned char i, j;
	_nop_();
	_nop_();
	i = 22;
	j = 128;
	do
	{
		while (--j);
	} while (--i);
}

void SMG_Disp()
{	
//*******第一位显示1*************
	Init_74HC138(6);  //Y6C有效,P0控制显示哪一位
	P0=0x01;          //P0=0000 0001,选通第一位(最左边一位)
	Init_74HC138(7);  //Y7C有效,P0控制显示哪一个数字
	P0=SMG_DuanMa[1];	//给P0输入数字1的段码,让数码管显示1	
	Delay2ms();
//*******第二位显示2*************	
	Init_74HC138(6);	//Y6C有效
	P0=0x02;          //P0=0000 0010,选通第二位
	Init_74HC138(7);	//Y7C有效
	P0=SMG_DuanMa[2];	//给P0输入数字2的段码,让数码管显示2		
	Delay2ms();
//*******第三位显示3*************		
	Init_74HC138(6);	//Y6C有效
	P0=0x04;					//P0=0000 0100,选通第三位
	Init_74HC138(7);	//Y7C有效
	P0=SMG_DuanMa[3];	//给P0输入数字3的段码,让数码管显示3
	Delay2ms();
//*******第四位显示4*************		
	Init_74HC138(6);
	P0=0x08;					//P0=0000 1000,选通第四位
	Init_74HC138(7);
	P0=SMG_DuanMa[4];	//数码管显示4
	Delay2ms();
//*******第五位显示*************		
	Init_74HC138(6);
	P0=0x10;					//P0=0001 0000,选通第五位
	Init_74HC138(7);
	P0=SMG_DuanMa[5];	//数码管显示5
	Delay2ms();
//*******第六位显示6*************		
	Init_74HC138(6);
	P0=0x20;					//P0=0010 0000,选通第六位
	Init_74HC138(7);
	P0=SMG_DuanMa[6];	//数码管显示6	
	Delay2ms();
//*******第七位显示7*************		
	Init_74HC138(6);
	P0=0x40;					//P0=0100 0000,选通第七位
	Init_74HC138(7);
	P0=SMG_DuanMa[7];	//数码管显示7	
	Delay2ms();
//*******第八位显示8*************		
	Init_74HC138(6);
	P0=0x80;					//P0=1000 0000,选通第八位
	Init_74HC138(7);
	P0=SMG_DuanMa[8];	//数码管显示8	
	Delay2ms();	
}
void main()
{
	while(1)
	{
		SMG_Disp();//调用数码管显示子函数
	}
}
	

        上述代码中的数码管显示函数SMG_Disp()是不是感觉代码稍微有点长,而且基本都是重复的语句,在对数码管显示原理搞懂之后,我们可以对这个函数进行修改,大家看下面这个函数,实现的功能一样,是不是精简了许多呢?

#include"reg51.h"
#include"intrins.h"
//数码管段码表
unsigned char code SMG_DuanMa[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
																 0x80,0x90,0x88,0x80,0xc6,0xc0,0x86,0x8e,0xff};

void Init_74HC138(unsigned char n)
{
	switch(n)
	{
		case 4://Y4有效,P0直接控制LED
			P2=(P2 & 0x1f) | 0x80;
			break;
		case 5://Y5有效,P0控制蜂鸣器、继电器
			P2=(P2 & 0x1f) | 0xa0;
			break;
		case 6://Y6有效,P0控制数码管位选
			P2=(P2 & 0x1f) | 0xc0;
			break;
		case 7://Y7有效,P0控制数码管段选
			P2=(P2 & 0x1f) | 0xe0;
			break;
	}
}
void Delay2ms()		//2ms的延时函数(视觉暂留)
{
	unsigned char i, j;
	_nop_();
	_nop_();
	i = 22;
	j = 128;
	do
	{
		while (--j);
	} while (--i);
}
//*******smg_wei代表第几位(注意这个是从0~7,0是第一位,1是第二位....)
//*******smg_val代表显示的数字
void SMG_Disp(unsigned char smg_wei,unsigned char smg_val)
{	
	Init_74HC138(6);
	P0=(0x01 << smg_wei);
	Init_74HC138(7);
	P0=SMG_DuanMa[smg_val];		
	Delay2ms();	
}
void main()
{
	while(1)
	{
		SMG_Disp(0,1);//第0位(也就是数码管的最左边的一位)显示数字1
		SMG_Disp(1,2);//第1位显示数字2
		SMG_Disp(2,3);//第2位显示数字3
		SMG_Disp(3,4);//第3位显示数字4
		SMG_Disp(4,5);//第4位显示数字5
		SMG_Disp(5,6);//第5位显示数字6
		SMG_Disp(6,7);//第6位显示数字7
		SMG_Disp(7,8);//第7位显示数字8
	}
}

	

        在SMG_Disp(unsigned char smg_wei,unsigned char smg_val)函数中,直接将数码管要显示的位和显示的数字给该函数,在该函数中用到了左移符号<<,减少了代码量。

        若想让数码管有的亮有的灭呢?因为我们用到的是共阳极数码管,只需要给P0写0xff即可。在上述代码中,我在段码表的第16位加上了0xff,这样可以直接控制该位熄灭。例如数码管前四位显示1 2 3 4 ,后四位不亮,用代码表示即为:

void main()
{
	while(1)
	{
		SMG_Disp(0,1);//第0位显示数字1
		SMG_Disp(1,2);//第1位显示数字2
		SMG_Disp(2,3);//第2位显示数字3
		SMG_Disp(3,4);//第3位显示数字4
		SMG_Disp(4,16);//第4位不显示
		SMG_Disp(5,16);//第5位不显示
		SMG_Disp(6,16);//第6位不显示
		SMG_Disp(7,16);//第7位不显示
	}
}


                                                            

  • 17
    点赞
  • 72
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
这里提供一份蓝桥杯单片机数码管定时器动态扫描的参考代码,供大家参考。 ```c #include <reg51.h> //头文件 // 数码管位选信号 unsigned char code LED_W[] = {0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F}; // 数码管段选信号 unsigned char code LED_D[] = { 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71 }; // 定时器中断服务函数 void Timer0_ISR() interrupt 1 { static unsigned char count = 0; // 计数器 static unsigned char index = 0; // 位选信号索引,表示当前显示的是哪一位数码管 count++; // 计数器加1 if (count >= 100) { // 计数器达到100时,表示100ms已经过去了 count = 0; // 计数器清零 P0 = LED_W[index]; // 先将位选信号输出到P0口 P2 = LED_D[index]; // 再将对应的段选信号输出到P2口 index = (index + 1) % 8; // 索引加1,循环显示8个数码管 } } void main() { TMOD = 0x01; // 定时器0工作在模式1,16位定时器 TH0 = 0xFC; // 定时器初值,定时1ms TL0 = 0x66; ET0 = 1; // 允许定时器0中断 EA = 1; // 允许总中断 TR0 = 1; // 启动定时器0 while(1); // 主函数空循环,等待中断触发 } ``` 该代码中,通过定时器0产生1ms的中断,然后在中断服务函数中动态扫描8个数码管。其中,`LED_W`为数码管的位选信号,`LED_D`为数码管的段选信号。在每次中断服务函数中,先输出位选信号,再输出对应的段选信号,就可以实现数码管的动态扫描了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值