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

UART更好的封装 添加容错代码

modbus_new_st_rtu函数里有pdev = GetUARTDevice((char*)device);

两个串口结构体使用了相似的函数,为避免代码冗余,特进行改进

uart_device.htypedef struct UART_Device{char* name;int (*Init)(struct UART_Device* pDev, int baud, char parity, int data_bit, int stop_bit);int (*Send)(struct UART_Device* pDev, uint8_t* datas, uint32_t len, int timeout);int (*RecvByte)(struct UART_Device* pDev, uint8_t* data, int timeout);int (*Flush)(struct UART_Device* pDev);void *priv_data;
}UART_Device, *PUART_Device;UART_Device* GetUARTDevice(char* name);
uart.c#define UART_RX_BUF_LEN 100//定义私有数据用于区分usart2和usart4
typedef struct UART_Data{UART_HandleTypedef* huart;//有了以下就可以删去以前定义的全局变量QueueHandle_t rxQueue;SemaphoreHandle_t txSemaphore;uint8_t rx_buf[UART_RX_BUF_LEN];
}UART_Data, *PUART_Data;static int UART2_Rx_Start(PUART_Device pDev, int baud, char parity, int data_bit int stop_bit){PUART_Data pdata = pDev->priv_data;    if(!pdata->rxQueue){pdata->rxQueue = xQueueCreate(200,1);pdata->txSemaphore = xSemaphoreCreateBinary();HAL_UARTEx_ReceiveToIdle_DMA(pdata->huart, pdata->rx_buf, UART_RX_BUF_LEN);}return 0;
}static int UART_Send(PUART_Device pDev, uint8_t* datas, uint32_t len, int timeout){PUART_Data pdata = pDev->priv_data;HAL_UART_Transmit_DMA(pdata->huart, datas, len);if(pdTRUE == xSemaphoreTake(pdata->txSemaphore, timeout))return 0;elsereturn -1;    
}int UART_GetData(PUART_Device pdev, uint8_t* pData, int timeout){PUART_Data pdata = pDev->priv_data;if(pdPASS == xQueueReceive(pdata->rxQueue, pData, timeout))return 0;elsereturn -1;
}int UART_Flush(PUART_Device pdev){PUART_Data pdata = pDev->priv_data;int cnt = 0;uint8_t data;while(1){if(pdPASS != xQueueReceive(pdata->rxQueue, &data, 0))break;cnt++;}return cnt;
}static UART_Data g_uart2_data = {&huart2,
};static UART_Data g_uart4_data = {&huart4,
};UART_Device g_uart2_dev = {"uart2", UART_Rx_Start, UART_Send, UART_GetData, UART_Flush, &g_uart2_data};
UART_Device g_uart4_dev = {"uart4", UART_Rx_Start, UART_Send, UART_GetData, UART_Flush, &g_uart4_data};
uart.cvoid HAL_UART_TxCpltCallback(UART_HandleTypeDef* huart){PUART_Data pdata;if(huart == &huart2){pdata = &g_uart2_data;}if(huart == &huart4){pdata = &g_huart4_data;}xSemaphoreGiveFromISR(pdata->txSemaphore, NULL);
}void HAL_UART_RxCpltCallback(UART_HandleTypeDef* huart){PUART_Data pdata;if(huart == &huart2){pdata = &g_uart2_data;}if(huart == &huart4){pdata = &g_huart4_data;}for(int i=0; i<UART_RX_BUF_LEN; ++i){xQueueSendFromISR(pdata->rxQueue, (const void*)&pdata->rx_buf[i], NULL);}HAL_UARTEx_ReceiveToIdle_DMA(pdata->huart, pdata->rx_buf, UART_RX_BUF_LEN);
}void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef* huart, uint16_t Size){PUART_Data pdata;if(huart == &huart2){pdata = &g_uart2_data;}if(huart == &huart4){pdata = &g_huart4_data;}for(int i=0; i<Size; ++i){xQueueSendFromISR(pdata->rxQueue, (const void*)&pdata->rx_buf[i], NULL);}HAL_UARTEx_ReceiveToIdle_DMA(pdata->huart, pdata->rx_buf, UART_RX_BUF_LEN);
}void HAL_UART_ErrorCallback(UART_HandleTypeDef* huart){PUART_Data pdata;if(huart == &huart2){pdata = &g_uart2_data;}if(huart == &huart4){pdata = &g_huart4_data;}HAL_UARTEx_ReceiveToIdle_DMA(pdata->huart, pdata->rx_buf, UART_RX_BUF_LEN);}

