数码管显示电路分析-74hc138+74hc164

1.方案选择

数码管的显示电路有两种方案,可以用数码管显示专用IC,如simHT16K33;也可以用74HC138和74HC164两个芯片来分别进行位选和段选。前者可以节省CPU资源,只需通过IIC等通讯方式来进行显示控制和按键读取。后者则需要CPU花费一定的时间来进行位选和段选控制,并以一定的频率刷新。本次采取了后者,CPU为STM32F103VE。

2.原理图设计

原理图如下所示:一个138对应8个数码管的位选,1个164对应一个数码管的段选。使用4个138和4个164即可进行32个数码管的显示,即8个4位数码管。

LED灯也接在164上进行显示控制,按键检测接在138上进行检测。显示电路通过排线与主板相连。

3.程序设计

驱动程序包含三部分:数码管的显示,LED灯的显示,按键的检测。而且这三者占用资源一样,在RTOS中不能同步运行。

数码管显示部分程序如下:

u8 number[20]={
	
	0x3f,
	0x6, 
	0x5b,
	0x4f,
	0x66,
	0x6d,
	0x7d,
	0x07,
	0x7f,
	0x6f,
	0xbf,
	0x86, 
	0xdb,
	0xcf,
	0xe6,
	0xed,
	0xfd,
	0x87,
	0xff,
	0xef


};//0,1,2,3,4,5,6,7,8,9,0.,1.,2.,3.,4.,5.,6.,7.,8.,9.
void send_byte(unsigned char dat1,unsigned char dat2,unsigned char dat3,unsigned char dat4)
	{
	unsigned char i;
	DISPLAY_SDA_H;
	for(i=0;i<8;i++)
	{
		DISPLAY_SCL_L;
		if((dat4<<i)&0x80)
			DISPLAY_SDA_H;
		else DISPLAY_SDA_L;
			DISPLAY_SCL_H;
	}
	DISPLAY_SCL_L;

	DISPLAY_SDA_H;
	for(i=0;i<8;i++)
	{
		DISPLAY_SCL_L;
		if((dat3<<i)&0x80)
			DISPLAY_SDA_H;
		else DISPLAY_SDA_L;
			DISPLAY_SCL_H;
	}
	DISPLAY_SCL_L;

	DISPLAY_SDA_H;
	for(i=0;i<8;i++)
	{
		DISPLAY_SCL_L;
		if((dat2<<i)&0x80)
			DISPLAY_SDA_H;
		else DISPLAY_SDA_L;
			DISPLAY_SCL_H;
	}
	DISPLAY_SCL_L;

	DISPLAY_SDA_H;
	for(i=0;i<8;i++)
	{
		DISPLAY_SCL_L;
		if((dat1<<i)&0x80)
			DISPLAY_SDA_H;
		else DISPLAY_SDA_L;
			DISPLAY_SCL_H;
	}
	DISPLAY_SCL_L;
} //164位选数字,一次位选4个数码管
void DISPLAY( u8 number1,u8 number2,
							u8 number3,u8 number4,
							u8 number5,u8 number6,
							u8 number7,u8 number8)//数码管显示整数
{
	DISPLAY_E1_H;
	DISPLAY_E2_H;
	DISPLAY_E3_H;
	DISPLAY_E4_H;
	
	u8 n1[4],n2[4],n3[4],n4[4],n5[4],n6[4],n7[4],n8[4];
	n1[0]=number1%10;
	n2[0]=number2%10;
	n3[0]=number3%10;
	n4[0]=number4%10;
	n5[0]=number5%10;
	n6[0]=number6%10;
	n7[0]=number7%10;
	n8[0]=number8%10;
					
	n1[1]=number1/10%10;
	n2[1]=number2/10%10;
	n3[1]=number3/10%10;
	n4[1]=number4/10%10;
	n5[1]=number5/10%10;
	n6[1]=number6/10%10;
	n7[1]=number7/10%10;
	n8[1]=number8/10%10;
	
	n1[2]=number1/100%10;
	n2[2]=number2/100%10;
	n3[2]=number3/100%10;
	n4[2]=number4/100%10;
	n5[2]=number5/100%10;
	n6[2]=number6/100%10;
	n7[2]=number7/100%10;
	n8[2]=number8/100%10;
	
	n1[3]=number1/1000%10;
	n2[3]=number2/1000%10;
	n3[3]=number3/1000%10;
	n4[3]=number4/1000%10;
	n5[3]=number5/1000%10;
	n6[3]=number6/1000%10;
	n7[3]=number7/1000%10;
	n8[3]=number8/1000%10;

	
	
	DISPLAY_A0_L;
	DISPLAY_A1_L;
	DISPLAY_A2_L;
	send_byte(number[n1[3]],number[n3[3]],number[n5[3]],number[n7[3]]);//扫描第一个
	rt_thread_delay(1);
	send_byte(0x00,0x00,0x00,0x00);
	
	DISPLAY_A0_H;
	DISPLAY_A1_L;
	DISPLAY_A2_L;
	send_byte(number[n1[2]],number[n3[2]],number[n5[2]],number[n7[2]]);//扫描第二个
	rt_thread_delay(1);
	send_byte(0x00,0x00,0x00,0x00);
	
	DISPLAY_A0_L;
	DISPLAY_A1_H;
	DISPLAY_A2_L;
	send_byte(number[n1[1]],number[n3[1]],number[n5[1]],number[n7[1]]);//扫描第三个
	rt_thread_delay(1);
	send_byte(0x00,0x00,0x00,0x00);
	
	DISPLAY_A0_H;
	DISPLAY_A1_H;
	DISPLAY_A2_L;
	send_byte(number[n1[0]],number[n3[0]],number[n5[0]],number[n7[0]]);//扫描第四个
	rt_thread_delay(1);
	send_byte(0x00,0x00,0x00,0x00);
		
	DISPLAY_A0_L;
	DISPLAY_A1_L;
	DISPLAY_A2_H;
	send_byte(number[n2[3]],number[n4[3]],number[n6[3]],number[n8[3]]);//扫描第五个
	rt_thread_delay(1);
	send_byte(0x00,0x00,0x00,0x00);
	
	DISPLAY_A0_H;
	DISPLAY_A1_L;
	DISPLAY_A2_H;
	send_byte(number[n2[2]],number[n4[2]],number[n6[2]],number[n8[2]]);//扫描第六个
	rt_thread_delay(1);
	send_byte(0x00,0x00,0x00,0x00);
	
	DISPLAY_A0_L;
	DISPLAY_A1_H;
	DISPLAY_A2_H;
	send_byte(number[n2[1]],number[n4[1]],number[n6[1]],number[n8[1]]);//扫描第七个
	rt_thread_delay(1);
	send_byte(0x00,0x00,0x00,0x00);
	
	DISPLAY_A0_H;
	DISPLAY_A1_H;
	DISPLAY_A2_H;
	send_byte(number[n2[0]],number[n4[0]],number[n6[0]],number[n8[0]]);//扫描第八个
	rt_thread_delay(1);
	send_byte(0x00,0x00,0x00,0x00);
	
 

}

