/// @brief 串口发送一条格式化数据
void send_OneWeld_list_to_uart(uint16_t id)
{
uint8_t char_data_uart[ONE_WEld_LIST_BYTE +2];
char_data_uart[0] = 'M';//MCU 的数据
char_data_uart[1] = 'I';//list
memcpy(&char_data_uart[2], &OneWeld_Data_new, sizeof(OneWeld_Data_TypeDef));
Send_Data_toLCD(char_data_uart, sizeof(char_data_uart),100);
}
/// @brief 通过DMA发送数据到LCD
/// @param pData 数据指针
/// @param Size 数据长度
/// @param timeout 超时时间
#pragma location = ".ccmram"
void Send_Data_toLCD(const uint8_t *pData, uint16_t Size,uint32_t timeout)
{
uint32_t tickstart; tickstart = HAL_GetTick();
while (huart1.gState != HAL_UART_STATE_READY) //等待发送完成
{
if (((HAL_GetTick() - tickstart) > timeout) || (timeout == 0U))
return;
Refresh_ModbusData_and_IWDG();
}
HAL_UART_Transmit_DMA(&huart1, pData, Size);
}
代码如上图,调用send_OneWeld_list_to_uart函数发送数据到LCD时,有几率出错!
原因是因为串口使用DMA发送,而给DMA的发送数据地址是一个临时变量,
在退出发送函数后,临时变量的地址被释放用于存储其他数据,
而串口发送速度是比较慢的(相较于CPU),这导致发送的数据有几率被修改。
解决方法:
- 将临时变量char_data_uart变量改为全局变量或静态变量,避免内存被释放。
- 或在send_OneWeld_list_to_uart函数内等待DMA发送完成后再进行后续的操作,避免退出函数后内存被释放!
- 修改Send_Data_toLCD函数,根据数据量拷贝数据到静态或全局变量,DMA指向拷贝后的变量
教训:一定要注意DMA的问题,之前还遇到过调试断点导出数据总是出错,运行时则没问题的情况,是因为DMA等大部分外设都不会因为CPU核心的停止而停止工作,调试断点时,CPU停止了,但是DMA并没有停止,导致导出的内存数据是错的。