999精品在线视频,手机成人午夜在线视频,久久不卡国产精品无码,中日无码在线观看,成人av手机在线观看,日韩精品亚洲一区中文字幕,亚洲av无码人妻,四虎国产在线观看 ?

Z-Stack協議棧的按鍵驅動機制分析*

2018-07-11 07:51:32
單片機與嵌入式系統應用 2018年7期

(河南城建學院 計算機與數據科學學院,平頂山 467036)

引 言

當前在實現ZigBee Pro標準組成的WSN無線傳感網技術方案中,有TI公司的CC2530+Z-Stack方案,也有ST公司的STM32W108+EmberZnet方案。TI公司的CC2530是基于8051內核,其Z-Stack協議棧被廣泛應用在ZigBee通信設備中,研究其工作原理有著重要意義。

1 Z-Stack協議棧簡介

Z-Stack是一款業界領先的商業級協議棧,它把底層(尤其是MAC層)做成lib庫文件封裝起來(不開源),供其它層調用[1]。其中,HAL硬件抽象層、MAC層位于最底層,與硬件相關;NWK網絡層、OSAL操作系統抽象層、APS應用支持子層、AF應用框架層、ZDO ZigBee設備對象以及安全層建立在HAL和MAC層之上,并且完全與硬件無關;整個協議棧的最頂層就是用戶的應用程序層APP。HAL提供各種硬件模塊的驅動,包括定時器Timer、通用I/O口、UART、ADC等應用程序接口API,提供各種服務的擴展集。Z-Stack協議棧基于事件驅動和消息傳遞的機制,協議棧中的每一層都設計了一個事件處理函數,用來處理與這一層操作相關的各種事件,將這些事件處理函數看成是與協議棧每一層相對應的任務,由ZigBee協議棧中OSAL來進行調度管理,這樣不管何時發生了何種事件,都可以通過調度協議棧相應層的事件處理函數/任務來進行處理[2]。

圖1示例解釋了Z-Stack協議棧中main()函數和osal_run_system()函數主循環的執行流程。

圖1 Z-Stack協議棧整體流程

2 Z-Stack協議棧的按鍵定義和配置

Z-Stack中總共定義了7個按鍵,其中SW1~SW5屬于Joystick的UP上、RT右、DN下、LT左、PUSH/CENTER中間5個按鍵,SW6和SW7屬于2個獨立的按鍵開關,當SW6按下時,相應P0.1引腳為低電平,彈起時靠上拉電阻處于高電平。在Z-Stack源代碼HALinclude目錄下的文件hal_key.h和hal_key.c中有按鍵的定義。Joystick按鍵對應于圖2中的S3按鍵,通過組合邏輯SN74HC32D芯片輸出JOYSTICK_INT信號給P2.0引腳,通過其電平從低到高的變化來判斷按鍵是否按下;同時將各個按鍵按下時的不同電位通過同相比例放大器輸出按鍵信號JOYSTICK_ADC輸入給ADC,經過ADC轉換之后獲取不同的按鍵值,以此判斷Joystick具體是哪個按鍵按下的動作。Joystick按鍵原理圖下半部分如圖3所示。

圖2 Joystick按鍵原理圖上半部

圖3 Joystick按鍵原理圖下半部

Z-Stack源代碼的hal_key.h中定義了按鍵的鍵值,hal_key.c中定義各個按鍵對應的I/O引腳、終端觸發的方式、Joystick按鍵對應的ADC通道等相關寄存器信息。

根據Z-Stack協議棧工作流程,main()函數調用HalDriverInit()函數進行硬件驅動的初始化,HalDriverInit()函數調用HalKeyInit()進行按鍵初始化,其中定義了全局變量HalKeyConfigured,用來作為按鍵是否已配置的標志,其初始化為FALSE。

在main()函數執行第二次InitBoard()函數,也就是板子的最終初始化時,傳入的參數為OB_READY,因此調用HalKeyConfig()函數來進行按鍵的配置。

void InitBoard( uint8 level ){

if ( level == OB_COLD ){

……

}

else// !OB_COLD{

/*調用HalKeyConfig函數對按鍵進行配置*/

HalKeyConfig(HAL_KEY_INTERRUPT_DISABLE, OnBoard_KeyCallback);

}

}

按鍵配置函數HalKeyConfig的定義如下:

void HalKeyConfig (bool interruptEnable, halKeyCBack_t cback){

/*通過傳入的參數interruptEnable決定是否采用中斷的方式*/

Hal_KeyIntEnable = interruptEnable;

/*通過傳入的參數cback來注冊按鍵處理回調函數指針pHalKeyProcessFunction*/

pHalKeyProcessFunction = cback;

/*如果采用按鍵中斷的方式*/

if (Hal_KeyIntEnable)

{/*SW_6鍵(P0.1引腳) 上升沿或者下降沿觸發中斷的配置*/

……

/*Joystick鍵 判斷按鍵是否動作(P2.0引腳) 上升沿或者下降沿觸發中斷的配置*/

HAL_KEY_JOY_MOVE_ICTL &=~(HAL_KEY_JOY_MOVE_EDGEBIT);

/* Clear the edge bit */

……

}

else/*沒有采用中斷方式,也就是按鍵輪詢方式*/

{/*SW_6鍵禁止中斷*/

……

osal_set_event(Hal_TaskID, HAL_KEY_EVENT);

/*產生HAL_KEY_EVENT事件*/

}

HalKeyConfigured = TRUE;

/*HalKeyConfigured變量最終配置為TRUE*/

}

可以看出,HalKeyConfig函數針對按鍵采用輪詢方式或者中斷方式進行了兩種配置,并且對按鍵處理回調函數指針pHalKeyProcessFunction進行賦值,指定相應的回調處理函數,最終HalKeyConfig全局變量設置為TRUE,代表按鍵配置完畢。在按鍵輪詢的方式中,調用了osal_set_event(Hal_TaskID, HAL_KEY_EVENT)函數,產生HAL_KEY_EVENT事件,交給HAL層去處理。

3 Z-Stack協議棧的按鍵驅動機制

Z-Stack中提供了兩種方式采集按鍵數據:輪詢方式和中斷方式。

在輪詢方式中,每隔一定時間(默認周期為100 ms)產生定時事件HAL_KEY_EVENT,OSAL調用HAL層的Hal_ProcessEvent()函數處理該事件,然后調用HalKeyPoll()函數來檢測按鍵狀態,如果按鍵有變化,則交給pHalKeyProcessFunction()回調函數進行相應的處理。

uint16 Hal_ProcessEvent(uint8 task_id, uint16 events){

……

if (events & HAL_KEY_EVENT){

#if (defined HAL_KEY) && (HAL_KEY == TRUE)

HalKeyPoll();/*按鍵檢測狀態函數*/

/*如果是按鍵輪詢方式,則通過定時器觸發HAL_KEY_EVENT事件來進行下一輪輪詢*/

if (!Hal_KeyIntEnable){/*100ms定時周期發送HAL_KEY_EVENT事件*/

osal_start_timerEx(Hal_TaskID,HAL_KEY_EVENT,100);

}

#endif // HAL_KEY

return events ^ HAL_KEY_EVENT;

}

……

}

函數HalKeyPoll()的定義如下:

void HalKeyPoll (void){

uint8 keys = 0;/*keys用來儲存鍵值*/

/*Joystick的P2.0引腳電平是高電平,表明Joystick有按鍵按下*/

if ((HAL_KEY_JOY_MOVE_PORT & HAL_KEY_JOY_MOVE_BIT)){

/*通過halGetJoyKeyInput函數返回Joystick按鍵鍵值*/

keys = halGetJoyKeyInput();

}

/*如果是按鍵輪詢方式,通過當前按鍵狀態與之前的狀態進行比較來判斷是否有按鍵按下*/

if (!Hal_KeyIntEnable){

if (keys == halKeySavedKeys){

/*如果當前按鍵狀態沒有變化,直接返回退出*/

return;

}

halKeySavedKeys = keys;

/*存儲當前的按鍵值用于下一次的比較*/

}

……

/*通過P0.1引腳電平的高低來設置keys鍵值*/

if (HAL_PUSH_BUTTON1()){/*等價于if(P0_1) */

keys |= HAL_KEY_SW_6;

}

/*如果有按鍵按下,調用按鍵的回調函數處理按鍵事務*/

if (keys && (pHalKeyProcessFunction)){

(pHalKeyProcessFunction) (keys, HAL_KEY_STATE_NORMAL);

}

}

在中斷方式中,按鍵觸發按鍵中斷,在按鍵中斷ISR中調用halProcessKeyInterrupt()函數,其通過延遲定時25 ms(按鍵消抖)后,產生按鍵HAL_KEY_EVENT事件,交給HAL層的Hal_ProcessEvent()函數進行相應處理,后續流程同輪詢方式。

