This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

串口接收中断事件:HAL_UART_RX_FULL

PC机每隔100ms给协调器发送28字节的数据,协调器接收后,回显。

过一段时间后,会提示:HAL_UART_RX_FULL,而且发送的数据也不是完整的28个字节。

  • 当缓冲区数据长度大于等于HAL_UART_DMA_FULL 时, 触发HAL_UART_RX_FULL事件
    你的数据是否及时读出以及及时释放。
    你把你uart 贴下
  • 我用的是中断方式:
    /********************************************
    * @brief 自定义的串口初始化函数
    * @para
    ********************************************/
    void MyApp_UartInit(void)
    {
    halUARTCfg_t uartConfig;
    uartConfig.configured = TRUE; // 2x30 don't care - see uart driver.
    uartConfig.baudRate = MY_APP_BAUD;
    uartConfig.flowControl = FALSE;
    uartConfig.flowControlThreshold = MY_APP_THRESH; // 2x30 don't care - see uart driver.
    uartConfig.rx.maxBufSize = MY_APP_RX_SZ; // 2x30 don't care - see uart driver.
    uartConfig.tx.maxBufSize = MY_APP_TX_SZ; // 2x30 don't care - see uart driver.
    uartConfig.idleTimeout = MY_APP_IDLE; // 2x30 don't care - see uart driver.
    uartConfig.intEnable = TRUE; // 2x30 don't care - see uart driver.
    uartConfig.callBackFunc = rxCB; //串口接收到数据时的处理
    HalUARTOpen (0, &uartConfig);
    }
    /********************************************************************
    * @brief 串口处理函数,将接收到的数据发送出去
    * @para uint8 port :串口号 0 、1
    * @para uint8 event:事件
    *********************************************************************/
    #define UART_DATA_MAX 28 //最大32个字节的数据
    static uint8 MyApp_AFTxBuf[UART_DATA_MAX+5]={0}; //缓存从串口中接收到的数据,+5:帧头4个字节,帧尾1个字节
    void rxCB( uint8 port, uint8 event )
    {
    static uint8 temp = 0;
    if((event & (HAL_UART_RX_FULL|HAL_UART_RX_ABOUT_FULL|HAL_UART_RX_TIMEOUT))&&(!MyApp_Tx_Len))
    {
    //打印事件
    temp = (event&0x0F)+'B';
    HalUARTWrite(0,&temp,1);
    //清空MyApp_AFTxBuf数组。
    osal_memset(MyApp_AFTxBuf,0,UART_DATA_MAX+5);
    MyApp_AFSendUartData(); //将数据读取并将标志位置位
    }
    }
    /*************************************************
    *
    *************************************************/
    void MyApp_AFSendUartData(void)
    {
    #ifdef MYAPP_LOOPBACK_TEST //还回测试,测试串口功能

    #else
    if(!MyApp_Tx_Len)
    {

    MyApp_Tx_Len=HalUARTRead(HAL_UART_PORT_0,MyApp_AFTxBuf+5,UART_DATA_MAX);

    MyApp_Tx_Len_Buf = MyApp_Tx_Len; //缓存
    osal_memcpy(Myapp_Uart_RBuf,MyApp_AFTxBuf,MyApp_Tx_Len_Buf+5);
    }
    #endif
    }

    //在事件处理函数中,每隔99ms,轮询MyApp_Tx_Len_Buf 是否非零,如果是,则AF发送
    uint16 MyApp_ProcessEvent( uint8 task_id, uint16 events )
    {
    ……
    if(events & MYAPP_UART_DTU_EVT)
    {
    MyApp_UartDtu_Pro();
    osal_start_timerEx(MyApp_TaskID,MYAPP_UART_DTU_EVT,99); //每隔90ms,检测一次是否有数据需要透传。
    return (events ^ MYAPP_UART_DTU_EVT);
    }
    ……
    }
    MyApp_UartDtu_Pro() //这个函数有点乱,没贴代码
    {
    判断MyApp_Tx_Len_Buf 是否非零,如果是,则进行处理;
    处理完成后,MyApp_Tx_Len_Buf = 0;MyApp_Tx_Len= 0;
    }
  • 数据怎么及时读出,及时释放?是要在底层更改还是应用层更改?
  • 给你个建议应该是个原因:
    你把你RXcall的处理修正一下:
    不要在callback去处理数据,仅去HalUARTRead,数据在其他地方处理,这样应该会有所改善。
  • 1、我只在callback中读取数据;
    2、定义用户事件处理函数,每隔100ms检测是否有数据,如果有在进行处理
    这样可以么?
  • 建议你直接在你的callback 里面read 到然后启动一个events去处理。
    你现在只在你的callback ,然后做一个events去 回write试试。
  • void rxCB( uint8 port, uint8 event )
    {
    uint8 *MyApp_AFTxBuf;

    if((event & (HAL_UART_RX_FULL|HAL_UART_RX_ABOUT_FULL|HAL_UART_RX_TIMEOUT))&&(!MyApp_Tx_Len))
    {
    if(!(MyApp_AFTxBuf=osal_mem_alloc(UART_DATA_MAX))) //申请一段内存,如果申请不成功,则直接返回。
    {
    HalUARTWrite(0,"Return\r\n",8);
    return ;
    }
    MyApp_Tx_Len=HalUARTRead(HAL_UART_PORT_0,MyApp_AFTxBuf,UART_DATA_MAX); //读取数据

    osal_memcpy(&Myapp_Uart_RBuf[5],MyApp_AFTxBuf,MyApp_Tx_Len_Buf); //数据缓冲

    osal_mem_free(MyApp_AFTxBuf); //释放申请的内存

    //数据处理事件
    osal_set_event(MyApp_TaskID,MYAPP_UART_DTU_EVT);
    }
    }

    请问这样可以么?是否还需要继续精简??
  • 测试了一下,还是不行,还是有产生rxbuf满事件HAL_UART_DMA_FULL
  • void rxCB( uint8 port, uint8 event )
    {
    static uint8 len = 0;
    if((event & (HAL_UART_RX_FULL|HAL_UART_RX_ABOUT_FULL|HAL_UART_RX_TIMEOUT))&&(!MyApp_Tx_Len))
    {

    Evt_temp = event; //保存事件
    MyApp_Tx_Len=HalUARTRead(HAL_UART_PORT_0,MyApp_AFTxBuf,UART_DATA_MAX); //读取数据
    MyApp_Tx_Len_Buf = MyApp_Tx_Len; //数据缓冲
    osal_set_event(MyApp_TaskID,MYAPP_UART_DTU_EVT); //数据处理事件
    }
    }

    这样还是会有接收缓冲区满的事件HAL_UART_DMA_FULL ,该怎么办呀
  • 你好,我自己写了一个测试正常如下:

    void AF_Uart_config(void)
    {
      halUARTCfg_t uartConfig;
      uartConfig.configured = TRUE;
      uartConfig.baudRate = HAL_UART_BR_9600;
      uartConfig.flowControl = FALSE;
      uartConfig.flowControlThreshold = 32; 
      uartConfig.rx.maxBufSize = 64; 
      uartConfig.tx.maxBufSize = 64; 
      uartConfig.idleTimeout = 6; 
      uartConfig.intEnable = TRUE; 
      uartConfig.callBackFunc = AF_Uart_Callback; 
      HalUARTOpen (HAL_UART_PORT_0, &uartConfig); 
    
    }
    void AF_Uart_Callback( uint8 port, uint8 event )
    {
      uint16 data_len;
      uint8 *uart_data;
      if(event & (HAL_UART_RX_FULL|HAL_UART_RX_ABOUT_FULL|HAL_UART_RX_TIMEOUT))
      { 
        data_len=Hal_UART_RxBufLen(HAL_UART_PORT_0);
       
    
            uart_data=osal_mem_alloc(data_len);
            if ( uart_data != NULL )
            {     
                  HalUARTRead(HAL_UART_PORT_0,uart_data,data_len);
                  HalUARTWrite(HAL_UART_PORT_0,uart_data,data_len);
                  data_len=0;
            }
            osal_mem_free( uart_data );
      } 
    
    }

  • void rxCB( uint8 port, uint8 event )
    {
    static uint8 *MyApp_AFTxBuf;

    if(event & (HAL_UART_RX_FULL|HAL_UART_RX_ABOUT_FULL|HAL_UART_RX_TIMEOUT))
    {

    MyApp_Tx_Len = Hal_UART_RxBufLen(HAL_UART_PORT_0); //长度

    MyApp_AFTxBuf = osal_mem_alloc(MyApp_Tx_Len);
    if(MyApp_AFTxBuf != NULL)
    {
    HalUARTRead(HAL_UART_PORT_0,MyApp_AFTxBuf,MyApp_Tx_Len); //读取数据
    HalUARTWrite( HAL_UART_PORT_0,MyApp_AFTxBuf,MyApp_Tx_Len);
    MyApp_Tx_Len = 0;
    }
    osal_mem_free( MyApp_AFTxBuf );

    }

    }
    我这样之后,偶尔还会提示事件HAL_UART_DMA_FULL 。
    请问你用的什么版本的协议栈?我用的时Zstack 2.5.1.a
  • 3.0.2,你可以更新一下试试看。
  • 我试了一下按照您的程序,接收之后立刻回显没有问题。
    但是如果程序如下,接收之后,产生一个事件,仍会有这个问题:
    void rxCB( uint8 port, uint8 event )
    {
    if((event & (HAL_UART_RX_FULL|HAL_UART_RX_ABOUT_FULL|HAL_UART_RX_TIMEOUT))&&(!MyApp_Tx_Len))
    {
    MyApp_Tx_Len = Hal_UART_RxBufLen(HAL_UART_PORT_0); //长度
    MyApp_AFTxBuf = osal_mem_alloc(MyApp_Tx_Len);
    if(MyApp_AFTxBuf != NULL)
    {
    HalUARTRead(HAL_UART_PORT_0,MyApp_AFTxBuf,MyApp_Tx_Len); //读取数据
    //HalUARTWrite( HAL_UART_PORT_0,MyApp_AFTxBuf,MyApp_Tx_Len);
    MyApp_Tx_Len_Buf = MyApp_Tx_Len;
    osal_set_event(MyApp_TaskID,MYAPP_UART_DTU_EVT);
    }
    osal_mem_free( MyApp_AFTxBuf );
    }
    }
  • 你这个有问题的,你去启动了这个定时器,但是你的数据已经释放掉了肯定无法使用的
  • 实际程序如下:
    void rxCB( uint8 port, uint8 event )
    {
    if((event & (HAL_UART_RX_FULL|HAL_UART_RX_ABOUT_FULL|HAL_UART_RX_TIMEOUT))&&(!MyApp_Tx_Len))
    {
    MyApp_Tx_Len = Hal_UART_RxBufLen(HAL_UART_PORT_0); //长度

    //申请内存
    MyApp_AFTxBuf = osal_mem_alloc(MyApp_Tx_Len);
    if(MyApp_AFTxBuf != NULL)
    {
    HalUARTRead(HAL_UART_PORT_0,MyApp_AFTxBuf,MyApp_Tx_Len); //读取数据
    MyApp_Tx_Len_Buf = MyApp_Tx_Len;
    MyApp_Tx_Len = 0;
    osal_set_event(MyApp_TaskID,MYAPP_UART_DTU_EVT);
    }
    }
    }

    if(events & MYAPP_UART_DTU_EVT)
    {
    MyApp_UartDtu_Pro();
    return (events ^ MYAPP_UART_DTU_EVT);
    }
    void MyApp_UartDtu_Pro(void)
    {
    osal_memcpy(&Myapp_Uart_RBuf[5],MyApp_AFTxBuf,MyApp_Tx_Len_Buf); //数据缓冲
    osal_mem_free( MyApp_AFTxBuf );
    …………
    }

    您看一下,
    1、串口接收callback中,只缓存了数据,然后产生事件。
    2、事件处理函数中,缓冲数据到Myapp_Uart_RBuf,然后释放原数据MyApp_AFTxBuf

    这样过20分钟左右,就会产生HAL_UART_RX_FULL 事件,
    这样的结果是:原本一次读取28个字节数据,变成了先读取n个字节,再读取28-n个字节。相当于分两次读取了。
  • 有没有什么更好的建议?
  • 没有太多想法,因为这个写法没有什么问题。你又换个板子看看吗?
  • 没有,我换一个试试。