zigbee协议栈串口收发 From zigbee菜鸟笔记(十 二)

一.串口问题

有问题发送邮件至468078841@qq.com

关于串口的一些常识欢迎点击进入串口中断

二.协议栈串口需用函数解读

这部分主要讲述串口发送问题在协议栈中

#include "hal_uart.h"
#include "MT_UART.h"

这两个文件中封装着关于串口的API函数

关于串口的日常收发问题我们主要使用以下的几个函数

(一)在#include "MT_UART.h"函数中
函数名:MT_UartInit
函数作用:MT层初始化串口
函数原型:

void MT_UartInit ()
{
  halUARTCfg_t uartConfig;

  /* Initialize APP ID */
  App_TaskID = 0;

  /* UART Configuration */
  uartConfig.configured           = TRUE;//确定配置
  uartConfig.baudRate             = MT_UART_DEFAULT_BAUDRATE; //这里是波特率
  uartConfig.flowControl          = MT_UART_DEFAULT_OVERFLOW;//流控
  uartConfig.flowControlThreshold = MT_UART_DEFAULT_THRESHOLD;//在RX缓存达到maxRxBufSize之前还有多少字节空余。当到达maxRxBufSize –flowControlThreshold时并且流控制打开时,会触发相应的应用事件:MT_UART_DEFAULT_THRESHOLD
  uartConfig.rx.maxBufSize        = MT_UART_DEFAULT_MAX_RX_BUFF;//最大接受字节
  uartConfig.tx.maxBufSize        = MT_UART_DEFAULT_MAX_TX_BUFF;//最大发送字节
  uartConfig.idleTimeout          = MT_UART_DEFAULT_IDLE_TIMEOUT;//接受数据时间
  uartConfig.intEnable            = TRUE;    //使能
#if defined (ZTOOL_P1) || defined (ZTOOL_P2)
  uartConfig.callBackFunc         = MT_UartProcessZToolData;
#elif defined (ZAPP_P1) || defined (ZAPP_P2)
  uartConfig.callBackFunc         = MT_UartProcessZAppData;
#else
  uartConfig.callBackFunc         = NULL;     //回调函数 这个很有用
#endif

  /* Start UART */
#if defined (MT_UART_DEFAULT_PORT)
  HalUARTOpen (MT_UART_DEFAULT_PORT, &uartConfig); //串口初始化
#else
  /* Silence IAR compiler warning */
  (void)uartConfig;
#endif

  /* Initialize for ZApp */
#if defined (ZAPP_P1) || defined (ZAPP_P2)
  /* Default max bytes that ZAPP can take */
  MT_UartMaxZAppBufLen  = 1;
  MT_UartZAppRxStatus   = MT_UART_ZAPP_RX_READY;
#endif

}

(二)函数名:extern void MT_UartRegisterTaskID( uint8 taskID );
函数作用:注册串口任务
函数原型:

void MT_UartRegisterTaskID( byte taskID )
{
  App_TaskID = taskID;
}

(三)在#include "hal_uart.h"文件中
函数名:extern uint16 HalUARTRead ( uint8 port, uint8 *pBuffer, uint16 length );
函数作用:读取 port 串口 将 length 字节内容读取到 pBuffer
函数原型:

uint16 HalUARTRead(uint8 port, uint8 *buf, uint16 len)
{
  (void)port;
  (void)buf;
  (void)len;

#if (HAL_UART_DMA == 1)
  if (port == HAL_UART_PORT_0)  return HalUARTReadDMA(buf, len);
#endif
#if (HAL_UART_DMA == 2)
  if (port == HAL_UART_PORT_1)  return HalUARTReadDMA(buf, len);
#endif
#if (HAL_UART_ISR == 1)
  if (port == HAL_UART_PORT_0)  return HalUARTReadISR(buf, len);
#endif
#if (HAL_UART_ISR == 2)
  if (port == HAL_UART_PORT_1)  return HalUARTReadISR(buf, len);
#endif

#if HAL_UART_USB
  return HalUARTRx(buf, len);
#else
  return 0;
#endif
}

(四)函数名:extern uint16 HalUARTWrite ( uint8 port, uint8 *pBuffer, uint16 length );
函数作用:将 length 字节长度的 pBuffer 发送到串口 port
函数原型:

