久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 7273|回復: 1
打印 上一主題 下一主題
收起左側

Z-STACK中按鍵KEY驅動流程-修改到任意IO口

[復制鏈接]
跳轉到指定樓層
樓主
ID:71477 發表于 2015-1-1 19:19 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
-STACK按鍵的使用總結
#define HAL_KEY_SW_6_ENABLE
// SW_6IO端口
#define HAL_KEY_SW_6_PORT P0
//SW6接到IO端口的位數 P0.1
#define HAL_KEY_SW_6_BIT HAL_KEY_BIT1
// SW_6IO端口選擇
#define HAL_KEY_SW_6_SEL P0SEL
// SW_6IO端口方向
#define HAL_KEY_SW_6_DIR P0DIR
// SW_6IO端口中斷使能
#define HAL_KEY_SW_6_IEN IEN1
// SW_6IO端口中斷使能的掩碼
#define HAL_KEY_SW_6_IENBIT HAL_KEY_BIT5
// SW_6IO端口中斷的邊沿選擇
#define HAL_KEY_SW_6_EDGE HAL_KEY_RISING_EDGE
// SW_6IO端口邊沿掩碼
#define HAL_KEY_SW_6_EDGEBIT HAL_KEY_BIT0
// SW_6IO端口總中斷
#define HAL_KEY_SW_6_ICTL PICTL
// SW_6IO端口總中斷掩碼
#define HAL_KEY_SW_6_ICTLBIT HAL_KEY_BIT3
// SW_6IO端口中斷標志位
#define HAL_KEY_SW_6_PXIFG P0IFG
按鍵主要使用的是IO來設置的,這里需要設置的參數主要有按鍵設置在哪個端口以及掩碼、按鍵中斷使能標志以及掩碼、引起中斷的上升沿還是下降沿以及掩碼
涉及的主要寄存器有
PICTL端口輸入中斷控制


