×
单片机 > 单片机程序设计 > 详情

串口不定长接收数据--空闲中断方式测试

发布时间:2020-06-18 发布时间:
|

1.问题描述:

    使用串口的空闲中断和接收中断进行串口数据的不定长接收


2.测试平台:

    (1)芯片STM32F756VGT6


    (2)IAR软件环境


    (3)使用芯片的串口6,和外接的RS485收发模块一起用做RS485通讯


3.实际操作:

    (1)串口初始化:

void MX_UART6_Init(void)

{

  

  huart6.Instance = USART6;

  huart6.Init.BaudRate = 115200;

  huart6.Init.WordLength = UART_WORDLENGTH_8B;

  huart6.Init.StopBits = UART_STOPBITS_1;

  huart6.Init.Parity = UART_PARITY_NONE;

  huart6.Init.Mode = UART_MODE_TX_RX;

  huart6.Init.HwFlowCtl = UART_HWCONTROL_NONE;

  huart6.Init.OverSampling = UART_OVERSAMPLING_16;

  huart6.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;

  huart6.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;

  if (HAL_UART_Init(&huart6) != HAL_OK)

  {

    // _Error_Handler(__FILE__, __LINE__);

  }

}

if(uartHandle->Instance==USART6)

 {

    /* USER CODE BEGIN USART6_MspInit 0 */

    

    /* USER CODE END USART6_MspInit 0 */

    /* USART6 clock enable */

    __HAL_RCC_USART6_CLK_ENABLE();

    

    /**USART6 GPIO Configuration    

    PC6     ------> USART6_TX

    PC7     ------> USART6_RX 

    */

    GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;

    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

    GPIO_InitStruct.Pull = GPIO_PULLUP;

    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

    GPIO_InitStruct.Alternate = GPIO_AF8_USART6;

    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    

    /* USART6 interrupt Init */

    HAL_NVIC_SetPriority(USART6_IRQn, 5, 0);

    HAL_NVIC_EnableIRQ(USART6_IRQn);

    /* USER CODE BEGIN USART6_MspInit 1 */

    __HAL_UART_ENABLE_IT(uartHandle,UART_IT_RXNE);

    __HAL_UART_ENABLE_IT(uartHandle,UART_IT_IDLE);

    /* USER CODE END USART6_MspInit 1 */

 }

(2)中断回调函数内部关于串口6部分的处理:

if(huart->Instance == USART6)

  {

    if(__HAL_UART_GET_FLAG(huart,UART_FLAG_RXNE) != 0)

    {

      temp = (uint8_t)huart->Instance->RDR;

      if((temp != 0) || (Rs485_Driver.ReciveBufferLen > 0))//根据自身算法过滤无用数据

      {     

        Rs485_Driver.ReciveBuffer[Rs485_Driver.ReciveBufferLen++] = temp;

        Rs485_Driver.ReciveBuffer[Rs485_Driver.ReciveBufferLen] = 0; //根据实际项目部分算法需求,后一位数据清0,可不要

      }//if((temp != 0) || (receiveBufferPointUart1 > 0))

    }//if(__HAL_UART_GET_FLAG(huart,UART_FLAG_RXNE) != 0)

    else if(__HAL_UART_GET_FLAG(huart,UART_FLAG_ORE) != 0)

    {

      __HAL_UART_CLEAR_OREFLAG(huart);

    }//else if(__HAL_UART_GET_FLAG(huart6,UART_FLAG_ORE) != 0)

    else if(__HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE) != 0)

    {

      Rs485_Driver.ReciveFlag = 1;//接收完成,进入空闲终端,接收标志位置位

      __HAL_UART_CLEAR_IDLEFLAG(huart);

    }//else if(__HAL_UART_GET_FLAG(huart6,UART_FLAG_IDLE) != 0)

  }//else if(huart->Instance == USART6)

(3)对应收发函数处理写法:

  I.头文件:

#ifndef _RS485_h_

#define _RS485_h_

 

#include "usart.h"

#include "FreeRTOS.h"

#include "cmsis_os.h"

//#include "SYSTEM_Manage.h"

 

#define RS485_BUFFER_SIZE 512

 

typedef void FUNCTION(unsigned int);

 

typedef struct _RS485_STRU

{

uint8_t               ReciveBuffer[RS485_BUFFER_SIZE];   //接收缓存

uint8_t               ReciveFlag;                        //接收完成标志   

uint8_t               OverTimeCount;                     //超时计数最大值,和实际函数配合

        uint32_t              ReciveBufferLen;                   //接收长度

FUNCTION              *Delay;                            //函数指针,用于指向延时函数

UART_HandleTypeDef    *UsartHandle;                      //串口句柄

}_rs485_stru;

 

extern _rs485_stru Rs485_Driver;

 

void Rs485_Transmit(_rs485_stru *Rs485Driver,uint8_t *Buffer,uint16_t Size);

uint8_t Rs485_Transmit_Recive(_rs485_stru *Rs485Driver,uint8_t *Buffer,uint16_t Size);

 

#endif

II.源文件:

#include "rs485.h"

 

_rs485_stru Rs485_Driver = 

{

  {0},

  0,

  50,

  0,

  &osDelayTask,        //实际项目使用FreeRtos,如果裸跑可以换成自己的延时函数

  &huart6,

};

 

//可用宏函数替代,实际未使用

void Rs485_Transmit(_rs485_stru *Rs485Driver,uint8_t *Buffer,uint16_t Size)

{

HAL_UART_Transmit(Rs485Driver->UsartHandle,Buffer,Size,0xFFFF);

while(__HAL_UART_GET_FLAG(Rs485Driver->UsartHandle,UART_FLAG_TC)!=SET); 

}

 

uint8_t Rs485_Transmit_Recive(_rs485_stru *Rs485Driver,uint8_t *Buffer,uint16_t Size)

{

uint8_t counter = 0;

//接收准备,初始化

Rs485Driver->ReciveFlag = 0;

Rs485Driver->ReciveBufferLen = 0;

//发送数据帧,一般为读取报文帧

HAL_UART_Transmit(Rs485Driver->UsartHandle,Buffer,Size,0xFFFF);

while(__HAL_UART_GET_FLAG(Rs485Driver->UsartHandle,UART_FLAG_TC)!=SET); 

//接收判断

while((!Rs485Driver->ReciveFlag)&&(counter < Rs485Driver->OverTimeCount))//超时检测,超时计数可放到函数参数中,节省空间

{

Rs485Driver->Delay(20);

counter++;

}


if(counter == Rs485Driver->OverTimeCount)//接收失败返回0,否则返回1

return 0;


return 1;

}

4.测试结果:

    图片就不发了,说说实际测试现象。


    1.当接收字节数较少时,该方式能很好的解决不定长数据接收,且接收数据无错误,长度一致。


    2.当接收字节数较长时,发现会有单个字节出错,实际检查发现有可能是硬件本身接收这块出现问题,空闲中断会发生在接收字节的中途,这就导致了当处理时数据某一字节丢失。但本身这种机制保证了数据传输过来,你能做出接收到数据的判断,并且在对数据内容使用前,加上一个合适的延时,也一样能够保证数据的完整性。因为这时候就算后面继续来数据,接收中断那边仍能够继续正常的工作,即使是标志位已经置位。实际项目使用中,我用该代码测试接收串口摄像头传来的图片数据,一张图12K,每次传输字节数512Byte,每次使用数据比较前加了一个2ms的延时,保证数据完整接收,测试时间1星期,接收数据没有发生错误。


关键字:串口  接收数据  空闲中断 

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
MSP430F5529 上手小例程2