7天快速入门Zigbee:串口透传数据

7天快速入门Zigbee:串口透传数据



1. 概述

  这篇文章主要是想让大家了解如何配置Z-Stack中串口功能的参数,如何开启串口功能,如何使用串口发送和接收功能,最后实现我们要的串口透传功能。

2. 配置串口参数,开启串口功能

  在Z-Stack中我们可以直接调用API接口来开启设备的串口功能,此API接口函数为“uint8 HalUARTOpen(uint8 port, halUARTCfg_t *config)”。我们先来看看这个函数的形参,形参“port”表示要开启的串口号,CC2530有两个串口,串口0和串口1,这个看个人硬件所用的串口来选择开启哪个串口。形参“config”里包含了这个串口的使用参数,详情如下:

typedef struct
{
  bool                  configured;
  uint8                 baudRate;
  bool                  flowControl;
  uint16                flowControlThreshold;
  uint8                 idleTimeout;
  halUARTBufControl_t   rx;
  halUARTBufControl_t   tx;
  bool                  intEnable;
  uint32                rxChRvdTime;
  halUARTCBack_t        callBackFunc;
}halUARTCfg_t;

要自己配置的参数如下:
configured

  调用“HalUARTOpen()”函数时会自动将“.configured”参数置为TRUE;若“.configured”=TURE,再调用“HalUARTOpen()”函数打开同一个串口时,则会自动清除串口的RX、TX缓存和串口配置“uartRecord”再重新配置。此处我们设置为TRUE。

baudRate

  串口的波特率。有“HAL_UART_BR_9600”、“HAL_UART_BR_19200”、“HAL_UART_BR_38400”、“HAL_UART_
BR_115200
”可选。此处我们设置为“HAL_UART_BR_9600”波特率。

flowControl

  硬件流控制,TRUE为开启硬件流控,FALSE为关闭硬件流控。有硬件流控功能的可以开启硬件流控,此处我们设置为FALSE,关闭硬件流控功能。

flowControlThreshold

  此参数表示RX缓存达到“maxRxBufSize”之前还有多少字节空余。当RX缓存到达“maxRxBufSizeflowControlThreshold”时,会触发相应的应用事件:“HAL_UART_RX_ABOUT_FULL”。此处我们设置为64,一般设置为“maxRxBufSize”的一半。

扫描二维码关注公众号,回复: 2419661 查看本文章

idleTimeout

  如果设备串口收到数据之后在“idleTimout”时间内RX没有收到新的数据了,将会触发相应的事件“HAL_UART_RX_TIMEOUT”,这时应用程序可以选择读出所有RX的值或者一部分的值,单位:毫秒。此处我们设置为6ms,当串口收到数据后,6ms内没有再收到新的数据,则触发“HAL_UART_RX_ABOUT_FULL”事件。

rx.maxBufSize

  rx包含“halUARTBufControl_t”数据结构,用于操作RX 缓冲区。当接收的字节数到达“rx.maxBufSize”时,会产生“HAL_UART_RX_FULL”事件。此处我们设置为128个字节

intEnable

  串口中断使能,TRUE为使能串口中断功能,FALSE为失能串口中断功能。此处我们设置为TRUE,使能串口中断功能。

callBackFunc

  回调函数,应用程序可以根据RX、TX出发的不同事件进行处理。此处会指向我们自己的串口事件处理函数“Handle_UartEvent()”。

配置串口参数,开启串口0。代码如下:
———————————————————————– Gateway.c ———————————————————————–

void Gateway_Init( uint8 task_id )
{
  halUARTCfg_t uartconf;
  ……
  // 配置串口
  uartconf.baudRate = HAL_UART_BR_115200;
  uartconf.callBackFunc = Handle_UartEvent;
  uartconf.configured = TRUE;
  uartconf.flowControl = FALSE;

  uartconf.flowControlThreshold = 64;
  uartconf.idleTimeout = 6;             // 6ms后串口空闲则发送串口空闲事件,参数不可设为0
  uartconf.rx.maxBufSize = 128;
  uartconf.tx.maxBufSize = 128;
  uartconf.intEnable = TRUE;

  // 开启串口0
  HalUARTOpen(HAL_UART_PORT_0, &uartconf);
  ……
}

