交通灯控制设计
每个城市的交通就犹如人体的血管,人类生命的持续需要心脏为血液提供动力,依靠血液来在人体内完成各类物质交换,完成新陈代谢,保持一个健康的体魄,而城市的交通于整个城市的重要性不亚于血液于人体,城市需要依靠一个可以正常运转的交通系统来推动交流与发展。
交通系统也可以称作为交通网,由各个部分的道路和相关设施组成,现如今的交通网是发达但不完善的,虽然随着智能化的覆盖面越来越广,几年后就可能不再需要交通灯,但交通灯依然是城市规划者引导车流人流最实惠又最稳定的工具。步入下一个时代前,需要工程师先参透旧时代,有故方能新是经过历史的证明的,所以下一个工具的诞生需要对交通灯的工作原理进行剖析及稳定实现,此次设计的目的更多的是在于对旧事物的思考,并引出新事物的设想
我国交通信号灯分为3种:红灯代表暂停;黄灯代表缓行;绿灯代表通行。本设计通过采用电子元件对交通灯控制电路进行设计,实现十字路口交通管理的自动化。
针对本次交通灯的制作,设计者依次使用Altium designer 2016完成原理图的设计,PCB的手动布线,再使用相关设备制作电路板,最后依靠keil软件写入C语言程序以达到硬件和软件的相互兼容的效果。
单片机又称单片微控制器,它不是完成某一个逻辑功能的芯片,而是把一个计算机系统集成到一个芯片上,相当于一个微型的计算机,和计算机相比,单片机只缺少了I/O设备。概括的讲:一块芯片就成了一台计算机。它的体积小、质量轻、价格便宜、控制功能强、使用方便、容易产品化,为学习、应用和开发提供了便利条件。
程序设计需要编程语言,常用的编程语言有:机器语言、汇编语言和高级语言。
机器语言是CPU硬件唯一能够直接识别的语言,在设计CPU时就已经确定了其代码的含义。要执行任何操作,都必须转换为相应的机器语言,由CPU识别、控制执行。机器语言必须为二进制代码,不便于记忆、使用和直接编写程序。
汇编语言使用人们便于记忆的符号来描述与之相应的机器语言,这些符号称为助记符。用助记符表示的指令称为汇编语言指令,用助记符编写出来的程序称为汇编语言程序。用汇编语言编写的程序运行速度快、占用内存单元少、效率高,但程序设计者必须熟悉单片机内部资源等硬件设施。
目前,社会上广泛使用的是高级语言(如C语言)。单片机不能识别高级语言的程序,因此需要用编译器对高级语言程序翻译成机器语言程序后再写入单片机。作为一种更接近人们习惯的程序设计语言,它使用人们熟悉的文字、符号及数学表达式来编写程序,因此程序的编写和操作都十分方便,本次交通灯控制程序也选用C语言。
2.1.1系统功能
(1)在LED数码管上显示倒计时,单位为秒。
(2)采用LED模拟信号灯,信号灯分东西、南北二组,分别有“红”“黄”“绿”三种颜色。分别设定有南北通行状态,东西通行状态,夜间黄灯闪烁状态。
(3)采用矩阵键盘控制状态切换,同时实现按0——9的数字键能够修改南北、东西红绿黄灯亮灯的时间。分别设置一个红、黄、绿灯按钮设置键,选择一个方向设置,另外一个方向通过计算可知。设置一个数字输入确认键。
2.1.2 硬件设计
(1)CPU为89C52单片机;
(2)键盘为4×4行列式键盘,接入单片机的P1口,用于输入相关的控制指令;
(3)两个3位LED数码管,显示相应通行方向的倒计时时间;
2.1.3 软件设计
(1)控制交通灯程序。软件需要使交通灯在不同模式下实现不同的亮闪模式,且需要绿灯、红灯与黄灯的相互配合,实现在同一时序下严格按照图2.1的要求实现功能;
(2)LED数码管显示程序。需要在软件的设计中实现段选、位选,同时运用动态显示的方式,完成倒计时及计数输入显示的功能;
(3)键盘管理程序(包括键扫描、键处理程序)。键盘为4 * 4矩阵键盘,不同于独立按键,需要在软件的编写过程中进行循环,以实现不断扫描键盘,检测是否输入及其键值,一来实现各种功能的选择,二来完成计数值的输入。
鉴于实验室提供的元器件,设计者选择了STC89C52,在方案设计中选择P0口为三位数码管的段选端口,P1口为位选口,P2口为矩阵键盘,两个接数码管的I/O口都连接了74LS573来进行锁存,P3则用于交通灯信号的输出,同时采用了USB供电,且为上电复位,同时采用12M晶振来构成51单片机的最小系统板。
2.3.1所用元器件
STC89C52芯片 1
74LS573 2
12MHz晶振 1
30PF电容 2
10uf/50V电解电容 1
10kΩ电阻 1
键盘 1
键盘插针 1
按键 1
1kΩ排阻 2
1kΩ电阻 6
LED灯 6
USB口 1
3位共阴极数码管 2
2.3.2硬件详细介绍
(1)STC89C52
STC89C51RC/RD+系列单片机(包括STC89C52RC)是宏晶科技推出的新一代超强抗干扰、高速、低功耗的单片机,基于Intel 标准的8052,指令代码完全兼容传统的8051 系列单片机,12 时钟/机器周期和6 时钟/机器周期可任意选择。工作电压:5.5V- 3.4V(5V 单片机) 。工作频率范围:0 – 40 MHz,相当于普通的8051 的0~80 Mhz,实际工作频率可达到48MHz。用户应用程序空间4K、8K、13K、16K、20K、32K、64K 字节。片上集成1280 字节、512 字节RAM。通用I/O(32个),复位后为:P0、P1、P2、P3是准双向口、弱上拉(普通8051 传统I/O 口),P0 口是开漏输出,作为总线拓展用时,不用加上拉电阻,作为I/O 口用时,需要加上拉电阻。
(2)单片机供电电路
89C52为5V单片机,采用USB供电是最常用的方式,不管是连接电脑或移动电源都可以达到相应的适配效果。
(3)振荡电路
根据89C52单片机的相关设定,采用了12MHz晶振,它起到的作用是为单片机提供基准的时针信号,单片机内部所有的工作都是以这个时钟信号为步调基准来进行工作的。除了晶振以外,还需要两个30pF的电容,电容的作用是帮助晶振起振,并维持振荡信号的稳定。单片机晶体振荡器提供的时钟频率越高,单片机运行的速度就越快。
(4)复位电路
根据实验要求,要实现上电复位,且对于89C52而言,需要实现上电时为RST引脚提供一个高电平以实现复位。
(5)3位数码管电路
数码管分为共阴极数码管和共阳极数码管两种。共阴极数码管所有LED灯的阴极连在一起,而共阳极数码管则是所有LED灯的所有阳极连接在一起。在实验中,由于实验室提供的元器件选择了图2.7所示的共阴极数码管,选用时,拉低选用位,拉高选用段,且选择74LS573作为驱动,74LS573 的八个锁存器都是透明的D 型锁存器,当使能LE引脚为高时,(O)输出将随数据(D)输入而变。当使能为低时,输出将锁存在已建立的数据电平上。输出控制不影响锁存器的内部工作,即老数据可以保持,甚至当输出被关闭时,新的数据也可以置入。实验中总共6位数码管,为了在节省I/O口的条件下,使电流稳定输出,必须在位选端和段选端都接入74LS573作为驱动。
(6)键盘电路
为了提高单片机系统中I/O口的利用率矩阵键盘采用四条I/O线作为行线,四条I/O线作为列组成键盘,在行和列的每个交叉点上设置一个按键,采用4 * 4键盘共16个键。
在一个循环中先扫描第一行,即将第一行输出0电平,然后读入列值,哪一列出现0电平,就说明该列与第一行跨接的按键被按下,若读入的列值全为1,则说明与第一行跨接的按键没有被按下,然后按以上步骤逐行扫描,直到找到被按下的按键。
同时需要在每一条列线都接上拉电阻,这是为了给高阻抗输入提供一个稳定的高电平,因为有些单片机的I/O口作为输出时只能提供高阻抗输出与低电平输出,被称作“准三态门”,在这些“准三态门”口线作为键盘行线的扫描时,提供所谓的“高电平”实际上驱动能力是很弱的,列线在读取时,可能会发生误判,所以必须要在读取时加上拉电阻,将高阻态转换为稳定的高电平,才能保证读取的正确
(7)红绿灯电路
在实验中采用了南北方向红绿黄灯和东西方向红绿黄灯两组LED,同时为了保护LED接入1kΩ电阻。
本次实验的原理图绘制采用了Altium Designer 2016软件,第一步建立一个工程,在其中建一个原理图文件原理图库文件。根据实验要求,将所需的元件库复制到原理图库文件,等待调用,由于元件库的收集过程中不够全面,还需要自己绘制元器件,同时绘制相应元件的封装库。确定具体的电路后,将相应的元件放置到原理图中,在不同的硬件电路之间采用网络端口,使得原理图看起来更加简洁。
考虑到P0口和键盘需要上拉电阻,选用8位的排阻连接以作为上拉电阻;LED用P3口控制;数码管驱动电路中,74LS573的LE端接+5V。
新建PCB文件,导入原理图,布置元器件的位置后,进行手动布线,要求电源线和地线宽度至少在50mil到100mil之间,而一般的线宽度为25mil,线与线之间、线与孔之间间距为20mil至30mil,不能再IC脚之间过线,防止短路。一般的IC焊盘大小为80×80mil,电源管脚的焊盘应尽量大一些,键盘的焊盘应为80×100mil,因为USB口固定位置的两个引脚比较大,所以固定位置的两个焊盘要设置为5×5mm。之后在PCB板空的位置进行覆铜,并设置覆铜与线和焊盘的距离至少50mil。
腐蚀电路板前要先将PCB文件打印在转印纸上,用钻孔机在铜板的一角钻孔,后将铜板和打印好的纸放入环保型多功能制板系统影印,完成后取出,在刚刚打好的孔间穿上绳子,浸泡于用于显影的溶液几分钟,之后用清水清洗,再悬挂于腐蚀液上,浸泡一段时间后取出。
将元器件按照原理图焊接在PCB板后使用万用表对每一段铜线进行检测,以排除不必要的麻烦。
3.4.1 主要程序结构分析
在程序设计中要求实现交通灯功能,在主程序中需要设置开启键,为了实现按键功能的更加人性化,主程序中设置了两个开启键,分别是白天模式开启键和夜晚模式开启键,按下相应开启键即可进入相应模式,进入到各个模式的子程序中,期间只要按下停止键即可重新返回主函数。
而在进入白天模式后,键盘扫描即进入了计数值设置模式阶段,期间按下各个方向通行时间的设置键即可输入相关计数值改变倒计时时间,输入期间还可在第一个3位数码管上显示相关数值,直至按下数值确认键,结束输入的同时返回白天模式,进行新一轮的倒计时,同时完成新一轮的时序。
(1)键盘扫描程序
在键盘扫描子函数前,采用while()循环,以实现对程序的不间断运行,让矩阵按键的一行输出低电平,其它三行输出高电平,判断当前所有列的状态,下次中断时再让下一行输出低电平,其它三行输出高电平,再次判断所有列,通过快速的中断不停的循环进行判断,最终确定哪个按键按下了,同时将按键的键值制作为数组,根据行值和列值判断键值,以输出Statu值以及Value值以用于各个程序。
程序中首先对所有的列输入做了扫描、消抖,然后才切换到了下一次的行输出,也就是说中断每次扫描的实际是上一次输出选择的那行按键,这样做是因为任何信号从输出到稳定都需要一个时间,有时它足够快而有时却不够快,这里的输入输出顺序的颠倒就是为了让输出信号有足够的时间来稳定,并有足够的时间来完成它对输入的影响
(2)定时器T0中断程序
定时器 T0中断程序的主要作用是完成倒计时计数,同时控制等待时间中黄灯闪烁功能。定时器采用工作模式1,即16位定时器。通过给定时器0赋初值的方式可以让定时器每隔50ms进行一次中断,循环20次完成1S的倒计时,同时每一次中断都会判断一次交通灯的状态,当时间到达黄灯等待阶段时,程序将执行每半秒对黄灯控制口取反操作,实现黄灯闪烁功能。
(3)定时器T1中断程序
定时器T1中断程序主要的作用是夜晚模式模式黄灯闪烁功能。采用的定时器T1初值与T0相同,50ms进行一次中断,在中断中对黄灯所在I/O口取反,完成黄灯闪烁功能。在开TO的情况下,另外开启T1对黄灯实现闪烁功能,主要是为了排除两个模式下黄灯闪烁的相互作用,充分利用单片机的闲置资源,同时让不同模式下的黄灯闪烁时间都独立可调,分离两种模式,完全排除联系以实现完全的模块化。
#include
//--定义使用的IO口--//
#defineGPIO_DIG P0 //段选
#defineGPIO_PLACE P2 //位选
#defineGPIO_KEY P1 //矩阵键盘
#defineGPIO_TRAFFIC P3
sbitRED11 = P3^2; //东西方向
sbitYELLOW11= P3^3;
sbitGREEN11 = P3^4;
sbitRED01 = P3^5; //南北方向
sbitYELLOW01= P3^6;
sbitGREEN01 = P3^7;
//--定义全局变量--//
unsignedchar code DIG_PLACE[6] = {
0x7f,0xbf,0xdf,0xfb,0xf7,0xef}; //位选控制
unsignedchar code DIG_CODE[17] = {
0xeb,0x88,0xd3,0xda,0xb8,0x7a,0x7b,0xc8,
0xfb,0xfa,0x77,0x7c,0x39,0x5e,0x79,0x71};
//0、1、2、3、4、5、6、7、8、9、A、b、C、d、E、F的显示码
unsignedchar DisplayData[6]; //用来存放要显示的8位数的值
unsigned
char Time,Time1,Time2,Time3,Second;//存放定时时间
unsignedchar KeyState; //记录按键的状态,0没有,1有
unsignedchar KeyValue; //用来存放读取到的键值
unsignedchar KeyNum; //用来存放输入的键值
unsignedchar NS_In; //南北通行时间
unsignedchar Y_In; //黄灯时间
unsignedchar EW_In; //东西通行时间
//--声明全局函数--//
voidTimer0Cofig(void); //定时器0
voidTimer1Cofig(void); //定时器1
voidDelay10ms(unsigned int c); //延时10ms
voidDigDisplay(unsigned int n); //动态显示函数
voidSETMODE(unsigned char keyValue); //设置计数值函数
voidDayLight(void); //白天模式
voidNightLight(void); //夜晚模式
unsignedchar KeyDown(void); //检测按键函数
unsignedchar KeyInput(void); //数值输入函数
/*********************************************************
*函 数 名 : main
*函数功能 :主函数
*输 入 : KeyValue
*输 出 :无
*********************************************************/
voidmain(void)
{
NS_In = 120;
EW_In = 80;
Y_In = 6; //初始时序
Time = 0;
Time1 = 0;
Second = 1; //初始化计数值
while(1)
{
KeyDown(); //执行按键检测函数
switch(KeyValue)
{
case 10:
Timer0Cofig(); //开定时器0
DayLight(); //调用白天模式
KeyValue = 17;
break;
case 11:
Timer1Cofig(); //开定时器1
NightLight(); //调用夜晚模式
KeyValue = 17;
break;
default: break;
}
}
}
/*********************************************************
*函 数 名 :中断开关
*函数功能 :打开定时器T0和T1
*输 入 :无
*输 出 :无
*********************************************************/
voidTimer0Cofig(void)
{
TMOD = 0x01;
TH0 = 0x3C;
TL0 = 0xB0; //50ms
EA = 1;
ET0 = 1;
TR0 = 1;
}
voidTimer1Cofig(void)
{
TMOD = 0x10;
TH1 = 0x3C;
TL1 = 0xB0; //50ms
EA = 1;
ET1 = 1;
TR1 = 1;
}
/*********************************************************
*函 数 名 :中断0
*函数功能 :定时器T0中断函数
*输 入 :无
*输 出 : Second
*********************************************************/
voidTimer0() interrupt 1
{
TH0 = 0x3C; //设置初始值
TL0 = 0xB0;
Time++;
if(Time == 20)
{
Second ++;
Time = 0;
} //秒数计时叠加
if((Second < (NS_In + Y_In+1))&&(Second > (NS_In)))
{
Time2++;
if(Time2 == 10)
{
YELLOW01 = ~YELLOW01;
Time2 = 0;
}
} //南北方向黄灯闪烁
if(Second > (NS_In + Y_In + EW_In ))
{
Time3++;
if(Time3 == 10)
{
YELLOW11 = ~YELLOW11;
Time3 = 0;
}
} //东西方向黄灯闪烁
}
/*********************************************************
*函 数 名 :中断1
*函数功能 :定时器T1中断函数
*输 入 :无
*输 出 :无
*********************************************************/
voidTimer1() interrupt 3
{
TH1 = 0x3C; //设置初始值
TL1 = 0xB0;
Time1++;
if(Time1 == 10)
{
YELLOW01 = ~YELLOW01; //黄灯双闪
YELLOW11 = ~YELLOW11;
Time1 = 0;
}
}
/*********************************************************
*函 数 名 :计数值设置函数
*函数功能 :改变计数值
*输 入 : KeyValue
*输 出 : NS_In,EW_In,Y_In
*********************************************************/
voidSETMODE(unsigned char KeyValue)
{
GPIO_TRAFFIC = 0x00;
GPIO_PLACE = 0xFF; //关闭交通灯,数码管
switch(KeyValue) //依照按下的键对应修改时间
{
case 12:
KeyInput();NS_In= KeyNum ; //南北通行时间输入
break;
case 13:
KeyInput();EW_In =KeyNum - Y_In ;//东西通行时间
break;
case 15:
KeyInput();Y_In = KeyNum ; //黄灯闪烁时间输入
break;
default: break;
}
Second = 1;
EA = 1;
}
/*********************************************************
*函 数 名 : DayLight
*函数功能 :白天
*输 入 :无
*输 出 :无
*********************************************************/
voidDayLight(void)
{
unsigned int a;
a = 1;
while(a)
{
KeyDown();
if(KeyValue == 11) //清零并停止计时
{
a = 0;
ET0 = 0;
Second = 0;
GPIO_TRAFFIC = 0xff;
}
if(Second == NS_In + EW_In + 2 *Y_In) //结束一个周期
{
Second = 1;
}
if((KeyValue == 12)||(KeyValue==13)||(KeyValue ==15))
{
EA=0;
SETMODE(KeyValue);
}
//--南北方向通行--//
if(Second < (NS_In + 1))
{
DisplayData[0] =DIG_CODE[(NS_In - Second) % 1000 / 100];
DisplayData[1] =DIG_CODE[(NS_In - Second) % 100 / 10];
DisplayData[2] =DIG_CODE[(NS_In - Second) % 10];
DisplayData[3] =DIG_CODE[(NS_In + Y_In - Second) % 1000 / 100];
DisplayData[4] =DIG_CODE[(NS_In + Y_In - Second) % 100 / 10];
DisplayData[5] =DIG_CODE[(NS_In + Y_In - Second) % 10];
DigDisplay(6); //第一个时序倒计时
GPIO_TRAFFIC = 0x7B;
Time2 = 0;
}
//--黄灯等待切换状态--//
else if(Second < (NS_In + Y_In+1))
{
DisplayData[0] =DIG_CODE[(NS_In + Y_In - Second) % 1000 / 100];
DisplayData[1] =DIG_CODE[(NS_In + Y_In - Second) % 100 / 10];
DisplayData[2] =DIG_CODE[(NS_In + Y_In - Second) % 10];
DisplayData[3] =DisplayData[0];
DisplayData[4] =DisplayData[1];
DisplayData[5] =DisplayData[2];
DigDisplay(6); //第二个时序倒计时
GREEN01 = 1;
RED11= 0; //东西方向红灯持续
}
//--东西方向通行--//
else if(Second < (NS_In + Y_In+ EW_In +1) )
{
DisplayData[0] =DIG_CODE[(NS_In + Y_In + EW_In - Second) % 1000 / 100];
DisplayData[1] =DIG_CODE[(NS_In + Y_In + EW_In - Second) % 100 / 10];
DisplayData[2] =DIG_CODE[(NS_In + Y_In + EW_In - Second) % 10];
DisplayData[3] =DIG_CODE[(NS_In + EW_In + 2 * Y_In - Second) % 1000 / 100];
DisplayData[4] =DIG_CODE[(NS_In + EW_In + 2 * Y_In - Second) % 100 / 10];
DisplayData[5] =DIG_CODE[(NS_In + EW_In + 2 * Y_In - Second) % 10];
DigDisplay(6); //第三个时序倒计时
GPIO_TRAFFIC = 0xCF;
Time2 = 0;
}
//--黄灯等待切换状态--//
else
{
DisplayData[0] =DIG_CODE[(NS_In + EW_In + 2 * Y_In - Second) % 1000 / 100];
DisplayData[1] =DIG_CODE[(NS_In + EW_In + 2 * Y_In - Second) % 100 / 10];
DisplayData[2] =DIG_CODE[(NS_In + EW_In + 2 * Y_In - Second) % 10];
DisplayData[3] =DisplayData[0];
DisplayData[4] =DisplayData[1];
DisplayData[5] =DisplayData[2];
DigDisplay(6); //第四个时序倒计时
GREEN11 = 1;
RED01 = 0; //南北方向红灯亮
}
}
}
/*****************************************************************************
*函 数 名 : NightLight
*函数功能 :夜晚
*输 入 :无
*输 出 :无
*****************************************************************************/
voidNightLight(void)
{
unsigned int a;
a = 1;
GPIO_TRAFFIC = 0xB7;
while(a)
{
KeyDown();
if(KeyValue == 10)
{
a = 0;
ET1 = 0;
}
}
Time1 = 0;
}
/*****************************************************************************
*函 数 名 : DigDisplay
*函数功能 :使用数码管显示
*输 入 :无
*输 出 :无
*****************************************************************************/
voidDigDisplay(unsigned int n)
{
unsigned char i;
unsigned int j;
for(i=0; i< n; i++)
{
GPIO_PLACE = DIG_PLACE[i]; //发送位选
GPIO_DIG = DisplayData[i]; //发送段码
j = 10; //扫描间隔时间设定
while(j--);
GPIO_DIG = 0x00; //消隐
}
}
/*****************************************************************************
*函 数 名 : Delay10ms
*函数功能 :延时函数,延时10ms
*输 入 :无
*输 出 :无
*****************************************************************************/
voidDelay10ms(unsigned int c) //误差0us
{
unsigned char a, b;
for (;c>0;c--)
{
for (b=4;b>0;b--)
{
for (a=130;a>0;a--);
}
}
}
/*****************************************************************************
*函 数 名 : KeyDown
*函数功能 :检测有按键按下并读取键值
*输 入 :无
*输 出 :无
*****************************************************************************/
unsignedchar KeyDown(void)
{
GPIO_KEY = 0xfe;
while((GPIO_KEY & 0xf0) != 0xf0)
{
Delay10ms(1);
while((GPIO_KEY & 0xf0) !=0xf0)
{
KeyState=1;
switch(GPIO_KEY)
{
case 0xbe:KeyValue=0;
break;
case 0xee:KeyValue=13;
break;
case 0x7e:KeyValue=14;
break;
case 0xde:KeyValue=15;
break;
}
while((GPIO_KEY & 0xf0)!= 0xf0)
;
}
}
GPIO_KEY = 0xfd;
while((GPIO_KEY & 0xf0) != 0xf0)
{
Delay10ms(1);
while((GPIO_KEY & 0xf0) != 0xf0)
{
KeyState=1;
switch(GPIO_KEY)
{
case 0x7d: KeyValue=7;
break;
case 0xbd: KeyValue=8;
break;
case 0xdd:KeyValue=9;
break;
case 0xed:KeyValue=12;
break;
}
while((GPIO_KEY & 0xf0)!= 0xf0)
;
}
}
GPIO_KEY = 0xfb;
while((GPIO_KEY & 0xf0) != 0xf0)
{
Delay10ms(1);
while((GPIO_KEY & 0xf0) != 0xf0)
{
KeyState=1;
switch(GPIO_KEY)
{
case 0x7b:KeyValue=4;
break;
case 0xbb:KeyValue=5;
break;
case 0xdb:KeyValue=6;
break;
case 0xeb:KeyValue=11;
break;
}
while((GPIO_KEY & 0xf0)!= 0xf0)
;
}
}
GPIO_KEY = 0xf7;
while((GPIO_KEY & 0xf0) != 0xf0)
{
Delay10ms(1);
while((GPIO_KEY & 0xf0) != 0xf0)
{
KeyState=1;
switch(GPIO_KEY)
{
case 0x77: KeyValue=1;
break;
case 0xb7:KeyValue=2;
break;
case 0xd7:KeyValue=3;
break;
case 0xe7:KeyValue=10;
break;
}
while((GPIO_KEY & 0xf0)!= 0xf0)
;
}
}
return KeyValue;
}
/*****************************************************************************
*函 数 名 : KeyInput
*函数功能 :使用键盘输入数值
*输 入 :无
*输 出 :无
*****************************************************************************/
unsignedchar KeyInput(void)
{
unsigned int Ge,Shi,Bai,a;
KeyNum = 0;
Ge = 0;
Shi = 0;
Bai = 0;
a=1;
while(a)
{
KeyDown();
if(KeyValue < 10 &&KeyState == 1)
{
Bai = Shi;
Shi = Ge;
Ge = KeyValue;
KeyState = 0;
} //移位显示
DisplayData[0] = DIG_CODE[Bai];
DisplayData[1] = DIG_CODE[Shi];
DisplayData[2] = DIG_CODE[Ge];
DigDisplay(3);
if(KeyValue == 14)
{
a = 0;
KeyNum = 100 * Bai + 10 *Shi + Ge;
} //数据确认键
}
}