zigbee 中的按键驱动的设置

Posted f-beifeng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了zigbee 中的按键驱动的设置相关的知识,希望对你有一定的参考价值。

对于按键驱动修改不错的博文:https://wenku.baidu.com/view/12e61922aef8941ea66e05b9.html

                                                                                                     https://blog.csdn.net/stone8761/article/details/79563594

技术分享图片
    此外,使用的TI BLE协议栈版本是1.3.2。
 

KEY服务API

 
    KEY服务一共有7个API。分别是:
  • HalKeyInit()
  • HalKeyConfig()
  • HalKeyRead()
  • HalKeyEnterSleep()
  • HalKeyExitSleep()
  • HalKeyPoll()
  • HalKeyPressed()
    其中,HalKeyInit()、HalKeyConfig()、HalKeyRead()、HalKeyPoll()是我们需要关注的。
 

1.五向按键的硬件原理

 
技术分享图片
    五向按键的五个方向:上、下、左、右、垂直向下。原理是只要五向按键有按压动作,在JOY_MOVE引脚会产生中断,此时再去采集JOY_LEVEL的电压,根据电压范围来判断当前的五向按键的方向。原理还是很简单的,电路倒是有点复杂。
 
技术分享图片
    此外,开发板还有一个单独的按键S1。

2.KEY服务API源码分析

 
    因为我使用的是开发板的例程,五向按键部分的电路和官方是不一样的,因此使用开发板提供的修改文件hal_key.c。
 

2.1 HalKeyInit()

  1.  
    /**************************************************************************************************
  2.  
    * @fn HalKeyInit
  3.  
    *
  4.  
    * @brief Initilize Key Service
  5.  
    *
  6.  
    * @param none
  7.  
    *
  8.  
    * @return None
  9.  
    **************************************************************************************************/
  10.  
    void HalKeyInit( void )
  11.  
    {
  12.  
    #if (HAL_KEY == TRUE)
  13.  
    /* Initialize previous key to 0 */
  14.  
    halKeySavedKeys = HAL_KEY_CODE_NOKEY;
  15.  
     
  16.  
    /* The advanced remote doesn‘t have the same 8X8 row/column matrix as in other
  17.  
    * products. Instead, a 3X16 row/column matrix is used, with the rows continuing
  18.  
    * to be utilized by GPios, but the columns are generated via a 16 bit
  19.  
    * shift register. Controls for the shift register are, however, utilized with
  20.  
    * GPIOs.
  21.  
    *
  22.  
    * Another difference is that the GPIOs utilized for the rows are split between
  23.  
    * P0 and P1.
  24.  
    */
  25.  
    //ghostyu from EM
  26.  
    HAL_KEY_SW_6_SEL &= ~(HAL_KEY_SW_6_BIT); /* Set pin function to GPIO */
  27.  
    HAL_KEY_SW_6_DIR &= ~(HAL_KEY_SW_6_BIT); /* Set pin direction to Input */
  28.  
    HAL_KEY_JOY_MOVE_SEL &= ~(HAL_KEY_JOY_MOVE_BIT); /* Set pin function to GPIO */
  29.  
    HAL_KEY_JOY_MOVE_DIR &= ~(HAL_KEY_JOY_MOVE_BIT); /* Set pin direction to Input */
  30.  
     
  31.  
    /* Initialize callback function */
  32.  
    <span style="font-size:10px;">pHalKeyProcessFunction = NULL;</span>
  33.  
     
  34.  
    /* Start with key is not configured */
  35.  
    HalKeyConfigured = FALSE;
  36.  
     
  37.  
    <span style="font-size:10px;">halKeyTimerRunning = FALSE;</span>
  38.  
    #endif /* HAL_KEY */
  39.  
    }

        这里主要是对两个引脚(一个用于触发中断,一个用于AD采样)进行设置,并设置相关文件域的全局变量,包括pHalKeyProcessFunction、HalKeyConfigured、halKeyTimerRunning。在使用KEY服务前必须要调用该函数,在TI的例程中只要开启相关宏定义即可,这时会在HalDriverInit()中进行初始化:
 
技术分享图片
 
 

