蓝桥杯-单片机组基础3——数码管的静动态显示(附小蜜蜂课程代码)

蓝桥杯单片机组备赛指南请查看 :本专栏第1篇文章

本文章针对蓝桥杯-单片机组比赛开发板所写,代码可直接在比赛开发板上使用。

型号:国信天长4T开发板(绿板),芯片:IAP15F2K61S2

(使用国信天长蓝板也可以完美兼容,与绿板几乎无差别)


1.编程目的

1.静态显示:搞懂段码是做什么的,并将数字6显示到一个数码管上;

2.动态显示:搞懂位码和段码共同工作的原理,并实现延时函数方式的计时器。

2.原理图介绍

2.1 单个数码管,与什么是段码?

(下图截取自知乎(侵权删):单片机数码管显示,看完这篇就够了

        上图为单个数码管的原理图,其中红色的线条为7个发光二极管,dp为单独的一个发光二极管,用于显示小数点。通过不同的二极管发光,即可实现不同数字的显示,例如,我们让“gfedca”共6个发光二极管亮,而剩下的“dp,b”共2个发光二极管不亮,则实现了数字6的显示。

        在编程时,需要用十六进制数从高位往低位对8个二极管进行整体赋值。假设对单个二极管引脚赋值为0时亮,则编程时,对应引脚编号为“dp gfedcba”,则对应赋值的二进制为“1000 0010”,转换为十六进制BCD码为“0x82”。于是赋值语句会写成:duanma = 0x82。

        这时,你会发现,变量名我写的时duanma——段码,可以认为,段码的作用就是定义单个数码管中,哪几段LED要发光。也就是段码决定显示什么内容。

2.2 多个数码管,与什么是位码?

8位显示内容的数码管,在开发板上长这样:

对应的原理图如下:

(截取自官方4T开发板SCH_硬件原理图V30.pdf)

        我们对这个原理图进行观察,它是由两块4位数码管DS1,DS2共同组成,从而让比赛的开发板可以显示8位内容。其中DS1和DS2拥有分别的段码位( dp1,g1,f1,e1,d1,c1,b1,a1),与位码位(com8~1)。我们需要理解的一个地方在于,com引脚时做什么用的,因此我们需要看一下8位数码管原理图:

(比赛开发板的数码管全是共阳极连接)

        观察原理图,可以看出共阳极连接就是8个发光二极管的阳极全部连接到一起,并接一个高电平。而发光二极管的另一端则对应段码的每一个位,哪一位赋值为0则哪一位亮。则编程时,需要先将阳极的连接公共端赋值为1,使其处于高电平;再对阴极的段码为赋值为0,使二极管发光。

        上段中提到的公共端,就是com8~1,称之为公共端,和位码有关。我们对com的任意一个引脚进行赋值为1,则相当于选中了这一位,让这一位的单个数码管显示内容。在编程时,如果我们要让从左往右第3个数码管显示数字6,则我们的步骤是:

        1.使用十六进制BCD码,对com口进行整体的赋值,com8~1对应二进制为“0000 0100”,转换后为0x08;       

        2.进行位码的赋值从而选择该位。比赛开发板的硬件焊接与原理图是反着的,从原理图来看,我们选择第三位应该是“0010 0000”,但硬件上应该是“0000 0100”,硬件位置与原理图相反,则赋值语句为 weima=0x04;        

        3.对该位赋值要显示的内容,duanma=0x82。

        因此,我们可以将位码理解为,选中哪一位进行显示。

2.3 开发板的原理图

(截取自官方4T开发板SCH_硬件原理图V30.pdf)

        我们首先找关键词com和abcdefg,因此明白带有com的U8为控制位码选择;带有abcdefg的U7为段码选择。通过进一步的观察,U8和U7的左端居然都连接的是P0口,不仅让人疑惑那我怎么让单片机的P0既要去传输段码,又要去传输位码捏?

        在进行观察,发现U8还连接了一个Y6C,当Y6C输入为低电平时,锁存器74HC573被激活,则P0口输出的内容,会输入到DSP1和DPS2的公共端口——位码端——com8~1。

        同理可得,U8连接了一个Y7C,当Y7C输入为低电平时,锁存器74HC573被激活,则P0口输出的内容,会输入到DSP1和DPS2的段码端口——dp1,g1,f1,e1,d1,c1,b1,a1。

        因此在编程时,通过设置Y6C为低电平来实现公共端的选择,设置Y7C为低电平来实现段码端的选择。而我们又要通过与P2端口相连的74HC138译码器来设置Y6C或是Y7C。对于锁存器与译码器之间的亲密关系讲解,可以参考:蓝桥杯-单片机组基础1——LED流水灯-CSDN博客。编程时,选中Y6C则设置74HC138译码器的“CBA”位为“110”,选中Y7C则设置为“111”。

3.代码参考

3.1 静态显示代码

代码效果为:在第三位数码管显示数字6

#include <reg52.h>
#include <intrins.h>

sbit HCB173_A = P2^5;
sbit HCB173_B = P2^6;
sbit HCB173_C = P2^7;

void Delay5ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 54;
	j = 199;
	do
	{
		while (--j);
	} while (--i);
}
		
