今天搞定了zigbee的第一个入门级的led无线控制,针对z-stack协议栈的组网暂时还没搞明白,最起码也算是第一次把无线的芯片玩了起来,现在我把总结下.
此次的这个实验并不是完整的基于zigbee协议栈的,而是仅仅其中的一小块实现的点对点的通信, 基于Basic RF的,我们实验的效果就是一个节点可以去控制另外一个节点的led开关.
环境要求
1:CC2530模块:我的板子是在淘宝随便买的,具体哪家的也不说了,总之市面上的基于CC2530芯片的大多数板子都跟TI兼容的,否则也不会去卖的.其实买哪家都一样,只要能用就行了,不过个人感觉最好是有完善点的售后最好,比如卖家会送你点教程或者什么之类的,不像我全部都是一个人瞎摸索过来的;
2:电脑要安装z-stack的开发工具包以及开发zigbee比较不错的一个IDE工具:IAR Embedded,也就是:EW8051-751A这个软件.这两个软件都是傻瓜式的安装,直接全部默认安装即可,不过如果自己选择路径最好不要出现中文路径,否则后面遇到莫名其妙的问题,难解决.我把这两个软件的下载地址在本文的最后都会给贴出来,大家可以自行下载.
3:操作系统,xp,windows 7都可以的,我用的是windows 7的.
4:cc2530板子的usb转串载驱动以及ccdebug的驱动,这个卖家应该会提供,本人就不做什么补充了,自行解决即可.不过我还是附上一份比较不错的文档,大家可以参考去下文档里的产品的环境搭建.
好了,下面我们可以开始来做实验了,首先我们的代码要从TI公司的官网下载,找到CC2530-Software Examples,下载地址:http://www.ti.com/cn/litv/zip/swrc135b,本文最后我也提供此份代码的下载地址.
下载解压之后,里面有三个文件夹docs, ide, source,docs目录下的文档是非常重要的一份文档,看完之后会对整个通信过程有个非常准确的了解, ide目录里面是本代码提供的3个例子,一个是led无线控制,一个是通信质量包测试,最后一个是频谱分析.source目录里面是ide项目里面所需的源代码文件.整体目录结构如下:
docs目录里的收获
首先我们来看docs目录里面的pdf:CC2530_Software_Examples.pdf,这份文档我们针对lightSwitch进行讲解.
pdf的前2个章节,没有什么太多的,主要是一个概述,还有一些词语的简写等等.
第三章颇为重要,第三章列出的步骤,正好是开发zigbee的步骤,如果不会的话,赶紧看看,抓紧巩固下,步骤主要有如下:
建立开发环境:
1:安装IAR Embedded开发软件,支持cc2530的开发;
2:下载CC2530的示例代码(我们已经在上边提到过了);
3:把cc2530的模块放到cc2530的控制主板,或者电池板也行,不过最好是控制主板;
4:用USB连接cc2530控制主板与电脑,这个过程中的驱动需要提前安装好的哦,上文我提过了;
使用IAR编程开发:
5:打开IAR workbench;
6:使用IAR打开我们下载的源码目录里面的ide目录里面的文件,操作办法是直接双击打开或者在IAR里面选择"file->open->workspace",选择:cc2530_sw_examples.eww打开这个项目.打开之后,我们发现里面包含的是三个例子,我们只需要lightSwitch.我们workspace下选择cc2530即可,如下图:
或者我们也可以进入iar目录下的srf05_cc2530\iar目录,找到light_switch.eww直接打开即可,这样子就只有light_switch cc2530的项目了;
7:假如我们代码编辑好了,那么便可直接选择菜单"Project->Rebuild Al"来编译,或者点击IAR右上角的make按钮;
8:编译完成之后,我们便可以通过cc debug来进行烧写到cc 2530模块上了,连接cc debug跟cc2530模块,注意ccdebug的驱动要提前安装好的;
9:连接好cc debug之后,就可以开始下载固件了,选择:"Project->Debug"直接烧写到板子上,然后在调试界面点击Stop Debugging即可完成烧写;
如上的7-9步骤可为如下图所示:
其中过程如下:1:make;2:debug;3:go;4:stop debugging
10:调试板子.
如上便是开发zigbee的过程,如果不熟悉的可以多练习下.
第四章的话,便是对示例的一些讲解,我们只讲Light/Switch例子.
light switch的例子演示的是一个模块A作为控制端,一个模块B作为受控端,通过A可以控制B的led开关.操作的过程就是两个模块各自上电,然后控制端A点击按键然后模块B即可看到led被A端控制打开或者关闭led.
我们的例子是没有带任何的加密协议的,其中Basic RF是支持CCM加密的,只不过我们没有用到.这个地方可以参考pdf的讲解以及设置.
那么这些例子是基于一种什么样的架构呢?在第五章文档详细给我们讲解了整个框架的结构,如下图:
由上图我们可知道整个软件分为了三层,有如下:
Application Layer:主要是提供一些程序来调用Basic RF以及HAL的函数等等;
Basic RF:这一层是一个协议层,提供了简单的传输以及接收这两种方式一个协议;
HAL:这一层是硬件抽象层,主要是一些液晶显示器,按键,时钟等等的一些设置,类似驱动层.
对于我们写过单片机程序的人来说,按键驱动或者lcd驱动等等的都是小case了,那么在这个无线控制中最重要的莫过于:Basic RF的协议了,那么这个协议是如何来工作的呢?下面文档便详细的讲解了:
首先是这个Basic RF有个非常重要的结构体,那就是:basicRfCfg_t,他的结构如下:
typedef struct { uint16 myAddr; //16位的节点地址 uint16 panId; //网络中的操作该节点的id uint8 channel; //RF Channel(必须在11~26) uint8 ackRequest; //如果设置为true的话会接收目的节点的反馈信息 #ifdef SECURITY_CCM //如果定义了加密 uint8* securityKey; uint8* securityNonce; #endif } basicRfCfg_t;
还有一些相关的函数,也在pdf里面定义了,这里限于篇幅就不再讲解.
紧接着就是Basic RF的操作流程了
1:初始化
2:发送数据
3:接收数据
上面三个图描述了Basic RF工作的过程,具体的部分可以从pdf里面细读过程.pdf剩下都就是HAL RF的一些API函数,看看大致了解下.
ide目录下的收获
下面我们就开始着手看代码分析代码来做实验了.打开ide\srf05_cc2530\iar目录下的:light_switch.eww
打开项目之后,根据经验,看代码从main函数开始,main函数在:application目录下的light_switch.c文件中,我们看到main函数里面的初始化正是上面Basic RF的初始化过程,然后我们根据自己的开发板来修改main函数的代码,下面我将把根据我cc2530模块更改的代码贴上:
main函数这块需要改:
void main(void)
{
uint8 appMode = NONE;
// Config basicRF
basicRfConfig.panId = PAN_ID;
basicRfConfig.channel = RF_CHANNEL;
basicRfConfig.ackRequest = TRUE;
#ifdef SECURITY_CCM
basicRfConfig.securityKey = key;
#endif
// Initalise board peripherals
halBoardInit();
halJoystickInit();
// Initalise hal_rf
if(halRfInit()==FAILED) {
HAL_ASSERT(FALSE);
}
// Indicate that device is powered
// 根据开发板的实际情况,红色的led灯为P1_1端口,所以,halLedSet(2),这样初始化都是熄灭的;
halLedSet(2);
// 根据开发板的实际情况,蓝色的led灯为P1_0端口,所以,halLedClear(1),这样初始化蓝灯是亮着的;
halLedClear(1);
// Print Logo and splash screen on LCD
//utilPrintLogo("Light Switch");
// Wait for user to press S1 to enter menu
//while (halButtonPushed()!=HAL_BUTTON_1);
//halMcuWaitMs(350);
//halLcdClear();
// Set application role
//appMode = appSelectMode();
//halLcdClear();
// Transmitter application
//if(appMode == SWITCH) {
// No return from here
appSwitch(); //如果是控制端,用这一行代码
//}
// Receiver application
//else if(appMode == LIGHT) {
// No return from here
//appLight();//如果是受控端,用这一行代码
//}
// Role is undefined. This code should not be reached
HAL_ASSERT(FALSE);
}
代码红色部分为修改的部分,大家可以根据源文件进行比对,根据我的开发板实际情况,没有lcd,那就把lcd相关的代码全部注释掉,然后开发板启动的时候只需要点亮蓝灯即可.那么我们可以针对
halLedSet(2);
进行分析:
这个halLedSet(2);函数在源代码可以看到原型如下,这个文件是:source/components/targets/srf05_soc/Hal_led.c:
void halLedSet(uint8 id) { switch (id) { case 1: HAL_LED_SET_1(); break; case 2: HAL_LED_SET_2(); break; case 3: HAL_LED_SET_3(); break; case 4: HAL_LED_SET_4(); led4State=1; break; default: break; } }
其中HAL_LED_SET_1(),HAL_LED_SET_2()这些函数定义在:source/components/targets/srf05_soc/Hal_board.h:
// SmartRF05EB rev 1.7 and later has four LEDs available #define HAL_LED_SET_1() MCU_IO_SET_HIGH(HAL_BOARD_IO_LED_1_PORT, HAL_BOARD_IO_LED_1_PIN) #define HAL_LED_SET_2() MCU_IO_SET_HIGH(HAL_BOARD_IO_LED_2_PORT, HAL_BOARD_IO_LED_2_PIN) #define HAL_LED_SET_3() MCU_IO_SET_HIGH(HAL_BOARD_IO_LED_3_PORT, HAL_BOARD_IO_LED_3_PIN) #define HAL_LED_SET_4() MCU_IO_SET_HIGH(HAL_BOARD_IO_LED_4_PORT, HAL_BOARD_IO_LED_4_PIN) ......
如上代码中的MCU_IO_SET_HIGH(HAL_BOARD_IO_LED_1_PORT, HAL_BOARD_IO_LED_1_PIN)原型在:source/components/common/cc8051/Hal_cc8051.h:
#define MCU_IO_SET_HIGH(port, pin) MCU_IO_SET_HIGH_PREP(port, pin)
然后我们看下这个MCU_IO_SET_HIGH_PREP(port, pin)函数做了些什么,原型在:source/components/common/cc8051/Hal_cc8051.h:
#define MCU_IO_SET_HIGH_PREP(port, pin) st( P##port##_##pin## = 1; )
说到底就是给IO口一个高电平,在我的开发板也就是让红灯熄灭了,分析
halLedClear(1);
一样的道理,是给蓝灯的IO口低电平,这样蓝灯就点亮了.
appLight()函数也要改
static void appLight()
{
//halLcdWriteLine(HAL_LCD_LINE_1, "Light");
//halLcdWriteLine(HAL_LCD_LINE_2, "Ready");
#ifdef ASSY_EXP4618_CC2420
halLcdClearLine(1);
halLcdWriteSymbol(HAL_LCD_SYMBOL_RX, 1);
#endif
// Initialize BasicRF
basicRfConfig.myAddr = LIGHT_ADDR;
if(basicRfInit(&basicRfConfig)==FAILED) {
HAL_ASSERT(FALSE);
}
basicRfReceiveOn();
// Main loop
while (TRUE) {
while(!basicRfPacketIsReady());
if(basicRfReceive(pRxData, APP_PAYLOAD_LENGTH, NULL)>0) {
if(pRxData[0] == LIGHT_TOGGLE_CMD) {
halLedToggle(1);
}
}
}
}
halLedToggle(1);函数,这个函数与第一点中的halLedSet(1)大同小异,这个就是设置led点亮,或者熄灭,可以跟踪下代码,了解halLedToggle(1);函数的作用.
appSwitch()函数也要改
static void appSwitch()
{
//halLcdWriteLine(HAL_LCD_LINE_1, "Switch");
//halLcdWriteLine(HAL_LCD_LINE_2, "Joystick Push");
//halLcdWriteLine(HAL_LCD_LINE_3, "Send Command");
#ifdef ASSY_EXP4618_CC2420
halLcdClearLine(1);
halLcdWriteSymbol(HAL_LCD_SYMBOL_TX, 1);
#endif
pTxData[0] = LIGHT_TOGGLE_CMD;
// Initialize BasicRF
basicRfConfig.myAddr = SWITCH_ADDR;
if(basicRfInit(&basicRfConfig)==FAILED) {
HAL_ASSERT(FALSE);
}
// Keep Receiver off when not needed to save power
basicRfReceiveOff();
// Main loop
while (TRUE) {
//查看hal_button.c可以判断当前cc2530MB的K1为P01端口
if( halButtonPushed() == HAL_BUTTON_1 ) {
basicRfSendPacket(LIGHT_ADDR, pTxData, APP_PAYLOAD_LENGTH);
// Put MCU to sleep. It will wake up on joystick interrupt
halIntOff();
halMcuSetLowPowerMode(HAL_MCU_LPM_3); // Will turn on global
// interrupt enable
halIntOn();
}
}
}
红色代码部分之前是:halJoystickPushed()函数,这个根据自己的板子来写对应的按键检测,我们改为halButtonPushed()函数,这个函数也由hal_button.c里面定义了,HAL_BUTTON_1是对应板子的按键IO口
整个过程的原理是:
控制端:如果检测到有按钮按下,那就发送数据;
受控端:如果检测有数据来,那就接收数据,改变led的灯开关状态.
烧写注意:如果是控制端的话,烧写的时候,在main函数里面是appSwitch();如果是受控端的话,在main函数里面是appLight();
附上资源下载链接:
IAR Embedded软件下载地址:http://sdrv.ms/10RB54N
ZStack-CC2530-2.3.1-1.4.0下载地址:http://sdrv.ms/10RB1SG
本文例子代码:http://sdrv.ms/VjCcYM
文章的脚注信息由WordPress的wp-posturl插件自动生成
2018年03月11日 下午 12:36 沙发
您好,请问能提供一下ew的下载方式吗?在官网下载的是最新版10.1,似乎不能支持cc2530