2.2 HalKeyConfig()

  1.  
    /**************************************************************************************************
  2.  
    * @fn HalKeyConfig
  3.  
    *
  4.  
    * @brief Configure the Key serivce
  5.  
    *
  6.  
    * @param interruptEnable - TRUE/FALSE, enable/disable interrupt
  7.  
    * cback - pointer to the CallBack function
  8.  
    *
  9.  
    * @return None
  10.  
    **************************************************************************************************/
  11.  
    void HalKeyConfig (bool interruptEnable, halKeyCBack_t cback)
  12.  
    {
  13.  
    #if (HAL_KEY == TRUE)
  14.  
    /* Enable/Disable Interrupt */
  15.  
    Hal_KeyIntEnable = interruptEnable;
  16.  
     
  17.  
    /* Register the callback fucntion */
  18.  
    pHalKeyProcessFunction = cback;
  19.  
     
  20.  
    /* Determine if interrupt is enabled or not */
  21.  
    if (Hal_KeyIntEnable)
  22.  
    {
  23.  
     
  24.  
    //ghostyu from EM
  25.  
    /* Rising/Falling edge configuratinn */
  26.  
    PICTL &= ~(HAL_KEY_SW_6_EDGEBIT); /* Clear the edge bit */
  27.  
    /* For rising edge, the bit must be set. */
  28.  
    PICTL &= ~(HAL_KEY_SW_6_EDGEBIT);
  29.  
     
  30.  
     
  31.  
     
  32.  
    /* Interrupt configuration:
  33.  
    * - Enable interrupt generation at the port
  34.  
    * - Enable CPU interrupt
  35.  
    * - Clear any pending interrupt
  36.  
    */
  37.  
    HAL_KEY_SW_6_ICTL |= HAL_KEY_SW_6_ICTLBIT;
  38.  
    HAL_KEY_SW_6_IEN |= HAL_KEY_SW_6_IENBIT;
  39.  
    HAL_KEY_SW_6_PXIFG = ~(HAL_KEY_SW_6_BIT);
  40.  
     
  41.  
     
  42.  
     
  43.  
    /* Rising/Falling edge configuratinn */
  44.  
     
  45.  
    HAL_KEY_JOY_MOVE_ICTL &= ~(HAL_KEY_JOY_MOVE_EDGEBIT); /* Clear the edge bit */
  46.  
    /* For falling edge, the bit must be set. */
  47.  
     
  48.  
    HAL_KEY_JOY_MOVE_ICTL |= HAL_KEY_JOY_MOVE_EDGEBIT;
  49.  
     
  50.  
     
  51.  
    /* Interrupt configuration:
  52.  
    * - Enable interrupt generation at the port
  53.  
    * - Enable CPU interrupt
  54.  
    * - Clear any pending interrupt
  55.  
    */
  56.  
    HAL_KEY_JOY_MOVE_ICTL |= HAL_KEY_JOY_MOVE_ICTLBIT;
  57.  
    HAL_KEY_JOY_MOVE_IEN |= HAL_KEY_JOY_MOVE_IENBIT;
  58.  
    HAL_KEY_JOY_MOVE_PXIFG = ~(HAL_KEY_JOY_MOVE_BIT);
  59.  
     
  60.  
     
  61.  
    /* Do this only after the hal_key is configured - to work with sleep stuff */
  62.  
    if (HalKeyConfigured == TRUE)
  63.  
    {
  64.  
    osal_stop_timerEx( Hal_TaskID, HAL_KEY_EVENT); /* Cancel polling if active */
  65.  
    }
  66.  
    }
  67.  
    else /* Interrupts NOT enabled */
  68.  
    {
  69.  
    HAL_KEY_SW_6_ICTL &= ~(HAL_KEY_SW_6_ICTLBIT); /* don‘t generate interrupt */
  70.  
    HAL_KEY_SW_6_IEN &= ~(HAL_KEY_SW_6_IENBIT); /* Clear interrupt enable bit */
  71.  
     
  72.  
     
  73.  
    osal_start_timerEx (Hal_TaskID, HAL_KEY_EVENT, HAL_KEY_POLLING_VALUE); /* Kick off polling */
  74.  
    }
  75.  
     
  76.  
    /* Key now is configured */
  77.  
    HalKeyConfigured = TRUE;
  78.  
    #endif /* HAL_KEY */
  79.  
    }



    该函数对KEY服务进行配置,形参有2个:interruptEnable, cback。
    interruptEnable用来选择按键的扫描方式,KEY服务的按键扫描方式有两种,一种是循环扫描,另外一种是中断扫描。循环扫描和中断扫描的具体过程后面会介绍。cback就是应用层传给HAL KEY服务的回调函数,用于通知应用层相关按键的触发动作。回调函数的原型是:
typedef void (*halKeyCBack_t) (uint8 keys, uint8 state);
 

    keys表示哪个按键被按下,state表示按键是怎么被按下的,TI的HAL进行如下定义:
 
技术分享图片技术分享图片
    
    state中HAL_KEY_STATE_SHIFT好像不怎么用得到,用HAL_KEY_STATE_NORMAL比较多。
 

2.3 HalKeyConfig()

  1.  
    /**************************************************************************************************
  2.  
    * @fn HalKeyRead
  3.  
    *
  4.  
    * @brief Read the current value of a key
  5.  
    *
  6.  
    * @param None
  7.  
    *
  8.  
    * @return keys - current keys status
  9.  
    **************************************************************************************************/
  10.  
    uint8 HalKeyRead ( void )
  11.  
    {
  12.  
    uint8 keys = 0;
  13.  
     
  14.  
    //注意这里的SW6对应SmartRF开发板上的S1,是高电平有效
  15.  
    if ((HAL_KEY_SW_6_PORT & HAL_KEY_SW_6_BIT)) /* Key is active HIGH */
  16.  
    {
  17.  
    keys |= HAL_KEY_SW_6;
  18.  
    }
  19.  
     
  20.  
    if ((HAL_KEY_JOY_MOVE_PORT & HAL_KEY_JOY_MOVE_BIT)) /* Key is active low */
  21.  
    {
  22.  
    keys |= halGetJoyKeyInput();
  23.  
    }
  24.  
    return keys;
  25.  
    }
 
    该函数不需要应用层调用,是有HAL层调用的,在开发板的例程中,因为硬件上只有一个按键和一个五向按键,所以该函数的前面部分是通过IO口电平判断按键现在的状态,后面部分则是具体检测五向按键的状态。首先要确定五向按键被操作了,之后再执行函数halGetJoyKeyInput()。
  1.  
    /**************************************************************************************************
  2.  
    * @fn halGetJoyKeyInput
  3.  
    *
  4.  
    * @brief Map the ADC value to its corresponding key.
  5.  
    *
  6.  
    * @param None
  7.  
    *
  8.  
    * @return keys - current joy key status
  9.  
    **************************************************************************************************/
  10.  
    uint8 halGetJoyKeyInput(void)
  11.  
    {
  12.  
    /* The joystick control is encoded as an analog voltage.
  13.  
    * Read the JOY_LEVEL analog value and map it to joy movement.
  14.  
    */
  15.  
    uint8 adc;
  16.  
    uint8 ksave0 = 0;
  17.  
    uint8 ksave1;
  18.  
     
  19.  
    /* Keep on reading the ADC until two consecutive key decisions are the same. */
  20.  
    do
  21.  
    {
  22.  
    ksave1 = ksave0; /* save previouse key reading */
  23.  
     
  24.  
    adc = HalAdcRead (HAL_KEY_JOY_CHN, HAL_ADC_RESOLUTION_8);
  25.  
     
  26.  
    if ((adc >= 2) && (adc <= 38))
  27.  
    {
  28.  
    ksave0 |= HAL_KEY_UP;
  29.  
    }
  30.  
    else if ((adc >= 74) && (adc <= 88))
  31.  
    {
  32.  
    ksave0 |= HAL_KEY_RIGHT;
  33.  
    }
  34.  
    else if ((adc >= 60) && (adc <= 73))
  35.  
    {
  36.  
    ksave0 |= HAL_KEY_LEFT;
  37.  
    }
  38.  
    else if ((adc >= 39) && (adc <= 59))
  39.  
    {
  40.  
    ksave0 |= HAL_KEY_DOWN;
  41.  
    }
  42.  
    else if ((adc >= 89) && (adc <= 100))
  43.  
    {
  44.  
    ksave0 |= HAL_KEY_CENTER;
  45.  
    }else{
  46.  
    ksave0=0;
  47.  
    }
  48.  
     
  49.  
    } while (ksave0 != ksave1);
  50.  
     
  51.  
    return ksave0;
  52.  
    }