void main ()
{	
	HCB173_A = 0 ;
	HCB173_B = 1 ;
	HCB173_C = 1 ;//设置Y6C为低电平
	
	P0 = 0x04;  //设置位码,选择第三位
	
	Delay5ms();//需要一个短暂的延时,消除发光二极管的拖影
	//可以尝试注释掉这一句延时函数,看一看有什么变化。在实际编程中,这一句延时很重要
	
	HCB173_A = 1 ;
	HCB173_B = 1 ;
	HCB173_C = 1 ;//设置Y7C为低电平
	
	P0 = 0x82;  //设置段码,为数字6	
}

3.2 动态显示代码

代码效果为:利用延时函数实现计时器.

        其实你会发现,用延时函数实现的计时器效果很不好。十位总是不能完整的显示清楚,这是因为我们对1秒的延时是停留在个位的,此时10位会熄灭。想要让十位和个位都显示清楚的话,可以将1秒的延时函数拆成多个延时过程,每一次延时都刷新一次位码和段码。拆的越多,效果越好,但没有意义,后面我们会学习使用更高级的中断方式,可以更方便实现完美的十位以上显示。

//使用数码管,前六位显示 2023-- ,最后两位显示月份,并不断变化

#include < reg52.h>
#include <intrins.h>

sbit HC173_A = P2^5;
sbit HC173_B = P2^6;
sbit HC173_C = P2^7;

unsigned char time;

unsigned char code SMG_duanma [18]=
			{ 0xc0 , 0xf9 , 0xa4 , 0xb0 , 0x99 , 0x92 , 0x82 , 0xf8 , 
				0x80 , 0x90 , 0x88 , 0x80 , 0xc6 , 0xc0 , 0x86 , 0x8e ,
				0xbf , 0x7f };
			
void select_HC173 ( unsigned char channal )
{
	switch ( channal )
	{
		case 4 :
			HC173_A = 0;
			HC173_B = 0 ;
			HC173_C = 1 ;
		break;
		case 5 :
			HC173_A = 1;
			HC173_B = 0 ;
			HC173_C = 1 ;
		break;		
		case 6 :
			HC173_A = 0;
			HC173_B = 1 ;
			HC173_C = 1 ;
		break;
		case 7 :
			HC173_A = 1;
			HC173_B = 1 ;
			HC173_C = 1 ;
		break;		
	}
}

void Initsys () //将数码管初始化一下,即取消选择所有位,公共端全部不选择
{
	select_HC173 ( 5 );
	P0 = 0x00;
}

void Input_SMG_bit ( unsigned char pos_SMG , unsigned char value_SMG )
{
	//用于对数码管的位码和段码进行统一管理与选择
	select_HC173 ( 6 );
	P0 = 0x01 << pos_SMG;
	select_HC173 ( 7 );
	P0 = value_SMG;
}

void Delay5ms()		//@12.000MHz
{
	unsigned char i, j;

	i = 59;
	j = 90;
	do
	{
		while (--j);
	} while (--i);
}

