日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

单片机基础学-按键篇

發布時間:2023/12/14 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 单片机基础学-按键篇 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

其實我現在也是一個菜鳥,但是這是我學習的過程中的總結,我想寫出來,可能對初學者有用,在此獻丑了。

按鍵總結篇

???????????????????????????????????????????????? 作者:HouZuping

在所有智能產品中,按鍵是最為常用的,所以按鍵程序的好壞很重要。以前我們在學校里學的按鍵檢測方法都是不適用,很浪費時間,減少了CPU的效率。在大家的不斷努力下,基本上編程都是用狀態轉移思想。用狀態機思想編的按鍵檢測程序也很多,像一些高手就寫過很好的按鍵檢測程序,下面我總結了用一個定時器的獨立按鍵檢測,能檢測單擊,連擊,長擊等。這個按鍵檢測程序中包含了狀態轉移思想,時間片段思想,對象編程。

關于按鍵流程圖我就不說了,這個大家都清楚。首先對按鍵進行一個數據結構定義。

struct KeyData

{

?????? unsigned char KeyValue;???????????????????? //按鍵返回值

?????? unsigned char LongClickFlag;?????? ?? //長擊標志

?????? unsigned char RunClickFlag;??????? //連擊標志

?????? unsigned char JudgeRunFlag;?????? ??? //軟定時器的連擊標志

?????? unsigned int? RunCount;???????????? ??? //連擊間隔時間計數

};

?

//按鍵常量的定義 ,根據具體的時鐘來跟改

#define? KeyLongTime_2s?????? 100? //??? 1/Fcy*timerValue*1000

#define? KeyRunClick_500Ms??? 40?? //連擊間隔時間大約是500ms左右

?

這個數據結構是把按鍵當成一個對象,這樣每次按鍵按下后都會有一個返回值,其他標志都是按鍵需要其他功能功能。不管有幾個獨立按鍵,每個按鍵返回值都不同。需要幾個按鍵時,就定義幾個按鍵關鍵字。

//------------接口區

#define KeyOne?? P1_0

#define KeyTwo?? P1_1

?

//----------初始狀態

#define IdleState?? 1

?

這里我只用了兩個按鍵,其實本按鍵最為不好的地方就是按鍵檢測和讀取按鍵的值,每次移植時都需要修改,這里還需要修改,在讀取按鍵值時,我可以采用關鍵字固定,是來確定按鍵返回值固定這種方式,但是我覺得沒有必要,移植時就改吧,有的單片機直接支持位操作,有的不支持。

//****************************************************************

//鍵盤掃描接口部分,移植時需要修改

//****************************************************************

unsigned char KeySwap()

{

?????? if((KeyOne!=IdleState)||(KeyTwo!=IdleState))//按鍵數目判斷狀態,這里是位變量

?????? return 1;

?????? else

?????? return 0;

}

//***************************************************************

//讀取接口值函數,移植時需要修改

//********************************************************************

unsigned char RdKeyValue()

{

?????? if(KeyOne!=IdleState)

?????? return 0x02;

?????? if(KeyTwo!=IdleState)

?????? return 0x03;

?????? else

?????? return 0;

}

?

下面來看看我主要的按鍵檢測部分,也是最重要的部分,我在定時器內定義每隔12ms就去掃描一次按鍵,這樣每個狀態間隔的時間就是12ms,我就是利用這個時間來去抖動,我也是利用這個時間來進行連擊和長擊的判斷。不說了,看程序吧

