基于STM32F103芯片HAL库的串口DMA通讯

网上有好多关于DMA的原理介绍文章,这里不再介绍了,直接上干货。

但是网上的例子都 是很简单的,没有实用价值,而且还容易丢包,所以自己写了一个,经过测试不会丢包了。写得不好请见谅。

STM32CUBE配置串口1与串口3的DMA,因为是Demo,所以只配置用到的内容

配置串口波特率, 这里只截取一个图片,因为串口1与串口3的波特率设置是一样的

串口1 DMA的中断设置,级别设置成3  ,串口3DMA的中断设置,也是如此 

串口1的DMA设置  ,接收速度 可以设置成LOW或Dedium或high,看你自己需求设置

串口3的DMA设置  ,接收速度 可以设置成LOW或Dedium或high,看你自己需求设置

RCC设置一下

SYS设置一下,

时钟再设置一下,因为我是有外部晶振,这里直接在红框里写上72,然后敲回车,就自己配置好了 ,

然后就是工程设置了,这里就直接截图了,没有啥套路

然后就可以 GENERATE CODE了。

生成 工程后,打开工程,开始编写DEMO, 我这里将关键代码 直接贴出来

1。先写一个头文件 common_types.h

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    common_types.h
  * @brief   This file contains all the function prototypes for
  *          the usart.c file
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __COMMON_TYPES_H__
#define __COMMON_TYPES_H__

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"



/* USER CODE BEGIN Includes */

#define DEBUG_FLAG 1   //print uart1 flag 1:print 0:no print
#define UART_BANDRATE 115200



#define BUFFERSIZE  2048  //接收数据缓存区的大小
//目的是为了不让接收出现接收完成中断(回调),这样容易出现两次判断点,所以+1 大于单次接收的长度,保证只产生空闲中断(回调)
#define RX_MAX  1600       // //单次接收最大量   预计单次接收数据的最大值+1,
#define NUM        4                   //se指针对结构体数组长度





typedef struct{
    uint8_t *start;     //s用于标记起始位置
    uint8_t *end;       //e用于标记结束位置
}LCB;                   //se指针对结构体

typedef struct{
    uint32_t RxCounter;                 //累计接收数据量
    uint32_t TxCounter;                 //累计接收数据量
    uint32_t TxState;                   //发送数据状态  0:表示空闲 1:表示忙碌
    LCB      RxLocation[NUM];           //se指针对结构体数组
    LCB      TxLocation[NUM];           //se指针对结构体数组
    LCB      *RxInPtr;                  //指针 用于标记接收数据
    LCB      *RxOutPtr;                 //OUT指针 用于提取接收的数据
    LCB      *RxEndPtr;                 //IN和OUT指针的结尾标志
    LCB      *TxInPtr;                  //指针 用于标记发送数据
    LCB      *TxOutPtr;                 //OUT指针 用于提取发送的数据
    LCB      *TxEndPtr;                 //IN和OUT指针的结尾标志
    UART_HandleTypeDef uart;
    DMA_HandleTypeDef hdma_usart_rx;    //dmarx
    DMA_HandleTypeDef hdma_usart_tx;    //dmatx
}UCB;                                   //串口控制结构体



#ifdef __cplusplus
}
#endif

#endif /* __COMMON_TYPES_H__ */

2.修改USART.h

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    usart.h
  * @brief   This file contains all the function prototypes for
  *          the usart.c file
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USART_H__
#define __USART_H__

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "main.h"

#include "common_types.h"

extern uint8_t UART1_RxBuff[BUFFERSIZE];    //接收缓冲区长度
extern uint8_t UART1_TxBuff[BUFFERSIZE];    //发送缓冲区长度

extern uint8_t UART3_RxBuff[BUFFERSIZE];
extern uint8_t UART3_TxBuff[BUFFERSIZE];
/* USER CODE END Includes */



/* USER CODE BEGIN Private defines */


extern UCB huart1;   //变量外部声明
extern UCB huart3;   //变量外部声明
/* USER CODE END Private defines */

void MX_USART1_UART_Init(uint32_t bandrate);
void MX_USART3_UART_Init(uint32_t bandrate);


/* USER CODE BEGIN Prototypes */
void USART_PrtInit(UCB *huart, uint8_t * USART_RxBuff, uint8_t * USART_TxBuff);
void USART_TxData(UCB *huart, uint8_t * USART_TxBuff,uint8_t *data, uint32_t data_len);
void ProcessData(UCB * huart, uint8_t * USART_TxBuff);

