当前位置: 首页 > news >正文

小华HC32F460串口性能问题与处理思路

问题描述

在使用HC32F460串口中断方式接收较多数据(每包209字节)且连续接收,预计发送20包数据。此时RxFull数据接收中断会出现似乎是性能瓶颈的问题,导致数据接收不及时出现丢包。
我的项目中设计方式为Rx中断不断接收数据,主循环不断处理数据且主循环参考ModbusRtu协议的处理方式以数据间的时间间隔来判断是否到达1帧数据,因此对数据的接收时间要求较高,接收不及时会导致丢包。

本文函数内容并不完整,只提供问题的记录和排查思路。

发现并测试该问题

首先是很通用的串口配置函数,启用了Rx数据接收中断和错误中断

void InitUSART1(int baud)
{stc_usart_uart_init_t stcUartInit;stc_irq_signin_config_t stcIrqSigninConfig;/* Configure USART RX/TX pin. */GPIO_SetFunc(USART1_RX_PORT, USART1_RX_PIN, USART1_RX_GPIO_FUNC);GPIO_SetFunc(USART1_TX_PORT, USART1_TX_PIN, USART1_TX_GPIO_FUNC);/* Enable peripheral clock */USART1_FCG_ENABLE();/* Initialize UART. */(void)USART_UART_StructInit(&stcUartInit);stcUartInit.u32ClockDiv = USART_CLK_DIV64;//stcUartInit.u32Baudrate = 115200UL;stcUartInit.u32Baudrate = baud;stcUartInit.u32OverSampleBit = USART_OVER_SAMPLE_8BIT;if (LL_OK != USART_UART_Init(USART1_UNIT, &stcUartInit, NULL)) {Led_SetDeviceState(DEV_STATE_ERROR);//红灯提示出错for (;;) {}}/* Register RX error IRQ handler && configure NVIC. */stcIrqSigninConfig.enIRQn = USART1_RX_ERR_IRQn;stcIrqSigninConfig.enIntSrc = USART1_RX_ERR_INT_SRC;stcIrqSigninConfig.pfnCallback = &USART1_RxError_IrqCallback;INTC_IrqInstalHandler(&stcIrqSigninConfig, DDL_IRQ_PRIO_DEFAULT);/* Register RX full IRQ handler && configure NVIC. */stcIrqSigninConfig.enIRQn = USART1_RX_FULL_IRQn;stcIrqSigninConfig.enIntSrc = USART1_RX_FULL_INT_SRC;stcIrqSigninConfig.pfnCallback = &USART1_RxFull_IrqCallback;INTC_IrqInstalHandler(&stcIrqSigninConfig, DDL_IRQ_PRIO_DEFAULT);//    /* Register TX empty IRQ handler && configure NVIC. */
//    stcIrqSigninConfig.enIRQn = USART1_TX_EMPTY_IRQn;
//    stcIrqSigninConfig.enIntSrc = USART1_TX_EMPTY_INT_SRC;
//    stcIrqSigninConfig.pfnCallback = &USART1_TxEmpty_IrqCallback;
//    INTC_IrqInstalHandler(&stcIrqSigninConfig, DDL_IRQ_PRIO_DEFAULT);//    /* Register TX complete IRQ handler && configure NVIC. */
//    stcIrqSigninConfig.enIRQn = USART1_TX_CPLT_IRQn;
//    stcIrqSigninConfig.enIntSrc = USART1_TX_CPLT_INT_SRC;
//    stcIrqSigninConfig.pfnCallback = &USART1_TxComplete_IrqCallback;
//    INTC_IrqInstalHandler(&stcIrqSigninConfig, DDL_IRQ_PRIO_DEFAULT);USART_FuncCmd(USART1_UNIT, (USART_RX | USART_INT_RX | USART_TX), ENABLE);//POLL使用,需要开启tx,但是会导致设备启动和复位时候发送垃圾数据0x00
}

而后是数据接收中断

