我做操作的芯片是TiCC2530。就不考虑Zstack协议栈而言,如果要用到按键,无非是中断或者查询两种方式。
查询方式是通过查询按键对应I/O口的状态来判断按键的状态,从而进行相应的处理。
外部中断的方式是使能按键对应得I/O口的中断,当I/O口的状态改变时触发中断,从而在相应的中断处理函数中进行处理。
万变不离其宗,Zigbee协议栈的按键操作本质上也是对于基本查询方式和终端方式的封装。对于查询方式我们关键要找到它是如何配置引脚的功能/输入输出/上拉下拉,以及是如何查询引脚状态的,对于中断方式关键是配置相应引脚的中断和相应的中断处理函数。
首先是ZMain.c文件中的两个函数涉及到了按键的配置,分别是InitBoard( )和 HalDriverInit()其中InitBoard()调用了两次
1
2// Initialize board I/O InitBoard( OB_COLD );
右键GO TO,其中参数OB_COLD是一个宏#define OB_COLD 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18void InitBoard( uint8 level ) { if ( level == OB_COLD ) { // Interrupts off osal_int_disable( INTS_ALL ); // Turn all LEDs off HalLedSet( HAL_LED_ALL, HAL_LED_MODE_OFF ); // Check for Brown-Out reset ChkReset(); } else // !OB_COLD { /* Initialize Key stuff */ OnboardKeyIntEnable = HAL_KEY_INTERRUPT_DISABLE; HalKeyConfig( OnboardKeyIntEnable, OnBoard_KeyCallback); } }
第一个if是成立的,所以关闭所有的中断并关闭LED。我们回到main()函数
1
2// Initialze HAL drivers HalDriverInit();
右键GO TO,找到了按键的初始化函数HalKeyInit()
1
2
3
4/* KEY */ #if (defined HAL_KEY) && (HAL_KEY == TRUE) HalKeyInit(); #endif
右键GO TO ,这里主要是配置了P0SEL、P0DIR和P1SEL、P1DIR为通用和输入。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18void HalKeyInit( void ) { /* Initialize previous key to 0 */ halKeySavedKeys = 0; //默认当前键值为0 HAL_KEY_SW_6_SEL &= ~(HAL_KEY_SW_6_BIT); /* Set pin function to GPIO */ //P0.1设置为通用 HAL_KEY_SW_6_DIR &= ~(HAL_KEY_SW_6_BIT); /* Set pin direction to Input */ //P0.1设置为输入 HAL_KEY_JOY_MOVE_SEL &= ~(HAL_KEY_JOY_MOVE_BIT); /* Set pin function to GPIO */ //P2.0设置为通用 HAL_KEY_JOY_MOVE_DIR &= ~(HAL_KEY_JOY_MOVE_BIT); /* Set pin direction to Input */ //P2.0设置为输入 /* Initialize callback function */ pHalKeyProcessFunction = NULL; //默认无回调函数 /* Start with key is not configured */ HalKeyConfigured = FALSE; }
GO TO HAL_KEY_SW_6_SEL发现就是P0SEL寄存器,到这里终于揭开了Zigbee包装的一角,其中寄存器的配置是也是以宏的方式给出的
1
2
3
4#define HAL_KEY_SW_6_PORT P0 #define HAL_KEY_SW_6_BIT BV(1) #define HAL_KEY_SW_6_SEL P0SEL #define HAL_KEY_SW_6_DIR P0DIR
1
2
3#ifndef BV #define BV(n) (1 << (n)) #endif
1
2
3
4
5/* Joy stick move at P2.0 */ #define HAL_KEY_JOY_MOVE_PORT P2 #define HAL_KEY_JOY_MOVE_BIT BV(0) #define HAL_KEY_JOY_MOVE_SEL P2SEL #define HAL_KEY_JOY_MOVE_DIR P2DIR
特别的,1<<(n)就是将1左移n位,整数型立即数默认类型是int型,占有4个字节,所以1<<(1)等价于 0x 0000 0000 0000 0010。
1
2/* Initialize callback function */ pHalKeyProcessFunction = NULL;
回调函数为空,说明中断方式的中断处理函数不是在这里进行设置的。我们回到main()函数,发现再次调用了InitBoard(),这次的参数为2 ,#define OB_READY 2
1
2// Final board initialization InitBoard( OB_READY );
右键GO TO,由于参数为2,这次进入了第一次调用InitBoard()时没有进入的另一个if分支
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18void InitBoard( uint8 level ) { if ( level == OB_COLD ) { // Interrupts off osal_int_disable( INTS_ALL ); // Turn all LEDs off HalLedSet( HAL_LED_ALL, HAL_LED_MODE_OFF ); // Check for Brown-Out reset ChkReset(); } else // !OB_COLD { /* Initialize Key stuff */ OnboardKeyIntEnable = HAL_KEY_INTERRUPT_DISABLE; HalKeyConfig( OnboardKeyIntEnable, OnBoard_KeyCallback); } }
右键GO TO 按键配置函数HalKeyConfig(),发现这里配置了引脚的中断
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67void HalKeyConfig (bool interruptEnable, halKeyCBack_t cback) { /* Enable/Disable Interrupt or */ Hal_KeyIntEnable = interruptEnable; /* Register the callback fucntion */ pHalKeyProcessFunction = cback; /* Determine if interrupt is enable or not */ if (Hal_KeyIntEnable) { /* Rising/Falling edge configuratinn */ PICTL &= ~(HAL_KEY_SW_6_EDGEBIT); /* Clear the edge bit */ /* For falling edge, the bit must be set. */ #if (HAL_KEY_SW_6_EDGE == HAL_KEY_FALLING_EDGE) PICTL |= HAL_KEY_SW_6_EDGEBIT; #endif /* Interrupt configuration: * - Enable interrupt generation at the port * - Enable CPU interrupt * - Clear any pending interrupt */ HAL_KEY_SW_6_ICTL |= HAL_KEY_SW_6_ICTLBIT; HAL_KEY_SW_6_IEN |= HAL_KEY_SW_6_IENBIT; HAL_KEY_SW_6_PXIFG = ~(HAL_KEY_SW_6_BIT); /* Rising/Falling edge configuratinn */ HAL_KEY_JOY_MOVE_ICTL &= ~(HAL_KEY_JOY_MOVE_EDGEBIT); /* Clear the edge bit */ /* For falling edge, the bit must be set. */ #if (HAL_KEY_JOY_MOVE_EDGE == HAL_KEY_FALLING_EDGE) HAL_KEY_JOY_MOVE_ICTL |= HAL_KEY_JOY_MOVE_EDGEBIT; #endif /* Interrupt configuration: * - Enable interrupt generation at the port * - Enable CPU interrupt * - Clear any pending interrupt */ HAL_KEY_JOY_MOVE_ICTL |= HAL_KEY_JOY_MOVE_ICTLBIT; HAL_KEY_JOY_MOVE_IEN |= HAL_KEY_JOY_MOVE_IENBIT; HAL_KEY_JOY_MOVE_PXIFG = ~(HAL_KEY_JOY_MOVE_BIT); /* Do this only after the hal_key is configured - to work with sleep stuff */ if (HalKeyConfigured == TRUE) { osal_stop_timerEx( Hal_TaskID, HAL_KEY_EVENT); /* Cancel polling if active */ } } else /* Interrupts NOT enabled */ { HAL_KEY_SW_6_ICTL &= ~(HAL_KEY_SW_6_ICTLBIT); /* don't generate interrupt */ HAL_KEY_SW_6_IEN &= ~(HAL_KEY_SW_6_IENBIT); /* Clear interrupt enable bit */ osal_start_timerEx (Hal_TaskID, HAL_KEY_EVENT, HAL_KEY_POLLING_VALUE); /* Kick off polling */ } /* Key now is configured */ HalKeyConfigured = TRUE; }
Hal_KeyIntEnable = interruptEnable;而interruptEnable的值等于宏HAL_KEY_INTERRUPT_DISABLE,默认是不采用外部中断方式,那也就是查询方式,可以通过选择不同的宏来控制采用哪种方式。
1
2
3/* Interrupt option - Enable or disable */ #define HAL_KEY_INTERRUPT_DISABLE 0x00 #define HAL_KEY_INTERRUPT_ENABLE 0x01
1
2/* Register the callback fucntion */ pHalKeyProcessFunction = cback;
1if (Hal_KeyIntEnable)
否则的话就清除中断配置,并产生一个HAL_KEY_EVENT事件
1
2
3
4
5
6
7else /* Interrupts NOT enabled */ { HAL_KEY_SW_6_ICTL &= ~(HAL_KEY_SW_6_ICTLBIT); /* don't generate interrupt */ HAL_KEY_SW_6_IEN &= ~(HAL_KEY_SW_6_IENBIT); /* Clear interrupt enable bit */ osal_start_timerEx (Hal_TaskID, HAL_KEY_EVENT, HAL_KEY_POLLING_VALUE); /* Kick off polling */ }
有事件产生就有相应的事件处理函数,如果对Zigbee事件机制不太理解的可以参考点击打开链接。
这个事件在hal_drivers.c文件里的Hal_ProcessEvent函数被处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16if (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( Hal_TaskID, HAL_KEY_EVENT, 100); } #endif // HAL_KEY return events ^ HAL_KEY_EVENT; }
如果Hal_KeyIntEnable == 0 即采用轮询方式就周期性设置这一事件,从而达成了一个循环调用的效果,轮询函数为HalKeyPoll(),可以看到轮询的事件大约是100ms。HalKeyPoll()函数会检查按键的状态以确定是否要按键状态的改变。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50void HalKeyPoll (void) { uint8 keys = 0; // if ((HAL_KEY_JOY_MOVE_PORT & HAL_KEY_JOY_MOVE_BIT)) /* Key is active HIGH */ //如果P2.0是高位 // { // keys = halGetJoyKeyInput(); // } /* If interrupts are not enabled, previous key status and current key status * are compared to find out if a key has changed status. */ if (!HAL_PUSH_BUTTON1()) //HAL_PUSH_BUTTON1() = !!(P0_1) { keys |= HAL_KEY_SW_6; } if (!HAL_PUSH_BUTTON2()) //HAL_PUSH_BUTTON2() = !!(P2_0) { keys |= HAL_KEY_SW_1; } if (!Hal_KeyIntEnable) { if (keys == halKeySavedKeys) { /* Exit - since no keys have changed */ return; } /* Store the current keys for comparation next time */ halKeySavedKeys = keys; } else { /* Key interrupt handled here */ } /* Invoke Callback if new keys were depressed */ if (keys && (pHalKeyProcessFunction)) { (pHalKeyProcessFunction) (keys, HAL_KEY_STATE_NORMAL); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19// if ((HAL_KEY_JOY_MOVE_PORT & HAL_KEY_JOY_MOVE_BIT)) /* Key is active HIGH */ //如果P2.0是高位 // { // keys = halGetJoyKeyInput(); // } /* If interrupts are not enabled, previous key status and current key status * are compared to find out if a key has changed status. */ if (!HAL_PUSH_BUTTON1()) //HAL_PUSH_BUTTON1() = !!(P0_1) { keys |= HAL_KEY_SW_6; } if (!HAL_PUSH_BUTTON2()) //HAL_PUSH_BUTTON2() = !!(P2_0) { keys |= HAL_KEY_SW_1; }
hal_key.c中HalKeyPoll()中的这一段是我私自更改的地方,由于我用的开发板的P0_1和P2_0是上拉状态,所以未按下时引脚是高电平,而协议栈默认是以高电平作为按键按下的状态,所以我的板子初始化之后就会自动识别为有按键按下,因此我改成了低电平时才认为有按键按下。同时,由于我的开发板无操纵杆,所以注销了操作杆的状态识别。
这里的按键是以位区分的,这样做的好处是可以将多个按键的触发事件按位存储到keys中,并通过位运算识别和增删。
1
2
3
4
5
6
7
8/* Switches (keys) */ #define HAL_KEY_SW_1 0x01 // Joystick up #define HAL_KEY_SW_2 0x02 // Joystick right #define HAL_KEY_SW_5 0x04 // Joystick center #define HAL_KEY_SW_4 0x08 // Joystick left #define HAL_KEY_SW_3 0x10 // Joystick down #define HAL_KEY_SW_6 0x20 // Button S1 if available #define HAL_KEY_SW_7 0x40 // Button S2 if available
1
2
3
4
5/* Invoke Callback if new keys were depressed */ if (keys && (pHalKeyProcessFunction)) { (pHalKeyProcessFunction) (keys, HAL_KEY_STATE_NORMAL); }
回调函数在当前文件中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37void OnBoard_KeyCallback ( uint8 keys, uint8 state ) { uint8 shift; (void)state; /* Get shift key status */ shift = ((keys & HAL_KEY_SW_6) ? true : false); if ( OnBoard_SendKeys( keys, shift ) != ZSuccess ) { // Process SW1 here if ( keys & HAL_KEY_SW_1 ) // Switch 1 { } // Process SW2 here if ( keys & HAL_KEY_SW_2 ) // Switch 2 { } // Process SW3 here if ( keys & HAL_KEY_SW_3 ) // Switch 3 { } // Process SW4 here if ( keys & HAL_KEY_SW_4 ) // Switch 4 { } // Process SW5 here if ( keys & HAL_KEY_SW_5 ) // Switch 5 { } // Process SW6 here if ( keys & HAL_KEY_SW_6 ) // Switch 6 { } } }
其重点是调用了OnBoard_SendKeys( keys, shift ),右键GO TO这个函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21uint8 OnBoard_SendKeys( uint8 keys, uint8 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 ); }
在这个函数中将按键触发状态key打包发送到应用层,并触发应用层事件处理函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events ) { afIncomingMSGPacket_t *MSGpkt; (void)task_id; if ( events & SYS_EVENT_MSG ) { MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID ); while ( MSGpkt ) { switch ( MSGpkt->hdr.event ) { case KEY_CHANGE: SampleApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys ); break;
然后就可以在应用层调用相应的事件处理函数来处理这个按键事件,而到底是哪个按键被按下,可以通过'&'操作来检查keys的位状态,哪一位为1就表示那一位对应的按键发生了改变。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27void SampleApp_HandleKeys( uint8 shift, uint8 keys ) { (void)shift; if ( keys & HAL_KEY_SW_6 ) { /* This key sends the Flash Command is sent to Group 1 * This device will not receive the Flash Command from this * device (even if it belongs to group 1) */ // SampleApp_SendFlashMessage( SAMPLEAPP_FLASH_DURATION ); HalLedSet( HAL_LED_1 , HAL_LED_MODE_TOGGLE ) ; zgWriteStartupOptions(ZG_STARTUP_SET, ZCD_STARTOPT_DEFAULT_NETWORK_STATE); SystemReset(); } if ( keys & HAL_KEY_SW_1 ) { /* The Flashr Command is sent to Group 1. * This key toggles this device in and out of group 1. * If this device doesn't belong to group 1, this application * will not receive the Flash command sent to group 1. */ } }
水平有限,如有差错,请不吝赐教!
最后
以上就是简单面包最近收集整理的关于Zigbee 按键机制的全部内容,更多相关Zigbee内容请搜索靠谱客的其他文章。
发表评论 取消回复