2.4 HalKeyPoll()

  1.  
    /**************************************************************************************************
  2.  
    * @fn HalKeyPoll
  3.  
    *
  4.  
    * @brief Called by hal_driver to poll the keys
  5.  
    *
  6.  
    * @param None
  7.  
    *
  8.  
    * @return None
  9.  
    **************************************************************************************************/
  10.  
    #define GHOSTYU_CODE_NOKEY 0x00
  11.  
    void HalKeyPoll (void)
  12.  
    {
  13.  
    #if (HAL_KEY == TRUE)
  14.  
     
  15.  
    uint8 keys = 0;
  16.  
    /*
  17.  
    * If interrupts are enabled, get the status of the interrupt-driven keys from ‘halSaveIntKey‘
  18.  
    * which is updated by the key ISR. If Polling, read these keys directly.
  19.  
    */
  20.  
    keys = HalKeyRead();
  21.  
     
  22.  
    /* Exit if polling and no keys have changed */
  23.  
    if (!Hal_KeyIntEnable)
  24.  
    {
  25.  
    if (keys == halKeySavedKeys)
  26.  
    {
  27.  
    return;
  28.  
    }
  29.  
    halKeySavedKeys = keys; /* Store the current keys for comparation next time */
  30.  
    }
  31.  
     
  32.  
    if(keys==0){
  33.  
    (pHalKeyProcessFunction) (0, HAL_KEY_STATE_NORMAL);
  34.  
    }
  35.  
     
  36.  
    /* Invoke Callback if new keys were depressed */
  37.  
    if ((keys != 0 /*HAL_KEY_CODE_NOKEY*/) && Hal_KeyIntEnable &&
  38.  
    (pHalKeyProcessFunction))
  39.  
    {
  40.  
    // When interrupt is enabled, send HAL_KEY_CODE_NOKEY as well so that
  41.  
    // application would know the previous key is no longer depressed.
  42.  
     
  43.  
    (pHalKeyProcessFunction) (keys, HAL_KEY_STATE_NORMAL);
  44.  
     
  45.  
    }
  46.  
     
  47.  
    //如果使能了中断触发,在中断触发后,poll按键,先是去抖动,去抖动结束后,如果该按键仍存在,
  48.  
    //则调用按键回调函数,向用户传递按键数据
  49.  
    //然后执行下面的代码,再延时50ms,看时候该按键是否仍然没有释放。如果没有释放,则继续调用按键的回调函数。
  50.  
     
  51.  
    if (Hal_KeyIntEnable)
  52.  
    {
  53.  
    if (keys != 0/*HAL_KEY_CODE_NOKEY*/)
  54.  
    {
  55.  
    // In order to trigger callback again as far as the key is depressed,
  56.  
    // timer is called here.
  57.  
    osal_start_timerEx(Hal_TaskID, HAL_KEY_EVENT, 50);
  58.  
     
  59.  
    }
  60.  
    else
  61.  
    {
  62.  
    halKeyTimerRunning = FALSE;
  63.  
     
  64.  
    }
  65.  
    }
  66.  
    #endif /* HAL_KEY */
  67.  
     
  68.  
    }
    该函数是对应开发板硬件修改的,它也是HAL层来执行,不需要应用层进行判断,主要功能是对按键的状态进行采集分析,并作回调。不过我看这个函数有些怪怪的,可以再优化下,增加可读性。另外,该函数和TI官方代码最大不同是,它增加了回调函数的一个功能,就是所有按键都释放时会有回调,此时state=0。下面贴一下官方的代码:
  1.  
    /**************************************************************************************************
  2.  
    * @fn HalKeyPoll
  3.  
    *
  4.  
    * @brief Called by hal_driver to poll the keys
  5.  
    *
  6.  
    * @param None
  7.  
    *
  8.  
    * @return None
  9.  
    **************************************************************************************************/
  10.  
    void HalKeyPoll (void)
  11.  
    {
  12.  
    uint8 keys = 0;
  13.  
    uint8 notify = 0;
  14.  
    #if defined (CC2540_MINIDK)
  15.  
    if (!(HAL_KEY_SW_1_PORT & HAL_KEY_SW_1_BIT)) /* Key is active low */
  16.  
    {
  17.  
    keys |= HAL_KEY_SW_1;
  18.  
    }
  19.  
    if (!(HAL_KEY_SW_2_PORT & HAL_KEY_SW_2_BIT)) /* Key is active low */
  20.  
    {
  21.  
    keys |= HAL_KEY_SW_2;
  22.  
    }
  23.  
    #else
  24.  
    if (!(HAL_KEY_SW_6_PORT & HAL_KEY_SW_6_BIT)) /* Key is active low */
  25.  
    {
  26.  
    keys |= HAL_KEY_SW_6;
  27.  
    }
  28.  
     
  29.  
    if ((HAL_KEY_JOY_MOVE_PORT & HAL_KEY_JOY_MOVE_BIT)) /* Key is active HIGH */
  30.  
    {
  31.  
    keys = halGetJoyKeyInput();
  32.  
    }
  33.  
    #endif
  34.  
     
  35.  
    /* If interrupts are not enabled, previous key status and current key status
  36.  
    * are compared to find out if a key has changed status.
  37.  
    */
  38.  
    if (!Hal_KeyIntEnable)
  39.  
    {
  40.  
    if (keys == halKeySavedKeys)
  41.  
    {
  42.  
    /* Exit - since no keys have changed */
  43.  
    return;
  44.  
    }
  45.  
    else
  46.  
    {
  47.  
    notify = 1;
  48.  
    }
  49.  
    }
  50.  
    else
  51.  
    {
  52.  
    /* Key interrupt handled here */
  53.  
    if (keys)
  54.  
    {
  55.  
    notify = 1;
  56.  
    }
  57.  
    }
  58.  
     
  59.  
    /* Store the current keys for comparation next time */
  60.  
    halKeySavedKeys = keys;
  61.  
     
  62.  
    /* Invoke Callback if new keys were depressed */
  63.  
    if (notify && (pHalKeyProcessFunction))
  64.  
    {
  65.  
    (pHalKeyProcessFunction) (keys, HAL_KEY_STATE_NORMAL);
  66.  
     
  67.  
    }
  68.  
    }