/*** @brief  USART1 RX IRQ callback* @param  None* @retval None*/
void USART1_RxFull_IrqCallback(void)
{//读取串口数据到m_stcRingBufu8 u8Data  = USART_ReadData(USART1_UNIT) & 0xFF;rx1[rx1_cnt++] = u8Data;//不断累加记录串口传回的字符串netProtocol_S.usart1TimeStamp = netProtocol_S.timeStampNow;//记录最后一次接收到数据的时间}

最后是在主循环中运行的数据处理。
此处为优化后的函数,去除了可能消耗性能的协议解析和数据移动内容,只进行简单的赋值和加减法。
当接收到的一包数据不足8字节的时候触发串口返回ERROR提示。

void Usart1RxPoll(void)
{//RX数据寄存器有数据后,读取
//	if(SET == USART_GetStatus(USART1_UNIT, USART_FLAG_RX_FULL))
//	{
//		u8 u8Data  = USART_ReadData(USART1_UNIT) & 0xFF;//		rx1[rx1_cnt++] = u8Data;//不断累加记录串口传回的字符串
//		//int processBytes = CProtocol_AddToStream(&g_proUsart1Rx, (u16*)&u8Data, 1, 1);	
//    
//		netProtocol_S.usart1TimeStamp = netProtocol_S.timeStampNow;//记录最后一次接收到数据的时间
////		
////		u8 u8Data  = USART_ReadData(USART1_UNIT);
////		int processBytes = CProtocol_AddToStream(&g_proUsart1Rx, (u16*)&u8Data, 1, 1);	
//	}//以时间为间隔处理数据包if((netProtocol_S.timeStampNow - netProtocol_S.usart1TimeStamp >= 50 )//uint类型的数据无需担心溢出&& netProtocol_S.usart1TimeStamp != 0){netProtocol_S.usart1TimeStamp = 0;netProtocol_S.usart1LastPackageTime = netProtocol_S.timeStampNow;//记录最后一个接收到数据包的时间节点parseLen = rx1_cnt;//记录此时已经收到数据长度,将该长度的数据视作一帧进行处理//ATParse(rx1, parseLen);if(parseLen < 8){USART1SendBuf("ERROR", 5);}else{USART1SendBuf("OK", 2);memset(rx1, 0, RX1_TOTAL_LEN);}//memmove(rx1, rx1 + parseLen, RX1_TOTAL_LEN - parseLen);//将未处理的数据移动到前面,上一帧的数据丢弃rx1_cnt = rx1_cnt - parseLen;//移除已处理的长度}}

问题的触发方式

上位机通过串口向芯片下发大包数据并连续发送
参考的modbusRtu数据帧,209字节如下:
若出现数据接收不及时,串口就会返回ERROR
数据手动发送,大概发送间隔0.2s或更短(手动点击串口调试助手进行发送),包大小209字节

02 10 03 EA 00 64 C8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 FF F0 00 00 00 00 00 00 00 00 00 00 00 00 00 7F 00 3F 80 00 00 00 00 00 00 00 00 00 00 00 0F C0 00 00 FC 00 00 00 00 00 00 00 00 00 00 00 78 00 3F 00 07 80 00 00 00 00 00 00 00 00 00 01 C0 3F FF FF 00 E0 00 00 00 00 00 00 00 00 00 0F 03 FF FF FF F0 1C 00 00 00 00 00 00 00 00 00 38 1F FF FF FF FE 07 00 00 00 00 00 00 00 00 00 E0 FF FF FF FF FF C1 C0 00 00 00 00 00 00 00 01 83 FD BF FF FF FF F0 70 00 00 00 00 00 00 00 06 0F FC 3F FF FF FF FC 18 00 00 00 00 00 00 00 18 3F FC 3F FF 8E AE

为什么确认是中断性能问题

1、在InitUSART1函数中提高串口接收数据函数的中断优先级后,出现丢包概率变低,但仍会出现

/* Register RX full IRQ handler && configure NVIC. */stcIrqSigninConfig.enIRQn = USART1_RX_FULL_IRQn;stcIrqSigninConfig.enIntSrc = USART1_RX_FULL_INT_SRC;stcIrqSigninConfig.pfnCallback = &USART1_RxFull_IrqCallback;INTC_IrqInstalHandler(&stcIrqSigninConfig, DDL_IRQ_PRIO_00);

2、改善串口接收函数,每次进中断就接收完所有数据,出现丢包概率变低,但仍会出现

void USART1_RxFull_IrqCallback(void)
{while (USART_GetStatus(USART1_UNIT, USART_FLAG_RX_FULL) == SET) {u8 u8Data = USART_ReadData(USART1_UNIT) & 0xFF;rx1[rx1_cnt++] = u8Data;}netProtocol_S.usart1TimeStamp = netProtocol_S.timeStampNow;}

由上述现象总结判断,中断频繁触发导致性能不足,无法在限定时间内接收完数据,进而导致了主循环丢包。
我的芯片倍频后按照200Mhz运行,串口波特率115200,理论上性能应该不会不足,但还是出现该现象,只能将其暂时归类至中断性能问题。

最终处理方案

数据接收部分修改至主循环中,并关闭Rx数据接收中断,从而节约频繁切换中断对性能的消耗。

void Usart1RxPoll(void)
{//RX数据寄存器有数据后,读取if(SET == USART_GetStatus(USART1_UNIT, USART_FLAG_RX_FULL)){u8 u8Data  = USART_ReadData(USART1_UNIT) & 0xFF;rx1[rx1_cnt++] = u8Data;//不断累加记录串口传回的字符串netProtocol_S.usart1TimeStamp = netProtocol_S.timeStampNow;//记录最后一次接收到数据的时间}//以时间为间隔处理数据包if((netProtocol_S.timeStampNow - netProtocol_S.usart1TimeStamp >= 50 )//uint类型的数据无需担心溢出&& netProtocol_S.usart1TimeStamp != 0){netProtocol_S.usart1TimeStamp = 0;netProtocol_S.usart1LastPackageTime = netProtocol_S.timeStampNow;//记录最后一个接收到数据包的时间节点parseLen = rx1_cnt;//记录此时已经收到数据长度,将该长度的数据视作一帧进行处理ATParse(rx1, parseLen);memmove(rx1, rx1 + parseLen, RX1_TOTAL_LEN - parseLen);//将未处理的数据移动到前面,上一帧的数据丢弃rx1_cnt = rx1_cnt - parseLen;//移除已处理的长度}}

总结

目前排查和总结为芯片存在的频繁切换中断导致的性能不足问题,通过在主循环中接收和处理数据,不使用中断,进而解决该问题。
不过仍然不排除是rx1_cnt字段被中断和主循环竞争使用导致的问题。字段竞争导致该问题的可能很小,因而不继续排查。
若是字段竞争导致的问题可以通过维护一个头尾相接的缓冲区,中断向缓冲写数据,主循环从末尾读走数据来解决。

http://www.dtcms.com/a/582494.html

相关文章:

  • Java_Hashtable使用及扩容
  • Django序列化器
  • 跳表与B+树
  • 上海外贸网站优化自己做提卡网站
  • 学习日报 20251107|Nacos 注册同一服务多实例架构图
  • 营销型网站建设运营苏州园区
  • 广州站在哪个区酒店 网站构建
  • 网站开发的合同网络工程师中级职称报考条件
  • 相亲网站源码php模版wordpress听歌插件
  • 微网站 服务器在线设计logo图案免费
  • stm32 gpio 先写电平再初始化,是否可行?
  • 数字签名、 数字信封、数字证书
  • 马云的网站是谁建设的wordpress多广告位
  • Leetcode 47
  • 营销型网站分类自己服务器可以做网站
  • EtherCAT命令整理
  • Windows 常用命令行(CMD/PowerShell 通用,标注差异)
  • 小迪安全v2023学习笔记(一百四十五讲)—— Webshell篇魔改冰蝎打乱特征指纹新增加密协议过后门查杀过流量识别
  • 网站源码做exe执行程序域名被墙查询检测
  • HarmonyOS:ArkWeb在新窗口中打开页面
  • 青岛谁做网站多少钱做网站大概需要多少费用
  • jmeter内存踩坑记录
  • 浙江建设职业技术学院网站彬县网
  • PowerShell 和 CMD
  • EFS `<br>` 标签渲染修复:从文本到换行的完整解决方案
  • 怎样在建设厅网站查询安全员证彩票网站开发与建设
  • 创建一个网站要钱吗梅林网站建设公司
  • 成都小程序定制开发企业网站怎样做seo优化 应该如何做
  • Java中的设计模式------策略设计模式
  • 太原做网站设计电子商务网站设计原理书籍