ZigBee學習筆記十三—串口無線透傳

一、什麼是透傳

透傳的基本概念:
透傳就是透明傳輸的簡稱。那麼什麼是透明傳輸呢?顧名思義,透明傳輸就是指在傳輸過程中,對外界完全透明,不需要關係傳輸過程以及傳輸協議,終目的是要把傳輸的內容原封不動的傳遞給被接收端,發送和接收的內容完全一致。這就相當於把信息直接扔給你想要傳輸的人,只需要扔(也就是傳輸)這一個步驟,不需要其他的內容安排。

二、ZigBee無線透傳的流程

發送和接收數據的流程:

發送數據:
填充並註冊端點描述符 配置發送模式及目的地址 AF_DataRe quest()發送數據

接收數據:
填充並註冊端點描述符 處理系統事件 SYS_EVENT_MSG 中的AF_INCOMING _MSG_CMD 消息獲得消息包中的無線數據

三、功能需求

1、協調器獲取PC機通過串口發來的數據,並且廣播給終端,終端收到數據後打印在串口調試工具
2、終端獲取PC機通過串口發來的數據,並且單播給協調器,協調器收到數據後打印到串口調試器上

四、具體操作

1、首先在我們的工程模板SampleApp.c內添加我們的頭文件

#include "mt_uart.h"
#include "string,h"
#include "MT.h"  //新的頭文件,我們要輪詢串口任務裏的事件,這些事件包含在這個頭文件中

2、串口初始化,串口打印、波特率的設置以及關閉流控

void SampleApp_Init( uint8 task_id )
{
  SampleApp_TaskID = task_id;
  SampleApp_NwkState = DEV_INIT;
  SampleApp_TransID = 0;
  
   MT_UartInit ();
   //這次要添加一個串口任務註冊,只有註冊了串口任務,我們纔可以去檢測串口任務裏的某一個事件
   MT_UartRegisterTaskID(task_id);    //mt_uart.h  117行   
   HalUARTWrite ( 0, "uart0 is ok\n", strlen("uart0 is ok\n"));

#if !defined( MT_UART_DEFAULT_OVERFLOW )
  #define MT_UART_DEFAULT_OVERFLOW       FALSE
#endif

#if !defined MT_UART_DEFAULT_BAUDRATE
#define MT_UART_DEFAULT_BAUDRATE         HAL_UART_BR_115200
#endif

3、協調器和終端配置

 //協調器以廣播的形式發送給終端
  SampleApp_Periodic_DstAddr.addrMode = (afAddrMode_t)AddrBroadcast;
  SampleApp_Periodic_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;
  SampleApp_Periodic_DstAddr.addr.shortAddr = 0xFFFF;

 //終端以單播的方式發送給協調器
  SampleApp_Flash_DstAddr.addrMode = (afAddrMode_t)Addr16Bit; //單播形式
  SampleApp_Flash_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;
  SampleApp_Flash_DstAddr.addr.shortAddr = 0x0000;  //協調器地址

再往下的端口描述符無需改動,組播相關代碼註釋掉

4、進入事件輪詢函數

檢測到網絡狀態改變之後,我們不再需要週期性的發送數據,只在有串口數據到來的時候發送數據
先看一下串口數據的格式

typedef struct
{
  osal_event_hdr_t  hdr;//數據頭
  uint8             *msg;  //指針,指向一個數組,數組的第一個元素是數據長度,後邊的纔是真正的數據
} mtOSALSerialData_t;

我們需要在事件輪詢中加入一個新的情況 有串口數據到達

 case CMD_SERIAL_MSG://代表有串口數據的到達
            SerialData_Analysis(((mtOSALSerialData_t *)MSGpkt)->msg);
            break

5、串口消息到達之後,我們通過調用下面的函數將其發送出去

void SerialData_Analysis(uint8 *msg)
{
  if(zgDeviceLogicalType == ZG_DEVICETYPE_COORDINATOR)
  {
    AF_DataRequest( &SampleApp_Periodic_DstAddr, &SampleApp_epDesc,
                       SAMPLEAPP_PERIODIC_CLUSTERID,
                       *msg,
                       msg+1,
                       &SampleApp_TransID,
                       AF_DISCV_ROUTE,
                       AF_DEFAULT_RADIUS );
  }
  else if(zgDeviceLogicalType == ZG_DEVICETYPE_ENDDEVICE )
  {
    AF_DataRequest( &SampleApp_Flash_DstAddr, &SampleApp_epDesc,
                       SAMPLEAPP_FLASH_CLUSTERID,
                       *msg,
                       msg+1,
                       &SampleApp_TransID,
                       AF_DISCV_ROUTE,
                       AF_DEFAULT_RADIUS );
  }
}

6、接收到的數據處理

那麼數據發送出去之後,我們就要接收數據後的處理
事件輪詢:有新的無線消息到達
調用 SampleAPP_MessageMSGCB(MSGpkt)

void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
  uint16 flashTime;

  switch ( pkt->clusterId )
  {
    case SAMPLEAPP_PERIODIC_CLUSTERID:
      HalUARTWrite ( 0, pkt->cmd.Data, pkt->cmd.DataLength );
      break;

    case SAMPLEAPP_FLASH_CLUSTERID:
      HalUARTWrite ( 0, pkt->cmd.Data, pkt->cmd.DataLength );
      break;
  }
}

7、 最後,有一個問題,我們設置的事件輪詢中,case CMD_SERIAL_MSG:這一事件並沒有真正觸發。

那爲什麼不能觸發呢?

我們來看 mt_uart.c文件:
我們在進行串口初始化的時候,我們可以看到協議棧是利用一個結構體,對結構體的成員變量的一個賦值,在串口初始化中,有一個回調函數

只要執行了串口初始化函數,就要去執行這一個回調函數

而回調函數內纔是真正觸發我們設立的,有串口數據到達這一事件的。
但我們剛剛的代碼,並沒有觸發這一事件

沒有觸發的原因如下:
協議棧對串口數據的封裝有着明確的格式要求,如果我們沒有按照這個格式來傳送數據,那麼我們的串口數據是收不到,事件是觸發不了的

8、爲了簡便,我們也可以對回調函數進行一個處理,使其能夠發送我們未封裝的串口數據。

函數如下:

void MT_UartProcessZToolData ( uint8 port, uint8 event )
{
  uint8 ch,len = 0;
  uint8 uartData[128];   //定義一個數據暫存數組
  uint8 i;
  (void)event;  //
  while(Hal_UART_RxBufLen(port))  //只要檢測到串口緩存區有數據
  {
    HalUARTRead(port,&ch,1);//就把數據一個一個的傳輸給ch變量
    uartData[len+1] = ch;  //再把ch的數據傳給數組
    len++;
  }
  if(len)
  {
    uartData[0] = len; //第一個元素設爲數據長度
    pMsg = (mtOSALSerialData_t *)osal_msg_allocate(sizeof(mtOSALSerialData_t)+len+1);
    //爲串口數據包分配內存
  }
  if(pMsg)
  {
    pMsg->hdr.event = CMD_SERIAL_MSG;   //設置串口數據到達事件
    pMsg->msg=(uint8*)(pMsg+1);   //把數據定位到結構體數據部分
    for(i=0;i<=len;i++)
      pMsg->msg[i]=uartData[i];   //再把暫存區數據放入串口數據中
    osal_msg_send(App_TaskID,(byte*)pMsg);  //把數據包發往消息隊列
  }
  osal_msg_deallocate((uint8*)pMsg); //分配的內存用完後記得刪除,以免內存溢出
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章