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

发布者:学海飘香最新更新时间:2019-03-06 来源: eefocus关键字:串口  接收数据  空闲中断 手机看文章 扫描二维码
随时随地手机看文章

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星期,接收数据没有发生错误。


关键字:串口  接收数据  空闲中断 引用地址:串口不定长接收数据--空闲中断方式测试

上一篇:STM32 Flash操作(擦写)过程中器件复位导致数据丢失问题
下一篇:基于STM32平台的BMP180测试(模拟IIC)

推荐阅读最新更新时间:2024-03-16 16:24

如何利用STM32单片机串口发送字符串
最近由于要调试一个SMS发送短信的模块,该模块需要发送一系列AT指令,且需要字符串发送,但是STM32官方给的usart.c中并没有直接发送字符串的函数,因此写了一个发送字符串的函数。 其实发送字符串的本质还是发送一个个字符,所以只需在字符串结束标志之前,循环发送字符即可。不罗嗦,上程序。 //程序功能:利用串口发送一个字符串 // 参数:USARTx USART编号 可取 USART1、USART2、USART3、USART4、 USART5(STM32F103ZET6) str 需要发送的字符串 #include “stm32f10x.h” void Usart_SendString(USART_TypeDef* US
[单片机]
关于单片机通过串口发送浮点数信息
最近弄一个小东西的时候,需要将AD采集的数据,通过串口发送上位机。由于还得在下位机部分显示出来,所以这个AD采集的数据转换之后发送到串口,比较容易点。但是问题来了,以前的串口,只有从GPS模块接收的信息是浮点类型外。其他的东西,都只是把字符类型或者字符串类型的数据发到串口。 查阅了一点资料,这里是资料的链接。 单片机将浮点数从串口发送出去: 1.http://www.51hei.com/bbs/dpj-31223-1.html 采用了将浮点数转换为四个字节的数据,放到数组中,发送到串口。 2.http://blog.sina.com.cn/s/blog_a8576df901011efv.html 加入了标准输入输
[单片机]
DS18b20在Atmega8下的编程,串口通信电脑显示
=****************************************************** MCU:Atmega8 内部振荡器:8M 环境:ICCAVR 7.0 程序:sdyzxue 薛海涛 2010/06/16 =******************************************************* #include macros.h #include iom8v.h #define fosc 8000000 #define baud 9600 #define SEI() asm( sei ) #define CLR_DIR_1WIRE DDRC&=~BIT(1)
[单片机]
STC12C5A60S2单片机串口1无法连续发送字符的问题
开发环境 1,开发板:STC12C5A60S2,串口1。 在使用STC12C5A60S2串口1发送数据的时候,接收端无法收到完整的字符串,我的发送方式如下: UART_Send_Str( 00 ); UART_Send_Byte(':'); UART_Put_Num(dat ); UART_Send_Byte('.'); UART_Put_Num(dat ); UART_Send_Byte(':'); UART_Put_Num(dat ); UART_Send_Byte('.');
[单片机]
STC12C5A60S2单片机<font color='red'>串口</font>1无法连续发送字符的问题
有关Keil软件仿真的51单片机串口调试技巧
引言   在单片机系统中,串口(UART,通用异步收发接口)是一个非常重要的组成部分。通常使用单片机串口通过RS232/RS485电平转换芯片与上位机连接,以进行上位机与下位机的数据交换、参数设置、组成网络以及各种外部设备的连接等。RS232/RS485串行接口总线具有成本低、简单可靠、容易使用等特点,加上其历史悠久,所以目前应用仍然非常广泛;特别对于数据量不是很大的场合,串口通信仍然是很好的选择,有着广阔的使用前景。   在单片机编程中,串口占了很重要的地位。传统方式串口程序的调试,往往是利用专用的单片机硬件仿真器。在编写好程序后,利用仿真器来设置断点,观察变量和程序的流程,逐步对程序进行调试,修正错误。使用硬件仿真器的确是很有
[单片机]
有关Keil软件仿真的51单片机<font color='red'>串口</font>调试技巧
MSP430 串口通讯
MSP430 串口1 实现即时通讯 芯片:430F169 现在市面上大多数单片机都自带串口,本章介绍如何建立430串口通讯 单片机通过接收口(URXD)和发送口(UTXD)和外界进行通讯 430F169自带串口0和串口1两个通讯口 串口通讯是基于系统时钟上进行的,系统时钟的配置可以参考我之前的系统时钟进行配置。 1 串口控制各种寄存器 1 UxCTL,串口控制寄存器 2 UxTCTL,串口传输控制寄存器 3 UxRCTL,串口接收控制寄存器 4 UxBR0,波特率控制寄存器0 5 UxBR1,波特率控制寄存器1 6 UxMCTL,调制控制寄存器 7 UxRXBUF,接收缓存寄存器 8 UxTXBUF,传
[单片机]
MSP430 <font color='red'>串口</font>通讯
STM32串口介绍
串口作为 MCU 的重要外部接口,同时也是软件开发重要的调试手段, 其重要性不言而喻。STM32 的串口资源相当丰富的,功能也相当强劲。ALIENTEK 战舰 STM32 开发板所使用的 STM32F103ZET6 最多可提供 5 路串口,有分数波特率发生器、支持同步单线通信和半双工单线通讯、支持 LIN、 支持调制解调器操作、 智能卡协议和 IrDA SIR ENDEC 规范、具有 DMA等。 串口设置的一般步骤可以总结为如下几个步骤: 1) 串口时钟使能,GPIO 时钟使能 2) 串口复位 3) GPIO 端口模式设置 4) 串口参数初始化 5) 开启中断并且初始化 NVIC(如果需要开启中断才需要这个步骤) 6) 使能串
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved