蓝桥杯单片机基础模板一:动态数码管显示

蓝桥杯单片机有一些基础模块的写法,他是没有一定的公式模板的。

好比动态数码管扫描显示,原理就是快速地 传输段选和位选。

但因为电路上添加了74HC573芯片,导致了我们移植别处 51单片机的动态扫描代码

会出现诸多问题,比如闪烁,鬼影,甚至崩溃不显示了......

备赛14届省赛时,我花费数日不断调整程序结构,结合芯片速率,尝试各种

段选位选上的延时,最终调试出来了一个比较稳定可靠的数码管动态扫描函数。

此篇文章将围绕我调试出的 数码管动态扫描函数来进行讲解,欢迎大佬批评指正!

为使讲解更完善,我会循序渐进地从硬件底层开始分析,

如果急于想看代码,可以点目录进行传送:

目录

电路图与数码管动态扫描原理简要介绍:

定时器的配置与使用:

数码管显示函数的编写与介绍:

整体工程代码:

显示效果展示:


电路图与数码管动态扫描原理简要介绍:

 我们先看一位数码管是怎么点亮和操作的:

下图中有四位数码管,我们先只看最左边的就行了:

 我们看到,每一位数码管上八个段,每一个段都标有专属的a,b,c,d,e,f,g,dq.

(其中dq是右下角的小数点)

这八个字母分别对应着八根连在74hc573芯片上的线a,b,c,d,e,f,g,dq.

对应着的线打低电平(0)过去,就能使数码管对应段点亮了,

比如我想让数码管显示1,那只要让b和c亮,其余灭即可,端口读取的顺序是

dq g f e d c b a  所以对应段码为 1111 1001 ,转换为16进制数即为:0xf9

照这样,我们将0~9,甚至一些字母的显示段码推算出来,

就获得了常用字库,我们可以将其存在数组中:

此处贴出常用字库:

/*//数码管字库数组:
数组下标对应数字 字符段码速查:(PS:0~9数字和下标一致,0~9的下标 +20 就能加上小数点)
	0_0  1_1  2_2  3_3  4_4  5_5  6_6  7_7  8_8  9_9  10_a 
  11_b 12_c	13_d 14_e 15_f 16_空 17_根线 18_H 19_P 
	20_0. 21_1. 22_2. 23_3. 24_4. 25_5. 26_6. 27_7. 28_8. 29_9. 30_L 31_n
*/
u8 code smgZK[35]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0xff,0xbf,0x89,0x8c,0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0xc7,0xc8};

我们开发板板载了四片74hc573芯片,都是读取的单片机端口P0的高低电平情况,

其中有俩片是与我们数码管有关的,一片用于段选,一片用于位选。

位选很容易理解,就是com1~com8,对应74hc573芯片的引脚打高电平就能使

当前被选中位的数码管按照之前传过来的段码进行显示

而该如何选择哪片74hc573芯片来锁存 P0端口数据呢?

我们查阅原理图:

 发现还有74hc138芯片(8选1)与或非门进行运算后,才能使能进行对应

Y6C_74hc573芯片 ,Y7C_74hc573芯片来锁存P0端口数据。

此处贴出74hc138使能74hc573芯片开启锁存函数:

//74HC138\74hc573芯片片选	函数
//传入一个参数,用来选择打开哪个74HC573锁存芯片									
void inint_port(u8 select)
{
	switch(select)
	{
		case 4:	P2=(P2&0X1F)|0X80;break;    //LED
		case 5:	P2=(P2&0X1F)|0XA0;break;	//蜂鸣器继电器
		case 6:	P2=(P2&0X1F)|0XC0;break;	//数码管位选
		case 7:	P2=(P2&0X1F)|0XE0;break;	//数码管段选
	}
}

 可见我们开发板P0端口的强大,可以给许多模块传输控制信号。

 从以上电路原理图可见,八位数码管连接着俩片74HC573芯片:

分别是a1~dq1 控制段选 的 Y7C_74HC573芯片 (a~g决定七段码显示,dq表示要不要加小数点)

以及com1~com8控制位选的 Y6C_74HC573芯片    

数码管的动态扫描就是一位一位传送对应 位选 和 段选码,比如我想让八位数码管