void DISPLAYfloatp( float number1,float number2,
							float number3,float number4,
							float number5,float number6,
							float number7,float number8)//数码管显示浮点数,两位小数
{ u16 int_number1,int_number2,int_number3,int_number4,int_number5,int_number6,int_number7,int_number8;
	u16 point1[4],point2[4],point3[4],point4[4],point5[4],point6[4],point7[4],point8[4]; 	
	if(number1/100>1)
	{
		int_number1=number1*10;
		point1[1]=10;
		point1[2]=0;
	}
	else
	{
	int_number1=number1*100;
		point1[1]=0;
		point1[2]=10;
	}
	
	
		if(number2/100>1)
	{
		int_number2=number2*10;
		point2[1]=10;
		point2[2]=0;
	}
	else
	{
	int_number2=number2*100;
		point2[1]=0;
		point2[2]=10;
	}
	
		if(number3/100>1)
	{
		int_number3=number3*10;
		point3[1]=10;
		point3[2]=0;
	}
	else
	{
	int_number3=number3*100;
		point3[1]=0;
		point3[2]=10;
	}
	
		if(number4/100>1)
	{
		int_number4=number4*10;
		point4[1]=10;
		point4[2]=0;
	}
	else
	{
	int_number4=number4*100;
		point4[1]=0;
		point4[2]=10;
	}
	
		if(number5/100>1)
	{
		int_number5=number5*10;
		point5[1]=10;
		point5[2]=0;
	}
	else
	{
	int_number5=number5*100;
		point5[1]=0;
		point5[2]=10;
	}
	
		if(number6/100>1)
	{
		int_number6=number6*10;
		point6[1]=10;
		point6[2]=0;
	}
	else
	{
	int_number6=number6*100;
		point6[1]=0;
		point6[2]=10;
	}
	
		if(number7/100>1)
	{
		int_number7=number7*10;
		point7[1]=10;
		point7[2]=0;
	}
	else
	{
	int_number7=number7*100;
		point7[1]=0;
		point7[2]=10;
	}
	
		if(number8/100>1)
	{
		int_number8=number8*10;
		point8[1]=10;
		point8[2]=0;
	}
	else
	{
	int_number8=number8*100;
		point8[1]=0;
		point8[2]=10;
	}
//整数化
	

	
	u8 n1[4],n2[4],n3[4],n4[4],n5[4],n6[4],n7[4],n8[4];
	n1[0]=int_number1%10;
	n2[0]=int_number2%10;
	n3[0]=int_number3%10;
	n4[0]=int_number4%10;
	n5[0]=int_number5%10;
	n6[0]=int_number6%10;
	n7[0]=int_number7%10;
	n8[0]=int_number8%10; //分离第一位
					
	n1[1]=int_number1/10%10;
	n2[1]=int_number2/10%10;
	n3[1]=int_number3/10%10;
	n4[1]=int_number4/10%10;
	n5[1]=int_number5/10%10;
	n6[1]=int_number6/10%10;
	n7[1]=int_number7/10%10;
	n8[1]=int_number8/10%10; //分列第二位
	
	n1[2]=int_number1/100%10;
	n2[2]=int_number2/100%10;
	n3[2]=int_number3/100%10;
	n4[2]=int_number4/100%10;
	n5[2]=int_number5/100%10;
	n6[2]=int_number6/100%10;
	n7[2]=int_number7/100%10;
	n8[2]=int_number8/100%10; //分离第三位
	
	n1[3]=int_number1/1000%10;
	n2[3]=int_number2/1000%10;
	n3[3]=int_number3/1000%10;
	n4[3]=int_number4/1000%10;
	n5[3]=int_number5/1000%10;
	n6[3]=int_number6/1000%10;
	n7[3]=int_number7/1000%10;
	n8[3]=int_number8/1000%10;  //分离第四位

	DISPLAY_E1_H;
	DISPLAY_E2_H;
	DISPLAY_E3_H;
	DISPLAY_E4_H; //开启所有位选开关
	DISPLAY_LED1_H;
	DISPLAY_LED2_H;
	
	DISPLAY_A0_L;
	DISPLAY_A1_L;
	DISPLAY_A2_L;//位选第一个
	send_byte(number[n1[3]],number[n3[3]],number[n5[3]],number[n7[3]]);//扫描第一个
	rt_thread_delay(2);

	
	DISPLAY_A0_H;
	DISPLAY_A1_L;
	DISPLAY_A2_L;
	send_byte(number[n1[2]+point1[2]],number[n3[2]+point3[2]],number[n5[2]+point5[2]],number[n7[2]+point7[2]]	);//扫描第二个
	rt_thread_delay(2);

	
	DISPLAY_A0_L;
	DISPLAY_A1_H;
	DISPLAY_A2_L;
	send_byte(number[n1[1]+point1[1]],number[n3[1]+point3[1]],number[n5[1]+point5[1]],number[n7[1]+point7[1]]);//扫描第三个
	rt_thread_delay(2);

	
	DISPLAY_A0_H;
	DISPLAY_A1_H;
	DISPLAY_A2_L;
	send_byte(number[n1[0]],number[n3[0]],number[n5[0]],number[n7[0]]);//扫描第四个
	rt_thread_delay(2);

		
	DISPLAY_A0_L;
	DISPLAY_A1_L;
	DISPLAY_A2_H;
	send_byte(number[n2[3]],number[n4[3]],number[n6[3]],number[n8[3]]);//扫描第五个
	rt_thread_delay(2);

	
	DISPLAY_A0_H;
	DISPLAY_A1_L;
	DISPLAY_A2_H;
	send_byte(number[n2[2]+point2[2]],number[n4[2]+point4[2]],number[n6[2]+point6[2]],number[n8[2]+point8[2]]);//扫描第六个
	rt_thread_delay(2);

	
	DISPLAY_A0_L;
	DISPLAY_A1_H;
	DISPLAY_A2_H;
	send_byte(number[n2[1]+point2[1]],number[n4[1]+point4[1]],number[n6[1]+point6[1]],number[n8[1]+point8[1]]);//扫描第七个
	rt_thread_delay(2);

	
	DISPLAY_A0_H;
	DISPLAY_A1_H;
	DISPLAY_A2_H;
	send_byte(number[n2[0]],number[n4[0]],number[n6[0]],number[n8[0]]);//扫描第八个
	rt_thread_delay(2);
	send_byte(0,0,0,0);
	
	DISPLAY_E1_L;
	DISPLAY_E2_L;
	DISPLAY_E3_L;
	DISPLAY_E4_L; //关闭所有位选开关
 

}

