串口透传(转自天运科技)

第十六讲 ZigBee串口透传       
一、 串口透明传输工程说明       
        串口透明传输工程是在 SampleApp 工程基础之上进行修改而成,主要功能是完成简单的串口透明传输,功能要求:
1、 设备上电后自动选择设备类型。第一个启动的设备为协调器,后续启动的为路由器。(所有设备中程序相同)
2、 路由器的 232 串口接收到数据后将数据以单播的形式发送到协调器。当路由器接收到来自空中的数据包将数据写入 232 串口。
3、 协调器的 232 串口接收到数据后将数据以广播的形式发送到网络中所有的设备。当协调器接收到来自空中的数据包将数据写入 232 串口。
       
file:///C:\Users\WANGJI~1\AppData\Local\Temp\ksohtml\wps_clip_image-27697.png
file:///C:\Users\WANGJI~1\AppData\Local\Temp\ksohtml\wps_clip_image-32668.png                     
串口透明传输应用
二、 编译选项说明
串口透明传输工程在 SampleApp 工程基础之上进行修改,但是编译选项使用原 SampleApp 工程的编译选项, SampleApp 工程编译选项具体如下:
CC2430EB、ZTOOL_P1、MT_TASK、SOFT_START
通过编译选项ZTOOL_P1
编译选项SOFT_START。
三、 工程初始化与事件处理函数
串口透明传输工程来源于对SampleApp 工程的修改,工程初始化函数与 SampleApp 工程的初始化函数完全相同,读者可以参见前面章节。串口透明传输工程事件处理函数在SampleApp 工程事件处理函数的基础之上添加了对事件UART_RX_CB_EVT的处理,具体代码如下。
程序代码:
uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )
{
  if ( events & SYS_EVENT_MSG )
  {
    while ( MSGpkt )
    {
      switch ( MSGpkt->hdr.event )
      {
        case KEY_CHANGE:
……
          break;
        case AF_INCOMING_MSG_CMD:
          ……
          break;
        case ZDO_STATE_CHANGE:
……
          break;
        default:
          break;
      }
    }
    return (events ^ SYS_EVENT_MSG);
  }
  if ( events & SAMPLEAPP_SEND_PERIODIC_MSG_EVT )
  {
……
    return (events ^ SAMPLEAPP_SEND_PERIODIC_MSG_EVT);
  }
  
  if ( events & UART_RX_CB_EVT )  // 串口有数据需要处理
  {
    SampleApp_SPI_SendData( rbuf, rxlen+1);  // 调用处理函数,将信息发送出去
    return (events ^ UART_RX_CB_EVT);
  }
  return 0;
}
四、 工程修改
1、 添加事件
串口透明传输工程在SampleApp 工程基础上添加事件UART_RX_CB_EVT,当串口回调函数有接收到数据后将触发该事件,该事件在SampleApp.h 中被定义,具体代码如下。
程序代码:
#define UART_RX_CB_EVT                        0x0002
2、 回调函数
编译选项中的ZTOOL_P1说明原 SampleApp 工程默认使用 Z-Tool ,我们这里对其修改,将其在串口初始化中的回调函数函数进行修改。
程序代码:
void SPIMgr_Init ()
{
……
#if defined (ZTOOL_P1) || defined (ZTOOL_P2)
  uartConfig.callBackFunc         = rxCB;
……
}
        相应我们在SPIMgr.c 文件中添加该回调函数rxCB( uint8 port, uint8 event ),具体代码如下。
程序代码
static void rxCB( uint8 port, uint8 event )
{
  extern uint8 SampleApp_TaskID;
  rxlen=Hal_UART_RxBufLen(SPI_MGR_DEFAULT_PORT);  // 接收缓冲区数据长度 , 字节为单位
  rbuf=osal_mem_alloc(rxlen+1);  // 多分配 1 字节 , 分配如下
  rbuf[0]=rxlen;                // 一字节存放数据长度
  HalUARTRead ( SPI_MGR_DEFAULT_PORT, rbuf+1, rxlen); // 读接收缓冲区数据到内存 databuf+1
  if(!rxlen)
    osal_mem_free( rbuf );  // 释放内存  
  osal_set_event(SampleApp_TaskID,UART_RX_CB_EVT);
}
       
