CC2430中的 Key中断程序

CC2430中的 Key中断程序

写在前面

这篇文章是关于TICC2430芯片中按键中断的详细说明,是我自己在看ZStack代码后的总结,按键中断涉及到的所有文件以及程序,我都给了一个比较详细的说明。

对于刚接触ZStack代码的人,通过对这个中断的编程可以对基于OSAL的编程有一定的了解,包括任务的初始化,消息的传递,等等。希望通过这篇文章对你使用ZStack有一定的帮助。

 

1.       OSAL中的一些基本概念和函数

操作系统相当于一个大的执行机构,所有任务通过规定方式加入以后,操作系统先分给每个任务一个ID,然后运行任务,类似于大循环工作,任务之间通过传递消息和事件的方式通信、其他操作。

一般情况下一个任务都是处于未执行状态,只有当接收到消息或则事件,相应标志位被置位后才进入运行状态。

 

1.1下面将介绍一下常用操作系统函数:

void osalTaskAdd( const pTaskInitFn pfnInit,

const pTaskEventHandlerFn pfnEventProcessor,

const byte taskPriority);

该函数将一个任务加入,由操作系统自动分配TASK_ID

这里有两个参数pfnInitpfnEventProcessor,分别该任务的初始化函数和处理函数。

这样这个任务就加入到任务列表中了。

 

举例:在sampple例子中,有如下代码:

void osalAddTasks( void )

{

/* This task must be loaded first because Hal_Init() initializes

   many things that other task_init functions may need.

*/

  osalTaskAdd( Hal_Init, Hal_ProcessEvent, OSAL_TASK_PRIORITY_LOW );

 

#if defined( ZMAC_F8W )

  osalTaskAdd( macTaskInit, macEventLoop, OSAL_TASK_PRIORITY_HIGH );

#endif

 

#if defined( MT_TASK )

  osalTaskAdd( MT_TaskInit, MT_ProcessEvent, OSAL_TASK_PRIORITY_LOW );

#endif

 

  osalTaskAdd( nwk_init, nwk_event_loop, OSAL_TASK_PRIORITY_MED );

  osalTaskAdd( APS_Init, APS_event_loop, OSAL_TASK_PRIORITY_LOW );

  osalTaskAdd( ZDApp_Init, ZDApp_event_loop, OSAL_TASK_PRIORITY_LOW );

 

  osalTaskAdd( SampleApp_Init, SampleApp_ProcessEvent, OSAL_TASK_PRIORITY_LOW );

}

该代码将一批任务加入到了任务列表中,每个任务都有自己的初始化函数和处理函数。

 

1.2下面讲任务之间传递事件的一个函数:

byte osal_set_event( byte task_id, UINT16 event_flag )

该函数把事件event_flag(这个事件是一个标志位)传递给了task_id所指示的一个任务。表明该任务所需要的事件发生了。

 

1.3下面一个是消息传递行数

byte osal_msg_send( byte destination_task, byte *msg_ptr )

该函数把消息msg_ptr(这个消息是一个数据包)传递给了task_id所指示的一个任务。表明把数据包传递给该任务,这个数据包里一般情况下也携带了事件标志event_flag

 

其他的函数将在具体运用的时候介绍,其实看TI的文档都是比较好理解的。

 

 

2.       按键中断所需要的硬件的初始化

OSAL任务初始化里有这样一个语句:

void osalAddTasks( void )