显示程序写的有点复杂,应该可以用循环来解决,但是最近有点忙,先不管了。第一个可以显示整数,第二个可以自适应显示一位或两位小数。

LED显示程序和数码管显示类似,但是没有用到138:

void display_led(u8 Num1[8],u8 Num2[8])
{
	DISPLAY_E1_L;
	DISPLAY_E2_L;
	DISPLAY_E3_L;
	DISPLAY_E4_L; //关闭所有位选开关
	DISPLAY_LED1_L;
	DISPLAY_LED2_L;
	u8 i,D1,D2;
	u8 num1[8],num2[8];
	for(i=0;i<8;i++)
	{
		num1[i]=!Num1[i];
		num2[i]=!Num2[i];
	}

	for(i=3;i>0;i--)
	{
		num1[i-1]=(num1[i]<<1)|num1[i-1];
		num2[i-1]=(num2[i]<<1)|num2[i-1];
	}
	for(i=7;i>4;i--)
	{
		num1[i-1]=(num1[i]<<1)|num1[i-1];
		num2[i-1]=(num2[i]<<1)|num2[i-1];
		
	}
	send_byte(num1[0],num2[0],num1[4],(num2[4]<<1));	
	
	DISPLAY_E1_H;
	DISPLAY_E2_H;
	DISPLAY_E3_H;
	DISPLAY_E4_H; //开启所有位选开关
	rt_thread_delay(5);
	DISPLAY_LED1_H;
	DISPLAY_LED2_H;
}