3. 串口发送和接收功能

  串口发送数据就只需要调用“uint16 HalUARTWrite(uint8 port, uint8 *buf, uint16 len)”接口,形参“port”可选择串口0或串口1,开启了哪个串口就用哪个串口;形参“buf”为要发送的数据;形参“len”为要发送数据的长度,一次性最多只能发送“HAL_UART_DMA_TX_MAX”个字节的数据,协议栈中“HAL_UART_DMA_TX_MAX”的默认值为256。
  串口接收数据需要通过上面我们注册的回调函数“Handle_UartEvent”来处理串口事件。关于接收数据的串口事件只有三个:HAL_UART_RX_FULLHAL_UART_RX_ABOUT_FULLHAL_UART_RX_TIMEOUT
HAL_UART_RX_FULL:当RX缓存数据的字节数到达“rx.maxBufSize”时,会产生“HAL_UART_RX_FULL”事件。
HAL_UART_RX_ABOUT_FULL:当RX缓存数据的字节数到达“maxRxBufSizeflowControlThreshold”时,会产生“HAL_UART_RX_ABOUT_FULL”事件。
HAL_UART_RX_TIMEOUT:如果设备串口收到数据之后在“idleTimout”时间内串口没有收到新的数据了,会产生“HAL_UART_RX_TIMEOUT”事件。
  下面我们会在具体实现串口透传功能时应用串口发送和接收功能。

4. 串口透传功能

  串口透传功能具体为终端设备接收到PC端通过串口发送过来的数据,然后将数据发送至协调器端,协调器端接收到数据后再通过串口将数据发送至PC端。
这里写图片描述
  以下代码是基于上篇文章《7天快速入门Zigbee:无线传输与接收》代码的基础上编程的。

4.1. 终端节点编程

  要使用自己的串口功能,则必须确保关闭了Z-Stack内部的串口功能,不然两者会产生冲突,串口会出现不可预期的数据。要关闭Z-Stack内部的串口功能,我们只需要屏蔽以下几个预编译即可。
这里写图片描述
屏蔽掉Z-Stack默认开启的MT_TASKMT_SYS_FUNCMT_ZDO_FUNC
———————————————————————– Gateway.c ———————————————————————–
去掉与本项目无关的初始化,在自己的任务初始化函数当中配置串口参数,开启串口0功能。

void Gateway_Init( uint8 task_id )
{
  halUARTCfg_t uartconf;
  g_gateway_taskid = task_id;
  // 填充端口描述符
  g_gateway_epdesc.endPoint = GATEWAY_ENDPOINT;
  g_gateway_epdesc.task_id = &g_gateway_taskid;
  g_gateway_epdesc.simpleDesc = (SimpleDescriptionFormat_t *)&g_gateway_simpledesc;
  g_gateway_epdesc.latencyReq = noLatencyReqs;
  // 注册该端口
  afRegister(&g_gateway_epdesc);

  /* 新添加代码 START */
  // 配置串口参数
  uartconf.baudRate = HAL_UART_BR_115200;
  uartconf.callBackFunc = Handle_UartEvent;
  uartconf.configured = TRUE;
  uartconf.flowControl = FALSE;
  uartconf.flowControlThreshold = 64;
  uartconf.idleTimeout = 6;             // 6ms后串口空闲则发送串口空闲事件,参数不可设为0
  uartconf.rx.maxBufSize = 128;
  uartconf.tx.maxBufSize = 128;
  uartconf.intEnable = TRUE;
  // 开启串口0
  HalUARTOpen(HAL_UART_PORT_0, &uartconf);
/* 新添加代码 END */

  // 初始化LED灯
//  Init_IndicatorLight();
  // 通知g_gateway_taskid任务有LED灯闪烁事件发生
//  osal_set_event(g_gateway_taskid, EVENT_FLASH_LED);  // 关掉上一篇文章的LED灯闪烁功能
  // 开始定期发送数据给协调器
//  osal_set_event(g_gateway_taskid, EVENT_PERIOD_SEND_DATA);
}