{

  osalTaskAdd (Hal_Init, Hal_ProcessEvent, OSAL_TASK_PRIORITY_LOW);

...........

将硬件处理作为系统的一个任务这里有两个函数:

第一个(硬件初始化函数):

void Hal_Init( uint8 task_id )

{

  /* Register task ID */

  Hal_TaskID = task_id;

 

}

第二个(硬件处理函数):

uint16 Hal_ProcessEvent( uint8 task_id, uint16 events )

{

  uint8 *msgPtr;

 

...........

 

  if (events & HAL_KEY_EVENT)  //如果事件是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( Hal_TaskID, HAL_KEY_EVENT, 100);

//如果没有设置按键中断,每次都通过100毫秒的间隔,重新执行Hal_ProcessEvent函数

// 实现按键的重复查询,osal_start_timerEx的功能就是

//100毫秒系统时间后,将HAL_KEY_EVENT事件传递给Hal_TaskID所对应的

//任务,启动该任务,这里顺便提到HAL_KEY_EVENThal_drivers.h中给了定义。定义如下:

//#define HAL_KEY_EVENT         0x0001

//#define HAL_LED_BLINK_EVENT   0x0002

//#define HAL_SLEEP_TIMER_EVENT 0x0004

                                                         

    }

#endif // HAL_KEY

 

    return events ^ HAL_KEY_EVENT;

  }

 

...........

 

 

 

 

3.HAL层的一些函数

该部分讲讲hal层的按键驱动函数以及相关设置

    HAL/Target/cc2430DB/drivers下找到hal_key.c

    首先是宏定义,定义了一系列常量,我们来看看扩展板上的SW5(按键5)是怎么定义的。

    扩展板上的SW5对应的端口是P0.5(这里我们用的是某公司的平台,所以代码上与TI的协议栈有点不一样,不过这些基本上还是好理解的)做如下更改

  #define HAL_KEY_SW_5_ENABLE

  #define HAL_KEY_SW_5_PORT     P0                      /* p0 */

  #define HAL_KEY_SW_5_BIT      HAL_KEY_BIT5            /* 5个管脚 */

  #define HAL_KEY_SW_5_SEL      P0SEL                   /* Port Select Register for SW5 */

  #define HAL_KEY_SW_5_DIR      P0DIR                   /* Port Direction Register for SW5 */

  #define HAL_KEY_SW_5_INP      P0INP                   /* Port Input Mode Register for SW5 */

  #define HAL_KEY_SW_5_IEN      IEN1                    /* Interrupt Enable Register for SW5 */

  #define HAL_KEY_SW_5_IENBIT   HAL_KEY_BIT5            /* Interrupt Enable bit for SW5 */

  #define HAL_KEY_SW_5_EDGE     HAL_KEY_RISING_EDGE     /* Type of interrupt for SW5 */

  #define HAL_KEY_SW_5_EDGEBIT  HAL_KEY_BIT0            /* EdgeType enable bit SW5 */

  #define HAL_KEY_SW_5_ICTL     PICTL                   /* Port Interrupt Control for SW5 */

  #define HAL_KEY_SW_5_ICTLBIT  HAL_KEY_BIT4            /* Interrupt enable bit for SW5 */

  #define HAL_KEY_SW_5_PXIFG    P0IFG                   /* Port Interrupt Flag for SW5 */

   

    定义了一些API

void HalKeyInit( void ) 初始化按键服务;

void HalKeyConfig (bool interruptEnable, halKeyCBack_t cback) 按键服务的一些配置;

uint8 HalKeyRead ( void ) 读按键的值;

void HalKeyPoll (void) 查询按键;

void halProcessKeyInterrupt (void) 按键的中断处理;

void HalKeyEnterSleep ( void ) 按键休眠;

uint8 HalKeyExitSleep ( void ) 按键推出休眠;

HAL_ISR_FUNCTION( halKeyPort0Isr, P0INT_VECTOR ) 中断服务程序p0口;

HAL_ISR_FUNCTION( halKeyPort1Isr, P1INT_VECTOR ) 中断服务程序p1口;

HAL_ISR_FUNCTION( halKeyPort2Isr, P2INT_VECTOR ) 中断服务程序p2口;

   

我们要实现p0.5口的按键中断功能,所以我们只看每个API中的相关的代码。

 

3.1

void HalKeyInit( void )

