历史上的今天
返回首页

历史上的今天

今天是:2025年03月06日(星期四)

正在发生

2019年03月06日 | 串口不定长接收数据--空闲中断方式测试

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


推荐阅读

史海拾趣

CBM_America_Corporation公司的发展小趣事

在全球电子行业遭遇供应链危机时,CBM_America_Corporation面临着巨大的挑战。公司的原材料采购受到影响,生产成本大幅上升。为了应对这一危机,CBM积极调整采购策略,寻找新的供应商和合作伙伴。同时,公司还加大了研发投入,开发出了更加环保、节能的产品,以适应市场需求的变化。通过一系列措施的实施,CBM成功度过了危机,并保持了稳定的发展态势。

西安航天民芯公司的发展小趣事

在宇航领域,动力电池管理芯片的性能要求极高。西安航天民芯凭借其在集成电路设计领域的深厚积累,成功研发出全国第一颗宇航级动力电池管理芯片。这一突破不仅打破了国外垄断的局面,也为中国宇航事业的发展做出了重要贡献。

BOPLA公司的发展小趣事

BOPLA公司成立于XXXX年,初期主要致力于电子开关、熔断器等基础电子元件的研发与生产。创始人凭借对电子行业的深厚理解和敏锐的市场洞察力,带领公司逐步在竞争激烈的市场中站稳脚跟。通过不断的技术创新和品质提升,BOPLA的产品逐渐获得了客户的认可,为公司后续的发展奠定了坚实的基础。

Compostar Technology Co Ltd公司的发展小趣事

随着产品线的不断丰富,Compostar Technology Co Ltd开始积极寻求市场拓展。公司通过与国内外知名电子品牌建立战略合作关系,成功将产品打入国际市场。同时,公司还积极参加各类行业展会和技术交流会,与业界同行建立了广泛的联系。这些努力不仅为公司带来了更多的商机,也进一步提升了公司的知名度和影响力。

宇阳科技(EYANG)公司的发展小趣事

随着公司业务的不断发展,宇阳科技在产能扩张和全球布局方面也取得了显著进展。公司在深圳、东莞、安徽等地建立了多个生产基地,引进了先进的生产线和检测设备,确保了产品的高品质和稳定供应。同时,宇阳科技还积极拓展海外市场,与全球多家知名企业建立了长期稳定的合作关系。

Giga公司的发展小趣事
通过定时控制LED灯的亮灭,实现视觉效果。

问答坊 | AI 解惑

程控三相精密线性功率源的设计

  摘要:针对某些领域对三相程控高精度电源的需求,提出了一种三相功率源的设计方法。该方法主要利用单片EPROM实现三相稳定信号源的产生,采用同步跟随电源技术进行线性功率放大,采用功率合成技术实现大功率输出。测试结果表明该功率源波形失 ...…

查看全部问答>

威盛694XB公版主板电路图(INTEL810E)

威盛694XB公版主板电路图,需要的朋友看看吧.... 威胜的那套图被黑客给黑掉了,我也没有了.换一套INTEL810E的吧.再过几天我会陆续在上一些PC主板的图的. [ 本帖最后由 西门 于 2009-5-15 22:32 编辑 ]…

查看全部问答>

【新手指南】论坛帮助帖汇总

最近抽空整理了一些论坛的帮助帖,希望能对大家有帮助,不断完善中........ 大家多提意见,多问问题,我会帮大家找到答案并在帖子中逐步完善!                   一、 &nbs ...…

查看全部问答>

wince5.0怎样才能收到蓝牙耳机按键消息?

修改C:\\WINCE500\\PRIVATE\\WINCEOS\\COMM\\BLUETOOTH里面的代码,进行全编译都编不进去 有什么办法可以截获蓝牙耳机按键消息吗?…

查看全部问答>

高手进来指导下。我用C语言写了两天的日历时钟,有闹钟功能、计时功能。

#include #include #define UCHAR unsigned char #define UINT unsigned int void init(); void delay(UINT); void displayWeek(UCHAR week); void displayTime(UCHAR first, UCHAR second); void writeCmd(UCHAR cmd); void writeData(UCHAR dat) ...…

查看全部问答>

请问AT91RM9200的网络DMA

它的EMC的传输方式是不是就称为DMA?  还是说他另外有一种DMA的传输方式可以选择?…

查看全部问答>

帮个忙!!

本人搞软件的,会几门编程语言。比较熟悉的有vb、vc++,现在想往单片机方面靠靠。以前上学时学过单片机,汇编语言,计算机组成等,对单片机还特意学了一段时间(都是理论的,没实践过),毕业后因为工作的事就在也没接触过。现在想学的话从什么地方 ...…

查看全部问答>

段寄存器左移四位后,前四位不是溢出了吗?

8086微处理器课程中,在介绍存储器20位地址的形成时,说16位段寄存器中数据左移四位后再与偏移值相加,那么左移四位后前四位不是溢出了吗?如原来是ABCDH,左移后为BCD0H,不会为ABCD0H啊?…

查看全部问答>

cyclone2 FPGA 开发板转让

  [ 本帖最后由 wenhuawu 于 2011-6-3 10:57 编辑 ]…

查看全部问答>