查看: 10637|回复: 8

基于zigbee_Basic RF的led无线控制

[复制链接]
345161974 发表于 2013-1-23 22:38:27 | 显示全部楼层 |阅读模式
今天搞定了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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
bhm429462286 发表于 2013-3-19 20:51:54 | 显示全部楼层
这个例程与协议栈的模板为什么不一样。。新手求教
笨笨 发表于 2013-3-22 16:46:14 | 显示全部楼层
很好的文章,但是我还是不知道怎么把按键定义在p1.3,1.4,led定义在p1.2,求解~~求代码~~~~~~~~~~~~
x0star 发表于 2013-4-1 15:09:36 | 显示全部楼层
受益不少~O(∩_∩)O谢谢分享
yfj2010815 发表于 2013-4-11 16:17:02 | 显示全部楼层
笨笨 发表于 2013-3-22 16:46
很好的文章,但是我还是不知道怎么把按键定义在p1.3,1.4,led定义在p1.2,求解~~求代码~~~~~~~~~~~~

在HALBOARD.H文件中找到下面的程序:

// LEDs
#define HAL_BOARD_IO_LED_1_PORT        1   // 表示p1.0为Led1,port指那个端口,pin指该端口的哪个引脚
#define HAL_BOARD_IO_LED_1_PIN         0
#define HAL_BOARD_IO_LED_2_PORT        1   
#define HAL_BOARD_IO_LED_2_PIN         1
#define HAL_BOARD_IO_LED_3_PORT        1  
#define HAL_BOARD_IO_LED_3_PIN         4
#define HAL_BOARD_IO_LED_4_PORT        0
#define HAL_BOARD_IO_LED_4_PIN         1


// Buttons
#define HAL_BOARD_IO_BTN_1_PORT        0   // 按键连接p0.1
//#define HAL_BOARD_IO_BTN_1_PIN         1
#define HAL_BOARD_IO_BTN_1_PIN         4

basicrf还未真正用到协议栈,如果有其他协议栈的相关问题可以看链接的文章,http://www.docin.com/d-499785.html,里面有几篇文章将协议栈。
不知道上面的回答能否帮到你?
Jason_buaa 发表于 2013-4-15 16:46:10 | 显示全部楼层
学习学习
Jason_buaa 发表于 2013-4-15 16:59:52 | 显示全部楼层
多谢,我的板子终于工作起来了{:soso_e181:}
liuzhen3707 发表于 2014-10-1 20:16:36 | 显示全部楼层
为什么我按照流程坐下来,没有反应呢。
liuzhen3707 发表于 2014-10-5 15:56:05 | 显示全部楼层
休息两天回来,弄好了。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表