EC修煉之道—按鍵的做法
在EC的各項功能中,按鍵的作用非常重要。機器上的PowerSwitch按鍵,亮度加減按鍵,聲音加減按鍵,WIFI&Bluetooth開關等,都有可能用到按鍵功能。
按鍵的做法有兩種:一是使用中斷的方式;二是使用輪循GPIO的電平狀態來做按鍵功能。這篇文章的重點在於介紹輪循的方式,因為第一種方式讓我吃了不少苦頭,現在我都一般不會採用它。
1 中斷方式
這是做按鍵功能的正統方式,做的時候一板一眼,上學讀書的時候也是這麼做的。分為以下幾個步驟:第一步,想使用哪個GPIO做按鍵,就使能相應GPIO的中斷,並設定相應的中斷方式,即電平或邊沿觸發;第二步,在中斷函式中,關中斷清中斷標誌並延時去抖,然後判斷電平狀態,如果無誤,則呼叫該按鍵的功能函式;第三步,開中斷,迎接下一步的中斷。
2 輪循GPIO電平狀態
這是我大比較喜歡的方式,當我一接觸到這種方式時,便將以前的程式碼全改成這種方式。甚至連其它的8051微控制器程式,我都這樣做。
2.1 優勢
這種方法相對第1種方式,佔據比較大的優勢。首先,它不會用程式延時,所以不會拖慢其他模組的功能;其次,程式設計相對簡單,只要邏輯層做起來,留出一個數據陣列給OEM層來使用,填一個數組總比寫程式失誤率要小得多;再者,有很多按鍵功能需要repeat,用中斷的方式沒法準確控制repeat的時間,而且延時得太多,用輪循的方式可以輕而易舉完美地做到這個功能(我自己加的)。
2.2 具體實現方式
我們來看一下OEM介面:
typedefvolatile struct _EVENT_DESCRIPTOR
{
BYTE PortPin; //使用的GPI
BYTE Bounce; // 去抖延時時間
}EVENT_DESCRIPTOR;
static constEVENT_DESCRIPTOR Events_Table[] =
{
{PWRBTN_IN, 10}, //PowerSwitch
{VOLUME_UP, 10}, //聲音加
{VOLUME_DOWN, 10}, //聲音減
};
簽了NDA,就要為別人保密。掃描按鍵的程式碼就不貼了,畫張流程圖吧。
流程圖:
2.3 加repeat功能
Vendor畢竟不是OEM,並不知道OEM廠商的具體需求,所以沒有加入repeat功能,但基於vendor的codebase,加repeat功能並不困難。
首先改變結構體如下:
typedefvolatile struct _EVENT_DESCRIPTOR
{
BYTE PortPin; //使用的GPI
BYTE Bounce; // 去抖延時時間
BYTE DelayToRepeat; //開始Repeat的時間
BYTE PeroidRepeat; //Repeat的間隔時間
}EVENT_DESCRIPTOR;
static constEVENT_DESCRIPTOR Events_Table[] =
{
{PWRBTN_IN, 10,0,0}, //PowerSwitch
{VOLUME_UP, 10,50,10}, //聲音加
{VOLUME_DOWN, 10,50,10}, //聲音減
};
然後再改變一下掃描按鍵的程式碼,需要加三部分:一,在按鍵電平狀態不一致時,除了儲存上一電平外,還要清除一下儲存DelayToRepeat和PeroidRepeat值的計數陣列;二,在去拌時間結束後,要判斷當前狀態是否為ACTIVE和是否需要Repeat功能,如果這兩條件滿足,則將DelayToRepeat賦值給計數陣列;三,計數陣列計數結束後,執行按鍵功能函式,並將PeroidRepeat值重新賦給計數陣列。