admin管理员组

文章数量:1621139

项目场景:

51单片机按下按键在数码管上显示相应的值


问题描述

平常按键检测程序,按下延时消抖,记录一个数字,再按下另一个记录一个数字,然后在一位数码管上显示,就出现了问题。数码管一直显示0 。
下面就是出问题程序,解决方案展示正确程序

#include <regx52.h>
sbit LS_A=P2^2;
sbit LS_B=P2^3;
sbit LS_C=P2^4;
unsigned code Nixie_Value[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00};
void Delay(unsigned int xms)
{
	unsigned char i, j;
	while(xms--)
	{
		i = 2;
		j = 239;
		do
		{
			while (--j);
		} while (--i);
	}
}
void Nixie(unsigned char location,unsigned char number)
{ switch(location)
	{
		case 1: LS_A=0;LS_B=0;LS_C=0; break;
	    case 2: LS_A=1;LS_B=0;LS_C=0; break;
		case 3: LS_A=0;LS_B=1;LS_C=0; break;
		case 4: LS_A=1;LS_B=1;LS_C=0; break;
		case 5: LS_A=0;LS_B=0;LS_C=1; break;
		case 6: LS_A=1;LS_B=0;LS_C=1; break;
		case 7: LS_A=0;LS_B=1;LS_C=1; break;
		case 8: LS_A=1;LS_B=1;LS_C=1; break;
	}
	  P0=Nixie_Value[number];
		Delay(2);
		P0=0X00;
}
unsigned char Key()
{
	unsigned char KeyNumber=0;
	
	if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);KeyNumber=1;}
	if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);KeyNumber=2;}
	if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);KeyNumber=3;}
	if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);KeyNumber=4;}
	
	return KeyNumber;
}
int main()
{
	unsigned char value=0;
	while(1)
	{
		value=Key();
		Nixie(1,value);
	}
}
	

几个问题:

位选表示哪个数码管 段选表示数码管显示什么
1、在这条语句

 P0=Nixie_Value[number];

后加长延时,不就可以显示了吗?确实可以,但是加上延时,程序卡在这里,如果有按键按下,就检测不到了。
2、延时消隐P0=0x00有什么用?

        P0=Nixie_Value[number];
		Delay(2);
		P0=0X00;

这个延时然后清零消影很关键。若不加这两条语句,由于数码管由一个IO控制,所以当位选成功,段选来临。数码管显示该段选。此时程序执行确定下一个位选,上一个的段选会影响下一个段选,因为P0已经赋值,而下一次段选程序还没执行。这样就会出现鬼影。
延时也是必须存在的,不然可能直接就熄灭不显示东西。

原因分析:

程序解读:程序一直在跑。

    while(1)
	{
		value=Key();
		Nixie(1,value);
	}

当按键按下符合某一条语句,进入key()函数的if语句。假如P3_1按下

if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);KeyNumber=1;}

然后延时,程序就卡在这了,继续执行while循环,检测松手,再延时消抖,返回数值。这是数值就是某个数了 (1 2 3 4)其中一个 。
接着跳出key函数,执行下一条语句。

Nixie(1,value);

数码管显示这个数字。在分析数码管显示函数Nixie()。
位选表示哪个数码管 段选表示数码管显示什么
三八译码器选择数码管位选,在给P0赋值确定段选。按键按下确实数码管显示过数字(1 2 3 4),但是又接着熄灭了。因为程序接着执行key();人手不可能连续再按下另一个按键,所以数码管又显示0 。再次按下按键分析同理。


解决方案:

将数码管显示函数放到key();函数里面,实现了功能。同时进行了优化,将位选直接写在main函数while循环之前,然后直接操作P0确定段选即可。并且也没有延时。

#include <regx52.h>
#include "key.h"
sbit LS_A=P2^2;
sbit LS_B=P2^3;
sbit LS_C=P2^4;
unsigned code Nixie_Value[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00};
void Key()
{
	unsigned char KeyNumber=0;
	
	if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);KeyNumber=1;P0=Nixie_Value[KeyNumber];}
	if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);KeyNumber=2;P0=Nixie_Value[KeyNumber];}
	if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);KeyNumber=3;P0=Nixie_Value[KeyNumber];}
	if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);KeyNumber=4;P0=Nixie_Value[KeyNumber];}
}
int main()
{
	LS_A=0;LS_B=0;LS_C=0;
	P0=0x3F;
	while(1)
	{
		key();
	}
}

遇到的几个问题,个人体会