3、 发送函数
当串口接收到数据在串口回调函数中触发事件UART_RX_CB_EVT,应用层对其处理,并最终调用数据发送函数将串口接收到的数据发送出去。为此我们在SampleApp 工程基础之上添加了数据发送函数SampleApp_SPI_SendData(), 该函数具体如下。
程序代码
void SampleApp_SPI_SendData( uint8 *buf, uint8 len )
{
  if ( devStartMode == MODE_HARD )// 如果启动的时候是协调器,则用广播
  {
    SampleApp_SPI_SendData_DstAddr.addrMode = (afAddrMode_t)AddrBroadcast;
    SampleApp_SPI_SendData_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;
    SampleApp_SPI_SendData_DstAddr.addr.shortAddr = 0xFFFF;  
  }
  else// 其它设备类型则用单播
  {
    SampleApp_SPI_SendData_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;
    SampleApp_SPI_SendData_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;
    SampleApp_SPI_SendData_DstAddr.addr.shortAddr = 0x0000;  
  }
  if ( AF_DataRequest   ( &SampleApp_SPI_SendData_DstAddr,
                         (endPointDesc_t *)&SampleApp_epDesc,
                          SAMPLEAPP_FLASH_CLUSTERID,
                          len, buf,
                          &SampleApp_TransID,
                          0,
                          AF_DEFAULT_RADIUS ) == afStatus_SUCCESS )
  {
    osal_mem_free( rbuf );  // 必须释放内存 , 不然造成溢出 !
  }
  else
  {
    osal_mem_free( rbuf ); // 必须释放内存 , 不然造成溢出 !
  }
}
       
五、 数据流程
该串口透明传输工程与同为串口透明传输的 SerialApp 工程相比数据流程有很大的区别。该工程主要实现了多对一的数据透明传输,即协调器向所有路由广播,而路由器单播发送数据到协调器。数据流可分为两大部分,协调器到路由器和路由器到协调器。
下面我们梳理协调器到路由器数据流程,而路由器到协调器数据流程与其类似,读者可以自行对其梳理。协调器到路由器数据流程的流程图如图 X 所示。
file:///C:\Users\WANGJI~1\AppData\Local\Temp\ksohtml\wps_clip_image-17622.png
协调器到路由器数据流程图
1、 回调函数
当与协调器连接的设备(通常为 PC 机)向协调器通过 232 串口写入数据时,协调器的串口回调函数将处理相关信息,并在串口回调函数中触发事件UART_RX_CB_EVT通知应用层进行处理。串口回调函数代码如下。
程序代码
static void rxCB( uint8 port, uint8 event )
{
  extern uint8 SampleApp_TaskID;
  rxlen=Hal_UART_RxBufLen(SPI_MGR_DEFAULT_PORT);  // 接收缓冲区数据长度 , 字节为单位
  rbuf=osal_mem_alloc(rxlen+1);  // 多分配 3 字节 , 分配如下
  rbuf[0]=rxlen;                   // 一字节存放数据长度
  HalUARTRead ( SPI_MGR_DEFAULT_PORT, rbuf+1, rxlen); // 读接收缓冲区数据到内存 databuf+3
  if(!rxlen)
    osal_mem_free( rbuf );  // 释放内存  
  osal_set_event(SampleApp_TaskID,UART_RX_CB_EVT);
}
       