不过,TI的代码好像也有问题:
  1.  
    #else
  2.  
    if (!(HAL_KEY_SW_6_PORT & HAL_KEY_SW_6_BIT)) /* Key is active low */
  3.  
    {
  4.  
    keys |= HAL_KEY_SW_6;
  5.  
    }
  6.  
     
  7.  
    if ((HAL_KEY_JOY_MOVE_PORT & HAL_KEY_JOY_MOVE_BIT)) /* Key is active HIGH */
  8.  
    {
  9.  
    keys = halGetJoyKeyInput();
  10.  
    }
  11.  
    #endif
 
keys = halGetJoyKeyInput();
 
应该改为:
keys |= halGetJoyKeyInput();
 
 
    剩下的3个API:HalKeyEnterSleep()和HalKeyExitSleep()是没有内容的,HalKeyPressed()只找到声明没找到定义,就不管了。


3.KEY服务的工作流程


    前面已经大概介绍了几个API的主要功能,现在来说说他们是怎么被HAL层使用的。
    首先,当按键服务宏定义被打开后,HalKeyInit()函数会被调用(前面有介绍),之后,一般在设备启动任务中对KEY服务进行配置。
技术分享图片
    这里就有两个分支了,一个是当KEY_INT_ENABLED时,使用的是中断扫描,否则使用循环扫描方式,他们再HAL层工作流程就不太一样。
 