显示1,2,3,4,5,6,7,8,那我就得:

打开com1 关闭其余com2~com8,然后传送1的段码                    

打开com2,关闭其余com1,com3~com8,然后传送2的段码

打开com3,关闭其余com1,com2,com4~com8,然后传送3的段码

以此类推到com8 完成一整个动态扫描。

其运用的原理就是快速的一位一位地扫描,运用肉眼的视觉暂留,

造成每一位都在显示的假象,其实本质是一位一位亮过去的。

定时器的配置与使用:

定时器在蓝桥杯单片机中是十分重要的外设,这里简要介绍我们如何配置使用它

具体基础知识还是要大家自己努力学习才是!

我们可以用STC_ISP软件直接生成驱动定时器的代码:

这在比赛中也是提供此软件可以使用的:

以下示例   定时器0开启,12T模式 ,定时1ms的设置细节:

 但它写的不是完整的开启定时器0,所以还需添加俩句来打开定时器0的中断:

 这个函数就是用来初始化定时器0的,在主函数while(1)循环之外调用一次就行了。

其次就是中断服务函数的编写,函数名不重要,主要是对应中断号写正确就行了:

void TIMER0_serv() interrupt 1 
{

}

这样,定时器0每计时1ms,就会进入中断函数一次,来执行里面的语句.

这样我们就能 精准、实时、快速、稳定 地刷新数码管了!

数码管显示函数的编写与介绍:

这是本人省赛以来一直使用的数码管打印函数,直接放在定时器中断中调用的

1~15ms为周期的刷新都十分稳定,只是15ms会变暗,建议5~8ms为周期刷新最好

一次性打印8位数码管,传送完位选,段选后先延时,再P0=0Xff;进行消除鬼影

nr1~nr8,不是直接传送的段码,而是作为字库数组的下标使用的,因为段码都

存在数组中,而且有些数值的运算用段码非常不方便。

//数码管打印函数
//传入八个参数u8 nr1,nr2,nr3,nr4,nr5,nr6,nr7,nr8 进行打印
//一次性打印八位数码管
void smg_display(u8 nr1,nr2,nr3,nr4,nr5,nr6,nr7,nr8)
{
	u8 i;
	i=0;
	for(i=0;i<=8;i++)     //循环扫描1~8位的数码管
	{
		inint_port(6);    //每一位先开启位选
		switch(i)
	    {
		case 1:P0=0X01;inint_port(7);P0=smgZK[nr1];Delay250us();P0=0Xff;break;			
		case 2:P0=0X02;inint_port(7);P0=smgZK[nr2];Delay250us();P0=0Xff;break;
		case 3:P0=0X04;inint_port(7);P0=smgZK[nr3];Delay250us();P0=0Xff;break;
		case 4:P0=0X08;inint_port(7);P0=smgZK[nr4];Delay250us();P0=0Xff;break;
		case 5:P0=0X10;inint_port(7);P0=smgZK[nr5];Delay250us();P0=0Xff;break;
		case 6:P0=0X20;inint_port(7);P0=smgZK[nr6];Delay250us();P0=0Xff;break;		
		case 7:P0=0X40;inint_port(7);P0=smgZK[nr7];Delay250us();P0=0Xff;break;			
		case 8:P0=0X80;inint_port(7);P0=smgZK[nr8];Delay250us();P0=0Xff;break;
		}
	}
}

其中还调用了延时函数Delay250us();这也可用STC_ISP软件生成:

//@12.000MHz  数码管函数 必要的250us打印延时
//各类延时函数可在软件生成,不用记忆
void Delay250us()
{
	unsigned char i, j;
	i = 3;j = 232;
	do{while (--j);} while (--i);
}

整体工程代码:

 此工程为8ms一周期扫描数码管,动态扫描显示1~8;

#include "stc15f2k60s2.h"

typedef unsigned char u8;

//蜂鸣器引脚
sbit buzz=P0^6;

/*//数码管字库数组:
数组下标对应数字 字符段码速查:(PS:0~9数字和下标一致,0~9的下标 +20 就能加上小数点)
	0_0  1_1  2_2  3_3  4_4  5_5  6_6  7_7  8_8  9_9  10_a 
  11_b 12_c	13_d 14_e 15_f 16_空 17_根线 18_H 19_P 
	20_0. 21_1. 22_2. 23_3. 24_4. 25_5. 26_6. 27_7. 28_8. 29_9. 30_L 31_n
*/
u8 code smgZK[35]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0xff,0xbf,0x89,0x8c,0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0xc7,0xc8};

