我是靠谱客的博主 热情硬币,最近开发中收集的这篇文章主要介绍cc2530:<6>ZigBee通讯的易错点和实现无线聊天室,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

我们上一期讲了如何使用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通讯的易错点和实现无线聊天室所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(51)

评论列表共有 0 条评论

立即
投稿
返回
顶部