3.1 循环扫描

    当使用循环扫描时,HalKeyConfig()在最后会触发HAL_KEY_EVENT事件:
 
  1.  
    /* Do this only after the hal_key is configured - to work with sleep stuff */
  2.  
    if (HalKeyConfigured == TRUE)
  3.  
    {
  4.  
    osal_stop_timerEx(Hal_TaskID, HAL_KEY_EVENT); /* Cancel polling if active */
  5.  
    }
  6.  
    }
  7.  
    else /* Interrupts NOT enabled */
  8.  
    {
  9.  
    #if defined ( CC2540_MINIDK )
  10.  
    HAL_KEY_SW_1_ICTL &= ~(HAL_KEY_SW_1_ICTLBIT); /* don‘t generate interrupt */
  11.  
    HAL_KEY_SW_1_IEN &= ~(HAL_KEY_SW_1_IENBIT); /* Clear interrupt enable bit */
  12.  
    HAL_KEY_SW_2_ICTL &= ~(HAL_KEY_SW_2_ICTLBIT); /* don‘t generate interrupt */
  13.  
    HAL_KEY_SW_2_IEN &= ~(HAL_KEY_SW_2_IENBIT); /* Clear interrupt enable bit */
  14.  
    #else
  15.  
    HAL_KEY_SW_6_ICTL &= ~(HAL_KEY_SW_6_ICTLBIT); /* don‘t generate interrupt */
  16.  
    HAL_KEY_SW_6_IEN &= ~(HAL_KEY_SW_6_IENBIT); /* Clear interrupt enable bit */
  17.  
    #endif // !CC2540_MINIDK
  18.  
     
  19.  
    osal_set_event(Hal_TaskID, HAL_KEY_EVENT);
  20.  
    }

    
    而在HAL任务中,会进行如下工作:
 
  1.  
    if (events & HAL_KEY_EVENT)
  2.  
    {
  3.  
    #if (defined HAL_KEY) && (HAL_KEY == TRUE)
  4.  
    /* Check for keys */
  5.  
    HalKeyPoll();
  6.  
     
  7.  
    /* if interrupt disabled, do next polling */
  8.  
    if (!Hal_KeyIntEnable)
  9.  
    {
  10.  
    osal_start_timerEx( Hal_TaskID, HAL_KEY_EVENT, 100);
  11.  
    }
  12.  
    #endif
  13.  
    return events ^ HAL_KEY_EVENT;
  14.  
    }
 
 
 
这里我们可以注意到,当使用循环扫描时,扫描周期为100ms,每次处理该事件时调用的函数就是HalKeyPoll()。
 

3.2 中断扫描

    和循环扫描所不同的是,它不会定时扫描,只有当中断触发时才会设置HAL_KEY_EVENT事件。
    在中断处理中,当检测到是相应开关触发的中断后,会调用函数halProcessKeyInterrupt():
 
 
  1.  
    /**************************************************************************************************
  2.  
    * @fn halProcessKeyInterrupt
  3.  
    *
  4.  
    * @brief Checks to see if it‘s a valid key interrupt, saves interrupt driven key states for
  5.  
    * processing by HalKeyRead(), and debounces keys by scheduling HalKeyRead() 25ms later.
  6.  
    *
  7.  
    * @param
  8.  
    *
  9.  
    * @return
  10.  
    **************************************************************************************************/
  11.  
    void halProcessKeyInterrupt (void)
  12.  
    {
  13.  
     
  14.  
    #if (HAL_KEY == TRUE)
  15.  
    //ghostyu from EM
  16.  
    bool valid=FALSE;
  17.  
    if (HAL_KEY_SW_6_PXIFG & HAL_KEY_SW_6_BIT) /* Interrupt Flag has been set */
  18.  
    {
  19.  
    HAL_KEY_SW_6_PXIFG = ~(HAL_KEY_SW_6_BIT); /* Clear Interrupt Flag */
  20.  
    valid = TRUE;
  21.  
    }
  22.  
     
  23.  
    if (HAL_KEY_JOY_MOVE_PXIFG & HAL_KEY_JOY_MOVE_BIT) /* Interrupt Flag has been set */
  24.  
    {
  25.  
    HAL_KEY_JOY_MOVE_PXIFG = ~(HAL_KEY_JOY_MOVE_BIT); /* Clear Interrupt Flag */
  26.  
    valid = TRUE;
  27.  
    }
  28.  
     
  29.  
    if (valid)
  30.  
    {
  31.  
    if (!halKeyTimerRunning)
  32.  
    {
  33.  
    halKeyTimerRunning = TRUE;
  34.  
    osalTimeUpdate();
  35.  
    osal_start_timerEx (Hal_TaskID, HAL_KEY_EVENT, HAL_KEY_DEBOUNCE_VALUE);
  36.  
    }
  37.  
    }
  38.  
    #endif /* HAL_KEY */
  39.  
    }


 




 






















以上是关于zigbee 中的按键驱动的设置的主要内容,如果未能解决你的问题,请参考以下文章

ZigBee案例笔记 -- 外部中断

ZigBee案例笔记 -- 外部中断

ZigBee案例笔记 -- LED控制与按键检测(输入/输出)

ZigBee案例笔记 -- LED控制与按键检测(输入/输出)

ZigBee开发--基础实验按键

zigbee z-stack实现按键的长按