{

#if (HAL_KEY == TRUE)

  /* Initialize previous key to 0 */

  halKeySavedKeys = 0;

 

....................

 

#if defined (HAL_KEY_SW_5_ENABLE)

  HAL_KEY_SW_5_SEL &= ~(HAL_KEY_SW_5_BIT);    /* p0SEL的第5位置0,把P0.5作为普通IO */

  HAL_KEY_SW_5_DIR &= ~(HAL_KEY_SW_5_BIT);    /* p0DIR的第5位置0,把P0.5作为输入口 */

  HAL_KEY_SW_5_INP |= HAL_KEY_SW_5_BIT;       /* Set pin input mode to 三态 */

#endif

 

  /* 回调函数的初始化 ,赋值为NULL*/

  pHalKeyProcessFunction  = NULL;

 

  /* 按键还未经配置,赋值为FALSE*/

  HalKeyConfigured = FALSE;

#endif /* HAL_KEY */

}

总结:这个函数基本完成了相应管脚的基本配置管脚的输入输出等等,给一些变量赋初值。

 

3.2

void HalKeyConfig (bool interruptEnable, halKeyCBack_t cback)

{

#if (HAL_KEY == TRUE)

  /* 中断使能赋值 */

  Hal_KeyIntEnable = interruptEnable;

 

  /* 配置回调函数,将函数指针赋值给变量pHalKeyProcessFunction */

  pHalKeyProcessFunction = cback;

 

  /* 根据赋值,判断中断是不是被允许 */

  if (Hal_KeyIntEnable)

  {

 

    /*

  因为调试仿真用得IO口和P2管脚的冲突问题,这里专指某公司的DB平台,他们用了P2口的按键,这里要禁止p2口的中断。

  这里我们把原来的语句做一些更改,在前面加上///以示删除

    */

    ///#if defined (HAL_BOARD_CC2430DB)

    ///#undef HAL_KEY_SW_5_ENABLE                      /* Dis-allow SW5 when key interrupt is enable */

    ///#endif

 

  #if defined (HAL_KEY_SW_5_ENABLE)

    PICTL &= ~(HAL_KEY_SW_5_EDGEBIT);                 /* 中断触发设置为上升沿触发 */

  #if (HAL_KEY_SW_5_EDGE == HAL_KEY_FALLING_EDGE)

    PICTL |= HAL_KEY_SW_5_EDGEBIT;

  #endif

    HAL_KEY_SW_5_ICTL |= HAL_KEY_SW_5_BIT;        /* 允许中断*/

    HAL_KEY_SW_5_IEN |= HAL_KEY_SW_5_IENBIT;

    HAL_KEY_SW_5_PXIFG = ~(HAL_KEY_SW_5_BIT);        /* 清除相关中断标志位 */

#endif

 

   .............

    /* 在休眠模式下,如果是按键查询模式的话,按键查询任务停止,这里与我现在要做的无关,因为我是中断模式 */

    if (HalKeyConfigured == TRUE)

    {

   ............ 

    }

 

  /* 按键完成相应的配置,给变量赋值为TURE */

  HalKeyConfigured = TRUE;

#endif /* HAL_KEY */

}

 

总结:这个函数配置了回调函数,中断模式或者查询模式下的一些配置,比如:上升沿出发,中断使能等等。

 

3.3

uint8 HalKeyRead ( void )

{

  uint8 keys = 0;

#if (HAL_KEY == TRUE)

  .............

 

  #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

 

 

#endif /* HAL_KEY */

 

  return keys;

 

}

 

总结:这个函数把按键的值赋给变量keys

3.4

void HalKeyPoll (void)

 

这是一个按键查询函数。

void HalKeyPoll (void)

{

#if (HAL_KEY == TRUE)

 

  uint8 keys = 0;

…………….

#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

…………….

    /* Invoke Callback if new keys were depressed */

  if (keys && (pHalKeyProcessFunction))

  {  

//看这里,执行了回调函数

    (pHalKeyProcessFunction) (keys, HAL_KEY_STATE_NORMAL);

  }

 

#endif /* HAL_KEY */

 

}

总结:这个函数把按键的值赋给变量keys,然后执行回调函数发送消息给其他需要keys值的任务。

 

3.5

void halProcessKeyInterrupt (void)

{

 

#if (HAL_KEY == TRUE)

 

  bool    valid=FALSE;

 

............

 

#if defined (HAL_KEY_SW_5_ENABLE)

  if (HAL_KEY_SW_5_PXIFG & HAL_KEY_SW_5_BIT)      /* 中断标志位被置1 */

  {

    HAL_KEY_SW_5_PXIFG = ~(HAL_KEY_SW_5_BIT);    /* 清除中断标志位,并使能中断 */

    valid = TRUE;

  }

#endif

 

  if (valid)

  {

    osal_start_timerEx (Hal_TaskID, HAL_KEY_EVENT, HAL_KEY_DEBOUNCE_VALUE);

  }                                              /*如果中断被使能了,返回原任务,这里给了任务ID和相关事件*/

#endif /* HAL_KEY */

}

 

总结:这个程序的功能主要是在中断处理结束后,清标志位,并返回任务。

 

3.6

HAL_ISR_FUNCTION( halKeyPort0Isr, P0INT_VECTOR )

{

  /* P0IF is cleared by HW for CHVER < REV_E */

 

  halProcessKeyInterrupt();

 

  if( CHVER >= REV_E )

  {

    /* Make sure that we clear all enabled, but unused P0IFG bits.

     * For P0 we can only enable or disable high or low nibble, not bit by

     * bit. For P1 and P2 enabling of single bits are possible, therefore

     * will not any unused pins generate interrupts on P1 or P2.

     * We could have checked for low and high nibble in P0, but this

     * isn't necessary as long as we only clear unused pin interrupts.

     */

    P0IFG = (HAL_KEY_P0INT_LOW_USED | HAL_KEY_POINT_HIGH_USED);

    P0IF = 0;

    CLEAR_SLEEP_MODE();

  }

}

 

4.中断函数的编写

接下来讲讲在哪个地方修改已存在的中断服务函数或则怎样创建自己的中断处理函数。

    找到hal_mcu.h这个文件,这里有中断服务程序的声明原型。

    #define HAL_ISR_FUNCTION(f,v)我们在使用的时候修改相应的参数就行。

    f表示中断服务函数,v表示对应的中断服务向量见下表

/* ------------------------------------------------------------------------------------------------

 *                                        Interrupt Vectors

 * ------------------------------------------------------------------------------------------------

 */

#define  RFERR_VECTOR   VECT(  0, 0x03 )   /*  RF TX FIFO Underflow and RX FIFO Overflow   */

#define  ADC_VECTOR     VECT(  1, 0x0B )   /*  ADC End of Conversion                       */

#define  URX0_VECTOR    VECT(  2, 0x13 )   /*  USART0 RX Complete                          */

#define  URX1_VECTOR    VECT(  3, 0x1B )   /*  USART1 RX Complete                          */

#define  ENC_VECTOR     VECT(  4, 0x23 )   /*  AES Encryption/Decryption Complete          */

#define  ST_VECTOR      VECT(  5, 0x2B )   /*  Sleep Timer Compare                         */

#define  P2INT_VECTOR   VECT(  6, 0x33 )   /*  Port 2 Inputs                               */

#define  UTX0_VECTOR    VECT(  7, 0x3B )   /*  USART0 TX Complete                          */

#define  DMA_VECTOR     VECT(  8, 0x43 )   /*  DMA Transfer Complete                       */

#define  T1_VECTOR      VECT(  9, 0x4B )   /*  Timer 1 (16-bit) Capture/Compare/Overflow   */

#define  T2_VECTOR      VECT( 10, 0x53 )   /*  Timer 2 (MAC Timer)                         */

#define  T3_VECTOR      VECT( 11, 0x5B )   /*  Timer 3 (8-bit) Capture/Compare/Overflow    */

#define  T4_VECTOR      VECT( 12, 0x63 )   /*  Timer 4 (8-bit) Capture/Compare/Overflow    */

#define  P0INT_VECTOR   VECT( 13, 0x6B )   /*  Port 0 Inputs                               */

#define  UTX1_VECTOR    VECT( 14, 0x73 )   /*  USART1 TX Complete                          */

#define  P1INT_VECTOR   VECT( 15, 0x7B )   /*  Port 1 Inputs                               */

#define  RF_VECTOR      VECT( 16, 0x83 )   /*  RF General Interrupts                       */

#define  WDT_VECTOR     VECT( 17, 0x8B )   /*  Watchdog Overflow in Timer Mode             */

 

5. onBoard.c中的函数

看看另外一些相关的key的一些函数在onBoard.c这个文件中有这样一些函数:

 

/*********************************************************************

注册任务,只有注册了的任务才能收到按键触发的相关消息

 *********************************************************************/

byte RegisterForKeys( byte task_id )

{

  // Allow only the first task

  if ( registeredKeysTaskID == NO_TASK_ID )

  {

    registeredKeysTaskID = task_id;//注意这句话,就是给任务注册。

    return ( true );

  }

  else

    return ( false );

}

 

/*********************************************************************

   发送按键的事件给相应的任务,KEY_CHANGE

 *********************************************************************/

byte OnBoard_SendKeys( byte keys, byte state )

{

  keyChange_t *msgPtr;

 

  if ( registeredKeysTaskID != NO_TASK_ID )//如果相应的任务已经被注册到按键中,那么发送该消息到那个任务

  {

    // 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 );

}

   

类型Keychange_t的格式如下

typedef struct

{

  osal_event_hdr_t hdr;

  byte             state; // shift

  byte             keys;  // keys

} keyChange_t;

 

在这个文件中我们还看到了这样一个函数:

void InitBoard( byte level )

{

  if ( level == OB_COLD )

  ..........................

  else  // !OB_COLD

  {

#ifdef ZTOOL_PORT

    MT_IndReset();

#endif

 

     /* Initialize Key stuff */

    OnboardKeyIntEnable = HAL_KEY_INTERRUPT_DISABLE;

    HalKeyConfig( OnboardKeyIntEnable, OnBoard_KeyCallback);//这里就是3.2中提到的按键配置函数,在boart初始化里被初始化

  }

 

}

那么再来看一看这个回调函数OnBoard_KeyCallback(),它的原型如下:

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);

……

}  

 

