HAL库配置UART
https://blog.csdn.net/u012523921/article/details/105411008
https://jiejie.blog.csdn.net/article/details/80563422
1、查询(基本不用)
2、中断
3、中断+DMA
操作分3个步骤
1、设置STM32cubeMX,初始化代码在stm32f4xx_hal_msp.c,执行代码在main.C
2、打开中断和接收相关函数
//开启空闲中断 __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); //UART_IT_IDLE 空闲中断 //UART_IT_RXNE //UART_IT_TXE //UART_IT_PE //UART_IT_TC //UART_IT_LBD //UART_IT_CTS //UART_IT_ERR //开启DMA接收, HAL_UART_Receive_DMA(&huart1, (uint8_t*)uart1_rx_buf, USART1_RX_BUF_SIZE); //@file stm32f4xx_hal_uart.c /* 阻塞模式Blocking mode:通信以轮询模式执行。 (+) HAL_UART_Transmit() (+) HAL_UART_Receive() 非阻塞模式Non-Blocking:使用中断执行通信,这些API会返回HAL状态 (+) HAL_UART_Transmit_IT() (+) HAL_UART_Receive_IT() (+) HAL_UART_IRQHandler() 非阻塞模式Non-Blocking:使用DMA执行通信或,这些API会返回HAL状态 (+) HAL_UART_Transmit_DMA() (+) HAL_UART_Receive_DMA() (+) HAL_UART_DMAPause() (+) HAL_UART_DMAResume() (+) HAL_UART_DMAStop() 非阻塞模式Non-Blocking回调函数: (+) HAL_UART_TxHalfCpltCallback() (+) HAL_UART_TxCpltCallback() (+) HAL_UART_RxHalfCpltCallback() (+) HAL_UART_RxCpltCallback() (+) HAL_UART_ErrorCallback() 非阻塞模式Non-Blocking中止执行函数: (+) HAL_UART_Abort() (+) HAL_UART_AbortTransmit() (+) HAL_UART_AbortReceive() (+) HAL_UART_Abort_IT() (+) HAL_UART_AbortTransmit_IT() (+) HAL_UART_AbortReceive_IT() (+) HAL_UART_AbortCpltCallback() (+) HAL_UART_AbortTransmitCpltCallback() (+) HAL_UART_AbortReceiveCpltCallback() */
3、处理相关函数
处理相关函数一般放在中断函数,或者回调函数内。先判断中断串口号,中断类型,清除中断类型。
/** * @brief This function handles USART1 global interrupt. */ void USART1_IRQHandler(void) { /* USER CODE BEGIN USART1_IRQn 0 */ /* USER CODE END USART1_IRQn 0 */ HAL_UART_IRQHandler(&huart1); /* USER CODE BEGIN USART1_IRQn 1 */ USER_UART_IRQHandler(&huart1); //加入自己的中断处理函数 /* USER CODE END USART1_IRQn 1 */ }
//下面是自己的空闲中断处理函数 void USER_UART_IRQHandler(UART_HandleTypeDef *huart) { if(USART1 == huart->Instance) //判断是否是串口1 { if(RESET != __HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE)) //判断是否是空闲中断 { __HAL_UART_CLEAR_IDLEFLAG(&huart1); //清楚空闲中断标志(否则会一直不断进入中断) USAR_UART_IDLECallback(huart); //调用中断处理函数 } } }
//空闲中断回调函数 void USAR_UART_IDLECallback(UART_HandleTypeDef *huart) { if(USART1 == huart->Instance){ uint8_t data_len1; //停止本次DMA传输 data_len1 = USART1_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx); //计算接收到的数据长度 fifo_uart1_rx.tail = data_len1; if(fifo_uart1_rx.head <= fifo_uart1_rx.tail) { fifo_uart1_rx.DMAsize = fifo_uart1_rx.tail - fifo_uart1_rx.head; } else if(fifo_uart1_rx.head > fifo_uart1_rx.tail) { fifo_uart1_rx.DMAsize = USART1_RX_BUF_SIZE - fifo_uart1_rx.head + fifo_uart1_rx.tail; } fifo_uart1_rx.flag = 1;//置位标志,表示接收到数据 __HAL_DMA_DISABLE(huart->hdmarx); //__HAL_DMA_SET_COUNTER(huart->hdmarx, USART1_RX_BUF_SIZE); __HAL_DMA_ENABLE(huart->hdmarx); /*用户实现的回调函数*/ uart1_get_data(uart1_tx_dma_buf,fifo_uart1_rx.DMAsize); HAL_UART_Transmit_DMA(&huart1, uart1_tx_dma_buf,fifo_uart1_rx.DMAsiz);
// HAL_UART_Transmit_DMA(&huart1, uart1_rx_buf, sizeof(uart1_rx_buf) - 1); // 采用DMA发送 str,按照str实际大小发送,不发送字符串末尾的'0' // if(p_uart1_rx_complete_callback != NULL) // (*p_uart1_rx_complete_callback)(); // //这里是定义的回调函数指针, // //用户可以自己定义这个回调函数, // //因为我做的这个模块是要打包给别人使用的, // //这种用户实现的函数都是通过函数指针定义的, // //这样用户可以自己定义回调函数的函数名,如果不需要回调,可以将这里注释掉; } }
//串口接收环形缓冲区取出函数 //参数1:串口接收环形缓冲区对象指针 //参数2:串口接收环形缓冲区最大长度 //参数3:取出的数据缓冲区地址 //参数4:取出的数据长度 //返回数据:取出的数据长度 uint16_t uart1_get_data(uint8_t *data_rsv,uint16_t len) { uint16_t i=0; if(fifo_uart1_rx.flag &&(fifo_uart1_rx.DMAsize > 0))//接收到数据 { for(;i<len;i++)//取出环形缓冲区的数据 { data_rsv[i] = fifo_uart1_rx.buf[fifo_uart1_rx.head]; fifo_uart1_rx.head ++; fifo_uart1_rx.head %= USART1_RX_BUF_SIZE; if(fifo_uart1_rx.head == fifo_uart1_rx.tail) { fifo_uart1_rx.flag = 0;//清空接收数据标志 i++; break; } } } return (i); }
//这里是发送和接收缓冲区的定义 __align(2) uint8_t uart1_tx_dma_buf[USART1_TX_BUF_SIZE]={0}; __align(2) uint8_t uart1_rx_buf[USART1_RX_BUF_SIZE]={0}; /*这里虽然是注释部分,但是这是工程中用到的代码,这里只是以这种方式进行说明一下: 关于fifo_uart1_rx的说明,在uart.h中定义的环形结构体:*/ typedef struct{ uint16_t head;//帧头位置 uint16_t tail;//帧尾位置 uint16_t DMAsize;//硬件DMA发送的长度【接收帧长度】 uint8_t *buf; //内存起始地址, uint8_t flag; //帧标志 }uart_fifo_t; //串口1的环形缓冲区 static __IO uart_fifo_t fifo_uart1_tx={0,0,0,uart1_tx_dma_buf,0}; //串口1的环形缓冲区 static __IO uart_fifo_t fifo_uart1_rx={0,0,USART1_RX_BUF_SIZE,uart1_rx_buf,0};
#define RX_MAX_COUNT 255 // 串口接收最大字节数
#define USART1_TX_BUF_SIZE 255
#define USART1_RX_BUF_SIZE 255
//uint8_t USART1_RX_BUF_SIZE //uint8_t uart1_rx_buf[USART1_RX_BUF_SIZE]; __IO uint8_t aRxBuffer[RX_MAX_COUNT]={0}; // 接收缓冲区 __IO uint16_t RxCount=0; // 已接收到的字节数 __IO uint8_t Frame_flag=0; // 帧标志:1:一个新的数据帧 0:无数据帧
extern uint8_t uart1_rx_buf[USART1_TX_BUF_SIZE];
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决