按键检测程序则只用到了138,程序如下:

u8 KEY[12];
void read_key()
{

	send_byte(0,0,0,0);
	
	DISPLAY_E1_L;
	DISPLAY_E2_L;
	DISPLAY_E3_L;
	DISPLAY_E4_H; //开启所有位选开关
	
	
	DISPLAY_A0_H;
	DISPLAY_A1_H;
	DISPLAY_A2_H;
	KEY[0]=GET_KEY;//扫描第八个
	
	DISPLAY_A0_L;
	DISPLAY_A1_H;
	DISPLAY_A2_H;
	KEY[1]=GET_KEY;//扫描第七个

	DISPLAY_A0_H;
	DISPLAY_A1_L;
	DISPLAY_A2_H;
	KEY[2]=GET_KEY;//扫描第六个	
	
	DISPLAY_A0_L;
	DISPLAY_A1_L;
	DISPLAY_A2_H;
	KEY[3]=GET_KEY;//扫描第五个
	
	DISPLAY_A0_H;
	DISPLAY_A1_H;
	DISPLAY_A2_L;
	KEY[11]=GET_KEY;//扫描第四个
	
	DISPLAY_A0_L;
	DISPLAY_A1_H;
	DISPLAY_A2_L;
	KEY[10]=GET_KEY;//扫描第九个
	

	
	DISPLAY_A0_H;
	DISPLAY_A1_L;
	DISPLAY_A2_L;
	KEY[9]=GET_KEY;//扫描第十个
	

	
	DISPLAY_A0_L;
	DISPLAY_A1_L;
	DISPLAY_A2_L;
	KEY[8]=GET_KEY;//扫描第十一个
	

	


	DISPLAY_E3_H;
	DISPLAY_E4_L; //开启所有位选开关
	
	DISPLAY_A0_L;
	DISPLAY_A1_L;
	DISPLAY_A2_L;//位选第一个
	KEY[7]=GET_KEY;//扫描第一个
	

	
	DISPLAY_A0_H;
	DISPLAY_A1_L;
	DISPLAY_A2_L;
	KEY[6]=GET_KEY;//扫描第二个


	
	DISPLAY_A0_L;
	DISPLAY_A1_H;
	DISPLAY_A2_L;
	KEY[5]=GET_KEY;//扫描第三个
	
	DISPLAY_A0_H;
	DISPLAY_A1_H;
	DISPLAY_A2_L;
	KEY[4]=GET_KEY;//扫描第十二个


	

	
	
	
	DISPLAY_E1_L;
	DISPLAY_E2_L;
	DISPLAY_E3_L;
	DISPLAY_E4_L; //关闭所有位选开关


}

按键存放的顺序按照PCB布局来的,这个可以自己定义,为了省事,直接用的全局变量。。。GET_KEY是一个宏定义,读取连接到CPU上的key_1。

4.结语

程序只是自己工作之余写的,应该还有很多可以优化的地方。。。

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值