用狀態機的編程思路,終于把這個功能實現了
/* ********************************************************************************************* */
// 處理器 : STC89C52RC
// 編譯環境 : Keil4 C51
// 系統時鐘 : 11.0592MHZ
// 簡單描述 : 1個獨立按鍵,短按開關燈,長按調光
/* ********************************************************************************************* */
#include<reg52.h>
typedef unsigned char uChar8;
typedef unsigned int uInt16;
/*初始狀態 確認狀態 單擊狀態 連發狀態 */
typedef enum KeyState{StateInit,StateAffirm,StateSingle,StateRepeat};//鍵值狀態值
uChar8 pwm_led_val = 0; //LED占空比值 0-20 0最亮
uChar8 pwm_t; //周期
sbit KEY1 = P3^0; //定義按鍵端口
sbit LED = P1^0; //定義LED燈端口
void Timer0Init(void)
{
TMOD |= 0x02; //設置定時器0工作模式2,8位自動重裝
TH0 = 240; //定時器裝初值
TL0 = 240; //11.0592M晶振下占空比最大比值是20,輸出2880HZ
EA = 1; //開總中斷
ET0 = 1; //開定時器0中斷
TR0 = 1; //啟動定時器0
}
void Timer1Init(void)
{
TMOD |= 0x10; // 設置定時器1工作模式1,16位計數器
TH1 = 0xDC; // 賦初始值
TL1 = 0x00; // 11.0592M晶振下,定時10ms
TR1 = 1; // 啟動定時器1
}
/* ***************************************************** */
// 函數名稱: Init()
// 函數功能: 初始化
// 入口參數: 無
// 出口參數: 無
/* ***************************************************** */
void Init() //初始化
{
Timer0Init();
Timer1Init();
}
//定時器0中斷
void timer0() interrupt 1
{
pwm_t++;
if(pwm_t == 20)
{
pwm_t = 0; LED = 1;
}
if(pwm_led_val == pwm_t)
LED = 0;
}
/* ***************************************************** */
// 函數名稱:KeyScan(void)
// 函數功能:掃描按鍵
// 入口參數:無
// 出口參數:鍵值(num)
/* ***************************************************** */
void KeyScan(void)
{
static uChar8 KeyStateTemp1 = 0; //按鍵狀態臨時存儲值1
static uChar8 KeyTime = 0; //按鍵延時時間
bit KeyPressTemp1; //按鍵是否按下存儲值1
bit falg; //亮度標志
KeyPressTemp1 = KEY1; //讀取I/O口的鍵值
switch(KeyStateTemp1)
{
case StateInit: //按鍵初始狀態
if(!KeyPressTemp1) //當按鍵按下,狀態切換到確認態
KeyStateTemp1 = StateAffirm;
break;
case StateAffirm: //按鍵確認態
if(!KeyPressTemp1)
{
KeyTime = 0;
KeyStateTemp1 = StateSingle; //切換到單次觸發態
}
else KeyStateTemp1 = StateInit; //按鍵已抬起,切換到初始態
break;
case StateSingle: //按鍵單發態
if(KeyPressTemp1) //按下時間小于1s
{
KeyStateTemp1 = StateInit; //按鍵釋放,則回到初始態
TR0 = !TR0;
LED = 1; //關閉LED
}
else if(++KeyTime > 100) //按下時間大于1s(100*10ms)
{
KeyStateTemp1 = StateRepeat; //狀態切換到連發態
KeyTime = 0;
}
break;
case StateRepeat: //按鍵連發態
if(KeyPressTemp1)
KeyStateTemp1 = StateInit; //按鍵釋放,則進初始態
else //按鍵未釋放
{
if(++KeyTime > 10) //按鍵計時值大于100ms(10*10ms)
{
KeyTime = 0;
if(falg == 0)
{
if(pwm_led_val < 20)
{
pwm_led_val++; //亮度變暗
if(pwm_led_val==20)
falg = 1;
}
}
if( falg ==1 )
{
if(pwm_led_val > 0)
{
pwm_led_val--; //亮度變亮
if(pwm_led_val==0)
falg = 0;
}
}
}
break;
}
break;
default: KeyStateTemp1 = KeyStateTemp1 = StateInit; break;
}
}
/* ***************************************************** */
// 函數名稱:ExecuteKeyNum(void)
// 函數功能:按鍵值來執行相應的動作
// 入口參數:無
// 出口參數:無
/* ***************************************************** */
void ExecuteKeyNum(void)
{
if(TF1) //定時器1溢出
{
TF1 = 0;
TH1 = 0xDC;
TL1 = 0x00;
KeyScan();
}
}
void main()
{
Init(); //首先初始化各數據
while(1) //進入主程序大循環
{
ExecuteKeyNum(); //不停的檢測按鍵是否被按下
}
} |