uint16 HalUARTWrite(uint8 port, uint8 *buf, uint16 len)
{
  (void)port;
  (void)buf;
  (void)len;
,
,
,

#if (HAL_UART_ISR == 2)
  if (port == HAL_UART_PORT_1)  return HalUARTWriteISR(buf, len);
  HalUARTTx(buf, len);
  return len;
#else
  return 0;
#endif
}

(五)在OSAL.h文件中
函数名:uint8 osal_set_event( uint8 task_id, uint16 event_flag )
函数作用:将 task_id 事件 event_flag 标志位置1这时候就处于待处理事件
函数原型:

uint8 osal_set_event( uint8 task_id, uint16 event_flag )
{
  if ( task_id < tasksCnt )
  {
    halIntState_t   intState;
    HAL_ENTER_CRITICAL_SECTION(intState);    // Hold off interrupts
    tasksEvents[task_id] |= event_flag;  // Stuff the event bit(s)
    HAL_EXIT_CRITICAL_SECTION(intState);     // Release interrupts
    return ( SUCCESS );
  }
   else
  {
    return ( INVALID_TASK );
  }
}

三.在协议栈中发送

(1):添加头文件 :

#include "hal_uart.h"
#include "MT_UART.h"

在系统事件初始化函数SampleApp_Init中加上串口初始化函数

MT_UartInit();
HalUARTWrite(0,"UART_OPEN_SUFFCESS",sizeof("UART_OPEN_SUFFCESS"));

关于串口0 串口1的问题可以看这里串口中断
这时将代码烧写进入2530中,每次重启,设备都会发送UART_OPEN_SUFFCESS到上位机,关于串口初始化杂乱消息解决方向会在后续出教程解决。

四.将PC端发送的消息回传PC端.事件监控

在前面一节我们知道了协议栈对于消息的处理是基于事件轮询模式,但是在初始自带中只有按键和RF等并没有串口事件,那我们如何添加自己的事件,让接收到的消息回传呢

(一).添加头文件:

#include "hal_uart.h"
#include "MT_UART.h"

(二)自己定义串口事件
uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )函数里自带了一个SAMPLEAPP_SEND_PERIODIC_MSG_EVT事件,我们goto一下,可以看到事件定义为

#define SAMPLEAPP_SEND_PERIODIC_MSG_EVT       0x0001

我们仿照自带的类型仿写 在这里我们要介绍一下这里的事件大小是二进制移位然后转16进制进行表示那我我们的接着就是0x0002 0x0004 等等,在这里我们添加自己的串口事件

#define UART_EVT    			   0x0002

(三).添加自己的初始化函数
在系统事件初始化函数SampleApp_Init中加上串口初始化函数

void SampleApp_Init( uint8 task_id )
{
  SampleApp_TaskID = task_id;
  SampleApp_NwkState = DEV_INIT;
  SampleApp_TransID = 0;
  .
  .
  .
  .
  .
 
  // Setup for the flash command's destination address - Group 1
  SampleApp_Flash_DstAddr.addrMode = (afAddrMode_t)afAddrGroup;
  SampleApp_Flash_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;
  SampleApp_Flash_DstAddr.addr.shortAddr = SAMPLEAPP_FLASH_GROUP;
  
  // Fill out the endpoint description.
  SampleApp_epDesc.endPoint = SAMPLEAPP_ENDPOINT;
  Samp
#endif
  HalLedSet( HAL_LED_2, HAL_LED_MODE_ON ); 
  
  
  MT_UartInit(); //
  HalUARTWrite(0,"UART_OPEN_SUFFCESS",sizeof("UART_OPEN_SUFFCESS"));
  MT_UartRegisterTaskID(task_id);//注册串口事件
  osal_set_event(task_id,UART_EVT);//调用此函数来设置任务的事件标志为1 UART_EVT我们已经绑定在串口了 并且在这里启动第一个串口。
}

(四)事件仿写

uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )
{
  afIncomingMSGPacket_t *MSGpkt;
  (void)task_id;  // Intentionally unreferenced parameter
  
  if ( events & SYS_EVENT_MSG )
  {
    MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );
    while ( MSGpkt )
    {
     。
     。
     。
     。
     。
     。
     
  
  // Send a message out - This event is generated by a timer
  //  (setup in SampleApp_Init()).
  if ( events & SAMPLEAPP_SEND_PERIODIC_MSG_EVT )
  {
    // Send the periodic message
    SampleApp_SendPeriodicMessage();
    
    // Setup to send message again in normal period (+ a little jitter)
    osal_start_timerEx( SampleApp_TaskID, SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
                       (SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT + (osal_rand() & 0x00FF)) );
    
    // return unprocessed events
    return (events ^ SAMPLEAPP_SEND_PERIODIC_MSG_EVT);
  }
  
  if ( events & UART_EVT )//如果UART_EVT被触发 我们就进入这里
  {
    
    UART_len =  Hal_UART_RxBufLen(0); //先读取串口0 监测是否有消息
    if(UART_len)  //有消息进入这里
    {
      osal_memset(UART_RX,'\0',128);   //将UART_RX内容清空
      HalUARTRead(0,UART_RX,UART_len); //读取消息
      HalUARTWrite(0,UART_RX,UART_len);//发送消息
      UART_len = 0; //清空这次的消息
    }
    
    //定时器执行
    osal_set_event(task_id,UART_EVT);//再次置1 进行消息监控
    // return unprocessed events
    return (events ^ UART_EVT); //将这次消息事件清空
  }
  // Discard unknown events
  return 0;
}

通过上述的操作我们就可以完成常见的串口收发,不过这样写有点麻烦,用这种写过GPRS登录的云端服务器的操作,很麻烦,要考虑很多东西,还容易被优化了。

五.将PC端发送的消息回传PC端.串口回调函数

(一).添加头文件:

#include "hal_uart.h"
#include "MT_UART.h"

(二)自己仿写串口初始化函数,这里可以去MT_UartInit();直接复制到void SampleApp_Init( uint8 task_id )改写

void SampleApp_Init( uint8 task_id )
{
  SampleApp_TaskID = task_id;
  SampleApp_NwkState = DEV_INIT;
  SampleApp_TransID = 0;
  .
  .
  .
  .
  .
 
  // Setup for the flash command's destination address - Group 1
  SampleApp_Flash_DstAddr.addrMode = (afAddrMode_t)afAddrGroup;
  SampleApp_Flash_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;
  SampleApp_Flash_DstAddr.addr.shortAddr = SAMPLEAPP_FLASH_GROUP;
  
  // Fill out the endpoint description.
  SampleApp_epDesc.endPoint = SAMPLEAPP_ENDPOINT;
  Samp
#endif
  HalLedSet( HAL_LED_2, HAL_LED_MODE_ON ); 
  
  
  halUARTCfg_t uartConfig;//定义个串口结构体
  uartConfig.configured             =TRUE;//串口配置为真
  uartConfig.baudRate               =HAL_UART_BR_115200;//波特率为9600
  uartConfig.flowControl            =FALSE;//流控制为假
  uartConfig.callBackFunc       =    Uart_Callback_Function ;//串口回调函数,当接受检测到串口消息,我们就调用这个函数
  HalUARTOpen(HAL_UART_PORT_0,&uartConfig);// 打开串口0
  HalUARTWrite(0,"UART_OPEN_SUFFCESS",sizeof("UART_OPEN_SUFFCESS"));

}

不要忘记声明函数static void Uart_Callback_Function();

(三)实现串口回调函数
在串口初始化的作用域下,自己随便找个地方写

static void Uart_Callback_Function ()
{
   UART_len =  Hal_UART_RxBufLen(0); //先读取串口0 长度
    if(UART_len)  //有消息进入这里
    {
      osal_memset(UART_RX,'\0',128);   //将UART_RX内容清空
      HalUARTRead(0,UART_RX,UART_len); //读取消息
      HalUARTWrite(0,UART_RX,UART_len);//发送消息
      UART_len = 0; //清空这次的消息
    }

}

通过上述步骤步骤,算是基本掌握了协议栈的串口问题,在后续将会写一些关于双串口调试的问题,有问题也欢迎大家一起讨论,后续忙完会陆续出一些其他的内容,欢迎提要求哈!

有问题请发邮件至468078841@qq.com

  • 11
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值