4 Joystick按鍵的工作原理

通過上面的分析,可以看出不論是輪詢方式還是中斷方式,均通過HalKeyPoll()函數來判定按鍵狀態的變化,其中Joystick依靠halGetJoyKeyInput()函數來獲取鍵值。在分析該函數之前,先來看看Joystick按鍵工作的原理。

由圖2可知,SN74HC32D是1個4組2輸入1輸出的或門,由其硬件電路可以推導出組合邏輯表達式:

JOYSTICK_INT=3Y=3A+3B=PUSH+4Y=

PUSH+4A+4B=PUSH+2Y+1Y=

PUSH+2A+2B+1A+1B=

PUSH+LT+RT+UP+DN

這意味著,JOYSTICK_INT(P2.0引腳)是Joystick的SW1~SW5這5個按鍵狀態的邏輯或,只要有任意1個按鍵按下(Joystick按鍵的機械結構決定了5個鍵中只能有1個按下,不可能有多個按鍵同時按下),那么P2.0引腳上就是高電平;否則當5個按鍵都不按下,P2.0引腳為低電平;反過來,如果P2.0引腳上是高電平,只知道這5個鍵中有某個鍵被按下,但不知道是具體哪一個。

具體按鍵的判斷是通過ADC轉換器獲取不同鍵值來判定的。當UP鍵按下時,圖3可以等效為圖4。

圖4 UP鍵按下時的等效電路

R//=(R16+R27)//(R11+R29+R30)//(R17+R36+R37)=300k//500k//764k=150.55k,由理想運放的“虛斷”可知,U1的同相輸入端電位:

由理想運放的“虛短”可知,U1的反向輸入端電位:

V-=V+=1.03125V

對于U1的反向輸入端節點,由基爾霍夫節點電流定律可知:

對于運放U2,構成了一個同相比例放大電路,其電壓增益為:

因此,U2輸出端JOYSTICK_ADC電位是:

JOYSTICK_ADC=Vout1×Av=

0.2394V×1.42553=0.3413V

這表明,當UP鍵按下時,通過2個運放放大之后,JOYSTICK_ADC電位是0.341 3 V。

同理,可以依次計算,當DN、LT、RT、CENTER鍵按下時,不同的JOYSTICK_ADC電位值,由于Z-Stack協議棧中,對Joystick按鍵的ADC采用8位有效數字(最高位0代表正),參考電壓為3.3 V,那么經過A/D轉換之后的值,如表1所列。

在之前的按鍵代碼分析中提到,HalKeyPoll()函數用來判定按鍵狀態的變化,其中Joystick依靠halGetJoyKeyInput()函數來獲取鍵值,halGetJoyKeyInput()函數的代碼如下,可以看到與表1的理論計算結果完美對應。

表1 理論上Joystick按鍵對應的電位值和A/D轉換值

uint8 halGetJoyKeyInput(void){

……

/*讀取Joystick按鍵ADC直到兩次連續ADC值相同(穩定)為止*/

adc = HalAdcRead (HAL_KEY_JOY_CHN, HAL_ADC_RESOLUTION_8);//ADC 8位有效數字

if ((adc >= 2) && (adc <= 38)){ // UP/13

ksave0 |= HAL_KEY_UP;

}

else if ((adc >= 74) && (adc <= 88)){ // RT/77

ksave0 |= HAL_KEY_RIGHT;

}

else if ((adc >= 60) && (adc <= 73)){// LT/68

ksave0 |= HAL_KEY_LEFT;

}

else if ((adc >= 39) && (adc <= 59)){// DN/49

ksave0 |= HAL_KEY_DOWN;

}

else if ((adc >= 89) && (adc <= 100)){// CENTER/90

ksave0 |= HAL_KEY_CENTER;

}

……

}

5 Z-Stack協議棧的按鍵事件處理

在按鍵狀態檢測函數HalKeyPoll()中,如果發現按鍵狀態有變化,就會通過 (pHalKeyProcessFunction) (keys,HAL_KEY_STATE_NORMAL)來實現對按鍵事務回調函數OnBoard_KeyCallback()的調用。OnBoard_KeyCallback()函數又通過調用OnBoard_SendKeys(keys,shift),將按鍵值和按鍵狀態打包成KEY_CHANGE事件,發送到RegisterForKeys()函數注冊層,交給該層進行按鍵事務的處理。

