STM32+CubeMX的串口非阻塞自动接收数据的实现
功能就是利用stm32的串口的空闲中断来实现一帧数据的完成判断。利用库函数直接弄也可以,这里是用CubeMX生成工程的修改。
DMA配置
中断优先级配置,好像串口优先级最好要高于dma优先级
工程这里最好勾选,这样会有独立的文件出来
直接上代码,usart.c中先插入以下
/* Includes ------------------------------------------------------------------*/
#include "usart.h"
/* USER CODE BEGIN 0 */
#include "string.h"
#define HUART1_BUF_SIZE 128
typedef struct {
uint8_t RxBuf[HUART1_BUF_SIZE];
uint8_t DealBuf[HUART1_BUF_SIZE];
uint16_t DealBufLen;
uint8_t DealFlag;
void (*callback)(uint8_t*, uint16_t);
} huartBuf_t;
huartBuf_t huart1RxBuf = {0};
huartBuf_t huart2RxBuf = {0};
huartBuf_t huart3RxBuf = {0};
uint8_t huartInitFlag = 0;
/* USER CODE END 0 */
在文件下边加入以下
/* USER CODE BEGIN 1 */
void usart1Send(uint8_t *pData, uint16_t Size)
{
HAL_UART_Transmit_DMA(&huart1, pData, Size);
}
void usart2Send(uint8_t *pData, uint16_t Size)
{
HAL_UART_Transmit_DMA(&huart2, pData, Size);
}
void usart3Send(uint8_t *pData, uint16_t Size)
{
HAL_UART_Transmit_DMA(&huart3, pData, Size);
}
void usart1SendStr(char *pData)
{
HAL_UART_Transmit_DMA(&huart1, (uint8_t*)pData, strlen(pData));
}
void usart2SendStr(char *pData)
{
HAL_UART_Transmit_DMA(&huart2, (uint8_t*)pData, strlen(pData));
}
void usart3SendStr(char *pData)
{
HAL_UART_Transmit_DMA(&huart3, (uint8_t*)pData, strlen(pData));
}
void usartRxCompleted(UART_HandleTypeDef *huart)
{
uint32_t tmp_flag = 0;
uint32_t temp;
tmp_flag = __HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE); //获取IDLE标志位
if((tmp_flag != RESET)) { //idle标志被置位
__HAL_UART_CLEAR_IDLEFLAG(huart);//清除标志位
temp = huart->Instance->SR; //清除状态寄存器SR,读取SR寄存器可以实现清除SR寄存器的功能
temp = huart->Instance->DR; //读取数据寄存器中的数据
temp = __HAL_DMA_GET_COUNTER(huart->hdmarx);// 获取DMA中未传输的数据个数,NDTR寄存器分析见下面
if(temp < HUART1_BUF_SIZE) {
HAL_UART_DMAStop(huart); //
if(huart->Instance == USART1) {
huart1RxBuf.DealBufLen = HUART1_BUF_SIZE - temp; //总计数减去未传输的数据个数,得到已经接收的数据个数
memset(huart1RxBuf.DealBuf, 0, HUART1_BUF_SIZE);
memcpy(huart1RxBuf.DealBuf, huart1RxBuf.RxBuf, temp);
huart1RxBuf.DealFlag = 1; // 接受完成标志位置1
HAL_UART_Receive_DMA(huart, huart1RxBuf.RxBuf, HUART1_BUF_SIZE);
} else if(huart->Instance == USART2) {
huart2RxBuf.DealBufLen = HUART1_BUF_SIZE - temp; //总计数减去未传输的数据个数,得到已经接收的数据个数
memset(huart2RxBuf.DealBuf, 0, HUART1_BUF_SIZE);
memcpy(huart2RxBuf.DealBuf, huart2RxBuf.RxBuf, temp);
huart2RxBuf.DealFlag = 1; // 接受完成标志位置1
HAL_UART_Receive_DMA(huart, huart2RxBuf.RxBuf, HUART1_BUF_SIZE);
} else if(huart->Instance == USART3) {
huart3RxBuf.DealBufLen = HUART1_BUF_SIZE - temp; //总计数减去未传输的数据个数,得到已经接收的数据个数
memset(huart3RxBuf.DealBuf, 0, HUART1_BUF_SIZE);
memcpy(huart3RxBuf.DealBuf, huart3RxBuf.RxBuf, temp);
huart3RxBuf.DealFlag = 1; // 接受完成标志位置1
HAL_UART_Receive_DMA(huart, huart3RxBuf.RxBuf, HUART1_BUF_SIZE);
}
}
}
}
static void uart1Handle(uint8_t* data, uint16_t len);
void usartDealHandle(void)
{
if(huartInitFlag == 0) {
huartInitFlag = 1;
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart1, huart1RxBuf.RxBuf, HUART1_BUF_SIZE);
__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart2, huart2RxBuf.RxBuf, HUART1_BUF_SIZE);
__HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart3, huart3RxBuf.RxBuf, HUART1_BUF_SIZE);
registerUsartNotic(&huart1, uart1Handle);
}
if(huart1RxBuf.DealFlag == 1) {
huart1RxBuf.DealFlag = 0;
if(huart1RxBuf.callback != NULL) {
huart1RxBuf.callback(huart1RxBuf.DealBuf, huart1RxBuf.DealBufLen);
}
}
if(huart2RxBuf.DealFlag == 1) {
huart2RxBuf.DealFlag = 0;
if(huart2RxBuf.callback != NULL) {
huart2RxBuf.callback(huart3RxBuf.DealBuf, huart2RxBuf.DealBufLen);
}
}
if(huart3RxBuf.DealFlag == 1) {
huart3RxBuf.DealFlag = 0;
if(huart3RxBuf.callback != NULL) {
huart3RxBuf.callback(huart3RxBuf.DealBuf, huart3RxBuf.DealBufLen);
}
}
}
void registerUsartNotic(UART_HandleTypeDef *huart, void(*callback)(uint8_t*, uint16_t))
{
if(callback == NULL) {
return;
}
if(huart->Instance == USART1) {
huart1RxBuf.callback = callback;
} else if(huart->Instance == USART2) {
huart2RxBuf.callback = callback;
} else if(huart->Instance == USART3) {
huart3RxBuf.callback = callback;
}
}
static void uart1Handle(uint8_t* data, uint16_t len)
{
usart1Send(data, len);
}
/* USER CODE END 1 */
usart.h加入
/* USER CODE BEGIN Prototypes */
void usart1Send(uint8_t *pData, uint16_t Size);
void usart2Send(uint8_t *pData, uint16_t Size);
void usart3Send(uint8_t *pData, uint16_t Size);
void usart1SendStr(char *pData);
void usart2SendStr(char *pData);
void usart3SendStr(char *pData);
void usartRxCompleted(UART_HandleTypeDef *huart);
void usartDealHandle(void);
void registerUsartNotic(UART_HandleTypeDef *huart, void(*callback)(uint8_t*, uint16_t));
/* USER CODE END Prototypes */
stm32l1xx_it.c加入以下两段
/* USER CODE BEGIN Includes */
#include "usart.h"
/* USER CODE END Includes */
/**
* @brief This function handles USART1 global interrupt.
*/
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
usartRxCompleted(&huart1);
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
main.c里这样改
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
usartDealHandle();
}
/* USER CODE END 3 */
代码里void registerUsartNotic(UART_HandleTypeDef *huart, void(*callback)(uint8_t*, uint16_t))
这个函数不是必须,registerUsartNotic(&huart1, uart1Handle);
这个就不是一定有 。但因为一般串口的协议处理都会单独有文件,所以,最好有个回调函数的注册,可以方便解耦。
发送也都是DMA形式的,不会阻塞。