void Delay1000ms()		//延时一秒钟
{
	unsigned char i, j, k;

	_nop_();
	_nop_();
	i = 43;
	j = 6;
	k = 203;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void SMGrunning ( )  //对数码管的功能进行封装,使其模块化
{
	Input_SMG_bit ( 6 , SMG_duanma [(time)/10] );//得到当前时间的十位
	Delay5ms();	
	Input_SMG_bit ( 7 , SMG_duanma [(time)%10] );//得到当前时间的个位
	Delay5ms();	
}

void main ()
{
	Initsys ();
	while ( 1 )
	{
		for ( time=1 ; time<100 ; time++ )
		{
			SMGrunning ();
			time = time % 100;//当时间大于三位数时,归零为数字1,这个算法很妙,理解一下
			Delay1000ms();//延时一秒钟
		}
		Delay5ms();	//数码管数值变化时适当的延时是必须的,建议注释掉这一行再运行一次,看看有什么区别
	}
	
	
}

3.3 小蜜蜂课程代码

        代码一://利用数码管移位依次显示0~9,随后同时显示0~9

//利用数码管移位依次显示0~9,随后同时显示0~9
#include <reg52.h>
#include <intrins.h>

sbit HCB173_A = P2^5;
sbit HCB173_B = P2^6;
sbit HCB173_C = P2^7;

void Delay500ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	_nop_();
	i = 22;
	j = 3;
	k = 227;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

unsigned char code SMG_duanma [18]=
			{ 0xc0 , 0xf9 , 0xa4 , 0xb0 , 0x99 , 0x92 , 0x82 , 0xf8 , 
				0x80 , 0x90 , 0x88 , 0x80 , 0xc6 , 0xc0 , 0x86 , 0x8e ,
				0xbf , 0x7f };
			
void InitHC138 ( unsigned char channal )
{
	switch ( channal )
	{
		case 4 :
			HCB173_A = 0 ;
			HCB173_B = 0 ;
			HCB173_C = 1 ;
			break;
		case 5 :
			HCB173_A = 1 ;
			HCB173_B = 0 ;
			HCB173_C = 1 ;
			break;
		case 6 :
			HCB173_A = 0 ;
			HCB173_B = 1 ;
			HCB173_C = 1 ;
			break;
		case 7 :
			HCB173_A = 1 ;
			HCB173_B = 1 ;
			HCB173_C = 1 ;
			break;		
	}
}

void InputSMG ( unsigned char dat_SMG , unsigned char pos_SMG )
{
	InitHC138 (6);	//select SMG postion
	P0 = 0x01 << pos_SMG ;
	InitHC138 (7);	//select SMG item
	P0 = dat_SMG;
}

void SMGrunning ()
{
	unsigned char i,j;
	for ( i=0 ; i<=7 ; i++ )
	{
		for ( j=0 ; j<10; j++ )
		{
			InputSMG ( SMG_duanma[j] , i );
			Delay500ms();
		}
	}
}
			
void main ()
{
	while ( 1 )
	{
		SMGrunning ();
	}
}

        代码二://使用数码管,前六位显示 2023-- ,最后两位显示月份,并不断变化

//使用数码管,前六位显示 2023-- ,最后两位显示月份,并不断变化

#include < reg52.h>
#include <intrins.h>

sbit HC173_A = P2^5;
sbit HC173_B = P2^6;
sbit HC173_C = P2^7;

unsigned char month;

unsigned char code SMG_duanma [18]=
			{ 0xc0 , 0xf9 , 0xa4 , 0xb0 , 0x99 , 0x92 , 0x82 , 0xf8 , 
				0x80 , 0x90 , 0x88 , 0x80 , 0xc6 , 0xc0 , 0x86 , 0x8e ,
				0xbf , 0x7f };
			
void select_HC173 ( unsigned char channal )
{
	switch ( channal )
	{
		case 4 :
			HC173_A = 0;
			HC173_B = 0 ;
			HC173_C = 1 ;
		break;
		case 5 :
			HC173_A = 1;
			HC173_B = 0 ;
			HC173_C = 1 ;
		break;		
		case 6 :
			HC173_A = 0;
			HC173_B = 1 ;
			HC173_C = 1 ;
		break;
		case 7 :
			HC173_A = 1;
			HC173_B = 1 ;
			HC173_C = 1 ;
		break;		
	}
}

void Initsys ()
{
	select_HC173 ( 5 );
	P0 = 0x00;
}

void Input_SMG_bit ( unsigned char pos_SMG , unsigned char value_SMG )
{
	select_HC173 ( 6 );
	P0 = 0x01 << pos_SMG;
	select_HC173 ( 7 );
	P0 = value_SMG;
}

void Delay2ms()		//@11.0592MHz
{
	unsigned char i, j;

	_nop_();
	_nop_();
	i = 22;
	j = 128;
	do
	{
		while (--j);
	} while (--i);
}


void SMGrunning ( )
{
	Input_SMG_bit ( 0 , SMG_duanma [2] );
	Delay2ms();
	Input_SMG_bit ( 1 , SMG_duanma [0] );	
	Delay2ms();
	Input_SMG_bit ( 2 , SMG_duanma [2] );	
	Delay2ms();
	Input_SMG_bit ( 3 , SMG_duanma [3] );
	Delay2ms();
	Input_SMG_bit ( 4 , SMG_duanma [16] );
	Delay2ms();
	Input_SMG_bit ( 5 , SMG_duanma [16] );
	Delay2ms();
	
	Input_SMG_bit ( 6 , SMG_duanma [(month+1)/10] );
	Delay2ms();	
	Input_SMG_bit ( 7 , SMG_duanma [(month+1)%10] );
	Delay2ms();	
}

void Delay_SMG ( unsigned char t )	//set 1 ms mode by Delay2ms() 
{
	t/=8;	//the FUNCTION SMGrunning has 8 Delay2ms code ,so / 8
	while ( (t)-- )
	{
		
		SMGrunning ();
	}
}

void main ()
{
	Initsys ();
	while ( 1 )
	{
		for ( month=1 ; month<13 ; month++ )
		{
			SMGrunning ();
			month = month % 12;
			Delay_SMG( 1000 );	// 1s
		}
	}
}

4.硬件相关与段码表

        共阳极段码:

unsigned char code SMG_duanma [18]=
            { 0xc0 , 0xf9 , 0xa4 , 0xb0 , 0x99 , 0x92 , 0x82 , 0xf8 , 
                0x80 , 0x90 , 0x88 , 0x80 , 0xc6 , 0xc0 , 0x86 , 0x8e ,
                0xbf , 0x7f };

        这个断码表的作用就是把我们会用到的0~9,a~f,以及其他可能用到的显示内容,提前写进一个数组,从而方便我们使用数组小标的序号直接调用需要的内容。

5.编程思路重述

        先设置74HC138译码器选中Y6,对P0口赋值设置位码值,从而选中你要显示的端口。再设置138译码器选中Y6,对P0口赋值设置段码值,从而设置你要显示的内容。

  • 37
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值