IEN1端口0總中斷使能
IEN2 端口12總中斷使能
比如需要設置HAL_KEY_SW_6P0.4為輸入下降沿有效中斷設置如下:
#define HAL_KEY_SW_6_ENABLE
#define HAL_KEY_SW_6_PORT P0
#define HAL_KEY_SW_6_BIT HAL_KEY_BIT4
#define HAL_KEY_SW_6_SEL P0SEL
#define HAL_KEY_SW_6_DIR P0DIR
#define HAL_KEY_SW_6_IEN IEN1
#define HAL_KEY_SW_6_IENBIT HAL_KEY_BIT5
#define HAL_KEY_SW_6_EDGE HAL_KEY_FALLING_EDGE
#define HAL_KEY_SW_6_EDGEBIT HAL_KEY_BIT0
#define HAL_KEY_SW_6_ICTL PICTL
#define HAL_KEY_SW_6_ICTLBIT HAL_KEY_BIT4
#define HAL_KEY_SW_6_PXIFG P0IFG
比如需要設置HAL_KEY_SW_6P2.1為輸入上升沿有效中斷設置如下:
#define HAL_KEY_SW_6_ENABLE
#define HAL_KEY_SW_6_PORT P2
#define HAL_KEY_SW_6_BIT HAL_KEY_BIT4
#define HAL_KEY_SW_6_SEL P2SEL
#define HAL_KEY_SW_6_DIR P2DIR
#define HAL_KEY_SW_6_IEN IEN2
#define HAL_KEY_SW_6_IENBIT HAL_KEY_BIT1
#define HAL_KEY_SW_6_EDGE HAL_KEY_RISING_EDGE
#define HAL_KEY_SW_6_EDGEBIT HAL_KEY_BIT2
#define HAL_KEY_SW_6_ICTL PICTL
#define HAL_KEY_SW_6_ICTLBIT HAL_KEY_BIT5
#define HAL_KEY_SW_6_PXIFG P2IFG
這樣設置后就可以正常使用KEY 中斷。
按鍵有兩種工作模式:輪詢(Poll)和中斷(Interrupt
輪詢
按鍵處理函數是HalKeyPoll (void),這個函數會在HAL的事件處理Hal_ProcessEvent()中的HAL_KEY_EVENT事件處理過程中被調用,輪詢周期由#define HAL_KEY_POLLING_VALUE 100這邊定義,通過在配置函數中設置軟件定時器osal_start_timerEx (Hal_TaskID, HAL_KEY_EVENT,HAL_KEY_POLLING_VALUE);來啟動定時器,
當溢出的時候向HAL發出HAL_KEY_EVENT事件。
在事件處理函數中會檢查當前是否使能中斷模式,如果使能的話就跳到中斷模式操作,否則重新啟動定時器,輪詢時間按100ms算。
HalKeyPoll()函數中會調用按鍵回調函數,根據按鍵狀態來處理按鍵信息。
中斷
對應處理函數是 halProcessKeyInterrupt (void)會在對應管腳的中斷處理函數中被調用。
根據配置函數的參數interruptEnable的情況來設置中斷或者輪詢。
中斷處理函數如下:
按鍵中斷處理函數:
當檢查到有按鍵按下則會啟動一個定時事件,定時長度有HAL_KEY_DEBOUNCE_VALUE定義。最終執行函數還是在HAL的事件處理函數中的HAL_KEY_EVENT中被執行。
區別
按鍵中斷和輪詢的主要區別是輪詢需要CPU定期的檢查按鍵狀態,當檢測到按鍵按下則發出HAL_KEY_EVENT消息到HAL層來執行處理,中斷則是當有按鍵按下立刻向HAL_KEY_EVENT發出消息,不需要CPU的檢查。輪詢的實時性比中斷要差點,推薦用中斷方式。
處理流程圖





  
Z-stack中對按鍵的處理
  
       在基于Z-stack的應用程序設計中,HAL(硬件抽象層)是這樣運行的:
void osalInitTasks( void )
{……
  Hal_Init( taskID++ );
……
}
        打開  Hal_Init( ),似乎什么也沒有做,只是完成了一件事情,給這個任務一個ID,實際上,對硬件的初始化的工作,在任務啟動之前都已經開始做了,任務的運行,只是可以接收發給它的事件和消息。
       那么,在HAL任務運行之前,系統對任務做了些什么呢?
       當然是初始化。在ZMain.c文件中,有main函數,這是所有程序的入口。由于硬件是所有程序運行的基礎,在這里要完成兩個重要的函數:
  // Initialize board I/O
  InitBoard( OB_COLD );
  // Initialze HAL drivers
  HalDriverInit();
        顯然,它們的執行時間是早于任務的運行,在InitBoard()完成對板級I/O的設置。進去看一下:
void InitBoard( byte level )
{
  if ( level == OB_COLD )
  {
    // Interrupts off
    osal_int_disable( INTS_ALL );
  }
  else  // !OB_COLD
  {
    OnboardKeyIntEnable = HAL_KEY_INTERRUPT_DISABLE;
    HalKeyConfig( OnboardKeyIntEnable, OnBoard_KeyCallback);
  }
}
         代碼太多,不再全部列出,主要是完成對LedTimerkey的配置。這里重點看按鍵有關的。由于InitBoard函數的參數是OB_COLD,郁悶的HalKeyConfig()沒有機會運行。
         在經過耐心的等待之后,main()需要再次對開發板初始化,調用函數:
        InitBoard( OB_READY );
         機會來了,這時可以處理按鍵了,
HalKeyConfig( OnboardKeyIntEnable, OnBoard_KeyCallback)函數可以運行,在該函數中定義了是以中斷的方式還是以查詢的方式檢測按鍵的狀態,如果是查詢方式,使用:
osal_start_timerEx (Hal_TaskID, HAL_KEY_EVENT, HAL_KEY_POLLING_VALUE);
        延遲100ms后向任務Hal_TaskID發送一個事件。在事件處理代碼中使用函數
HalKeyPoll()查詢是否有按鍵按下。
       如果是中斷方式,使用
osal_start_timerEx (Hal_TaskID, HAL_KEY_EVENT, HAL_KEY_DEBOUNCE_VALUE);
       延遲25ms后使用函數HalKeyPoll()獲取按鍵值。



安裝IAR 8051 7.30B
運行安裝程序EW8051-EV-730B.exe,這里說一下如何快速的查找代碼,按下Ctrl+Shift+f 可以在整個項目中查找你想要的關鍵字,注意選擇和你workspace工作空間對應的文件,通常有CC2430DBCC2430EB兩個。把光標放在函數名上,右鍵
選擇Go to definition fo XX就可以跳到該函數定義處,工具欄的Navigate Backward Navigate Forward 可以讓你來回穿梭,還有很多功能,這里不多說了。
安裝ZigBee2006
下載Zigbee協議棧壓縮包swrc073d.zip,安裝后一般在C盤可以找到Texas Instruments文件夾,把它復制,考到D盤,我的IAR裝在D盤,有必要看下Documents里面的文檔,如Create New Application For The CC2430DB_F8W-2005-0033_.pdf如何新建項目;其它的就不多說了,下面是按鍵的簡單說明,可以初步了解一下OSAL;例子目錄為:
Texas
Instruments\ZStack-1.4.3-1.2.1\Projects\zstack\Samples\SimpleApp\CC2430DB
Workspace 選擇 simplecollectorEB ;
我們先從主函數說起,如果不知主函數在哪,可以Ctrl+Shift+f輸入int main查找,...........為省略
ZSEG int main( void )
{
// Turn off interrupts
osal_int_disable( INTS_ALL );
………………..
// Initialze HAL drivers
HalDriverInit(); //HalKeyInit();初始化按鍵
………………..
// Determine the extended address
zmain_ext_addr(); //HalKeyRead();讀取按鍵
…………………..
osal_init_system(); //RegisterForKeys( sapi_TaskID ); 注冊按鍵任務
//或許你的協議棧注冊按鍵不在這里面。那就是在應用層任務初始化里面
……………………..
// Final board initialization
InitBoard( OB_READY ); /*HalKeyConfig( OnboardKeyIntEnable, OnBoard_KeyCallback);配置
按鍵,默認為輪詢方式*/
…………………
osal_start_system(); // No Return from here 進入系統大循環
} // main()
從主函數可以看出,里面都是初始化函數init,執行過程HalDriverInit()àHalKeyInit();HalKeyInit()里基本完成了相應管腳的輸入輸出配置,然后到zmain_ext_addr();時,判斷物理擴展地址是否合法,如果不合法,則LED1一直閃爍,等while ( HAL_KEY_SW_5 != HalKeyRead() )按下把無效的地址初始化為有效地物理地址,然后到
osal_init_system();àosalInitTasks();
SAPI_Init( taskID );
RegisterForKeys( sapi_TaskID );注冊按鍵事件,
//注意:可能你的協議棧注冊按鍵不在這里,而在應用層任務初始化里面。你的協議棧可能也沒有SAPI_Init( taskID );
最后InitBoard( OB_READY );
HalKeyConfig( OnboardKeyIntEnable, OnBoard_KeyCallback);配置按鍵為中斷方式還是輪詢方式,從
/* Initialize Key stuff */
OnboardKeyIntEnable = HAL_KEY_INTERRUPT_DISABLE;
HalKeyConfig( OnboardKeyIntEnable, OnBoard_KeyCallback);
可以看出默認是配置為輪詢方式的,這就是主函數大致對按鍵的處理過程,接下來從HalKeyConfig()入手,
void HalKeyConfig (bool interruptEnable, halKeyCBack_t cback)
{
#if (HAL_KEY == TRUE)
/* Enable/Disable Interrupt or */
Hal_KeyIntEnable = interruptEnable;
/* Register the callback fucntion */
pHalKeyProcessFunction = cback; //指向回調函數
/* Determine if interrupt is enable or not */
if (Hal_KeyIntEnable) //如果設為中斷方式
{
………………..進行一些中斷的相關配置
}
else /* Interrupts NOT enabled */ //否則為輪詢方式
{
…………………….
osal_start_timerEx (Hal_TaskID, HAL_KEY_EVENT, HAL_KEY_POLLING_VALUE); /* Kick off polling */
}
……………………..
}
可以看出,配置為輪詢方式是時啟動osal_start_timerEx()函數,那么這個函數是干什么的呢?這個是系統軟定時器,在HAL_KEY_POLLING_VALUE時間(100ms)內會觸發系統任務事件,也就是觸發uint16 Hal_ProcessEvent( uint8 task_id, uint16 events );觸發時會把Hal_TaskIDHAL_KEY_EVENT兩個參數傳給Hal_ProcessEvent();然后看看Hal_ProcessEvent()里面又做了些什么事,
uint16 Hal_ProcessEvent( uint8 task_id, uint16 events )
{
uint8 *msgPtr;
……………………….
if (events & HAL_KEY_EVENT) //按鍵處理
{
#if (defined HAL_KEY) && (HAL_KEY == TRUE)
/* Check for keys */
HalKeyPoll(); //查看是哪個鍵
/* if interrupt disabled, do next polling */
if (!Hal_KeyIntEnable) //如果還是輪詢方式,則再次啟動osal_start_timerEx();
{
osal_start_timerEx( Hal_TaskID, HAL_KEY_EVENT, 100);
}
#endif // HAL_KEY
return events ^ HAL_KEY_EVENT;
}
……………………..
}
函數里面執行完HalKeyPoll();后,如果還是輪詢方式,則再一次啟動osal_start_timerEx();如此一來,就會每隔100ms循環進入Hal_ProcessEvent()函數讀取按鍵,也就是說系統每隔100ms掃描一次按鍵,那么HalKeyPoll()又是干什么的呢?我們繼續看看,
void HalKeyPoll (void)
{
………………
#if defined (HAL_KEY_SW_6_ENABLE)
if (!(HAL_KEY_SW_6_PORT & HAL_KEY_SW_6_BIT)) /* Key is active low */
{
keys |= HAL_KEY_SW_6;
}
#endif
#if defined (HAL_KEY_SW_5_ENABLE)
if (HAL_KEY_SW_5_PORT & HAL_KEY_SW_5_BIT) /* Key is active high */
{
keys |= HAL_KEY_SW_5;
}
#endif
………….. 調用HalAdcRead()得出操縱桿的值,是通過AD進來了模擬電壓值得出;
/* Invoke Callback if new keys were depressed */
if (keys && (pHalKeyProcessFunction))
{
(pHalKeyProcessFunction) (keys, HAL_KEY_STATE_NORMAL); //回調函數
}
}
該函數讀出按鍵值keys,并執行了回調函數(pHalKeyProcessFunction) (keys, HAL_KEY_STATE_NORMAL); pHalKeyProcessFunction是在
void HalKeyConfig (bool interruptEnable, halKeyCBack_t cback)里面pHalKeyProcessFunction = cback;進行賦函數指針的,這樣我們就進入回調函數了,我們來看一下回調函數:
void OnBoard_KeyCallback ( uint8 keys, uint8 state ) //回調函數
{
uint8 shift;
// shift key (S1) is used to generate key interrupt
// applications should not use S1 when key interrupt is enabled
shift = (OnboardKeyIntEnable == HAL_KEY_INTERRUPT_ENABLE) ? false : ((keys & HAL_KEY_SW_6) ? true : false);
if ( OnBoard_SendKeys( keys, shift ) != ZSuccess )//ZFailure,如果不成功則執行下面
{
// Process SW1 here
if ( keys & HAL_KEY_SW_1 ) // Switch 1
{
}
…………………
}
回調函數里面又調用了OnBoard_SendKeys( keys, shift );接著看
byte OnBoard_SendKeys( byte keys, byte state )
{
keyChange_t *msgPtr;
if ( registeredKeysTaskID != NO_TASK_ID )//之前是否RegisterForKeys( sapi_TaskID );注冊過?
{
// Send the address to the task
msgPtr = (keyChange_t *)osal_msg_allocate( sizeof(keyChange_t) );
if ( msgPtr )
{
msgPtr->hdr.event = KEY_CHANGE;
msgPtr->state = state;
msgPtr->keys = keys;
osal_msg_send( registeredKeysTaskID, (uint8 *)msgPtr );
}
return ( ZSuccess );
}
else
return ( ZFailure );
}
如果之前注冊過按鍵事件,那么就會調用osal_msg_send( registeredKeysTaskID, (uint8 *)msgPtr );發送系統消息,它又會調用
osal_set_event(registeredKeysTaskID, SYS_EVENT_MSG );設置事件發生標志,
byte osal_set_event( byte task_id, UINT16 event_flag )
{
if ( task_id < tasksCnt )
{
halIntState_t intState;
HAL_ENTER_CRITICAL_SECTION(intState); // Hold off interrupts
tasksEvents[task_id] |= event_flag; // Stuff the event bit(s) 置任務標志,
HAL_EXIT_CRITICAL_SECTION(intState); // Release interrupts
}
else
return ( INVALID_TASK );
return ( ZSUCCESS );
}
然后觸發SAPI_ProcessEvent()應用層處理事件,SAPI_ProcessEvent()再調用zb_HandleKeys()函數進行最終的按鍵處理事件:
void zb_HandleKeys( uint8 shift, uint8 keys )
{
uint8 startOptions;
uint8 logicalType;
if ( keys & HAL_KEY_SW_5 )//我自己加的sw5按鍵處理
{
P1_0=~P1_0;
}
…………..
}
經過了層層函數,最終到達了zb_HandleKeys()按鍵處理函數,其中的各種函數關系我們應該理清,這樣對整個系統的OSAL編程有一定的了解,其中按鍵有兩種處理方式,輪詢和中斷方式,系統默認為輪詢方式,
下面再看一下中斷方式的過程:
如果修改InitBoard( OB_READY )里的
OnboardKeyIntEnable = HAL_KEY_INTERRUPT_ ENABLE;//HAL_KEY_INTERRUPT_DISABLE
HalKeyConfig( OnboardKeyIntEnable, OnBoard_KeyCallback);
那么會把按鍵配置為中斷方式,具體可看上面提到的HalKeyConfig()函數;此時如有按鍵按下,則會進入中斷服務函數:
HAL_ISR_FUNCTION( halKeyPort0Isr, P0INT_VECTOR )
{
/* P0IF is cleared by HW for CHVER < REV_E */
halProcessKeyInterrupt(); //按鍵的中斷處理
if( CHVER >= REV_E )
{
……………………
}
}
在中斷函數中會執行halProcessKeyInterrupt()函數,我們看看
void halProcessKeyInterrupt (void)
{
#if (HAL_KEY == TRUE)
bool valid=FALSE;
#if defined (HAL_KEY_SW_6_ENABLE)
if (HAL_KEY_SW_6_PXIFG & HAL_KEY_SW_6_BIT) /* Interrupt Flag has been set */
{
HAL_KEY_SW_6_PXIFG = ~(HAL_KEY_SW_6_BIT); /* Clear Interrupt Flag */
valid = TRUE;
}
#endif
#if defined (HAL_KEY_SW_5_ENABLE)
if (HAL_KEY_SW_5_PXIFG & HAL_KEY_SW_5_BIT) /* Interrupt Flag has been set */
{
HAL_KEY_SW_5_PXIFG = ~(HAL_KEY_SW_5_BIT); /* Clear Interrupt Flag */
valid = TRUE;
}
#endif
if (valid)
{
osal_start_timerEx (Hal_TaskID, HAL_KEY_EVENT, HAL_KEY_DEBOUNCE_VALUE);//25ms
}
#endif /* HAL_KEY */
}
我們終于發現了osal_start_timerEx()函數,在HAL_KEY_DEBOUNCE_VALUE時間(25ms)后再次觸發,用于按鍵去抖,然后osal_start_timerEx()會觸發Hal_ProcessEvent()函數,這樣就和輪詢方式的后半部分是一樣的,也就是說中斷法和輪詢法在前面的不同,一旦遇到Hal_ProcessEvent(),那么后面的也就一樣了,這就是整個按鍵的處理過程.


分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復

使用道具 舉報

沙發
ID:724764 發表于 2020-4-8 14:12 | 只看該作者
干貨,get
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 在线中文字幕视频 | 久久精品国产亚洲 | 欧美精品一区二区三区在线 | 久久人人网 | 欧美日韩久久精品 | 成人精品国产免费网站 | 99精品一区二区三区 | 爱爱视频在线观看 | 成人蜜桃av | 在线观看国产精品视频 | 91欧美激情一区二区三区成人 | 欧美激情在线精品一区二区三区 | 成人黄色电影在线观看 | 性高湖久久久久久久久3小时 | 日本久久久久久 | 国内精品伊人久久久久网站 | 欧美乱人伦视频 | 成人免费视频网站在线看 | 欧美日韩不卡 | 国产男女猛烈无遮掩视频免费网站 | 亚洲视频一区在线 | 久久久久久久久国产成人免费 | 久久久高清 | av在线天天| 成人av一区 | 91.xxx.高清在线 | 黑人巨大精品欧美黑白配亚洲 | 免费黄网站在线观看 | 视频二区在线观看 | 日韩在线免费 | 视频一区二区中文字幕 | 国产不卡在线播放 | 成人午夜激情 | 天天操夜夜骑 | 黄视频在线网站 | 久草在线在线精品观看 | 男女国产视频 | 成人午夜免费网站 | 日韩av免费在线电影 | 国产免费xxx | 欧美日韩在线一区 |