/********************************************************************

基于軟定時器的通用模塊的建立之一:獨立按鍵通用模塊

創建人? :侯祖平

創建日期:2010.7.01

博客網址:

歡迎大家到我的博客交流..........

*********************************************************************

?

?????? #include "EvenKey.h"

?????? #include "KeyBasic.h"

?

//********************************************************************

//狀態變量

//********************************************************************

enum?

{

?????? KeyIdle = 0,

?????? KeyDownDelay,??????????? //判斷按鍵按下

?????? KeyWait,??????? ??? //按下等待每隔一個軟定時器,變量就加一

?????? KeyFunction,???????? //長擊和短擊判斷

?????? KeyLongClick,????????????? //若按下時間超出,則為長按

?????? KeyShortClick,???????????? //

?????? KeyRunClick,??????? //連擊,可以用一個變量來記錄連擊的次數

?????? KeyUp,??????????????????????? //按鍵抬起

?????? KeyUpDelay,? ??? ?????? //長擊按下延時

?????? KeyOver

};

?

//********************************************************************

//鍵值掃描循環

//********************************************************************

void KeyLoop(struct KeyData *KeyNumber)??? ??????????????????? ???

{

?????? static unsigned char KeyCurValue = 0 , KeyLastValue = 0;

?????? static unsigned char KeyState = 0;

?????? static unsigned int? LongCount = 0;

?????? switch(KeyState)

?????? {

????????????? case KeyIdle :

?????????????????????????????????? if(KeySwap())

?????????????????????????????????? {

????????????????????????????????????????? KeyState = KeyDownDelay;

?????????????????????????????????? }

?????????????????????????????????? else

?????????????????????????????????? {

????????????????????????????????????????? KeyState = KeyIdle;

?????????????????????????????????? }

?????????????????????????????????? break;

?

????????????? case KeyDownDelay :

?????????????????????????????????? if(KeySwap())

?????????????????????????????????? {

????????????????????????????????????????? KeyState = KeyWait;

?????????????????????????????????? }

?????????????????????????????????? else

?????????????????????????????????? {

????????????????????????????????????????? KeyState = KeyIdle;

?????????????????????????????????? }

?????????????????????????????????? break;

?

????????????? case KeyWait : ????????????????????????????????????????????????????? ?//有鍵按下,看是否是連擊

?????????????????????????????????? KeyCurValue = RdKeyValue();

?????????????????????????????????? if((KeyCurValue==KeyLastValue)&&(KeyNumber->JudgeRunFlag))

?????????????????????????????????? {???????????????????????????????????????????????????????????? //

?????????????????????????????????? ?? if(KeyNumber->RunCount < KeyRunClick_500Ms)

????????????????????????????????????????? {????????????????????????????????????????????????????? //則為連擊

???????????????????????????????????????????????? KeyNumber->RunCount = 0;

???????????????????????????????????????????????? KeyNumber->JudgeRunFlag = 0;

???????????????????????????????????????????????? KeyState = KeyRunClick;??????????? //跳轉到連擊狀態

????????????????????????????????????????? }

????????????????????????????????????????? else

????????????????????????????????????????? {

???????????????????????????????????????????????? KeyNumber->RunClickFlag = 0;

???????????????????????????????????????????????? KeyNumber->RunCount = 0;

???????????????????????????????????????????????? KeyNumber->JudgeRunFlag = 0;

???????????????????????????????????????????????? KeyState = KeyFunction;???????????? //若不是繼續判斷

????????????????????????????????????????? }

?????????????????????????????????? }

?????????????????????????????????? else

?????????????????????????????????? {

????????????????????????????????????????? KeyState = KeyFunction;?????

?????????????????????????????????? }

?

?????????????????????????????????? break;

?

????????????? case KeyFunction :

?????????????????????????????????? if(KeySwap())

?????????????????????????????????? {???? ?

????????????????????????????????????????? ?KeyCurValue = RdKeyValue();

????????????????????????????????????????? ?LongCount ++;

????????????????????????????????????????? ?if(LongCount >= KeyLongTime_2s)

????????????????????????????????????????? ?{

????????????????????????????????????????? ????? LongCount = 0;

????????????????????????????????????????? ????? KeyState = KeyLongClick;???

????????????????????????????????????????? ?}

?????????????????????????????????? }

?????????????????????????????????? else

?????????????????????????????????? {

????????????????????????????????????????? if(LongCount < KeyLongTime_2s)

????????????????????????????????????????? ?{

????????????????????????????????????????? ????? LongCount = 0;

????????????????????????????????????????? ????? KeyState = KeyShortClick;??

????????????????????????????????????????? ?}

?????????????????????????????????? }

????????????????????

?????????????????????????????????? break;

?

????????????? case KeyLongClick :????????????????????????????????? ???? //長擊

?????????????????????????????????? #ifdef? HaveLongKey

?????????????????????????????????? KeyNumber->LongClickFlag = 1;

?????????????????????????????????? KeyNumber->KeyValue = KeyCurValue|0x80;

?????????????????????????????????? #endif

?????????????????????????????????? if(!KeySwap())?????????????????????????? //若按鍵抬起 ,則狀態跳轉

?????????????????????????????????? KeyState = KeyUpDelay;

?????????????

?????????????????????????????????? break;

?

?

????????????? case KeyRunClick :????????????????????????????????????????? //連擊

?????????????????????????????????? #ifdef? HaveRunKey

?????????????????????????????????? KeyNumber->RunClickFlag = 1;

?????????????????????????????????? KeyNumber->KeyValue = KeyCurValue|0x40;

?????????????????????????????????? #endif

?????????????????????????????????? if(!KeySwap())?????????????????????????? //若按鍵抬起 ,則狀態跳轉

?????????????????????????????????? KeyState = KeyUpDelay;

?????????????

?????????????????????????????????? break;

?

????????????? case KeyShortClick :????????????????????????? ???? //短擊和連擊的判斷

???????????????????? ????????????? KeyNumber->JudgeRunFlag = 1; //連擊判斷啟動標志位

?????????????????????????????????? KeyNumber->KeyValue = KeyCurValue;

?????????????????????????????????? KeyState = KeyUp;

???????????????????????????????????????????????????????

?????????????????????????????????? break;

?

????????????? case KeyUp :

?????????????????????????????????? KeyNumber->RunClickFlag? = 0;

?????????????????????????????????? KeyNumber->LongClickFlag = 0;

?????????????????????????????????? KeyState = KeyOver;

?????????????????????????????????? break;

?

?????????????

????????????? case KeyUpDelay:

?????????????????????????????????? if(!KeySwap())?????????????????????????? //若按鍵抬起 ,則狀態跳轉

?????????????????????????????????? KeyState = KeyOver;

?

?????????????????????????????????? break;

?

????????????? case KeyOver :????????????????????????????????????????? ???? //結束

?????????????????????????????????? KeyLastValue = KeyCurValue;?????

?????????????????????????????????? KeyState = KeyIdle;

?????????????????????????????????? break;

????????????????????

?????? }????

}

?

?

?

//********************************************************************

//end of file

//********************************************************************

其中連擊的判斷也是我寫這個按鍵檢測的真正目的,以前我都是用兩個定時器來判斷連擊的,我在以前的程序添加了一個程序。

//****************************************************************

//參數傳遞函數,用于傳遞連擊的時間間隔

//****************************************************************

void WrRunTime(struct KeyData *KeyNumber)

{????

?????? ?if(KeyNumber->JudgeRunFlag)

?????? ?{

?????? ????? KeyNumber->RunCount ++;??????? ? //間隔計數啟動

????????????? if(KeyNumber->RunCount >= KeyRunClick_500Ms)

????????????? KeyNumber->JudgeRunFlag = 0;? //若大于等待間隔,自動關閉標志

?????? ?}

?????? ?else

?????? ?{

?????? ????? KeyNumber->RunCount = 0;

?????? ?}??????????

}

?

void WrRunTime(struct KeyData *KeyNumber)這個函數放在定時器中斷函數中,在一次短擊過后,程序會啟動連擊檢測標志KeyNumber->JudgeRunFlag = 1; //連擊判斷啟動標志位

在中斷函數中,若標志KeyNumber->JudgeRunFlag = 1則啟動計時。

//********************************************************************

//中斷函數非常重要,一切以中斷函數為參考

//********************************************************************

void Timer0Interrupt(void) interrupt 1

{

?????? ?TH0 = (65536-22000)/256;? //12MS

?????? ?TL0 = (65536-22000)%256;

?????? ?RunFunction = 1;?????????????? ??? //時間片段標志位

?????? ?WrRunTime(&KeyNumber);????????????? //連擊時間判斷

}

?

一旦檢測到if(KeyNumber->RunCount >= KeyRunClick_500Ms)

則連擊檢測自動關閉。

?

我的長擊和連擊判斷后并沒有在返回值中加什么東西,只有返回了一個標志位。

所以在測試程序中,你需要寫看標志是否至1。

你的測試程序中需要寫一下函數:

struct KeyData? KeyNumber;

//時間片段標志位

unsigned char RunFunction = 0;

?

void TimerInit()

{

?????? ?TMOD = 0x01;

?????? ?TH0 = (65536-22000)/256;? //12MS

?????? ?TL0 = (65536-22000)%256;

?????? ?ET0 = 1;

?????? ?EA = 1;

?????? ?TR0 = 1;

}

//測試

void Loop_f(unsigned char KeyValue)

{

?????? switch(KeyValue)

?????? {

?????? }

}

//test

?

//test

?

void main()

{????

?????? TimerInit();

?????? while(1)

?????? {

????????????? if(RunFunction)

????????????? {

???????????????????? RunFunction = 0;

???????????????????? KeyLoop(&KeyNumber);

???????????????????? Loop_f(KeyNumber.KeyValue);

????????????? }????

?????? }

}

?

總結

以上是生活随笔為你收集整理的单片机基础学-按键篇的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。