蓝桥杯单片机组备赛——数码管动态显示

✨文章内容会不断优化,如果你感兴趣的话,欢迎点藏收藏关注我哟
🧨如果文章有哪里看不懂的欢迎评论区或私信留言,我会及时回复的
⏰如果文章出现错误,欢迎指正,看到后我会马上改正

一、动态显示原理

  在数码管动态显示中,工作原理主要基于视觉暂留效应。视觉暂留效应是一种生理现象,当图像快速闪烁或移动时,它在我们眼睛中留下的影像会持续留存短暂的时间,这使得我们可以看到一个连续不断的图像,而不是一系列单独的闪烁或移动的图像。
  数码管动态显示具体来说是这样实现的:首先,你选中其中一个数码管(通常由硬件电路如译码器完成),并且将你想要在数码管上显示的数字或字符传送到相应的段上。然后,你迅速切换(20ms左右)到下一个数码管,并将你想要显示的内容传送到这个数码管的相应段上。这个过程在所有的数码管之间快速循环,以达到同时显示在所有数码管上的效果。每个数码管的点亮时间非常短,但由于视觉暂留效应,我们看到的效果是所有的数码管都在同时显示内容。
  这种方式的优点是,尽管一次只能驱动一个数码管,但节省了大量的硬件资源。然而,缺点在于需要通过编程控制,以确保显示内容持续更新,从而创建出一种所有数码管都在持续显示的错觉。如果刷新速度过慢,我们可能会看到显示内容的闪烁。一般来说,如果刷新频率能够达到50Hz或以上,就足以避免人眼察觉到的闪烁现象。

二、动态显示的目的

2.1 单片机IO口有限

假设开发板上8个数码管都有独立的段码输入,8个数码管每个都要8个段选输入IO(a b c d e f g dp),且每一个都要有位选IO(com x),那么一共需要8*8+8=72个IO口,很明显51没有那么多IO口。如果8个数码管共用段码输入,那么只需要8+8=16个IO口,又因为段选和位选共用一个P0口,所以只需要8个IO口就能够实现段选和位选。

2.2 节省IO口资源

即使IO口够用的情况下,通常也不会采用每个数码管独立的段选信号,太浪费资源了。

2.3 节能

通过视觉暂留效应和数码管余辉效应,大脑感受不到数码管熄灭了一段时间,熄灭的这段时间就可以节省下大量的能力。

三、代码编写

动态数码管显示基于静态数码管显示,依次从左到右控制每一个数码管,每个数码光管点亮的时间大概为2ms,这样每一轮的刷新时间就是2*8=16ms,刷新频率大于50Hz,这就满足了人眼的视觉暂留效应

👉重点知识:数码管刷新频率指的是,所有用到的数码管刷新的频率,并不是单个数码管的刷新频率!

单个数码管显示代码

void display_SMG_Bit(unsigned char dat, unsigned pos)
{
	P0=0x01<<(pos-1);  	// 设置位选数据
	selectHC573(6);		// 打开位选锁存器
	selectHC573(0);		// 关闭位选锁存器
	
	P0=dat;				// 设置段码数据
	selectHC573(7);		// 开启段码锁存器
	selectHC573(0);		// 关闭段码锁存器
}

动态数码管显示代码

void display_D_SMG(int dat1)
{	
	display_SMG_Bit(dat[2],1);  // 显示第一个数码
	Delay2ms();					// 延时一段时间2ms左右最佳
	
	display_SMG_Bit(dat[0],2);	// 显示第二个数码
	Delay(300);					// 延时一段时间
	
	display_SMG_Bit(dat[2],3);	// 显示第三个数码
	Delay2ms();					// 延时一段时间

	display_SMG_Bit(dat[3],4);
	Delay2ms();
	
	display_SMG_Bit(dat[16],5);
	Delay2ms();
	
	display_SMG_Bit(dat[16],6);
	Delay2ms();
	
	display_SMG_Bit(dat[dat1 / 10],7);
	Delay2ms();

	display_SMG_Bit(dat[dat1 % 10],8);
	Delay2ms();
}

四、数码管残影问题以及如何消影

📌如何解决数码管“串台”,导致数码管显示不正常,也就是如何解决消影的问题?

4.1 问题现象

看下面这张图,对比箭头所指的两个数码管,可以看到上面那个数码管有前面一个数码管的残影,而下面的就没有,这个问题的出现跟代码有关系,所以我们要注意代码的编写。
在这里插入图片描述

4.1 问题分析

在这里插入图片描述

4.3 问题解决

将上面单个数码管显示的函数修改一下:

void display_SMG_Bit(unsigned char dat, unsigned pos)
{
	/*消影*/
	P0=0xff;   		// 清空段码数据
	selectHC573(7);	// 打开段码锁存器
	selectHC573(0);	// 关闭段码锁存器
	
	P0=0x01<<(pos-1);
	selectHC573(6);
	selectHC573(0);


	P0=dat;
	selectHC573(7);
	selectHC573(0);
}

五、数码管刷新方法

5.1 软件延时实现动态数码管显示

这种方式就是利用延时函数delay来实现动态数码管的显示,比较常见,不做赘述。

5.2 定时器中断实现动态数码管显示

这种方式就是在定时器中断服务函数中刷新动态数码管,具体做法就是设置定时器中断的时间为2ms,然后每次进入中断服务函数就刷新一个数码管

volatile unsigned char seg_pos=0; 	// 因为这个变量在中断中改变,所以需要添加volatile关键字修饰

void Timer0_Isr(void) interrupt 1
{
	display_SMG_Bit(seg_pos,segduan[segdat[seg_pos]]);
	
	seg_pos++;
	if(seg_pos==8)
		seg_pos=0;
}

void Timer0_Init(void)		//1800微秒@12.000MHz 1.8ms   
{
	AUXR &= 0x7F;			//定时器时钟12T模式
	TMOD &= 0xF0;			//设置定时器模式
	TL0 = 0xF8;				//设置定时初始值
	TH0 = 0xF8;				//设置定时初始值
	TF0 = 0;				//清除TF0标志
	TR0 = 1;				//定时器0开始计时
	ET0 = 1;				//使能定时器0中断
}

5.3 二者有什么区别?

软件延时会阻塞程序的其他函数运行,降低实时性。
同时,如果while(1)里面有运行的比较久的函数也会影响数码管的刷新显示。

✨博客会一直改进,有新的问题或知识我都会在这里分享,欢迎大家点赞收藏关注。
✨文中如果出现什么问题,欢迎大家帮忙指正,谢谢大家!

posted @ 2024-01-15 15:45  SuperCodeCat  阅读(199)  评论(0)    收藏  举报  来源