概述
我们上一期讲了如何使用ZigBee进行开关灯,我们是通过工程宏来区分我们的开关板和LED灯板的,我们其实是同一套代码的两个工程,使用的是基于BasicRF这个代码包,因为很多功能是不需要我们手写的,所以之前做了工程的移植,相信大家都成功了哈,我们使用到了:
uint8 basicRfInit(basicRfCfg_t* pRfConfig);
uint8 basicRfSendPacket(uint16 destAddr, uint8* pPayload, uint8 length);
uint8 basicRfPacketIsReady(void);
uint8 basicRfReceive(uint8* pRxData, uint8 len, int16* pRssi);
void basicRfReceiveOn(void);
这五个功能,都是BasicRF包里面的,我们拿来用就可以了,代码也很简单,第一个是初始化,第二个是发数据,第三个是判断是否准备好了接收数据,第四个是接收数据,第五个是接收数据的开关,我们一般都要打开;思路就是现将我们的basicRfCfg_t配置好,毕竟是初始化:
typedef struct {
uint16 myAddr;
uint16 panId;
uint8 channel;
uint8 ackRequest;
#ifdef SECURITY_CCM
uint8* securityKey;
uint8* securityNonce;
#endif
} basicRfCfg_t;
然后调用初始化函数和开启接收函数,根据工程宏来表写是发送还是接收,发送就调用发送函数,接收要先判断是否准备好了,然后调用接收函数,实现相应的功能;
这一期我们来讲解一下我们在收发数据是容易犯的错误:
1、时钟同步;
ZigBee通讯是需要数据同步的,所以我们需要接收板和发送板的系统时钟评率一致,当然我们可调用下面的函数来实现时钟同步:
static void SysClkInit(void)
{
//由16MHZ时钟切换到32MHZ时钟
CLKCONCMD &= ~0x40;
for(;CLKCONSTA & 0x40;);
CLKCONCMD &= ~0X7F;
}
2、内存溢出;
要注意,平时书写代码的时候数据类型一定不要写错了,如果运气好的话不会就触及到我们的通信地址,但是运气不好的话,就可能将内存地址给修改了,所以我们特别是在一些需要数据强转的时候,一定要考虑到这个问题,建议大家没事别爱强转数据类型:
len = basicRfReceive(TestRxBuf,sizeof(TestRxBuf),(unsigned short *)&pRssi);
这个是接收数据的函数,后面信号强度有一个强转,要注意,我们一定不要写其他类型,因为这里强转的是指针,所以我们写short型就可以了:
//定义一个强度
unsigned short pRssi = 0;
关于ZigBee的聊天室操作,其实前面学会的人就已经可以做出来了,无非就是在发送的时候使用串口来接收用户想要发送的信息,通过数组发送出去,在接受的时候在通过串口显示到屏幕上就可以了,那这一期我们就简单来做一下,当然在你们的板子上不一定可以实现,只是提供一个参考,一个思路:
1、我们要复制一下上一个工程了,因为这个功能不需要两个工程,一个就可以了:
再次声明一下,我这里只提供思路:
#include "LED.h"
#include "KEY.h"
#include "Timer.h"
#include "UART.h"
#include "ADC.h"
#include "basic_rf.h"
void KeyControlLedShow(unsigned char n)
{
if(n & 0x01)
{
LEDOn(1);
}
else
{
LEDOff(1);
}
if(n & 0x02)
{
LEDOn(2);
}
else
{
LEDOff(2);
}
if(n & 0x04)
{
LEDOn(3);
}
else
{
LEDOff(3);
}
if(n & 0x08)
{
LEDOn(4);
}
else
{ LEDOff(4);
}
}
void ShowNumber(void)
{
unsigned static char i = 0;
KeyControlLedShow(i++);
if(i > 15)
{
i = 0;
}
}
void TimeLed(void)
{
LEDToggle(0);
}
//创建一个存储单个数据的数组
static unsigned char TestTxBuf[255];
//3.2 创建一个拼接名字后的存储的数组
static unsigned char SwapBuf[] = "";
//创建一个接收数据的数组
static unsigned char TestRxBuf[255];
//3.4 创建一个滚动的位置用于数据接收判断
static unsigned char TestRxPos = 0;
unsigned char juge = 0;
//3.1 创建一个存储名字的数组
static unsigned char Myname[] = "";
//1.3定义一个需要发送数据的长度和采集数据的存储变量
unsigned char len = 0;
//3.3 设置名字
void setName(void)
{
UartSend("请填写名字",10);
while(1)
{
len = 0;
//控制其一个一个发以便于判断
len = UartRcv(TestRxBuf + TestRxPos,1);
if( len > sizeof(TestRxBuf) )
{
len = 0;
}
//4.2 接收数据
if(len > 0)
{
//从串口接收数据并且拷贝到Myname数组中
if(TestRxBuf[TestRxPos] == 'r')
{
memcpy(Myname,TestRxBuf,TestRxPos);
memcpy(SwapBuf,Myname,TestRxPos);
UartSend("名字设置成功!",14);
break;
}else{
TestRxPos += len;
}
}
}
}
void main(void)
{
//2.6 我们需要一个判断来确定按钮的状态
unsigned char switchstate = 0;
float ret = 0;
//定义一个强度
unsigned char pRssi = 0;
//1.1 通过传感器产生的数据,发送到pc端显示,
//2.3 定义通讯的结构体
basicRfCfg_t pRfConfig;
LEDInit();
KeyInit();
//KeyCallBackRegister(&ShowNumber);
// TimerInit();
// static unsigned long ledtime = 0;
// TimeSetCallBack(500,TimeLed,1);
UartInit(9600,'n');
// AdcInit();
pRfConfig.myAddr = 0x0001;
pRfConfig.panId = 0x1000;
pRfConfig.channel = 11;
pRfConfig.ackRequest = 1;
//2.1 初始化函数
basicRfInit(&pRfConfig);
//2.5 保持接收的打开
basicRfReceiveOn();
setName();
while(1)
{
len = 0;
//控制其一个一个发以便于判断
len = UartRcv(TestRxBuf + TestRxPos,1);
if( len > sizeof(TestRxBuf) )
{
len = 0;
}
//4.1 接收数据
if(len > 0)
{
if(TestRxBuf[TestRxPos] == 'r')
{
//将数组拷贝到带有名称的数组中
unsigned int length = sizeof(Myname);
memcpy(SwapBuf+length+TestRxPos,TestRxBuf,TestRxPos);
length = sizeof(SwapBuf);
basicRfSendPacket(0xffff,SwapBuf,length);
TestRxPos = 0;
}else{
TestRxPos += len;
}
}
//4.2 发送数据
// //2.8 判断是否收到数据
if(basicRfPacketIsReady())
{
//收到之后我们接收到数组中,然后判断亮灯
//接收函数的第三个参数是信号的强度
len = basicRfReceive(TestRxBuf,sizeof(TestRxBuf),(unsigned short *)&pRssi);
UartSend(TestRxBuf,len);
}
//#ifdef SWITCH
// //2.4 发送逻辑
// //每次按下按钮我们将switchstate取反
// if(Key1Getstate()|| Key2Getstate())
// {
// switchstate = !switchstate;
// }
// //将数据检测出来之后我们要存入数组
// TestTxBuf[0] = switchstate;
//
// //2.7 我们按照地址发送数据,一次第一个
// basicRfSendPacket(0x0002,TestTxBuf,1);
//#else
// //2.8 判断是否收到数据
// if(basicRfPacketIsReady())
// {
// //收到之后我们接收到数组中,然后判断亮灯
// //接收函数的第三个参数是信号的强度
// len = basicRfReceive(TestRxBuf,sizeof(TestRxBuf),(unsigned short *)&pRssi);
// if(TestRxBuf[0])
// {
// LEDOn(0);
// }
// else
// {
// LEDOff(0);
// }
// }
//#endif
// //1.2 我们利用定时器1s中采集一次显示即可
// if(TimerCheck(ledtime))
// {
// ledtime = TimerSet(1000);
// //1.5 通过adc模块拿到采集到的数据
// ret = AdcGetValue();
// //1.4 进行数据的格式化处理
// len = sprintf(TestBuf,"The value of ADC is %f",ret);
// UartSend((char *)TestBuf,len);
// }
/*Delay(2000);
len = UartRcv(TestBuf,1);
if(len > 0)
{
UartSend(TestBuf,len);
}
LEDToggle(i++);
Delay(100);
if(i > 4)
{
i = 1;
}
*/
}
}
其实还是和之前的代码差不多,只是我们就不需要宏定义了,我这里为了让大家更理解,就没有删除之前的代码,只是注释掉了,然后在上面写一个处理串口的函数;
2、我们一般会在要发的数据前面加一个昵称,所以我们写一个函数来初始化一下要发的数据,思路就是定义一个数据,现将在串口需要设置的昵称存起来,在将要发的数据存起来,然后在用一个大数组将两个存有数据和昵称的数组拼接起来,也就是memcp()这个函数发挥了关键作用,至于串口收发数据的函数直接使用之前的就可以:
void setName(void)
{
UartSend("请填写名字",10);
while(1)
{
len = 0;
//控制其一个一个发以便于判断
len = UartRcv(TestRxBuf + TestRxPos,1);
if( len > sizeof(TestRxBuf) )
{
len = 0;
}
//4.2 接收数据
if(len > 0)
{
//从串口接收数据并且拷贝到Myname数组中
if(TestRxBuf[TestRxPos] == 'r')
{
memcpy(Myname,TestRxBuf,TestRxPos);
memcpy(SwapBuf,Myname,TestRxPos);
UartSend("名字设置成功!",14);
break;
}else{
TestRxPos += len;
}
}
}
我们在启动时通过串口发送提示用户输入名字,然后等待进入死循环,当用户发送了名字之后我们将其存到数组里面,注意,是在敲了回车的数据后面,不然的话串口无法判断数据的结束;一旦检测到换行就证明数据发完退出并提示用户设置姓名成功,然后就可以开始发送信息了;
3、既然用到串口就肯定有串口初始化,所以我们不要忘了调用一下初始化函数,结构体里的数据的话就随意设置就好,但是不要设置一些太特殊的,而且注意范围,上一期我们讲过,当然也可以就照这样设置,当然,不止用到一块板,既然是通讯,肯定是不同的板子,不同板子的地址肯定也就不一样,但是信道要一样:
UartInit(9600,'n');
// AdcInit();
pRfConfig.myAddr = 0x0001;
pRfConfig.panId = 0x1000;
pRfConfig.channel = 11;
pRfConfig.ackRequest = 1;
//2.1 初始化函数
basicRfInit(&pRfConfig);
//2.5 保持接收的打开
basicRfReceiveOn();
setName();
while(1)
{
len = 0;
//控制其一个一个发以便于判断
len = UartRcv(TestRxBuf + TestRxPos,1);
if( len > sizeof(TestRxBuf) )
{
len = 0;
}
//4.1 接收数据
if(len > 0)
{
if(TestRxBuf[TestRxPos] == 'r')
{
//将数组拷贝到带有名称的数组中
unsigned int length = sizeof(Myname);
memcpy(SwapBuf+length+TestRxPos,TestRxBuf,TestRxPos);
length = sizeof(SwapBuf);
basicRfSendPacket(0xffff,SwapBuf,length);
TestRxPos = 0;
}else{
TestRxPos += len;
}
}
//4.2 发送数据
// //2.8 判断是否收到数据
if(basicRfPacketIsReady())
{
//收到之后我们接收到数组中,然后判断亮灯
//接收函数的第三个参数是信号的强度
len = basicRfReceive(TestRxBuf,sizeof(TestRxBuf),(unsigned short *)&pRssi);
UartSend(TestRxBuf,len);
}
然后接收串口收到的数据,将其和我们的姓名考到一个数组里发出去就可以了,这里用到了一个指示当前位置的变量,比较重要,因为我们要判断是么时候收完,拼接好数组之后无线发送出去就可以,然后就是接收数据,直接接在后面写就可以,毕竟一块板子要发还要接,接收就更简单,判断一些接收准备,然后直接收,收到之后发给串口显示就行;
好了,那么这一期,就到这,只是提供一个思路,咱下一期在做详细讲解;
最后
以上就是热情硬币为你收集整理的cc2530:<6>ZigBee通讯的易错点和实现无线聊天室的全部内容,希望文章能够帮你解决cc2530:<6>ZigBee通讯的易错点和实现无线聊天室所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复