STM32+CubeMX的串口非阻塞自动接收数据的实现

STM32+CubeMX的串口非阻塞自动接收数据的实现

功能就是利用stm32的串口的空闲中断来实现一帧数据的完成判断。利用库函数直接弄也可以,这里是用CubeMX生成工程的修改。
DMA配置
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形式的,不会阻塞。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值