6.按键中断的整个处理流程

 

上面我们介绍了所有在按键中断中用到的程序和代码。这里我将通过程序的执行流程,分析一下这写代码的工作过程以及相关的作用。(为了方便大家我会给出代码的基本位置)

 

6.1 Main函数

所有程序运行首先是在主函数下开始的,这里也不例外。找到Zmain.c文件下的主函数:ZSEG int main( void )

{

  // 初始化时要关中断

  osal_int_disable( INTS_ALL );

  // 电压检测程序

  zmain_vdd_check();

  // 初始化堆栈

  zmain_ram_init();

  // 第一次初始化平台  ***** 注释1*******

  InitBoard( OB_COLD );

  // 硬件驱动初始化******注释2******

  HalDriverInit();

…………

//系统初始化*******注释3*******

 

  osal_init_system();

 

  // 第二次初始化平台*******注释4*******

  InitBoard( OB_READY );

…………….

  osal_start_system(); // 操作系统开始运行

}

 

注释1该函数在onboard.c中,原型如下

void InitBoard( byte level )

{

  if ( level == OB_COLD )

  {这里执行第一次初始化的内容

   }

  else

}

注释2这个函数在hal_drivers.c

void HalDriverInit (void)

{

………

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

  HalKeyInit();

#endif

………..

}

