单片机系统键盘的设计小结

时间:2024.4.13

单片机系统键盘的设计小结

一、概述
      键盘在单片机应用系统中,实现输入数据、传送命令的功能,是人工干预的主要手段。键盘分两大类:编码键盘和非编码键盘。
      编码键盘:由硬件逻辑电路完成必要的键识别工作与可靠性措施。每按一次键,键盘自动提供被按键的读数,同时产生一选通脉冲通知微处理器,一般还具有反弹跳和同时按键保护功能。这种键盘易于使用,但硬件比较复杂,对于主机任务繁重之情况,采用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);
}

更多相关推荐:
单片机课程设计总结

单片机课程设计心得体会这个学期的单片机课已经早早的上完了但是理论纯属理论没有与实践的结合总让我们学的不踏实感觉没有达到学以致用的效果所庆幸的是在课程介绍考试完之后老师给我们安排了这次单片机课程设计给了我们学以致...

单片机课程设计及个人心得感受

本科课程设计(论文)单片机控制流水灯的正常工作及外部中断控制灯的亮灭学院名称:汽车与交通工程学院专业:汽车服务工程班级:13汽服B学号:*************姓名:*******指导教师姓名:***二〇**…

单片机课程设计小结

单片机课程设计小结单片机课程设计小结一做了两周的课程设计有很多的gt心得体会有关于单片机方面的更多的是关于人与人之间关系方面的我们组一共有三个人但其他两个人是真的神龙见首不见尾除了在最后答辩的时候他们一起坐在了...

20xx单片机课程设计心得体会

20xx单片机课程设计心得体会单片机课程设计心得体会课程设计是大学课堂中常见的课堂模式该模式更好的培养学生的综合能力课程模式主要由选题到定稿从理论到实践组成以下由第一公文网整理关于单片机课程设计的心得单片机课程...

单片机课程设计总结

单片机基础知识单片机的外部结构:1、DIP40双列直插;2、P0,P1,P2,P3四个8位准双向I/O引脚;(作为I/O输入时,要先输出高电平)3、电源VCC(PIN40)和地线GND(PIN20);4、高电平…

单片机课程设计

信息与电气工程学院课程设计说明书20xx20xx学年第2学期课程名称单片机应用课程设计题目简易数字计数器设计专业班级自动化1101学生姓名学号110410指导教师设计周数2周设计成绩20xx年7月10日单片机课...

单片机课程设计报告

JINGCHUUNIVERSITYOFTECHNOLOGY电子信息工程学院单片机原理与应用技术课程设计报告电子秒表系统专业班级11电气三班姓名学号指导教师邓鹏提交日期20xx年6月目录一前言311课程设计的目的...

单片机课程设计报告

单片机课程设计报告姓名张磊学号20xx123345班级机制1413一实验课题微型直流电机调速控制二实验原理直流电机即将直流电能转换成机械能直流电动机或将机械能转换成直流电能直流发电机的旋转电机本设计主要是利用单...

单片机课程设计报告

江南大学课程名称设计题目基于单片机的步进电机控制器的设计班级姓名指导教师物联网工程学院课程设计报告单片机原理及应用自动化班学号评分20xx年6月29日一步进电机概述步进电动机又称脉冲电动机或阶跃电动机国外一般称...

单片机课程设计报告

单片机原理及系统课程设计报告单片机原理及系统课程设计专业自动控制班级控1101班姓名陈姣学号20xx05320指导教师李亚宁兰州交通大学自动化与电气工程学院20xx年1月17日基于单片机的汽车转向灯设计1引言在...

单片机课程设计实验报告

单片机课程设计实验报告组员20xx0109题目分析本小车是由一块8位单片机AT89S52开发板作为小车的控制器用两个360舵机作为小车的动力前轮用一个单向滚动小球构成后轮单片机开发板上前端留有一块面包板做为小车...

单片机课程设计实验报告

中国民航大学单片机课程设计报告数字温度计姓名白杨学号专业班级指导老师常美华赵淑舫所在学院航空自动化学院20xx年12月18日1概述11课程设计的意义本次课程设计是在我们学过单片机后的一次实习可增加我们的动手能力...

单片机课程设计小结(42篇)