单片机系统键盘的设计小结
一、概述
键盘在单片机应用系统中,实现输入数据、传送命令的功能,是人工干预的主要手段。键盘分两大类:编码键盘和非编码键盘。
编码键盘:由硬件逻辑电路完成必要的键识别工作与可靠性措施。每按一次键,键盘自动提供被按键的读数,同时产生一选通脉冲通知微处理器,一般还具有反弹跳和同时按键保护功能。这种键盘易于使用,但硬件比较复杂,对于主机任务繁重之情况,采用8279可编程键盘管理接口芯片构成编码式键盘系统是很实用的方案。
非编码键盘:只简单地提供键盘的行列与矩阵,其他操作如键的识别,决定按键的读数等仅靠软件完成,故硬件较为简单,但占用CPU较多时间。有:独立式按键结构、矩阵式按键结构。
二、键盘系统设计
首先,确定键盘编码方案:采用编码键盘或非编码键盘。随后,确定键盘工作方式:采用中断或查询方式输入键操作信息。然后,设计硬件电路。非编码键盘系统中,键闭合和键释放的信息的获取,键抖动的消除,键值查找及一些保护措施的实施等任务,均由软件来完成。
(一)非编码键盘的键输入程序应完成的基本任务
1.监测有无键按下;键的闭合与否,反映在电压上就是呈现出高电平或低电平,所以通过电平的高低状态的检测,便可确认按键按下与否。
2.判断是哪个键按下。
3.完成键处理任务。
(二)从电路或软件的角度应解决的问题
1.消除抖动影响。键盘按键所用开关为机械弹性开关,利用了机械触点的合、断作用。由于机械触点的的弹性作用,一个按键开关在闭合和断开的瞬间均有一连串的抖动,波形如下:
抖动时间的长短由按键的机械特性决定,一般为5~10ms,这是一个很重要的参数。抖动过程引起电平信号的波动,有可能令CPU误解为多次按键操作,从而引起误处理。
为了确保CPU对一次按键动作只确认一次按键,必须消除抖动的影响。按键的消抖,通常有软件,硬件两种消除方法。
这种方法只适用于键的数目较少的情况。
软件消抖:如果按键较多,硬件消抖将无法胜任,常采用软件消抖。通常采用软件延时的方法:在第一次检测到有键按下时,执行一段延时10ms的子程序后,再确认电平是否仍保持闭合状态电平,如果保持闭合状态电平,则确认真正有键按下,进行相应处理工作,消除了抖动的影响。(这种消除抖动影响的软件措施是切实可行的。)
2.采取串键保护措施。串键:是指同时有一个以上的键按下,串键会引起CPU错误响应。
通常采取的策略:单键按下有效,多键同时按下无效。
3.处理连击。连击:是一次按键产生多次击键的效果。要有对按键释放的处理,为了消除连击,使得一次按键只产生一次键功能的执行(不管一次按键持续的时间多长,仅采样一个数据)。否则的话,键功能程序的执行次数将是不可预知,由按键时间决定。连击是可以利用的。连击对于用计数法设计的多功能键特别有效。
三、键盘工作方式
单片及应用系统中,键盘扫描只是CPU的工作内容之一。CPU忙于各项任务时,如何兼顾键盘的输入,取决于键盘的工作方式。考虑仪表系统中CPU任务的份量,来确定键盘的工作方式。
键盘的工作方式选取的原则是:既要保证能及时响应按键的操作,又不过多的占用CPU的工作时间。
键盘的工作方式有:查询方式(编程扫描,定时扫描方式)、中断扫描方式。
四、键盘电路结构
(一)独立式按键接口设计
独立式按键就是各按键相互独立,每个按键单独占用一根I/O口线,每根I/O口线的按键工作状态不会影响其他I/O口线上的工作状态。因此,通过检测输入线的电平状态可以很容易判断哪个按键被按下了。
优点:电路配置灵活,软件结构简单。
缺点:每个按键需占用一根I/O口线,在按键数量较多时,I/O口浪费大,电路结构显得复杂。
因此,此键盘是用于按键较少或操作速度较高的场合。
中断方式 查询方式
也可以用扩展I/O口搭接独立式按键接口电路,可采用8255扩展I/O口,用三态缓冲器扩展。这两种配接方式,都是把按键当作外部RAM某一工作单元的位来对待,通过读片外RAM 的方法,识别按键的工作状态。
上电路中独立式按键电路,各按键开关均采用了上拉电阻,是为了保证在按键断开时,各I/O有确定的高电平。如输入口线内部已有上拉电阻,则外电路的上拉电阻可省去。
(二)矩阵式键盘接口设计
矩阵式键盘适用于按键数量较多的场合,由行线和列线组成,按键位于行列的交叉点上。节省I/O口。
矩阵键盘工作原理:行线通过上拉电阻接到+5V上。无按键,行线处于高电平状态,有键按下,行线电平状态将由与此行线相连的列线电平决定。列线电平为低,则行线电平为低;列线电平为高,则行线电平为高。
五、双功能及多功能键设计
在单片机应用系统中,为简化硬件线路,缩小整个系统的规模,总希望设置最少的按键,获得最多的控制功能。
矩阵键盘与独立式按键键盘相比,硬件电路大大节省。可通过软件的方法让一键具有多功能。方法:选择一个RAM工作单元,对某一个按键进行按键计数,根据不同计数值,转到子程序。这种计数多功能键最好与显示器结合用,以便知道当前计数值,同时配合一个启动键。
复合键是使用软件实现一键多功能的另一个途径。所谓复合键,就是两个或两个以上的键的联合,当这些键同时按下时,才能执行相应的功能程序。实际情况做不到“同时按下”,他们的时间差别可以长到50ms,解决策略是:定义一个或两个引导键,这些引导键按下时没什么意义,执行空操作。引导键的例子:微机键盘上的CTRL、SHIFT、ALT。
缺点:一是操作变得复杂,二是操作时间变长。
多功能键的利用,应具体情况具体分析。要求速度的场合最好做一键一功能。如果系统功能很多,一键一功能不现实,可采取一键多功能。
六、功能开关及拨码盘接口设计
设计原因:键盘输入灵活性大,操纵方便。但某些重要功能或数据由键盘输入,误操作将产生一些不良后果。因此常设定静态开关的方法来执行这些功能或输入数据。静态开关一经设定,将不再改变,一直维持设定的开关状态。通常这些开关状态是在单片机系统加电时由CPU读入内存RAM的,以后CPU将不再关注这些开关的状态,因此,即使加电后,这些开关的状态发生变化,也不会影响CPU的正常工作,只有在下一次加电时,这些新状态才能生效。
第一,功能开关:主要是根据开关的状态执行一些重要的功能。
第二,拨码盘:单片机应用系统中,有时要输入一些控制参数,这些参数一经设定,将维持不变,除非给系统断电后重新设定。这时使用数字拨码盘既简单直观,又方便可靠。
七、按键介绍
常用的按键有三种:机械触点式按键、导电橡胶式和柔性按键(又称触摸式键盘)。
机械触点式按键是利用弹性使键复位,手感明显,连线清晰,工艺简单,适合单件制造。但是触点处易侵入灰尘而导致接触不良,体积相对较大。
导电橡胶按键是利用橡胶的弹性来复位,通过压制的方法把面板上所有的按键制成一块,体积小,装配方便,适合批量生产。但是时间长了,橡胶老化而使弹力下降,同时易侵入灰尘。
柔性按键是近年来迅速发展的一种新型按键,可以分为凸球型和平面型两种。凸球型动作幅度触感明显,富有立体感,但制造工艺相对复杂;平面型幅度微小,触感较弱,但工艺简单,寿命长。柔性按键最大特点是防尘、防潮、耐蚀,外形美观,装嵌方便。而且外形和面板的布局、色彩、键距可按照整机的要求来设计。
八、单片机系统键盘设计实例
本次设计中,键盘结构采用非编码键盘系统中的独立式按键结构。用三态缓冲器573扩展I/O口搭接独立式按键接口电路,按键状态由573锁存。
键盘工作方式采用定时扫描方式。采用定时器T0定时,CPU每隔200ms扫描键盘一次,即通过读取573的输出数据,识别按键的工作状态。
设计中对于重键和连击的处理:对于重键(串键:指同时有一个以上的键按下),采用软件提供保护,当判断为一个以上的键按下,则不处理,返回重新进行监测。只有监测到一个键按下时,才判断键值,执行相应键处理工作。
键盘对液晶显示的控制是通过显示画面的页码作为接口参数来完成的。在每一页中,键盘对数据的修改是通过对按键次数的计算作为接口参数来实现的。
具体例程如下:
void keyscan() /*键盘扫描*/
{ucher data newz ,temp,pat;
if(time_out)
{ACC=MJP; /*读取573数据*/
temp=ACC&0x0f, /*取低四位*/
if(temp!=0x0f) /*有键按下*/
{msec(10); /*延时10MS*/
ACC=MJP; /*读取573数据*/
temp=ACC&0x0f
if(temp=0x0f)
{newz=temp; /*读取新键值*/
pat=newz^old; /*键值有无变化*/
if(pat)>0) /*有变化*/
{old=newz; /*原键值等于新键值*/
keymana(); /*调键散转程序*/
}
(下转第66页)
(上接第64页)
else;
}
else;
}
elsr;
old=temp; /*原键值不变*/
time_out=0 /*标志位置零*/
}
esel;
}
九、结语
键盘是单片机系统设计中一种主要的信息输入接口,合理的设计,不仅可以节省系统的设计成本,更可使仪器设备的操作变得更为简单、方便,很大程度上提高系统综合性能。
摘 要:本文介绍采用AT89C2051构成多达128键的键盘扩展电路及其编程。该电路是采用串行口与上位机进行通讯的。经长期使用,证明这一方法是可行和可靠的,有较强的实用价值。
关键词:AT89C2051; 键盘; 串行口
1. 扩展键盘电路
AT89C2051是美国ATMEL公司采用CMOS工艺生产的20脚八位单片机。它带有2k字节flash ROM和128字节的片内RAM,15根I/O线,2个16位定时/计数器,5个两级中断源,一个全双工串行口。另外还带有精确的模拟比较器、片内振荡器和时钟电路。其指令集和输出管脚与工业标准的MCS-51系列器件兼容,是当前性/价比较高的一种八位单片机。
虽然采用8279/8155 等芯片扩展键盘较为方便,但在某些场合,特别是电路要求较为紧凑、印刷电路板较小的情况下,AT89C2051扩展键盘较为合适。其优点是体积小、成本低,同时在合理安排15根I/O口线的情况下,可以获得与8279/8155相同数量甚至更高的键盘数。其难点在于,在软件中必须妥善解决键盘扫描、去抖动、双键同时按下、与上位机通讯等问题。
图1所示为采用AT89C2051构成的键盘扩展电路。AT89C2051的串行口作为上位机的通讯口,以减轻多机通讯时上位机的串行负担,P1.0口线向上位机申请中断。为提高电路工作的可靠性,可以采用MAX705/706、MAX813L等看门狗电路,负责对CPU进行监视。本文采用MAX706复位/看门狗电路,并采用P3.7口线对其定时刷新,即“喂狗”。采用74LS138扩展行扫线,使用 P1.1、P1.2、P1.3对其进行控制,使行扫线依次改变状态。采用这种方法,行扫线最多为八根。由于本文键盘仅为20键,因此采用P1.4、 P1.5、P1.6、P1.7作为列扫线已经足够。对于所需键盘数更多的情况,可以补充P3.5、P3.4、P3.3、P3.2等口线作为列扫线。在此情况下,可以扩展的键盘数为64键。如不存在多机通讯的要求,可以继续补充P1.0口线作为列扫线。在此情况下,可扩展的键盘数为72个。如以P1.0扩展行扫线,采用两片74LS138或其它4-16译码器,则可扩展的键盘数最多可达128个。本电路中采用AT89C52作为上位机。
2. 软件结构
2.1 软件去抖动处理
按键的触点在闭合和断开时均会产生抖动,这时触点的逻辑电平是不稳定的,如不妥善处理,将会引起按键命令的错误执行或重复执行。本文采用软件延时的方法来避开抖动阶段,在延时开始和结束时读取列扫线状态,如果一致,则判断有键按下。延时时间为10ms。
2.2 按键连击的处理
连击是指操作者按下某一键但没有释放该键,则该键对应的功能将反复被执行,好象操作者在连续操作该键一样。由于单片机的速度较快,这种情况很容易发生。连击在很多情况下是不允许的,它使操作者很难准确地进行操作。
解决连击的关键是一次按键只让它响应一次,该键不释放就不执行第二次。
2.3 键盘扫描
本文采用的键盘为20键的小键盘,其扫描码较为简单,可参见图1,在此不作专门介绍。
2.4 与上位机通讯本文提出的方法是采用串行口进行通讯的。采用定时/计数器1为波特率发生器,具体数值为1200bps。AT89C2051采用串行中断方式与上位机进行通讯;而上位机的键盘响应与处理则安排在外中断1服务程序中。上位机在INT1中断服务程序中首先应向键盘发送相应的地址,然后再进入接收状态。在上位机的中断服务程序中,还可以设置接收键值的时间范围,超时则认为此键值作废。
2.5 MAX706的复位
AT89C2051对MAX706的复位安排在定时/计数器0的中断服务程序中。而上位机对MAX706等监控电路的复位可以自由安排,但必须在1.6s之内完成。
3. 软件程序清单
软件的流程框图如图2所示。具体的程序清单如下:
THIS_051 EQU #0AAH
NO_KEY EQU #0F0H
ORG 0000H
AJMP MAIN
ORG 000BH
AJMP INT_T0
ORG 0023H
AJMP INT_SERIES
ORG 0030H
MAIN:
MOV SP,#40H
SETB P1.0
SETB P1.1
SETB P1.2
SETB P1.3
CLR P3.7
MOV TMOD,#21H
MOV TL1,#0E6H
MOV TH1,#0E6H
MOV TL0,#00H
MOV TH0,#80H
CLR ET1
SETB TR1
SETB ET0
SETB TR0
MOV PCON,#80H
MOV SCON,#0D0H
SETB ES
SETB EA
READKEY:
CLR P1.1
CLR P1.2
CLR P1.3
MOV R1,#00H
LCALL DELAY10US
MOV A,P1
ANL A,#0F0H
CJNE A,NO_KEY,DEL_SHAKER1
SJMP TEST_LINE2
DEL_SHAKER1:
LCALL DELAY10MS
MOV A,P1
ANL A,#0F0H
CJNE A,NO_KEY,KEY_VALUE
TEST桳INE2:
SETB P1.1
MOV R1,#01H
LCALL DELAY10US
MOV A,P1
ANL A,#0F0H
CJNE A,NO_KEY,DEL_SHAKER2
SJMP TEST_LINE3
DEL_SHAKER2:
LCALL DELAY10MS
MOV A,P1
ANL A,#0F0H
CJNE A,NO_KEY,KEY_CALUE
TEST_LINE3:
SETB P1.2
CLR P1.1
MOV R1,#02H LCALL DELAY10US
MOV A,P1
ANL A,#0F0H
CJNE A,NO_KEY,DEL_SHAKER3
SJMP TEST_LINE4
DEL_SHAKER3:
LCALL DELAY10MS
MOV A,P1
ANL A,#0F0H
CJNE A,NO_KEY,KEY_VALUE
TEST_LINE4:
SETB P1.1
MOV R1,#03H
LCALL DELAY10US
MOV A,P1
ANL A,#0F0H
CJNE A,NO_KEY,DEL_SHAKER4
SJMP TEST_LINE5
DEL_SHAKER4:
LCALL DELAY10MS
MOV A,P1
ANL A,#0F0H
CJNE A,NO_KEY,KEY_VALUE
TEST_LINE5:
SETB P1.3
CLR P1.1
CLR P1.2
MOV R1,#04H
LCALL DELAY10US
MOV A,P1
ANL A,#0F0H
CJNE A,NO_KEY,DEL_SHAKER5
SJMP RET_READKEY
DEL_SHAKER5:
LCALL DELAY10MS
MOV A,P1
ANL A,#0F0H
CJNE A,NO_KEY,KEY_VALUE
RET_READKEY:
AJMP READKEY
KEY_VALUE:
JNB ACC.7,FIRST_LINE
JNB ACC.6,SECOND_LINE
JNB ACC.5,THIRD_LINE
JNB ACC.4,FOUTH_LINE
AJMP READKEY
FIRST_LINE:
MOV R0,#03H
SJMP SEND_KEY
SECOND_LINE:
MOV R0,#02H
SJMP SEND_KEY
THIRD_LINE:
MOV R0,#01H
SJMP SEND-KEY
FOUTH_LINE:
MOV R0,#00H
SEND_KEY:
MOV A,R0
MOV B,#05H
MUL AB
ADD A,R1
MOV DPTR,#KBTAB
MOVC A,@A+DPTR
MOV R3,A
CLR P1.0
LCALL DELAY10US
SETB P1.0 KEY_LOOP:
LCALL DELAY10US
MOV A,P1
ANL A,#0F0H
CJNE A,NO_KEY,KEY_LOOP
SETB P1.1
SETB P1.2
SETB P1.3
AJMP READKEY
INT桾0:
MOV TL0,#00H
MOV TH0,#80H
CPL P3.7
RETI
INT_SERIES:
PUSH ACC
JNB RI,TRANSMISSION
CLR RI
MOV A,SBUF
CJNE A,THIS?051,RETURN
MOV A,R3
MOV SBUF,A
SJMP RETURN
TRANSMISSION:
CLR TI
RETURN:
POP ACC
RETI
DELAY10MS:
MOV R6,#10
DELAY1:MOV R5,#250
DELAY2:DJNZ R5,DELAY2
DJNZ R6,DELAY1
RET
DELAY1MS:
MOV R5,#250
DELAY4:DJNZ R5,DELAY4
RET
DELAY10US:
MOV R5,#05H
DELAY3:DJNZ R5,DELAY3
RET
KBTAB:DB′TG369CF258DP147SH0IR′
74LS164连接IO口动态扫描键盘
#ifndef _DISP_KEY_H_
#define _DISP_KEY_H_
#i nclude "Common.h"
#define DISP_KEY 3 //显示和键盘任务Identificatio
#define PROCESS_KEY 5 //键值处理任务Identification
#define KEYSPEED 1 //越大越慢,2慢4倍,4慢8倍
#define KEY_VALID_COUNT 12 //检测有效次数
//定义设置的参数
#define SETUP_RUNMODE 0x01
#define SETUP_DEST 0x02
#define SETUP_PROP 0x03
#define SETUP_INTEGRAL 0x04
#define SETUP_DERIVATIVE 0x05
#define SETUP_TIME 0x06
//定义命令字
#define SETUP 0x02
#define INC 0x04
#define DEC 0x08
#define START_STOP 0x10
//定义模式
#define HRD_MODE 0x00
#define CONST_TEMP_MODE 0x01
#define DEFAULT_RUN_MODE HRD_MODE
//显示和键盘
#define KEY_BASE 1
sbit KEY = P2^0;
sbit KEY0 = P2^(KEY_BASE);
sbit KEY1 = P2^(KEY_BASE+1);
sbit KEY2 = P2^(KEY_BASE+2);
sbit KEY3 = P2^(KEY_BASE+3);
sbit DISPDATA = P2^5;
sbit DISPCLK = P2^6;
//extern Variable
extern unsigned char cDispBuff[4];
//function prototype
void InitDispPort(void);
void Write74HC164(unsigned char i);
void WriteDispBuffer(unsigned int cNo);
void WriteDispBuffer4Bit(unsigned int iNo);
//
extern code unsigned char SCBlackLED;
#endif
//Write BY :Xukaiming
#i nclude "DISP_KEY.H"
#i nclude "PID.H"
#i nclude "main.h"
#i nclude "x5043.h"
//#i nclude ""
#i nclude <intrins.h>
/*********************************************************************************************************/
volatile unsigned char cCurrKey = 0; //键值
volatile unsigned char cKey = 0;
volatile unsigned char ValidCount = 0; //键次数,方便改变温度时的连加
unsigned char cDispBuff[4]; //显示缓冲区
//code unsigned char SegCode[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};
code unsigned char SegCode[] = {0xBB,0x82,0x5B,0xCB,0xE2,0xE9,0xF9,0x83,0xFB,0xEB,0xF3,0xF8,0x39,0xDA,0x79,0x71};
code unsigned char SCBlackLED = 0xFF;
code unsigned char SEGSetup = 0xED;
code unsigned char SEGH = 0xF6;
code unsigned char SEGC = 0x39;
code unsigned char SEGdest = 0xDE;
code unsigned char SEGProp = 0x77;
code unsigned char SEGIntegral = 0x34;
code unsigned char SEGdelta = 0xBF;
code unsigned char SEGTime = 0x35;
//模拟SPI总线写74ls164
/*********************************************************************************************************/
void Write74HC164(unsigned char i)
{
unsigned char j = 0;
CloseInt();
// P0 = i; //用于在KEIL上的模拟调?
for(j=0;j<8;j++)
{
DISPCLK = 0;
DISPDATA = (bit)(i&0x80);
Delay(20);
DISPCLK = 1;
i = i<<1;
Delay(20);
}
OpenInt();
}
/*********************************************************************************************************/
void disp_key(void) _task_ DISP_KEY
{
unsigned char i = 0;
unsigned char cScanCode = 0;
ValidCount = 0;
InitDispPort();
while(1)
{
cScanCode = 0x01;
//
for(i=0;i<4;i++)
{
//
os_wait(K_TMO,1,0); //延时20ms
//Delay(5);
cScanCode<<=1; //代码左移
KEY0=KEY1=KEY2=KEY3=1; //关闭数码管显示
Write74HC164(cDispBuff[i]); //显示显示缓冲区的
switch(cScanCode) //打开显示
{
case 0x02:KEY0 = 0;break;
case 0x04:KEY1 = 0;break;
case 0x08:KEY2 = 0;break;
case 0x10:KEY3 = 0;break;
default:break;
}
if(!KEY) //如果KEY =0,有键按下
{
if(cKey == cScanCode) //如果延时后值相等,认为键盘按下
{ //
ValidCount++;
if(ValidCount>KEY_VALID_COUNT) //到了有效次数后,保存键值
{
cCurrKey = cKey;
}
}
else //如果几个键盘粘连,清除键值
{
ValidCount = 0;
}
cKey = cScanCode; //Save key value for next compare
}
else //键盘释放发送键盘处理消息
{
if(ValidCount>KEY_VALID_COUNT)
{
//发送命令处理消息
os_send_signal(PROCESS_KEY);
}
}
}
}
}
//初始化端口
/*********************************************************************************************************/
void InitDispPort(void)
{
/*
DISPDATA = 1;
DISPCLK = 1;
KEY = 1;
*/
P2 = 0xFF;
}
//处理键盘消息
/*********************************************************************************************************/
void Process_Key(void) _task_ PROCESS_KEY
{
unsigned char SetupMode = 0; //设置参数模式
unsigned char RunMode = DEFAULT_RUN_MODE; //运行模式
unsigned char cResult = 0;
unsigned char ValidKeyCount = 0;
InitPIDParam();
while(1)
{
cResult = os_wait(K_SIG+K_TMO,50,0);
os_clear_signal(PROCESS_KEY);
if((cCurrKey!=0)&&(pidCtrl.bHeatUp==0))
{
os_delete_task(ADCONVERT); //防止a/d转换任务影响显示缓冲区
os_delete_task(CHANGEDESTTEMP);
}
//改变键速
ValidKeyCount = (ValidCount-KEY_VALID_COUNT)>>KEYSPEED;
if(ValidKeyCount==0 )
ValidKeyCount = 1; //防止很小时为0
//
switch(cCurrKey)
{
case SETUP:
if(cResult==TMO_EVENT) //设置键不能出现连加的情况
{
_nop_();
break;
}
if(pidCtrl.bHeatUp == 1) //if temperate is up shutdown the a/d convert task
{
os_delete_task(ADCONVERT);
os_delete_task(CHANGEDESTTEMP);
}
//轮换显示参数/切换模式
SetupMode+=1;
//其他位显示黑屏
cDispBuff[1] = cDispBuff[2] = cDispBuff[3] = SCBlackLED;
//修改显示缓冲区首位
switch(SetupMode)
{
case SETUP_RUNMODE:
cDispBuff[0] = ~SEGSetup; //设置运行模式
//显示运行模式
switch(RunMode)
{
case HRD_MODE:
cDispBuff[2] = ~SEGH;
break;
case CONST_TEMP_MODE:
cDispBuff[2] = ~SEGC;
break;
default:break;
}
break;
case SETUP_DEST:
cDispBuff[0] = ~SEGdest; //目标温度,<1000
WriteDispBuffer(pidCtrl.iDest); //显示目标温度
break;
case SETUP_PROP:
cDispBuff[0] = ~SEGProp; //设置比例系数
WriteDispBuffer(pidCtrl.Prop); //显示比例系数
break;
case SETUP_INTEGRAL:
cDispBuff[0] = ~SEGIntegral; //设置积分项
WriteDispBuffer(pidCtrl.Integral); //显示积分项
break;
case SETUP_DERIVATIVE: //设置微分项
cDispBuff[0] = ~SEGdelta;
WriteDispBuffer(pidCtrl.Derivative);
break;
case SETUP_TIME: //设置PID时间
cDispBuff[0] = ~SEGTime;
WriteDispBuffer(pidCtrl.Ti);
break;
default:
//SetupMode = SETUP_RUNMODE;
SetupMode = 0;
os_delete_task(DISP_KEY);
SavePIDParamToX5043(); //保存PID参数
os_create_task(DISP_KEY);
os_create_task(ADCONVERT);
break;
}
cCurrKey = 0; //清除键值
break; //设置参数
case INC:
//增加参数的值
//根据ValidCount的个数决定是否连加
//参数值+
case DEC:
//递减参数的值,
//根据ValidCount的个数决定是否连减
//参数值-
switch(SetupMode)
{
case SETUP_RUNMODE:
{
RunMode = (RunMode+1)%2;
cDispBuff[3] = cDispBuff[1] = SCBlackLED;
switch(RunMode)
{
case HRD_MODE:
cDispBuff[2] = ~SEGH;
break;
case CONST_TEMP_MODE:
cDispBuff[2] = ~SEGC;
break;
default:break;
}
}
break;
case SETUP_DEST: //修改目标温度值
switch(cCurrKey)
{
case INC:
pidCtrl.iDest+=ValidKeyCount;
break;
case DEC:
pidCtrl.iDest-=ValidKeyCount;
break;
default:break;
}
//计算显示缓冲区
if(pidCtrl.iDest>999L)
{
WriteDispBuffer4Bit(pidCtrl.iDest);
}
else
{
cDispBuff[0] = ~SEGdest;
WriteDispBuffer(pidCtrl.iDest);
}
break;
case SETUP_PROP: //修改比例系数
switch(cCurrKey)
{
case INC:
pidCtrl.Prop+=ValidKeyCount;
break;
case DEC:
pidCtrl.Prop-=ValidKeyCount;
break;
default:break;
}
//计算显示缓冲区
WriteDispBuffer(pidCtrl.Prop);
break;
case SETUP_INTEGRAL: //修改积分值
switch(cCurrKey)
{
case INC:
pidCtrl.Integral+=ValidKeyCount;
break;
case DEC:
pidCtrl.Integral-=ValidKeyCount;
break;
default:break;
}
//计算显示缓冲区
WriteDispBuffer(pidCtrl.Integral);
break;
case SETUP_DERIVATIVE: //修改微分值
switch(cCurrKey)
{
case INC:
pidCtrl.Derivative+=ValidKeyCount;
break;
case DEC:
pidCtrl.Derivative-=ValidKeyCount;
break;
default:break;
}
//计算显示缓冲区
WriteDispBuffer(pidCtrl.Derivative);
break;
case SETUP_TIME: //设置PID时间
switch(cCurrKey)
{
case INC:
pidCtrl.Ti+=ValidKeyCount;
break;
case DEC:
pidCtrl.Ti-=ValidKeyCount;
break;
default:break;
}
//计算显示缓冲区
WriteDispBuffer(pidCtrl.Ti);
break;
}
CloseInt();
//错误保护
ProtectPIDParam();
if(cResult==TMO_EVENT)
ValidCount = KEY_VALID_COUNT;
if(cResult==SIG_EVENT)
ValidCount = 0;
OpenInt();
break;
case START_STOP:
//开始试验/停止试验
if(cResult==TMO_EVENT) //确定键不能出现连加的情况
{
_nop_();
break;
}
if((SetupMode==SETUP_RUNMODE)||(SetupMode ==0))
{
switch(RunMode)
{
case HRD_MODE:
os_create_task(CHANGEDESTTEMP);
case CONST_TEMP_MODE:
//os_create_task(PID);
os_create_task(ADCONVERT);
pidCtrl.bHeatUp = 1;
break;
default:break;
}
//
cCurrKey = 0;
}
break; //确定
default:
_nop_();
break;
}
if(cResult==SIG_EVENT)
{
cCurrKey = 0;//如果是键盘释放后的消息,清除键值
ValidCount = 0;
}
}
}
//写显示缓冲区
void WriteDispBuffer(unsigned int cNo)
{
unsigned char i;
i = cNo/100;
cDispBuff[1] = ~SegCode[i];
i = (cNo%100)/10;
cDispBuff[2] = ~SegCode[i];
i = cNo%10;
cDispBuff[3] = ~SegCode[i];
}
void WriteDispBuffer4Bit(unsigned int iNo)
{
unsigned int i;
i = iNo/1000;
cDispBuff[0] = ~SegCode[i];
i = iNo%1000;
WriteDispBuffer(i);
}