2、 处理事件UART_RX_CB_EVT
当接收到来自串口的信息后,在串口回调函数的最后触发了事件UART_RX_CB_EVT,而该事件的任务 ID SampleApp_TaskID,即应用层任务 ID ,所以会被SampleApp 工程应用层的事件处理函数SampleApp_ProcessEvent() 处理,具体程序如下。
程序代码
uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )
{
  ……
  if ( events & UART_RX_CB_EVT )  // 串口有数据需要处理
  {
    SampleApp_SPI_SendData( rbuf, rxlen+1);  // 调用处理函数,将信息发送出去
    return (events ^ UART_RX_CB_EVT);
  }
……
}
       
3、 数据发送函数SampleApp_SPI_SendData( )
在处理事件 UART_RX_CB_EVT 时,协议栈调用了函数 SampleApp_SPI_SendData() 将串口数据发送到空中,具体代码如下。
程序代码
void SampleApp_SPI_SendData( uint8 *buf, uint8 len )
{
  if ( devStartMode == MODE_HARD )// 如果启动的时候是协调器,则用广播
  {
    SampleApp_SPI_SendData_DstAddr.addrMode = (afAddrMode_t)AddrBroadcast;
    SampleApp_SPI_SendData_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;
    SampleApp_SPI_SendData_DstAddr.addr.shortAddr = 0xFFFF;  
  }
  else// 其它设备类型则用单播
  {
    SampleApp_SPI_SendData_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;
    SampleApp_SPI_SendData_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;
    SampleApp_SPI_SendData_DstAddr.addr.shortAddr = 0x0000;  
  }
  
  if ( AF_DataRequest   ( &SampleApp_SPI_SendData_DstAddr,
                         (endPointDesc_t *)&SampleApp_epDesc,
                          SAMPLEAPP_FLASH_CLUSTERID,
                          len, buf,
                          &SampleApp_TransID,
                          0,
                          AF_DEFAULT_RADIUS ) == afStatus_SUCCESS )
  {
    osal_mem_free( rbuf );  // 必须释放内存 , 不然造成溢出 !
  }
  else
  {
    osal_mem_free( rbuf ); // 必须释放内存 , 不然造成溢出 !
  }
}
        在函数 SampleApp_SPI_SendData() 中根据设备的类型确定了地址为广播地址还是单播地址,因为我们现在梳理的是协调器到路由器的数据流程,所示 devStartMode == MODE_HARD ,即将地址设置为广播地址,串口数据被以广播的形式发送到网络中的所有设备。
4、 数据的接收
当协调器的串口接收到数据后将信息以广播的形式发送到网络中所有设备,网络中的路由器接收到来自空中的信息时会触发事件AF_INCOMING_MSG_CMD,具体程序如下。
程序代码
uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )
{
  if ( events & SYS_EVENT_MSG )// 判断任务(一个任务可以有多个事件)
  {
    while ( MSGpkt )// 对比事件
    {
      switch ( MSGpkt->hdr.event )
      {
        case AF_INCOMING_MSG_CMD:
          SampleApp_MessageMSGCB( MSGpkt );
          break;
……
}
        当触发事件AF_INCOMING_MSG_CMD时,协议中中调用了函数SampleApp_MessageMSGCB() 对来自空中的信息包进行进一步的处理。
5、 数据处理函数SampleApp_MessageMSGCB()
当路由器接收到来自协调器空中的信息后,触发事件AF_INCOMING_MSG_CMD并调用了函数SampleApp_MessageMSGCB() 对其处理,函数SampleApp_MessageMSGCB() 具体代码如下。
程序代码
void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{  
  switch ( pkt->clusterId )
  {
    uint8 *pointer1;
      
case SAMPLEAPP_PERIODIC_CLUSTERID:   
  break;
      
    case SAMPLEAPP_FLASH_CLUSTERID:      
      pointer1=&pkt->cmd.Data[1];  // 接收数据指针 , 指向数据
      HalUARTWrite(0,pointer1,pkt->cmd.Data[0]);//cmd.Data[0] 是数据的大小
      break;
  }
}

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值