应广单片机按键检测程序,为了方便大家理解,用生产者/消费者模型去做按键检测.
#include "extern.h"
#define HIGH 1
#define LOW 0
#define DISABLE 0
#define ENABLE 1
#define EMPTY 0
#define FULL 1
#define ON 1
#define OFF 0
/*单位 ms*/
#define RUN_TMR 15000
#define LOW_POW_TIMING_TMR 3000
BIT LED_G : PA.3;
BIT KEY_HIT : PA.4;
#define KEY_DEBOUNCE_CNT 20
#define GRE_LED_ON $ LED_G OUT,LOW
#define GRE_LED_OFF $ LED_G OUT,HIGH
#define GRE_LED_FLASH {if(LED_G){LED_G=0;}else{ LED_G=1;}}
/*计数值Cinit*/
word ucFlashTmrCnt;
/*cinit*/
BIT ubMsFlag;
/*cinit*/
BIT ubEnLedFlash;
/*unit 10ms*/
word usMsFlashTmr;
byte ucSysSt;
bit FLAG_NMS;
/*计数值cinit*/
byte count;
/*定时器初始化cinit*/
word T16COUNTER;
/*高低键盘倒计时*/
byte ucKeyHitHigtCnt;
byte ucKeyHitLowCnt;
/*按键状态*/
byte ucKeyHitSt;
byte ucKeyHitBak;
void UpDateLedSt(void);
/***************************************/
void TIME16_Init(void)
{
/*计数值清零*/
T16COUNTER =488;
/*ms标记reset*/
FLAG_NMS =0;
/*使能定时器*/
$ INTEN T16;
/*关中断*/
INTRQ = 0;
/*停止定时器*/
T16M.5 =0;
STT16 T16COUNTER;
/*计算方法16M/*/
$ T16M IHRC,/1,BIT11;
}
void UpdateLedTmr(void)
{
/*是否闪烁*/
if(ubEnLedFlash)
{
/*1ms进行一次计数*/
ucFlashTmrCnt++;
if(ucFlashTmrCnt>250)
{
ucFlashTmrCnt=0;
/*闪灯*/
GRE_LED_FLASH;
}
}
}
/**********************************************************************
生产者/消费者模型
每1ms执行一次,查看按键端口状态
如果端口为1,只生产商品"1";
如果端口为0,只生产商品"0"
根据端口状态,每1ms生产20个产品(商品"1"/商品"0"),
*********************************************
同时设置消费者
消费者每1ms值消费一个商品
******************************
1.如果生产者一直生产,那么消费者永远无法消费完商品(每1ms生产20个商品,而只消费1个)
2.如果生产者不在生产,那么消费者会吧商品消费完,(20ms之后,商品被消耗完了)此时可以反推生产者的状态.
***********************************************************************/
void UpDateKeyTmr(void)
{
/*********************生产者,要么生产 商品"1",要么生产商品"0"***************************/
/*当前状态为1*/
if(KEY_HIT)
{
/*如果按键释放,走这个分支,每1ms产生20个 商品"1"*/
ucKeyHitHigtCnt=KEY_DEBOUNCE_CNT;
}
/*当前状态为0*/
else
{
/*如果按键按下,走这个分支,每1ms产生20个 商品"0"*/
ucKeyHitLowCnt=KEY_DEBOUNCE_CNT;
}
/*********************商品"0"消费者****************************/
/*如果按键按下,商品"0"不会被消费完,因为生产商品"0"的速度远大于消费的速度(按键按下1ms生产20个商品"0",而1ms只消耗1个商品"0")*/
if(ucKeyHitLowCnt)
{
/*每1ms消费一个 商品"0"*/
ucKeyHitLowCnt--;
/*查看商品"0"是否被消耗完",*/
if(!ucKeyHitLowCnt)
{
/*一段时间后,如果没有生产者(当前端口状态为高)也就是无法产生商品"0",
那么商品"0"会被消耗完,当商品0为消耗殆尽,那么可以认为按键释放(反推生产者的状态)*/
ucKeyHitSt=HIGH;
}
}
/*********************商品"1"消费者****************************/
/*如果按键状态是1,商品"1"不会被消费完,因为生产商品"1"的速度远大于消费的速度(按键没有按下1ms生产20个商品"1",1ms,只消耗1个商品"1")*/
if(ucKeyHitHigtCnt)
{
/*每1ms消费一个 商品"1";*/
ucKeyHitHigtCnt--;
/*查看商品"1"是否被消耗完",*/
if(!ucKeyHitHigtCnt)
{
/*一段时间后,如果没有生产者(当前端口状态为低)也就是无法产生商品"1",
那么商品"1"会被消耗完,当商品1为消耗殆尽,那么可以认为按键按下(反推生产者的状态)*/
ucKeyHitSt=LOW;
}
}
/**************************************************/
}
void UpDateLedSt(void)
{
/*状态切换*/
ucSysSt++;
if(ucSysSt>2)
{
ucSysSt=0;
}
switch(ucSysSt)
{
/*开闪烁*/
case 0:
usMsFlashTmr=0;
/*使能闪烁*/
ubEnLedFlash=1;
break;
/*开灯*/
case 1:
ubEnLedFlash=0;
/*关灯,关闪烁*/
GRE_LED_OFF;
/*关灯*/
break;
/*关灯*/
case 2:
ubEnLedFlash=0;
/*关灯,关闪烁*/
GRE_LED_ON;
/*关灯*/
break;
default:
break;
}
}
void GetKeySt(void)
{
/*按键的历史状态和当前状态不一样,
说明按键状态有切换*/
if(ucKeyHitSt!=ucKeyHitBak)
{
/*保存当前状态*/
ucKeyHitBak=ucKeyHitSt;
/*如果当前按键被按下*/
if(!ucKeyHitSt)
{
/*更新状态*/
UpDateLedSt();
}
else
{
/*按键释放*/
}
}
}
/*按键端口状态初始化*/
void KeyAppInit(void)
{
/*检测端口状态*/
if(KEY_HIT)
{
/*当前状态*/
ucKeyHitSt=HIGH;
/*历史状态*/
ucKeyHitBak=HIGH;
}
else
{
/*当前状态*/
ucKeyHitSt=LOW;
/*历史状态*/
ucKeyHitBak=LOW;
}
/*初始化*/
ucKeyHitHigtCnt=KEY_DEBOUNCE_CNT;
ucKeyHitLowCnt=KEY_DEBOUNCE_CNT;
#if 0
usKeyHitLoPreCnt=0;
ucKeyHitPreSt=0;
#endif
}
void FPPA0 (void)
{
.ADJUST_IC SYSCLK=IHRC/8, IHRC=16MHz, VDD=3.0V;
$ CLKMD IHRC/8,En_IHRC,En_ILRC,En_WatchDog;
.delay 40000;
$ LED_G OUT,HIGH;
$ KEY_HIT IN,PULL;
TIME16_Init();
KeyAppInit();
ubMsFlag=0;
ubEnLedFlash=0;
/*状态初始化*/
ucSysSt=2;
engint;
while (1)
{
wdreset;
/*1ms定时时间到*/
if ( FLAG_NMS )
{
/*按键*/
UpDateKeyTmr();
/*点灯*/
UpdateLedTmr();
/*清除标记*/
FLAG_NMS=0;
}
/*按键状态切换*/
GetKeySt();
}
}
void Interrupt ( void )
{
pushaf;
if ( Intrq.T16 )
{
Intrq.T16 = 0;
STT16 T16COUNTER;
if ( count>0 )
{
count--;
}
else
{
count = 9;
/*1ms*/
FLAG_NMS= 1;
}
}
popaf;
}
/*end create by zhongvv QQ:85547259*/