对于手上拥有一个2530开发板的Zstack初学者来说,最经常做的事情也许就是按下开发板上的某个按键,进行绑定或者远程控制另一个开发板上的LED的亮灭。自然而然地,大家都想知道这个过程是如何实现的,协议栈的按键处理函数在哪里,如果想自己设计开发板,假如按键接口和2530标准开发板不一样的话,又应当修改哪些参数才能保证按键能够起作用,这里我就来详细地解释一下。 按键的配置是在hal_key.c里实现的,在文件的顶端,我们能够找到如下的预编译内容: /* SW_6 is at P0.1 */ #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
/* edge interrupt */ #define HAL_KEY_SW_6_EDGEBIT BV(0) #define HAL_KEY_SW_6_EDGE HAL_KEY_FALLING_EDGE
/* SW_6 interrupts */ #define HAL_KEY_SW_6_IEN IEN1 /* CPU interrupt mask register */ #define HAL_KEY_SW_6_IENBIT BV(5) /* Mask bit for all of Port_0 */ #define HAL_KEY_SW_6_ICTL P0IEN /* Port Interrupt Control register */ #define HAL_KEY_SW_6_ICTLBIT BV(1) /* P0IEN - P0.1 enable/disable bit */ #define HAL_KEY_SW_6_PXIFG P0IFG /* Interrupt flag at source */
对于具备大学英语水平的同学们来说,这些语句的含义并不难理解。这里是说Zstack协议栈的SW6按键被分配到了P0.1端口,下面所有的这些预编译内容都是为了保证按键被按下时,程序能够检测到并进行正确处理。我们看到这里的预编译内容涉及到了大量的寄存器,大家要适应Zstack的这一编码方式,习惯冗长的预编译命名(对于经常编写VC等高级语言代码的同学来说这也许并不算什么)。 好的,心急的同学也许已经迫不及待地想要开始修改了,我这里就列出我自己修改的将SW6分配到P0.7的配置代码: /* SW_6 is at P0.7 */ #define HAL_KEY_SW_6_PORT P0 #define HAL_KEY_SW_6_BIT BV(7) #define HAL_KEY_SW_6_SEL P0SEL #define HAL_KEY_SW_6_DIR P0DIR
/* edge interrupt */ #define HAL_KEY_SW_6_EDGEBIT BV(0) #define HAL_KEY_SW_6_EDGE HAL_KEY_FALLING_EDGE
/* SW_2 interrupts */ #define HAL_KEY_SW_6_IEN IEN1 /* CPU interrupt mask register */ #define HAL_KEY_SW_6_IENBIT BV(5) /* Mask bit for all of Port_0 */ #define HAL_KEY_SW_6_ICTL P0IEN /* Port Interrupt Control register */ #define HAL_KEY_SW_6_ICTLBIT BV(7) /* P0IEN - P0.6 enable/disable bit */ #define HAL_KEY_SW_6_PXIFG P0IFG /* Interrupt flag at source */ 如果对于以上配置有什么不很理解的地方我建议大家多去看看CC2530的说明文档,仔细理解每一个寄存器所起到的作用。对于嵌入式软件工程师来说,说明文档永远是最得力的帮手。 OK,在完成了以上配置之后,下面要关注的应该就是按键处理函数了,那么这个函数在哪呢?这里我们以Zstack协议栈的SampleSwitch工程为例,有一个文件我们要特别注意,这就是zcl_samplesw.c。这是应用层的源文件,对于广大Zstack协议栈开发者来说,以后对协议栈的修改很大一部分都是在这个文件中进行的。在这个文件中,找到这个函数: static void zclSampleSw_HandleKeys( byte shift, byte keys ) { zAddrType_t dstAddr; (void)shift; // Intentionally unreferenced parameter
if ( keys & HAL_KEY_SW_1 ) { // Using this as the "Light Switch" #ifdef ZCL_ON_OFF zclGeneral_SendOnOff_CmdToggle( SAMPLESW_ENDPOINT, &zclSampleSw_DstAddr, false, 0 ); #endif }
if ( keys & HAL_KEY_SW_2 ) { HalLedSet ( HAL_LED_4, HAL_LED_MODE_OFF );
// Initiate an End Device Bind Request, this bind request will // only use a cluster list that is important to binding. dstAddr.addrMode = afAddr16Bit; dstAddr.addr.shortAddr = 0; // Coordinator makes the match ZDP_EndDeviceBindReq( &dstAddr, NLME_GetShortAddr(), SAMPLESW_ENDPOINT, ZCL_HA_PROFILE_ID, 0, NULL, // No incoming clusters to bind ZCLSAMPLESW_BINDINGLIST, bindingOutClusters, TRUE ); }
if ( keys & HAL_KEY_SW_3 ) { }
if ( keys & HAL_KEY_SW_4 ) { HalLedSet ( HAL_LED_4, HAL_LED_MODE_OFF );
// Initiate a Match Description Request (Service Discovery) dstAddr.addrMode = AddrBroadcast; dstAddr.addr.shortAddr = NWK_BROADCAST_SHORTADDR; ZDP_MatchDescReq( &dstAddr, NWK_BROADCAST_SHORTADDR, ZCL_HA_PROFILE_ID, ZCLSAMPLESW_BINDINGLIST, bindingOutClusters, 0, NULL, // No incoming clusters to bind FALSE ); } } 聪明的同学一看就明白了,哦,原来如此简单啊,那我是不是只要这么添加就成了: if ( keys & HAL_KEY_SW_6 ) { 处理函数… } 没有错,杀人越货居家旅行必备的天下第一奇毒秘密配方已尽收你眼底了,哈哈。OK,修改之后编译下载,大功告成,按下按键,等待见证奇迹的时刻。咦,咋什么反应都没??? 呵呵,是不是有种想要砸电脑的感觉,Zstack协议栈确实相当令人各种厌烦,除了以上的配置,还有两个要注意的地方。在hal_board_cfg.h文件中,有下面两句预编译语句: /* S1 */ #define PUSH1_BV BV(1) #define PUSH1_SBIT P0_1 这时你心想,这不是S1么,跟S6有毛的关系啊!咦,不对啊,Zstack默认的的SW6不是对应着P0.1么,怎么这里的S1也关联到P0.1去了。呵呵,这个其实是TI的不对了,确实这里的S1和刚才的SW6是一回事,就让我们尽情地对着TI的协议栈送上各种“美好的”问候词吧。在hal_key.c中,也可以看到: if (HAL_PUSH_BUTTON1()) { keys |= HAL_KEY_SW_6; } 是不是憋不住想骂人了,淡定淡定。我们把hal_board_cfg.h中的那两个预编译代码进行相应的修改: /* S1 */ #define PUSH1_BV BV(7) #define PUSH1_SBIT P0_7 编译下载,按下按键,此刻,屏幕缓缓变黑,最后留下一行颇有深意的文字:To be continued… 影迷们请尽情期待13年悬疑大剧的下一集。 |