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引腳來實現多按鍵驅動。

主站蜘蛛池模板: www.av男人.com| 亚洲国产欧洲精品路线久久| 美女啪啪无遮挡| 国产乱视频网站| 精品国产成人av免费| 国产91蝌蚪窝| 久久黄色毛片| 亚洲国产成人精品一二区| 亚洲综合精品第一页| 免费在线成人网| 国产又粗又猛又爽| 国产亚洲欧美在线人成aaaa| 97人人模人人爽人人喊小说| 亚洲男人的天堂网| 91成人试看福利体验区| 国产国产人在线成免费视频狼人色| 任我操在线视频| 欧美第二区| 无码'专区第一页| 亚洲av无码片一区二区三区| 中文字幕亚洲另类天堂| 538国产视频| 亚洲婷婷在线视频| 久久久久久久久亚洲精品| 久久综合成人| 欧美日本在线| 久久网综合| 国产成人综合网| 免费视频在线2021入口| 国产综合欧美| 无码又爽又刺激的高潮视频| 亚洲视频欧美不卡| 香蕉色综合| 97国产在线视频| 欧美精品色视频| 露脸一二三区国语对白| 国产亚洲精品无码专| 高清久久精品亚洲日韩Av| 在线国产91| 亚洲乱码精品久久久久..| 欧美国产日韩另类| 蜜臀AV在线播放| 丁香综合在线| 久久综合色视频| 欧美特黄一免在线观看| 无码'专区第一页| 色播五月婷婷| 日韩在线永久免费播放| 四虎精品国产永久在线观看| 日本精品中文字幕在线不卡| 欧美a在线看| 久久中文字幕2021精品| 欧美a在线看| 国产成人综合久久精品尤物| 欧美成人精品高清在线下载| 一级全黄毛片| 欧美国产在线看| …亚洲 欧洲 另类 春色| av在线手机播放| 超清无码一区二区三区| 亚洲IV视频免费在线光看| 欧美日韩资源| 欧洲亚洲欧美国产日本高清| 四虎在线观看视频高清无码| 98精品全国免费观看视频| 婷婷色中文| 在线看免费无码av天堂的| 午夜天堂视频| 少妇高潮惨叫久久久久久| 伊人精品成人久久综合| 欧美一区二区三区国产精品| 国产一二三区在线| 最新亚洲人成网站在线观看| 亚洲精品在线影院| 好吊色妇女免费视频免费| 久久精品亚洲热综合一区二区| 福利片91| 波多野结衣一区二区三区AV| 亚洲精品免费网站| 波多野结衣无码视频在线观看| 69综合网| 免费中文字幕一级毛片|