在TI官方SampleApp項目例程中,SampleApp應用層的任務初始化函數SampleApp_Init()通過RegisterForKeys(SampleApp_TaskID)把按鍵的最終處理交給應用層。一旦有按鍵KEY_CHANGE事件,就會觸發應用層的事件處理函數SampleApp_ProcessEvent()來進行按鍵處理,如下所示:

uint16 SampleApp_ProcessEvent(uint8 task_id, uint16 events){

……

switch (MSGpkt->hdr.event){ //判斷消息包頭的事件是否是KEY_CHANGE

case KEY_CHANGE:

//應用層處理按鍵事務,交給SampleApp_HandleKeys函數,可根據不同的鍵值做相應處理

SampleApp_HandleKeys(((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys);

break;

……

}

……

}

結 語

簡單來說,Z-Stack中提供了兩種按鍵機制:輪詢方式和中斷方式,在HalKeyConfig()函數中按兩種機制分別進行按鍵配置。兩者均調用HalKeyPoll()函數來檢測按鍵狀態,如果按鍵有變化,則交給回調函數處理,同時回調函數會向RegisterForKeys()函數注冊層(一般是應用層APP)發送事件KEY_CHANGE,最終交給該層的事件處理函數APP_ProcessEvent()集中處理[1,3]。

需要注意的地方總結一下:①按鍵默認為輪詢的方式,如果想修改按鍵為中斷方式,則需要將OnBoard.c中的函數void InitBoard()中的語句修改為HalKeyConfig(HAL_KEY_INTERRUPT_ENABLE,OnBoard_KeyCallback);②Joystick通過或門器件實現了多個按鍵的按下判斷,并通過獲取ADC按鍵值來判定具體哪個按鍵被按下,通過這種方式,多按鍵的時候可以通過ADC外加2個I/O引腳來實現多按鍵驅動。

主站蜘蛛池模板: 亚洲,国产,日韩,综合一区| 久久精品只有这里有| 在线观看精品国产入口| 丁香婷婷激情网| 制服丝袜一区| 国产亚洲精品资源在线26u| 中文字幕无码电影| 国产波多野结衣中文在线播放 | 在线免费不卡视频| 国产91视频观看| 精品国产成人a在线观看| 国产黄色免费看| 国产在线精品99一区不卡| 狠狠五月天中文字幕| 欧洲成人免费视频| 国产一级做美女做受视频| 亚洲男人的天堂久久香蕉| 这里只有精品在线| 国产二级毛片| 99久久国产自偷自偷免费一区| 97人妻精品专区久久久久| 久久天天躁狠狠躁夜夜2020一| 国产精品自在在线午夜| 亚洲狠狠婷婷综合久久久久| 国产精品浪潮Av| 国产精品夜夜嗨视频免费视频| 国产综合精品一区二区| 免费中文字幕在在线不卡| 三上悠亚精品二区在线观看| 特级做a爰片毛片免费69| 在线免费观看a视频| 99久久性生片| 国产精品亚洲片在线va| 国产亚洲精品91| 亚洲第一国产综合| 国产毛片不卡| 国产成本人片免费a∨短片| 日韩不卡免费视频| 亚洲视频在线青青| 特级毛片8级毛片免费观看| 极品av一区二区| 成人免费黄色小视频| 77777亚洲午夜久久多人| 成人午夜在线播放| 国产簧片免费在线播放| 大陆国产精品视频| 免费看av在线网站网址| 亚洲一区二区约美女探花| 中文国产成人精品久久一| 无码又爽又刺激的高潮视频| 国产亚洲精品自在久久不卡| 亚洲第一中文字幕| 91国内在线观看| 人妖无码第一页| 国产精品视频第一专区| 无码aⅴ精品一区二区三区| 666精品国产精品亚洲| 亚洲国产成熟视频在线多多| 噜噜噜久久| 老司机久久精品视频| 精品国产免费观看| 免费观看亚洲人成网站| 狠狠v日韩v欧美v| a级毛片免费看| 国产精品观看视频免费完整版| 国产美女无遮挡免费视频| 亚洲国产成人精品无码区性色| 久久永久视频| 亚洲欧美在线综合一区二区三区 | 麻豆精品在线视频| 高清免费毛片| 三级国产在线观看| 波多野结衣中文字幕久久| 91成人精品视频| 内射人妻无码色AV天堂| jizz在线免费播放| 在线无码九区| 亚洲欧美不卡| 中文字幕欧美日韩高清| 国产制服丝袜91在线| 亚洲全网成人资源在线观看| 国产女人18毛片水真多1|