//void USART1_PrtInit(void);
//void UART1_TxData(uint8_t *data, uint32_t data_len);

//void USART3_PrtInit(void);  
//void UART3_TxData(uint8_t *data, uint32_t data_len);
/* USER CODE END Prototypes */

#ifdef __cplusplus
}
#endif

#endif /* __USART_H__ */

3. 修改USART.c

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    usart.c
  * @brief   This file provides code for the configuration
  *          of the USART instances.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "usart.h"
#include "stdio.h"
#include "string.h"
/* USER CODE BEGIN 0 */

#if 1

#if (__ARMCC_VERSION >= 6010050)            /* 使用AC6编译器时 */
__asm(".global __use_no_semihosting\n\t");  /* 声明不使用半主机模式 */
__asm(".global __ARM_use_no_argv \n\t");    /* AC6下需要声明main函数为无参数格式,否则部分例程可能出现半主机模式 */

#else
/* 使用AC5编译器时, 要在这里定义__FILE 和 不使用半主机模式 */
#pragma import(__use_no_semihosting)

struct __FILE
{
    int handle;
    /* Whatever you require here. If the only file you are using is */
    /* standard output using printf() for debugging, no file handling */
    /* is required. */
};

#endif

/* 不使用半主机模式,至少需要重定义_ttywrch\_sys_exit\_sys_command_string函数,以同时兼容AC6和AC5模式 */
int _ttywrch(int ch)
{
    ch = ch;
    return ch;
}

/* 定义_sys_exit()以避免使用半主机模式 */
void _sys_exit(int x)
{
    x = x;
}

char *_sys_command_string(char *cmd, int len)
{
    return NULL;
}


/* FILE 在 stdio.h里面定义. */
FILE __stdout;

/* MDK下需要重定义fputc函数, printf函数最终会通过调用fputc输出字符串到串口 */
int fputc(int ch, FILE *f)
{
    if(DEBUG_FLAG)
    {
        while ((USART1->SR & 0X40) == 0);     /* 等待上一个字符发送完成 */

        USART1->DR = (uint8_t)ch;             /* 将要发送的字符 ch 写入到DR寄存器 */
    }
    return ch;
}
#endif

/* USER CODE END 0 */

uint8_t UART1_RxBuff[BUFFERSIZE];   //串口1接收缓冲区
uint8_t UART1_TxBuff[BUFFERSIZE];   //串口1发送缓冲区

uint8_t UART3_RxBuff[BUFFERSIZE];   //串口3接收缓冲区
uint8_t UART3_TxBuff[BUFFERSIZE];   //串口3发送缓冲区

UCB huart1;                         //串口1控制结构体
UCB huart3;                         //串口3控制结构体

/* USART1 init function */

void MX_USART1_UART_Init(uint32_t bandrate)
{

    /* USER CODE BEGIN USART1_Init 0 */

    /* USER CODE END USART1_Init 0 */

    /* USER CODE BEGIN USART1_Init 1 */

    /* USER CODE END USART1_Init 1 */
    huart1.uart.Instance = USART1;
    huart1.uart.Init.BaudRate = bandrate;                      //设置波特率
    huart1.uart.Init.WordLength = UART_WORDLENGTH_8B;        //8位数据位
    huart1.uart.Init.StopBits = UART_STOPBITS_1;             //1个停止位
    huart1.uart.Init.Parity = UART_PARITY_NONE;              //不使用校验位
    huart1.uart.Init.Mode = UART_MODE_TX_RX;                 //收发开启
    huart1.uart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart1.uart.Init.OverSampling = UART_OVERSAMPLING_16;
    if (HAL_UART_Init(&huart1.uart) != HAL_OK)
    {
        Error_Handler();
    }
    /* USER CODE BEGIN USART1_Init 2 */
    USART_PrtInit(&huart1,UART1_RxBuff,UART1_TxBuff);
    //USART1_PrtInit();
    /* USER CODE END USART1_Init 2 */

}


/* USART3 init function */

void MX_USART3_UART_Init(uint32_t bandrate)
{

    /* USER CODE BEGIN USART3_Init 0 */

    /* USER CODE END USART3_Init 0 */

    /* USER CODE BEGIN USART3_Init 1 */

    /* USER CODE END USART3_Init 1 */
    huart3.uart.Instance = USART3;
    huart3.uart.Init.BaudRate = bandrate;
    huart3.uart.Init.WordLength = UART_WORDLENGTH_8B;
    huart3.uart.Init.StopBits = UART_STOPBITS_1;
    huart3.uart.Init.Parity = UART_PARITY_NONE;
    huart3.uart.Init.Mode = UART_MODE_TX_RX;
    huart3.uart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart3.uart.Init.OverSampling = UART_OVERSAMPLING_16;
    if (HAL_UART_Init(&huart3.uart) != HAL_OK)
    {
        Error_Handler();
    }
    /* USER CODE BEGIN USART3_Init 2 */
    USART_PrtInit(&huart3,UART3_RxBuff,UART3_TxBuff);
    //USART3_PrtInit();
    /* USER CODE END USART3_Init 2 */

}


void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{

    GPIO_InitTypeDef GPIO_InitStruct = {0};
    if(uartHandle->Instance==USART1)
    {
        /* USART1 clock enable */
        __HAL_RCC_USART1_CLK_ENABLE();
        __HAL_RCC_GPIOA_CLK_ENABLE();
        /* USER CODE BEGIN USART1_MspInit 0 */
        __HAL_RCC_DMA1_CLK_ENABLE();
        /* USER CODE END USART1_MspInit 0 */


        /**USART1 GPIO Configuration
        PA9     ------> USART1_TX
        PA10     ------> USART1_RX
        */
        GPIO_InitStruct.Pin = GPIO_PIN_9;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

        GPIO_InitStruct.Pin = GPIO_PIN_10;
        GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

        /* USART1 interrupt Init */
        HAL_NVIC_SetPriority(USART1_IRQn, 3, 0);
        HAL_NVIC_EnableIRQ(USART1_IRQn);

        /* USART1 DMA Init */
        /* USART1_RX Init */
        huart1.hdma_usart_rx.Instance = DMA1_Channel5;
        huart1.hdma_usart_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
        huart1.hdma_usart_rx.Init.PeriphInc = DMA_PINC_DISABLE;
        huart1.hdma_usart_rx.Init.MemInc = DMA_MINC_ENABLE;
        huart1.hdma_usart_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        huart1.hdma_usart_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        huart1.hdma_usart_rx.Init.Mode = DMA_NORMAL;
        huart1.hdma_usart_rx.Init.Priority = DMA_PRIORITY_MEDIUM;
        if (HAL_DMA_Init(&huart1.hdma_usart_rx) != HAL_OK)
        {
            Error_Handler();
        }

        __HAL_LINKDMA(uartHandle,hdmarx,huart1.hdma_usart_rx);

        HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 3, 0);
        HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);


        /* USART1_TX Init */
        huart1.hdma_usart_tx.Instance = DMA1_Channel4;
        huart1.hdma_usart_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
        huart1.hdma_usart_tx.Init.PeriphInc = DMA_PINC_DISABLE;
        huart1.hdma_usart_tx.Init.MemInc = DMA_MINC_ENABLE;
        huart1.hdma_usart_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        huart1.hdma_usart_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        huart1.hdma_usart_tx.Init.Mode = DMA_NORMAL;
        huart1.hdma_usart_tx.Init.Priority = DMA_PRIORITY_MEDIUM;
        if (HAL_DMA_Init(&huart1.hdma_usart_tx) != HAL_OK)
        {
            Error_Handler();
        }

        __HAL_LINKDMA(uartHandle,hdmatx,huart1.hdma_usart_tx);


        /* USER CODE BEGIN USART1_MspInit 1 */

        HAL_NVIC_SetPriority(DMA1_Channel4_IRQn, 3, 0);
        HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);
        /* USER CODE END USART1_MspInit 1 */
    }
    else if(uartHandle->Instance==USART3)
    {
        /* USER CODE BEGIN USART3_MspInit 0 */

        /* USER CODE END USART3_MspInit 0 */
        /* USART3 clock enable */
        __HAL_RCC_USART3_CLK_ENABLE();
        __HAL_RCC_GPIOB_CLK_ENABLE();
        __HAL_RCC_DMA1_CLK_ENABLE();
        /**USART3 GPIO Configuration
        PB10     ------> USART3_TX
        PB11     ------> USART3_RX
        */
        GPIO_InitStruct.Pin = GPIO_PIN_10;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

        GPIO_InitStruct.Pin = GPIO_PIN_11;
        GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

        /* USART3 interrupt Init */
        HAL_NVIC_SetPriority(USART3_IRQn, 3, 0);
        HAL_NVIC_EnableIRQ(USART3_IRQn);

        /* USART3 DMA Init */
        /* USART3_RX Init */
        huart3.hdma_usart_rx.Instance = DMA1_Channel3;
        huart3.hdma_usart_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
        huart3.hdma_usart_rx.Init.PeriphInc = DMA_PINC_DISABLE;
        huart3.hdma_usart_rx.Init.MemInc = DMA_MINC_ENABLE;
        huart3.hdma_usart_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        huart3.hdma_usart_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        huart3.hdma_usart_rx.Init.Mode = DMA_NORMAL;
        huart3.hdma_usart_rx.Init.Priority = DMA_PRIORITY_MEDIUM;
        if (HAL_DMA_Init(&huart3.hdma_usart_rx) != HAL_OK)
        {
            Error_Handler();
        }

        __HAL_LINKDMA(uartHandle,hdmarx,huart3.hdma_usart_rx);

        HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 3, 0);
        HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);

        /* USART3_TX Init */
        huart3.hdma_usart_tx.Instance = DMA1_Channel2;
        huart3.hdma_usart_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
        huart3.hdma_usart_tx.Init.PeriphInc = DMA_PINC_DISABLE;
        huart3.hdma_usart_tx.Init.MemInc = DMA_MINC_ENABLE;
        huart3.hdma_usart_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        huart3.hdma_usart_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        huart3.hdma_usart_tx.Init.Mode = DMA_NORMAL;
        huart3.hdma_usart_tx.Init.Priority = DMA_PRIORITY_MEDIUM;
        if (HAL_DMA_Init(&huart3.hdma_usart_tx) != HAL_OK)
        {
            Error_Handler();
        }

        __HAL_LINKDMA(uartHandle,hdmatx,huart3.hdma_usart_tx);
        /* USER CODE BEGIN USART3_MspInit 1 */
        HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 3, 0);
        HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
        /* USER CODE END USART3_MspInit 1 */
    }
}

void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{

    if(uartHandle->Instance==USART1)
    {
        /* USER CODE BEGIN USART1_MspDeInit 0 */

        /* USER CODE END USART1_MspDeInit 0 */
        /* Peripheral clock disable */
        __HAL_RCC_USART1_CLK_DISABLE();

        /**USART1 GPIO Configuration
        PA9     ------> USART1_TX
        PA10     ------> USART1_RX
        */
        HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);

        /* USART1 DMA DeInit */
        HAL_DMA_DeInit(uartHandle->hdmarx);
        HAL_DMA_DeInit(uartHandle->hdmatx);

        /* USART1 interrupt Deinit */
        HAL_NVIC_DisableIRQ(USART1_IRQn);
        /* USER CODE BEGIN USART1_MspDeInit 1 */

        /* USER CODE END USART1_MspDeInit 1 */
    }
    else if(uartHandle->Instance==USART3)
    {
        /* USER CODE BEGIN USART3_MspDeInit 0 */

        /* USER CODE END USART3_MspDeInit 0 */
        /* Peripheral clock disable */
        __HAL_RCC_USART3_CLK_DISABLE();

        /**USART3 GPIO Configuration
        PB10     ------> USART3_TX
        PB11     ------> USART3_RX
        */
        HAL_GPIO_DeInit(GPIOB, GPIO_PIN_10|GPIO_PIN_11);

        /* USART3 DMA DeInit */
        HAL_DMA_DeInit(uartHandle->hdmarx);
        HAL_DMA_DeInit(uartHandle->hdmatx);

        /* USART3 interrupt Deinit */
        HAL_NVIC_DisableIRQ(USART3_IRQn);
        /* USER CODE BEGIN USART3_MspDeInit 1 */

        /* USER CODE END USART3_MspDeInit 1 */
    }
}

/* USER CODE BEGIN 1 */


void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1)
    {
        huart1.TxState = 0;
        huart3.TxState = 0;
    }
    else if(huart->Instance == USART3)
    {
        huart3.TxState = 0;
        huart1.TxState = 0;
    }
}

void HAL_UART_AbortReceiveCpltCallback(UART_HandleTypeDef *huart)
{

    if(huart->Instance == USART1)
    {

        huart1.RxInPtr->end = &UART1_RxBuff[huart1.RxCounter -1];
        huart1.RxInPtr++;
        if(huart1.RxInPtr == huart1.RxEndPtr)
        {
            huart1.RxInPtr = &huart1.RxLocation[0];
        }
        if((BUFFERSIZE - huart1.RxCounter) < RX_MAX)
        {
            huart1.RxCounter = 0;
            huart1.RxInPtr->start = UART1_RxBuff;
        }
        else
        {
            huart1.RxInPtr->start = &UART1_RxBuff[huart1.RxCounter];
        }
        HAL_UART_Receive_DMA(&huart1.uart, huart1.RxInPtr->start, RX_MAX);

    }
    else if(huart->Instance == USART3)
    {

        huart3.RxInPtr->end = &UART3_RxBuff[huart3.RxCounter -1];
        huart3.RxInPtr++;
        if(huart3.RxInPtr == huart3.RxEndPtr)
        {
            huart3.RxInPtr = &huart3.RxLocation[0];
        }
        if((BUFFERSIZE - huart3.RxCounter) < RX_MAX)
        {
            huart3.RxCounter = 0;
            huart3.RxInPtr->start = UART3_RxBuff;
        }
        else
        {
            huart3.RxInPtr->start = &UART3_RxBuff[huart3.RxCounter];
        }
        HAL_UART_Receive_DMA(&huart3.uart, huart3.RxInPtr->start, RX_MAX);

    }
}


void USART_PrtInit(UCB *huart, uint8_t * USART_RxBuff, uint8_t * USART_TxBuff)
{
    huart->RxInPtr = &huart->RxLocation[0];                 //IN指针指向SE指针对结构体数组的0号成员
    huart->RxOutPtr = &huart->RxLocation[0];                //OUT指针指向SE指针对结构体数组的0号成员
    huart->RxEndPtr = &huart->RxLocation[NUM-1];            //END指针指向SE指针对结构体数组的最后一个成员
    huart->RxCounter = 0;                                   //累计接收数量清零
    huart->RxInPtr->start = USART_RxBuff;                   //使用IN指针指向的SE指针对中的S指针标记第一次接收的起始位置

    huart->TxInPtr = &huart->TxLocation[0];                 //IN指针指向SE指针对结构体数组的0号成员
    huart->TxOutPtr = &huart->TxLocation[0];                //OUT指针指向SE指针对结构体数组的0号成员
    huart->TxEndPtr = &huart->TxLocation[NUM-1];            //END指针指向SE指针对结构体数组的最后一个成员
    huart->TxCounter = 0;                                   //累计接收数量清零
    huart->TxInPtr->start = USART_TxBuff;                   //使用IN指针指向的SE指针对中的S指针标记第一次接收的起始位置
    huart->TxState = 0;                                     //初始发送状态为空闲

    __HAL_UART_ENABLE_IT(&huart->uart, UART_IT_IDLE);
    HAL_UART_Receive_DMA(&huart->uart, huart->RxInPtr->start, RX_MAX);
}


void USART_TxData(UCB *huart, uint8_t * USART_TxBuff,uint8_t *data, uint32_t data_len)
{

    if((BUFFERSIZE - huart->TxCounter) >= data_len)
    {
        huart->TxInPtr->start = & USART_TxBuff[huart->TxCounter];

    }
    else
    {
        huart->TxCounter = 0;
        huart->TxInPtr->start = USART_TxBuff;
    }
    memcpy(huart->TxInPtr->start, data, data_len);
    huart->TxCounter += data_len;
    huart->TxInPtr->end = &USART_TxBuff[huart->TxCounter - 1];
    huart->TxInPtr++;
    if(huart->TxInPtr == huart->TxEndPtr)
    {
        huart->TxInPtr = &huart->TxLocation[0];
    }
}

//此方法是将接收到的数据 ,再返回去, 如果是DEBUG模式,那么返回到串口1里,如果 不是DEBUG模式,就是哪个串口接收就返回哪个串口
//目前 这个方法暂时没有用, 在调试时,可以调用 这个方法

void ProcessData(UCB * huart, uint8_t * USART_TxBuff)
{
    if(huart->RxOutPtr != huart->RxInPtr)
    {
        USART_TxData(huart,USART_TxBuff, huart->RxOutPtr->start, huart->RxOutPtr->end - huart->RxOutPtr->start +1);
        huart->RxOutPtr++;
        if(huart->RxOutPtr == huart->RxEndPtr)
        {
            huart->RxOutPtr = &huart->RxLocation[0];
        }
    }
    if((huart->TxOutPtr != huart->TxInPtr) && (huart->TxState == 0))
    {

        huart->TxState = 1;
        if(DEBUG_FLAG)
        {
            HAL_UART_Transmit_DMA(&huart1.uart, huart->TxOutPtr->start, huart->TxOutPtr->end - huart->TxOutPtr->start +1);
        }
        else
        {
            HAL_UART_Transmit_DMA(&huart->uart, huart->TxOutPtr->start, huart->TxOutPtr->end - huart->TxOutPtr->start +1);
        }

        if(huart->uart.Instance == USART3)
        {
            //HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin); //led电平翻转
        }

        huart->TxOutPtr++;
        if(huart->TxOutPtr == huart->TxEndPtr)
        {
            huart->TxOutPtr = &huart->TxLocation[0];
        }
    }

}
/* USER CODE END 1 */

再修改中断里的内容 

,再修改main.c吧

。。。。。。
int main(void)
{
    。。。。。。
    MX_USART1_UART_Init(UART_BANDRATE);
    MX_USART3_UART_Init(UART_BANDRATE);
    /* USER CODE BEGIN 2 */

   
    while (1)
    {
        /* USER CODE END WHILE */
        ProcessData(&huart1, UART1_TxBuff);   //在串口输出数据测试所用
        ProcessData(&huart3, UART3_TxBuff);   //在串口输出数据测试所用
        HAL_Delay(10);
        /* USER CODE BEGIN 3 */
    }
    /* USER CODE END 3 */
}
。。。。

以上就是源码,想要最详细 的,去下载DEMO源码,让我赚点积分吧,嘻嘻!

演示效果

串口3发送数据 串口1接收 串口1发送数据 串口1 接收

修改下面的代码 

if(DEBUG_FLAG)
        {
            HAL_UART_Transmit_DMA(&huart1.uart, huart->TxOutPtr->start, huart->TxOutPtr->end - huart->TxOutPtr->start +1);
        }
        else
        {
            HAL_UART_Transmit_DMA(&huart->uart, huart->TxOutPtr->start, huart->TxOutPtr->end - huart->TxOutPtr->start +1);
        }

去掉判断 ,只保留下面的代码 :

HAL_UART_Transmit_DMA(&huart->uart, huart->TxOutPtr->start, huart->TxOutPtr->end - huart->TxOutPtr->start +1);

然后运行的效果如下 :

哦了,记录一下,省得忘记了

源码下载链接:

https://download.csdn.net/download/liangying0720/88419565

  • 13
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
正点原子 STM32F103 是一款基于STM32F103C8T6芯片的开发板,采用了HALLibrary实现串口DMA功能。 串口DMA(Direct Memory Access)是一种通过DMA控制器来实现串口数据传输的方式。使用DMA可以实现在数据传输过程中减少CPU的占用率,提高数据传输效率。 在正点原子 STM32F103中,可以通过HAL来方便地实现串口DMA功能。首先,需要使用HAL_UART_Init()函数初始化串口,设置波特率、数据位、停止位等参数。然后,使用HAL_UART_Receive_DMA()函数设置DMA接收数据的缓冲区和长度,通过DMA串口接收的数据直接传输到指定的缓冲区中。同样,可以使用HAL_UART_Transmit_DMA()函数设置DMA发送数据的缓冲区和长度,通过DMA将指定的数据发送到串口。 在使用串口DMA时,需要注意配置DMA的通道、流和优先级等参数,可以通过HAL_DMA_Init()函数进行配置。配置好DMA后,可以使用HAL_UART_Receive_DMA()和HAL_UART_Transmit_DMA()函数启动DMA传输。 使用串口DMA可以大大提高串口数据传输的效率和稳定性,特别适用于需要高速传输大量数据的应用场景。正点原子 STM32F103开发板搭配HALLibrary,相对于传统的轮询方式,实现串口DMA功能更加方便快捷,可以提高开发效率。 总结来说,正点原子 STM32F103开发板配合HAL可以方便地实现串口DMA功能,通过DMA控制器实现串口数据的高效传输,既提高了传输效率,又减少了CPU的占用率,为嵌入式开发提供了便利。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值