HalKeyInit()这个函数在hal_key.c中,它的功能在上面已经介绍过了。

 

注释3该函数在OSAL.c文件中,如下:

byte osal_init_system( void )

{……

  osalAddTasks();//任务加入列表

……

  return ( ZSUCCESS );

}

osalAddTasks()函数在上面的文章里已经讲过,其中对两个我们比较感兴趣的任务进行了初始化

void osalAddTasks( void )

{

  osalTaskAdd( Hal_Init, Hal_ProcessEvent, OSAL_TASK_PRIORITY_LOW );

//该任务里包含了按键的一些初始化和操作

  osalTaskAdd( SampleApp_Init, SampleApp_ProcessEvent, OSAL_TASK_PRIORITY_LOW );

//该任务是我们要通过按键来执行的任务,按键任务要把按键消息传给他

}

 

注释4该函数在onboard.c中,原型如下

void InitBoard( byte level )

{

  if ( level == OB_COLD )

  {//这里执行第一次初始化的内容

   }

  else//以下执行第二次初始化的内容

{

………

    OnboardKeyIntEnable = HAL_KEY_INTERRUPT_DISABLE;

    HalKeyConfig( OnboardKeyIntEnable, OnBoard_KeyCallback);

  }

}

这里执行第二次的内容,这里调用了HalKeyConfig()函数,这个函数是按键的一些配置,这个我们在上面已经介绍过了,这里终于看到了回调函数OnBoard_KeyCallback

