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

1.方案选择

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

2.原理图设计

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

数码管显示电路分析-74hc138+74hc164_第1张图片

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<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.结语

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

你可能感兴趣的:(STM32)