u8 nr1,nr2,nr3,nr4,nr5,nr6,nr7,nr8;//数码管八位打印内容,对应字库数组下标

void give_nr();
void inint_port(u8 select);
void Delay250us();
void smg_display(u8 nr1,nr2,nr3,nr4,nr5,nr6,nr7,nr8);
void Timer0Init(void);


void main()
{
	
	inint_port(5);       //清除蜂鸣器
	buzz=0;
	inint_port(4);       //清除LED
	P0=0XFF;
	
	Timer0Init();
	
	while(1)
	{
		
		
	}
}

//为nr1~nr8赋值为1~8
void give_nr()
{
	nr1=1;nr2=2;nr3=3;nr4=4;
	nr5=5;nr6=6;nr7=7;nr8=8;
}

//74HC138\74hc573芯片片选	函数
//传入一个参数,用来选择打开哪个74HC573锁存芯片									
void inint_port(u8 select)
{
	switch(select)
	{
		case 4:	P2=(P2&0X1F)|0X80;break;  //LED
		case 5:	P2=(P2&0X1F)|0XA0;break;	//蜂鸣器继电器
		case 6:	P2=(P2&0X1F)|0XC0;break;	//数码管位选
		case 7:	P2=(P2&0X1F)|0XE0;break;	//数码管段选
	}
}

//@12.000MHz  数码管函数 必要的250us打印延时
//各类延时函数可在软件生成,不用记忆
void Delay250us()
{
	unsigned char i, j;
	i = 3;j = 232;
	do{while (--j);} while (--i);
}

//数码管打印函数
//传入八个参数u8 nr1,nr2,nr3,nr4,nr5,nr6,nr7,nr8 进行打印
//一次性打印八位数码管
void smg_display(u8 nr1,nr2,nr3,nr4,nr5,nr6,nr7,nr8)
{
	u8 i;
	i=0;
	for(i=0;i<=8;i++)
	{
			inint_port(6);
			switch(i)
			{
				case 1:P0=0X01;inint_port(7);P0=smgZK[nr1];Delay250us();P0=0Xff;break;			
				case 2:P0=0X02;inint_port(7);P0=smgZK[nr2];Delay250us();P0=0Xff;break;
				case 3:P0=0X04;inint_port(7);P0=smgZK[nr3];Delay250us();P0=0Xff;break;
				case 4:P0=0X08;inint_port(7);P0=smgZK[nr4];Delay250us();P0=0Xff;break;
				case 5:P0=0X10;inint_port(7);P0=smgZK[nr5];Delay250us();P0=0Xff;break;
				case 6:P0=0X20;inint_port(7);P0=smgZK[nr6];Delay250us();P0=0Xff;break;				
				case 7:P0=0X40;inint_port(7);P0=smgZK[nr7];Delay250us();P0=0Xff;break;			
				case 8:P0=0X80;inint_port(7);P0=smgZK[nr8];Delay250us();P0=0Xff;break;
			}
	}
}

//1毫秒@12.000MHz 定时器0 初始化函数
//此函数可在软件生成,别忘了添加 EA=1; ET0=1;这俩句
//此函数初始化定时器0为 1ms 中断一次,满足普遍要求
void Timer0Init(void)
{
	AUXR &= 0x7F;		//定时器时钟12T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0x18;		  //设置定时初始值
	TH0 = 0xFC;		  //设置定时初始值
	TF0 = 0;		    //清除TF0标志
	TR0 = 1;		    //定时器0开始计时
	
	EA=1;           //打开总中断
	ET0=1;					//打开定时器0中断
}


//定时器0中断服务函数
void TIMER0_serv() interrupt 1 
{
	u8 i;
	i++;
	if(i==8)
	{
		i=0;
		give_nr();
		smg_display(nr1,nr2,nr3,nr4,nr5,nr6,nr7,nr8);
	}
}

 

显示效果展示:

 

  • 23
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 17
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NULL指向我

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值