该回调函数也在该文件中,原型如下:

void OnBoard_KeyCallback ( uint8 keys, uint8 state )

{

  uint8 shift;

  shift = (OnboardKeyIntEnable == HAL_KEY_INTERRUPT_ENABLE) ? false : ((keys & HAL_KEY_SW_6) ? true : false);

………

}

这里的任务是给shift赋值,回调函数就这样提供给上层一个接口,使得下层数据能传输给上层。

 

好了,执行完初始化以后,osal_start_system()把所有任务交给操作系统去控制。

 

6.2中断执行

一旦有中断发生,中断函数首先跳转到

HAL_ISR_FUNCTION( halKeyPort0Isr, P0INT_VECTOR )

{

  halProcessKeyInterrupt();

 

………

}

然后执行halProcessKeyInterrupt();

void halProcessKeyInterrupt (void)

{

#if (HAL_KEY == TRUE)

  bool    valid=FALSE;

#if defined (HAL_KEY_SW_5_ENABLE)

  if (HAL_KEY_SW_5_PXIFG & HAL_KEY_SW_5_BIT)      /*判断中断标志位有效*/

  {

    HAL_KEY_SW_5_PXIFG = ~(HAL_KEY_SW_5_BIT);    /* 清除中断标志位*/

    valid = TRUE;

  }

#endif

  if (valid)

  {

    osal_start_timerEx (Hal_TaskID, HAL_KEY_EVENT, HAL_KEY_DEBOUNCE_VALUE);

  }//然后把该事件传递给任务Hal,Hal_ProcessEvent()处理。我们看看这个任务干了些什么:

uint16 Hal_ProcessEvent( uint8 task_id, uint16 events )

{

……

   if (events & HAL_KEY_EVENT)

  {

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

    /* Check for keys */

    HalKeyPoll();//调用了这个函数

 

   ……

#endif // HAL_KEY

    return events ^ HAL_KEY_EVENT;

……

}

看看HalKeyPoll()做了什么

void HalKeyPoll (void)

{

#if (HAL_KEY == TRUE)

  uint8 keys = 0;

  ……

#if defined (HAL_KEY_SW_5_ENABLE)

  if (HAL_KEY_SW_5_PORT & HAL_KEY_SW_5_BIT)       /* Keys得到了按键的值 */

  {

    keys |= HAL_KEY_SW_5;

  }

#endif

   ……

    /* 使用回调函数,如果keys的值改变了的话*/

  if (keys && (pHalKeyProcessFunction))

  {

    (pHalKeyProcessFunction) (keys, HAL_KEY_STATE_NORMAL);

  }

 

#endif /* HAL_KEY */

 

}

这里再次讲讲这个回调函数的意义,它的任务是要把任务HAL里的keys值变化情况作为一个消息传递给任务sampple,通过shift这个变量的值。

 

6.3中断触发的按键消息的传递

刚才在执行的一直是任务HAL,先在讲讲究竟是怎么养通过回调函数把消息传递给任务sampple的。

继续看回调函数:

void OnBoard_KeyCallback ( uint8 keys, uint8 state )

{

  uint8 shift;

  shift = (OnboardKeyIntEnable == HAL_KEY_INTERRUPT_ENABLE) ? false : ((keys & HAL_KEY_SW_6) ? true : false);

  if ( OnBoard_SendKeys( keys, shift ) != ZSuccess )

//这里有很重要的一个函数OnBoard_SendKeys()

……

}

 

OnBoard_SendKeys()这个函数在文件Onboard.c中被定义了。原来它才是真正传递消息的函数。它的原型如下:

byte OnBoard_SendKeys( byte keys, byte state )

{

  keyChange_t *msgPtr;

  if ( registeredKeysTaskID != NO_TASK_ID )//注意这里,判断有没有事先注册事件

  {

    // Send the address to the task

    msgPtr = (keyChange_t *)osal_msg_allocate( sizeof(keyChange_t) );

    if ( msgPtr )

    {

      msgPtr->hdr.event = KEY_CHANGE;//发送KEY_CHANG这个事件标识符

      msgPtr->state = state;

      msgPtr->keys = keys;

      osal_msg_send( registeredKeysTaskID, (uint8 *)msgPtr );

    }

    return ( ZSuccess );

  }

  else

    return ( ZFailure );

}

 

到这里我们终于传递了事件KEY_CHANG,那么还有一个疑问是registeredKeysTaskID这个注册是怎么一回事,在哪里注册?

void SampleApp_Init( uint8 task_id )就有这样一句话:

RegisterForKeys( SampleApp_TaskID );

它调用了onboard.c中的一个函数RegisterForKeys()完成任务对按键事件的注册工作,这里如果不注册的话在后来的程序里是不会产生KEY_CHANG这个事件的。

接下来的我就不用说了吧,这里再提一点吧:KEY_CHANG这个在ZcomDef.h中定义

#define SYS_EVENT_MSG               0x8000  // A message is waiting event

 

/*********************************************************************

 * Global System Messages

 */

 

#define SPI_INCOMING_ZTOOL_PORT   0x21    // Raw data from ZTool Port (not implemented)

#define SPI_INCOMING_ZAPP_DATA    0x22    // Raw data from the ZAPP port (see serialApp.c)

#define MT_SYS_APP_MSG            0x23    // Raw data from an MT Sys message

#define MT_SYS_APP_RSP_MSG        0x24    // Raw data output for an MT Sys message

 

#define AF_DATA_CONFIRM_CMD       0xFD    // Data confirmation

#define AF_INCOMING_MSG_CMD       0x1A    // Incoming MSG type message

#define AF_INCOMING_KVP_CMD       0x1B    // Incoming KVP type message

#define AF_INCOMING_GRP_KVP_CMD   0x1C    // Incoming Group KVP type message

 

#define KEY_CHANGE    

 

学习就是要有耐心,要在这么大一个工程文件里找函数可不是一个简单的事情,不光要细心还要有点逻辑,不能盲目的寻找。

 

7.总结

上面主要通过一个中断程序让大家熟悉TI的编程环境,特别是在OSAL下如何编程。都是自己总结的,肯定存在很多不足,希望大家给予指点。谢谢。

                                      

              

                                                                       作者:劳 力

                                                                       08年8月25

http://bit-zigbee.cn/News.asp?Id=21

posted @ 2012-04-01 21:28  ijustwanttorun  阅读(560)  评论(0编辑  收藏  举报