捡 了一个Stm32f103X的工控板,
开发工具是 STM32cubeide ,复制了之前闲的时候建的一个485通讯的空工程,只配置了圈中的引脚,用的是usart3 ,增加了需要用的io,编程器是网上几块钱买的jlink-ob,带模拟串口的.
在学习串口通信的过程中总感觉不太顺利 ,刚开始用串口中断接收的时候有时正常有时不正常 ,后来每次都多出来一个字节(最后多出 00),怀疑是编程器模拟串口有问题,于是换了一个CH340模块,换了之后,竟然无法通讯了.此时发现只有上位机用编程器模拟串口可以和工控板的usart3通讯,
此时为了对比测试启用了uart4, 同样的代码,模拟串口和ch340都可以和工控板正常通讯,没有多出00.对我来说这是一个好消息至少有一个是正常的.
学习用空闲中断接收的时候,同样的接收完的数据也会多出00,死活查不出原因,有了前面的经验,经过处理,也算是正常通讯了.
学习DMA空闲中断收发的时候就出大问题了,工控板只有第一次收到数据能正常响应,再发送就没反应了,以为是没再次启动DMA空闲中断收发导致的,根据网上的资料一点点查,确定没有遗漏相关代码.于时放断点跟踪 ,发现单步调试的时候工控板可以正常收发5次左右才没有响应.同样代码使用uart4很正常.
为了找原因 重新建工程使用了usart3和uart4两个串口做对比测试,十分正常正常的.于是我就怀疑是不是我拷485通讯空工程的时候有一个报错导致的.于是重新拷过一遍,编译后还是出来同样的问题,
后来终于想到会不会是电路上有些特殊,于是找来原理图,才发现配置了 DE RE 两个引脚,于是复位了引脚 .再次编译测试.头疼的问题终于解决了...
附上DMA空闲中断接收的代码
定义接收数组等
#define REC_LENGTH 1
#define MAX_REC_LENGTH 100struct COMM
{uint8_t Rx_flg;//USARTx接收完成标志uint8_t Rx_cnt;//USARTx接受数据计数器uint8_t timeOut;uint8_t Rx_temp[MAX_REC_LENGTH];//USARTx接收数据缓存uint8_t Rx_Buf[MAX_REC_LENGTH]; //USARTx存储接收数据uint8_t Tx_Buf[MAX_REC_LENGTH];
} ;extern struct COMM comm1, comm3,comm4;
启动DMA空闲中断,放main中
/* USER CODE BEGIN 2 *///启动串口DMA空闲中断接收HAL_UARTEx_ReceiveToIdle_DMA(&huart3, comm3.Rx_temp,MAX_REC_LENGTH);//关闭DMA半满中断__HAL_DMA_DISABLE_IT(&hdma_usart3_rx, DMA_IT_HT) ;/* USER CODE END 2 */
回调函数
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{/* Prevent unused argument(s) compilation warning */UNUSED(huart);UNUSED(Size);//获取中断类型HAL_UART_RxEventTypeTypeDef RxEventType = HAL_UARTEx_GetRxEventType(huart);if (huart==&huart3) {switch (RxEventType){case HAL_UART_RXEVENT_TC:// 传输完成事件printf("Reception Complete\r\n");break;case HAL_UART_RXEVENT_HT:// 半传输完成事件printf("Half Reception Complete\r\n");break;case HAL_UART_RXEVENT_IDLE:// 空闲事件printf("Idle Event Detected\r\n");comm3.Rx_flg=1;comm3.Rx_cnt=Size;memset(comm3.Rx_Buf,0x00,sizeof (comm3.Rx_Buf));memcpy(comm3.Rx_Buf,comm3.Rx_temp,Size);break;default:// 其他事件printf("Unknown Event\r\n");break;}//因为是normal模式再次开启DMA的空闲中断接收HAL_UARTEx_ReceiveToIdle_DMA(&huart3,comm3.Rx_temp,sizeof(comm3.Rx_temp));__HAL_DMA_DISABLE_IT(&hdma_usart3_rx, DMA_IT_HT) ;}
通讯出错后会进,在这里需要再次开启DMA空闲中断接收,不然就没响应了.
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{if(huart->Instance == USART3){// 接收发生错误后重启HAL_UARTEx_ReceiveToIdle_DMA(&huart3, comm3.Rx_temp,sizeof(comm3.Rx_temp)); __HAL_DMA_DISABLE_IT(&hdma_usart3_rx, DMA_IT_HT); // 关闭DMA_IT_HT中断memset(comm3.Rx_Buf,0x00,sizeof (comm3.Rx_Buf)); // 清除接收缓存}printf("HAL_UART_ErrorCallback\r\n");
}
网上有网友推荐放在这里,不会因为进不了回调函数导致通讯出错后不能自动恢复.
void USART3_IRQHandler(void)
{/* USER CODE BEGIN USART3_IRQn 0 *//* USER CODE END USART3_IRQn 0 */HAL_UART_IRQHandler(&huart3);/* USER CODE BEGIN USART3_IRQn 1 *///启动串口DMA空闲中断接收HAL_UARTEx_ReceiveToIdle_DMA(&huart3, comm3.Rx_temp,MAX_REC_LENGTH);__HAL_DMA_DISABLE_IT(&hdma_usart3_rx, DMA_IT_HT) ;/* USER CODE END USART3_IRQn 1 */
}