为什么数码管滚动?
因为两个位选之间有延时,延时大了,人眼可分辨出来,其实只能控制一个数码管,上一个亮了然后消影,延时后刚好下一个亮。
发现诀窍:重要、重要、重要
静态数码管几个数码管共同点亮,这是利用人眼分辨率低,其实这些数码管已经经历了亮灭,这个亮然后灭,下一个再亮,延时太低,就会导致以为数码管都一直亮着。
数码管亮度控制,当段选后需要一个延时然后消影。然后在一个延时,下一个点亮(位选确定),这两个延时就导致数码管亮度变化。第一个延时长,第二个短,表示数码管亮的时间长,灭队时间短,有占空比理解,则亮度高,反之亮度很低。详细代码见程序二。
先执行Nixie()函数

	        Nixie(i,i);

执行Nixie()函数延时200毫秒。段选后有延时,点亮200毫秒

        P0=Nixie_Value[number];
		Delay(200);//延时时间要灵活,这是一个变化的值
		P0=0X00;

两个位选之间100毫秒延时,其实是熄灭100毫秒

            Nixie(i,i);
			Delay(100);

这两个延时就控制了数码管亮度,亮200灭100
程序一、数码管显示1-8不滚动
因此若想数码管都亮着则需要延时很短,可以消影和位选间没有延时。下面这个程序实现数码管显示1-8

    #include <regx52.h>
sbit LS_A=P2^2;
sbit LS_B=P2^3;
sbit LS_C=P2^4;
unsigned code Nixie_Value[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00};
void Delay(unsigned int xms)
{
	unsigned char i, j;
	while(xms--)
	{
		i = 2;
		j = 239;
		do
		{
			while (--j);
		} while (--i);
	}
}
void Nixie(unsigned char location,unsigned char number)
{ switch(location)
	{
		case 1: LS_A=0;LS_B=0;LS_C=0; break;
	    case 2: LS_A=1;LS_B=0;LS_C=0; break;
		case 3: LS_A=0;LS_B=1;LS_C=0; break;
		case 4: LS_A=1;LS_B=1;LS_C=0; break;
		case 5: LS_A=0;LS_B=0;LS_C=1; break;
		case 6: LS_A=1;LS_B=0;LS_C=1; break;
		case 7: LS_A=0;LS_B=1;LS_C=1; break;
		case 8: LS_A=1;LS_B=1;LS_C=1; break;
	}
	    P0=Nixie_Value[number];
		Delay(2);//延时时间要灵活,这是一个变化的值
		P0=0X00;
}
int main()
{
	unsigned char i=0;
	while(1)
	{
		for(i=1;i<=8;i++)
		{
			Nixie(i,i);
		}
	}
}

注意段选和消影之间必须有延时,否则不会亮。


	    P0=Nixie_Value[number];
		Delay(2);//延时时间要灵活,这是一个变化的值
		P0=0X00;

程序二、当延时长时,人眼可观察到,就实现了数码管滚动。逐个显示1-8
其实只是在程序一基础上改了延时,就可以实现滚动和亮度控制

#include <regx52.h>
sbit LS_A=P2^2;
sbit LS_B=P2^3;
sbit LS_C=P2^4;
unsigned code Nixie_Value[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00};
void Delay(unsigned int xms)
{
	unsigned char i, j;
	while(xms--)
	{
		i = 2;
		j = 239;
		do
		{
			while (--j);
		} while (--i);
	}
}
void Nixie(unsigned char location,unsigned char number)
{ switch(location)
	{
		case 1: LS_A=0;LS_B=0;LS_C=0; break;
	    case 2: LS_A=1;LS_B=0;LS_C=0; break;
		case 3: LS_A=0;LS_B=1;LS_C=0; break;
		case 4: LS_A=1;LS_B=1;LS_C=0; break;
		case 5: LS_A=0;LS_B=0;LS_C=1; break;
		case 6: LS_A=1;LS_B=0;LS_C=1; break;
		case 7: LS_A=0;LS_B=1;LS_C=1; break;
		case 8: LS_A=1;LS_B=1;LS_C=1; break;
	}
	    P0=Nixie_Value[number];
		Delay(200);//延时时间要灵活,这是一个变化的值
		P0=0X00;
}
int main()
{
	unsigned char i=0;
	while(1)
	{
		for(i=1;i<=8;i++)
		{
			Nixie(i,i);
			Delay(100);
		}
	}
}

本文标签: 数码管单片机亮度按键原理