#数码管显示
共阳数码管原理图在这里插入图片描述
数码管就是八个LED灯,针对共阳极数码管,为低电平点亮。a,b,c,d,e,f,g,dp分别对应于P0~P7。因此我们想要让数码管显示0,则让g和dp为高即可,即11000000,对应十六进制的0xc0
##数码管的控制
![[Pasted image 20220328132742.png]]
![[Pasted image 20220328132859.png]]

在蓝桥杯开发板中,数码管的状态通过两个锁存器来控制U8、U7。使能Y6C(置高)将启动位选锁存器,获取点亮数码管的位数据(0x01-0x80),拉低用Y6C(置低)锁存当前值。位数据可通过对P0赋值获得。同理,使能Y7C可以启动锁存器获取段码值(0-9),也是通过P0口输入给锁存器。
因此,假如我们想要使第一个数码管显示0,我们应该先选择数码管,再给段码值。

第一步,使能Y6C:
第二步,向P0赋值0x01,选择第一个数码管:
第三步,使能Y7C:
第四步,向P0赋值0xc0(共阳),让数码管显示0:

#LED显示
![[Pasted image 20220328135738.png]]

蓝桥杯开发板上的LED接法为阳极接高电平,阴极接锁存器的输出端。因此我们想要点亮某个LED,必须将对应的端口置低,锁存器的输出和P0的值是一一对应的。
因此,加入我们想要点亮第一个LED,我们应该先使能Y4C,然后给P0赋对应的值。

第一步,使能Y4C:
第二部,向P0赋值0xfe,即11111110,第一位为底其他为高,第一个LED将被点亮:

#锁存器的控制
![[Pasted image 20220328141501.png]]
![[Pasted image 20220328143723.png]]

上面说到,无论是显示数码管还是LED,都先要使能对应的锁存器。在蓝桥杯开发板中,锁存器的控制主要通过P25~P27即P2口的高三位来实现。
如果我们想要显示LED,那么我们的第一步就是使能Y4C,如上图,WR默认接地(IO模式),接P42则为MM模式。我们想要让Y4C输出高,对于74HC02或非门来说,WR和Y4只能都为低,WR默认为低。因此我们只需要控制Y4的状态即可,而Y4的状态又通过14HC138来控制,对于38译码器,它的真值表如上。所以我们只需要让P25~P27为001,即可使Y4C为低。

因此我们了解到,如果我们想要显示LED或者数码管,我们只需要操作P2口的高三位(使能锁存器)和P0口(给数据或者段码)即可

代码示例

//第一个数码管显示0
P2 = (P2&0X1F| 0xc0//初始化P2口的高三位为0,然后将高三位赋值为110,使能Y6C
P0=0x01;                            //选择第一个数码管
P2 =(P2&0X1F| 0xe0//使能Y7C
P0=0xc0
//点亮第一个LED
P2= (P2&0X1F) | 0X80; //使能Y4C
P0=0XFE; //把P0的第一位置低

同时我们应该意识到一个问题,数码的显示和LED的显示,都需要P0作为数据的输入端。那么当需要同时显示LED和数码管的时候,会不会出现他们两者互相影响的情况呢。在实际的操作中我也遇到了这种问题:当程序中数码管用中断显示的时候,显示LED的效果往往不好,容易出现不应该亮的LED微微发亮的情况和数码管显示不稳定的情况。

为了解决上面出现的情况,我的解决办法是,当使用完P2后,及时将高三位清零,使锁存器工作在锁存状态,显示完数码管后将P0的值进行一初始化,显示LED的时候,通过声明变量来保存赋值给P0的值

代码示例
代码将实现,全部数码管显示0-7,同时LED在按键控制下从左到右依次被点亮

#include "stc15f2k60s2.h"
#define uchar unsigned char
#define uint unsigned int

sbit S4=P3^3;

void InitTimer0();
void keyscan();

//声明数码管的段码,方便显示调用
uchar code SEG_daun[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
//声明LED显示的段码
uchar code LED_duan[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
uchar led=0xff;  //声明变量保存LED的数据

void main()
{
   InitTimer0();
   while(1)
   {
   	keyscan();
   }

}

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

   i = 117;
   j = 184;
   do
   {
   	while (--j);
   } while (--i);
}



//为了方便使能各个锁存器,往往把使能条件写在一个函数中供方便使用,输入形参n,即可使能对应的锁存器

void Cro_hc138(uchar n)
{
   switch(n)
   {
   	case 4: P2 = (P2&0X1F) | 0X80; break;  //使能Y4C
   	case 5: P2 = (P2&0X1F) | 0XA0; break;
   	case 6: P2 = (P2&0X1F) | 0XC0; break;
   	case 7: P2 = (P2&0X1F) | 0XE0; break;
   }
}

//按照数码管显示步骤,写一个显示一个数码管的函数,我们可以通过这个函数来选择显示哪一个数码管,显示什么数据,只需要给定两个形参即可

void SEG_bit(uchar p,uchar dat)
{
   Cro_hc138(6); //使能Y6C,第一步
   P0= 0x01 << p; //选择第几个数码管,若p=0,即1左移零位,还是0x01,为第一位数码管
   Cro_hc138(7); //使能Y7C,第三步
   P0=dat;       //给P0赋值段码,第四步
}


//按键检测程序,按键按下,下一个LED被点亮

void keyscan()
{
   static uchar i=0;
   if(S4==0)
   {
   	Delay10ms();//消抖
   	if(S4==0)
   	{
   		while(S4==0);//等待按键弹起
   		led=LED_duan[i];// 初始i为0,按键按下一次,i增加1,实现LED轮流点亮
   		i++;
   		i&=0x07; // i等于8的时候,清零,可以自己慢慢想一想,很妙用

   	}	
   }
}
//写一个专门的LED显示程序,放到中断里执行
void Dispaly_led()
{
   Cro_hc138(4);//使能Y4C,第一步
   P0=led;      //赋值,第二步
}

//因为要同时显示八个数码管,原理上还是每次只显示一个,但是我可以缩短每一个数码管显示的时间,每个只显示1ms,来达到视觉暂留即看起来全部同时亮了的目的。使用定时器中断,首先先初始化

void InitTimer0()
{
   TMOD=0X00; // 配置定时器的工作模式,可参考手册定时器模式控制寄存器IMOD
   TH0=(65536-1000)/255; //15定时器默认采用12T模式,即1us记一次数,在此定时1ms
   TL0=(65536-1000)%255;
   ET0=1;
   EA=1;      //开中断
   TR0=1;     //启动计时			
}

//T0中断服务函数,在中断里显示数码管和LED
void Timer0() interrupt 1
{
   static uchar i=0;//声明静态变量,目的是为了每次进入此函数,i的值不会被清零
   Dispaly_led();
   SEG_bit(i,SEG_daun[i]);//刚开始i=0,p=0x01,dat=0xc0,第一个数码管亮,显示0,以此类推
   i++;
   if(i==8)  //当显示完最后一个数码管的时候,从头再来,此时全部数码管都显示零
   	i=0;
   P2 &= 0X1F;
   P0=0XFF;
}

`

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