为了提高产品的稳定性,添加容错代码,增强健壮性。


void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{PUART_Data data = NULL;if (huart == &huart2){data = &g_uart2_data;}if (huart == &huart4){data = &g_uart4_data;}if (data){HAL_UART_DeInit(data->huart);HAL_UART_Init(data->huart);/* re-start DMA+IDLE rx */HAL_UARTEx_ReceiveToIdle_DMA(data->huart, data->rx_buf, RX_BUF_LEN);//HAL_UARTEx_ReceiveToIdle_IT(data->huart, data->rx_buf, 1);}
}在f030中添加如下容错代码:
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{if (huart == &huart1){struct UART_Data* uart_data = g_uart1_dev.priv_data;}HAL_UART_DeInit(uart_data->huart);HAL_UART_Init(uart_data->huart);HAL_UART_Receive_IT(data->huart, &uart_data->rx_buf, 1);}

粘包现象举例:传感器接收数据包超时时间太长,而H5传来的两包数据之间时间间隔太短,就会使得两包数据粘在一起,导致传输来的数据无法解析,传感器程序一直卡在接收那里:

for(;;){do{rc = modbus_receive(ctx, query); //内部会校验接收的数据是否正确,不正确继续循环下去}while(rc == 0);......}

modbus规范中,由于没有起始/结束符,因此在两个数据包之间间隔3.5个字符时间,一个完整的字符时间(包括起始位、数据位、停止位)通常是10-11个比特时间。

对于115200的波特率来说,两个数据包的时间间隔是10*3.5/115200 = 0.3ms.

在modbus_new_st_rtu函数中的_modbus_init_common函数内部ctx->byte_timeout.tv_usec, ctx->response_timeout.tv_usec(即接收一个字节的超时时间,回应的超时时间)都可以改小点,比如

表示Master程序发出请求后,等待回复时,最多等待多久,这个时间可以设置的大一点
#define _RESPONSE_TIMEOUT 10000表示的是,开始得到数据后,如果后续没有数据了,等待多久退出。这个时间可以设置的小一点。
#define _BYTE_TIMEOUT 10000在h5和f030中都做以上更改

以上是通过1)减小超时时间来减少粘包现象的,在此基础上可以2)增加发送数据包的间隔减小该现象。如以下在获得锁之后延时20ms使得发送和接收不再那么频繁。

以上会让传感器超时退出,进入新一波的等待流程。

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

相关文章:

  • Qt6用Chart模块做数据可视化?别再用老套路,看看这套35张图背后的秘密
  • [密码学实战](GBT 15843.2-2017)Java实现基于SM4的实体鉴别机制(四十八)
  • MinIO祭了,RustFS来了!
  • 关于node中的一些用到的读取文件方法
  • Dubbo3单端口多协议源码分析
  • 员工拍照泄密?U盘偷拷资料?终端数据安全如何守护?
  • G1垃圾收集器
  • 【高级】系统架构师 | 信息系统战略规划、EAI 与新技术
  • 攻防世界secret-galaxy-300
  • 深度学习----卷积神经网络的数据增强
  • 如何给JavaScript语句添加注释?
  • 19.JS
  • Jmeter怎么实现接口关联?
  • 算法题(198):数字三角形
  • 使用 Terraform、AWS 和 Python 构建无服务器实时数据管道
  • 学习React-9-useSyncExternalStore
  • Ubuntu下把 SD 卡格式化为 FAT32
  • 【工具变量】“国家级大数据综合试验区”试点城市DID(2000-2024年)
  • ArkTS状态管理V1
  • Llama v3 中的低秩自适应 (LoRA)
  • 头歌实训作业答案C++ 01
  • Proteus8 + STM32CubeMX 实现 STM32F103R6 串口通信教程
  • JMeter下载安装及使用入门
  • 常用符号 Emoji 对照表——Unicode UTF-8
  • SQLSERVER临时表
  • 关于专业化与多元化该怎么选?
  • 解决MQ访问不了或者登录不成功问题
  • 卷积神经网络CNN-part2-简单的CNN
  • TypeScript与JavaScript:从动态少年到稳重青年的成长之路
  • RabbitMQ相关知识