创建串口事件处理回调函数。

static void Handle_UartEvent(uint8 port, uint8 event)
{
  // 处理串口0接收事件
  if(port==HAL_UART_PORT_0)
  {
    switch(event)
    {
      // 当发生 RX 事件
      case HAL_UART_RX_FULL:
      case HAL_UART_RX_ABOUT_FULL:
      case HAL_UART_RX_TIMEOUT:
      {
        // 读取接收数据的长度
        uint16 rxbuflen = Hal_UART_RxBufLen(HAL_UART_PORT_0);
        // 创建接收数据内存
        uint8* rxbuf = osal_mem_alloc(rxbuflen);
        // 若内存创建成功
        if(rxbuf!=NULL)
        {
          // 读取 RX 数据
          HalUARTRead(HAL_UART_PORT_0, rxbuf, rxbuflen);
          // 直接透传给协调器
          SendMessageToCoor(rxbuf, rxbuflen);
          // 释放内存
          osal_mem_free(rxbuf);
        }
      }
      break;

      default:
        break;
    }
  }
}

创建数据无线发送函数,发送数据到协调器中。

static void SendMessageToCoor(uint8* data, uint16 datalen)
{
  // 目标地址为协调器
  afAddrType_t CoorAddr = {0};
  CoorAddr.addrMode = (afAddrMode_t)Addr16Bit;
  CoorAddr.addr.shortAddr = 0x00;
  CoorAddr.endPoint = GATEWAY_ENDPOINT;

  // 发送数据到协调器
  AF_DataRequest(&CoorAddr, &g_gateway_epdesc,
                    TRANSMISSION_CLUSTERID, datalen, data,
                      &g_transid, AF_DISCV_ROUTE, AF_DEFAULT_RADIUS);
}

4.2. 协调器编程

  要使用自己的串口功能,则必须确保关闭了Z-Stack内部的串口功能,不然两者会产生冲突,串口会出现不可预期的数据。要关闭Z-Stack内部的串口功能,我们只需要屏蔽以下几个预编译即可。
这里写图片描述
屏蔽掉Z-Stack默认开启的MT_TASKMT_SYS_FUNCMT_ZDO_FUNC
———————————————————————– Gateway.c ———————————————————————–
在自己的任务初始化函数当中配置串口参数,开启串口0功能。

void Gateway_Init( uint8 task_id )
{
  halUARTCfg_t uartconf;
  ……
  // 配置串口参数
  uartconf.baudRate = HAL_UART_BR_115200;
  uartconf.callBackFunc = NULL;
  uartconf.configured = TRUE;
  uartconf.flowControl = FALSE;

  uartconf.flowControlThreshold = 64;
  uartconf.idleTimeout = 6;             // 6ms后串口空闲则发送串口空闲事件,参数不可设为0
  uartconf.rx.maxBufSize = 128;
  uartconf.tx.maxBufSize = 128;
  uartconf.intEnable = TRUE;
    // 开启串口0
  HalUARTOpen(HAL_UART_PORT_0, &uartconf);
  ……
}

发送接收数据到PC端。

static void Gateway_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
  switch ( pkt->clusterId )
  {
    case TRANSMISSION_CLUSTERID:
      {
        // 置反LED灯开关状态
//        osal_set_event(g_gateway_taskid, EVENT_FLASH_LED);
        // 发送接收数据到PC端
        HalUARTWrite(HAL_UART_PORT_0, pkt->cmd.Data, pkt->cmd.DataLength);
      }
      break;
  }
}

  分别按下终端设备和协调器设备工程的编译按钮,0错误0警告。然后我们将程序分别烧录到两个CC2530设备中,等待设备自动组网后,通过“串口调试助手”发送数据给终端节点,然后再通过“串口调试助手”观察协调器就可以看到终端设备发送过来的数据了。
这里写图片描述
  软件源码的下载地址在下面的评论区有给出。
大家的支持就是我分享技术的动力,希望大家需转载时能附上原作者的博客:https://blog.csdn.net/u012993936,谢谢。

猜你喜欢

转载自blog.csdn.net/u012993936/article/details/81224962