ZigBee2006 CC2430 按键流程

本文是我在寻找zstack一些问题的解决方案中无意发现,该文对于zstack任务流程的分析十分透彻,十分值得参照和收藏,所以将其转载过来。以下开始为转载的全部原文:

很久没写过日志了,一转眼已过了好几过月,再过都几周就得领毕业证了,也就结束了校园生活,这段时间发生了很多事,一直没空写下来,其实说没空,那只是借口,只能说自己赖,最近在做个项目,用到CC2430,从网上搜索了很多别人的资料,从中得到了很多帮助,现在自己也总结一下写出来,希望对有需要的人有用,同时我自已日后忘记了也能看看。

安装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 );注册按键事件,最后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(),那么后面的也就一样了,这就是整个按键的处理过程,下面是我画的流程图,呵呵,很丑:

ZigBee2006 CC2430 按键流程 - 三贱客*龙 - 三贱客*龙的博客


原文地址:http://zhilong2382.blog.163.com/blog/static/7480422120104291112517/

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值