stm32串口+DMA环形缓冲收发保姆级

这篇具有很好参考价值的文章主要介绍了stm32串口+DMA环形缓冲收发保姆级。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

基于HAL库的STM32串口DMA环形缓冲收发实例

首先在此感谢开源项目,以及大佬们的无私奉献,让每一个逐梦人能够免费学习,再次感谢!
发布只为记录,记性不够,笔记来凑。记得点赞哦
具体实现原理讲起来确实挺复杂,不过用起来还是很NICE的!可以直接移植!

1、STM32CubeMax配置

1.1、选择单片机型号
stm32串口接收缓存,STM32cubeMX+HAL库,stm32,单片机,vscode,c语言

2、配置时钟和串口

stm32串口接收缓存,STM32cubeMX+HAL库,stm32,单片机,vscode,c语言
stm32串口接收缓存,STM32cubeMX+HAL库,stm32,单片机,vscode,c语言

stm32串口接收缓存,STM32cubeMX+HAL库,stm32,单片机,vscode,c语言

或者直接在HCLK位置输入72,点击OK自动配置

stm32串口接收缓存,STM32cubeMX+HAL库,stm32,单片机,vscode,c语言
stm32串口接收缓存,STM32cubeMX+HAL库,stm32,单片机,vscode,c语言

这个地方第四步,模式选择MODE。发送选择正常NOMAL.接收RX选择循环模式,第五步,外设地址不自增,存储器地址自增勾选

数字长度选择字节模式byte

stm32串口接收缓存,STM32cubeMX+HAL库,stm32,单片机,vscode,c语言
stm32串口接收缓存,STM32cubeMX+HAL库,stm32,单片机,vscode,c语言

stm32串口接收缓存,STM32cubeMX+HAL库,stm32,单片机,vscode,c语言

此处必须使能UART,原因后面会提到

然后点击生成文件就行。如果用的keil,则直接点击Open Project,如果用的VSCODE,选择打开文件夹Open folder

stm32串口接收缓存,STM32cubeMX+HAL库,stm32,单片机,vscode,c语言

stm32串口接收缓存,STM32cubeMX+HAL库,stm32,单片机,vscode,c语言

到这个页面后点击MDK_ARM,就是生成的文件

然后返回上一层,右击,选择打开方式,为通过code打开,

stm32串口接收缓存,STM32cubeMX+HAL库,stm32,单片机,vscode,c语言

stm32串口接收缓存,STM32cubeMX+HAL库,stm32,单片机,vscode,c语言

stm32串口接收缓存,STM32cubeMX+HAL库,stm32,单片机,vscode,c语言
stm32串口接收缓存,STM32cubeMX+HAL库,stm32,单片机,vscode,c语言

stm32串口接收缓存,STM32cubeMX+HAL库,stm32,单片机,vscode,c语言

stm32串口接收缓存,STM32cubeMX+HAL库,stm32,单片机,vscode,c语言

stm32串口接收缓存,STM32cubeMX+HAL库,stm32,单片机,vscode,c语言
stm32串口接收缓存,STM32cubeMX+HAL库,stm32,单片机,vscode,c语言
stm32串口接收缓存,STM32cubeMX+HAL库,stm32,单片机,vscode,c语言
右击,选择新建文件夹stm32串口接收缓存,STM32cubeMX+HAL库,stm32,单片机,vscode,c语言

新建文件夹BSP 和bsp_usart.h和bsp_usart.c

stm32串口接收缓存,STM32cubeMX+HAL库,stm32,单片机,vscode,c语言

将文件夹拖到目录栏

stm32串口接收缓存,STM32cubeMX+HAL库,stm32,单片机,vscode,c语言

stm32串口接收缓存,STM32cubeMX+HAL库,stm32,单片机,vscode,c语言

将刚才的两个文件夹路径放进来stm32串口接收缓存,STM32cubeMX+HAL库,stm32,单片机,vscode,c语言

至此,所有的构建操作已经全部完成,剩下的就是程序编辑

为了方便打印调试,引用printf打印输出,引入fputc,添加头文件#include “stdio.h”

#include "stdio.h"
int fputc(int ch, FILE *f)
{
    // while((USART1->SR&0X40)==0);//循环发送,直到发送完毕
    // USART1->DR = (unsigned char) ch;
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 100);
    return ch;
}

huart1结构体句柄由系统自动生成

stm32串口接收缓存,STM32cubeMX+HAL库,stm32,单片机,vscode,c语言
保姆级的提示到这一步结束,要是不会用就直接调用吧,下来可能就是关键步骤,不会这么详细的讲,至于如何使用这些引入的函数,点击这个链接

定义数组,用来存放发送的数据

#define UART1_RX_RB_LEN (128u)

uint8_t usart1_tx_rb_data[128];
uint8_t usart1_rx_rb_data[UART1_RX_RB_LEN];

绑定结构体指针BUFF和定义的实体数组

lwrb_init(&usart1_tx_rb, usart1_tx_rb_data, ARRAY_LEN(usart1_tx_rb_data));
lwrb_init(&usart1_rx_rb, usart1_rx_rb_data, ARRAY_LEN(usart1_rx_rb_data));

2、发送环节

​ 为了移植方便,使底层逻辑不暴露,引入发送函数,方便外部调用

void USART1_SendData(const uint8_t *p_data, uint16_t len)
{
    lwrb_write(&usart1_tx_rb, p_data, len); /* Write data to TX buffer for loopback */
    USART1_Start_DmaTx();
}

void USART1_Sendstring(const char *str)
{
    lwrb_write(&usart1_tx_rb, str, strlen(str)); /* Write data to TX buffer for loopback */
    USART1_Start_DmaTx();

}

真正的发送函数处理

uint8_t USART1_Start_DmaTx(void)
{
    uint32_t primask;
    uint8_t started = 0;

    primask = __get_PRIMASK();
    __disable_irq();
    if (usart1_tx_dma_current_len == 0
            && (usart1_tx_dma_current_len = lwrb_get_linear_block_read_length(&usart1_tx_rb)) > 0) 
    {
        __HAL_DMA_DISABLE(&hdma_usart1_tx);
         
        __HAL_DMA_CLEAR_FLAG(&hdma_usart1_tx
            , __HAL_DMA_GET_TC_FLAG_INDEX(&hdma_usart1_tx));
        __HAL_DMA_CLEAR_FLAG(&hdma_usart1_tx
            , __HAL_DMA_GET_HT_FLAG_INDEX(&hdma_usart1_tx));
        __HAL_DMA_CLEAR_FLAG(&hdma_usart1_tx
            , __HAL_DMA_GET_TE_FLAG_INDEX(&hdma_usart1_tx));
        __HAL_DMA_CLEAR_FLAG(&hdma_usart1_tx
            , __HAL_DMA_GET_GI_FLAG_INDEX(&hdma_usart1_tx));

        HAL_UART_Transmit_DMA(&huart1
            , (uint8_t*)lwrb_get_linear_block_read_address(&usart1_tx_rb)
            , (uint16_t)usart1_tx_dma_current_len);
        started = 1;
    }
    __set_PRIMASK(primask);
    
    return started;
}

发送完成后触发中断,跳过当前已经有的长度,然后再次进入发送状态,判断缓冲区中是否还存在数据,如果有进入IF语句,如果没有,返回started = 0;此时发送形成一个循环发送和检测

void USART1_TxTcCb(UART_HandleTypeDef *huart)
{
        lwrb_skip(&usart1_tx_rb, usart1_tx_dma_current_len);/* Skip sent data, mark as read */
        usart1_tx_dma_current_len = 0;           /* Clear length variable */
        USART1_Start_DmaTx();          /* Start sending more data */
}

3、接收环节

HAL_UARTEx_ReceiveToIdle_DMA(&huart1, usart1_rx_dma_buffer, ARRAY_LEN(usart1_rx_dma_buffer));

利用此函数可以接受数据,直至触发IDLE空闲中断,具体细节点击函数查看,不在此赘述

此时会产生三种情况,接受一半中断。接受溢出中断和接收完成后空闲中断

如果自己注册回调函数则,会调用自己的回调函数,不然则为系统默认回调函数

不会的可以参考此篇注册串口回调函数

//注册回调事件
HAL_UART_RegisterRxEventCallback(&huart1, USART1_RxEventCb);

HAL_UART_RegisterCallback(&huart1, HAL_UART_TX_COMPLETE_CB_ID, USART1_TxTcCb);

产生回调后,进入回调函数,可以自定义一些回调处理和动作

//接受半个缓冲区完成回调函数
void USART1_DMA_RxHtCb( DMA_HandleTypeDef * p_hdma)
{
    UNUSED(p_hdma);

    USART1_RxEventCheck();
}

//接收完成回调函数
void USART1_DMA_RxTcCb( DMA_HandleTypeDef * p_hdma)
{
    UNUSED(p_hdma);
    
    USART1_RxEventCheck();
	usart1_rx_flag = 1;
}

/*!< UART Reception Event Callback     */
void USART1_RxEventCb(struct __UART_HandleTypeDef *huart, uint16_t pos)
{
    UNUSED(huart);
    UNUSED(pos);
    
    USART1_RxEventCheck();
}

对回调事件进行检查分析,看是那种情况,具体参考大佬文章

stm32串口接收缓存,STM32cubeMX+HAL库,stm32,单片机,vscode,c语言

共有这么几种情况:

  • 情况A:缓冲区为空W == R = 0 == 0

  • 情况B:缓冲区将字节保存为W - R = 4 - 0 = 4``W > R

  • Case C : 缓冲区已满or orW == R - 1``7 == 0 - 1``7 = (0 - 1 + S) % S = (0 - 1 + 8) % 8 = (-1 + 8) % 8 = 7

    • R并且W可以保存S不同的值,从0到,即模数S - 1``S
    • 缓冲区将字节保存为W - R = 7 - 0 = 7``W > R
  • 情况D:缓冲区将字节保存为S - (R - W) = 8 - (5 - 3) = 6``R > W

  • 情况E:缓冲区已满为( ) 并保存字节W == R - 1``4 = 5 - 1``S - (R - W) = 8 - (5 - 4) ) = 7}

void USART1_RxEventCheck(void)
{
    static uint16_t old_pos;
    uint16_t pos;
    
    /* Calculate current position in buffer and check for new data available */
    //检查缓冲区中已用长度
    pos = ARRAY_LEN(usart1_rx_dma_buffer) - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
    if (pos != old_pos) 
    {    /* Check change in received data */
        if (pos > old_pos) 
        { /* Current position is over previous one */
            /*
             * Processing is done in "linear" mode.
             *
             * Application processing is fast with single data block,
             * length is simply calculated by subtracting pointers
             *
             * [   0   ]
             * [   1   ] <- old_pos |------------------------------------|
             * [   2   ]            |                                    |
             * [   3   ]            | Single block (len = pos - old_pos) |
             * [   4   ]            |                                    |
             * [   5   ]            |------------------------------------|
             * [   6   ] <- pos
             * [   7   ]
             * [ N - 1 ]
             */

            lwrb_write(&usart1_rx_rb, &usart1_rx_dma_buffer[old_pos], pos - old_pos);
        } 
        else 
        {
            /*
             * Processing is done in "overflow" mode..
             *
             * Application must process data twice,
             * since there are 2 linear memory blocks to handle
             *
             * [   0   ]            |---------------------------------|
             * [   1   ]            | Second block (len = pos)        |
             * [   2   ]            |---------------------------------|
             * [   3   ] <- pos
             * [   4   ] <- old_pos |---------------------------------|
             * [   5   ]            |                                 |
             * [   6   ]            | First block (len = N - old_pos) |
             * [   7   ]            |                                 |
             * [ N - 1 ]            |---------------------------------|
             */
            lwrb_write(&usart1_rx_rb, &usart1_rx_dma_buffer[old_pos], ARRAY_LEN(usart1_rx_dma_buffer) - old_pos);
            
            if (pos > 0) 
            {
                lwrb_write(&usart1_rx_rb, &usart1_rx_dma_buffer[0], pos);
            }
        }
         old_pos = pos; /* Save current position as old for next transfers */
		usart1_rx_flag = 1;

    }
}

当标志位置一后,对读取到的数据进行处理,此时传进来的数据需要我们自行进行拼接,比如上述情况E,发送的数据存到了两端,这样需要先将后面的读出来,再加上前面的

void USART1_ProcessData(void)
{
    uint8_t data[UART1_RX_RB_LEN];
    uint16_t len1 = lwrb_get_linear_block_read_length(&usart1_rx_rb);
    printf("len1 = %d\r\n", len1);
    if (len1 > 0) 
    {
        printf("lwrb_read(&usart1_tx_rb, data, len1) = %d\r\n"
            , lwrb_read(&usart1_rx_rb, data, len1));
        uint16_t len2 = lwrb_get_linear_block_read_length(&usart1_rx_rb);
        printf("len2 = %d\r\n", len2);
        if (len2 > 0)
        {
            printf("lwrb_read(&usart1_tx_rb, &data[len1], len2) = %d\r\n"
                , lwrb_read(&usart1_rx_rb, &data[len1], len2));
        }
        // 进行data进行处理

        // 处理usart1_rx_rb的一些东西
        lwrb_write(&usart1_tx_rb
            , data
            , len1 + len2); /* Write data to TX buffer for loopback */  

        USART1_Start_DmaTx();
    }
}

再main函数中对标志位进行处理,

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  HAL_Delay(50);
  USART1_Init();
  printf("stm32f103rct6_uart_dma_loopback_test!\r\n");
  // uint8_t str[] = "USART1_Init\r\n";
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    if (usart1_rx_flag == 1)
    {
      usart1_rx_flag = 0;
      // printf("usart1_rx_flag = 1\r\n");
      USART1_ProcessData();
    }
    HAL_Delay(1000);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

下面附上BSP_USART.c完整代码,


#include "bsp_usart.h"
#include "usart.h"
#include "dma.h"

#define UART1_RX_DMA_BUFFER_LEN (20u)
#define UART1_RX_RB_LEN (128u)

lwrb_t usart1_rx_rb;// Ring buffer instance for TX data
lwrb_t usart1_tx_rb;// Ring buffer instance for TX data

uint8_t usart1_rx_dma_buffer[UART1_RX_DMA_BUFFER_LEN];
uint8_t usart1_rx_rb_data[UART1_RX_RB_LEN];// Ring buffer data array for RX DMA
uint8_t usart1_tx_rb_data[128];// Ring buffer data array for TX DMA

volatile size_t usart1_tx_dma_current_len;// Length of currently active TX DMA transfer
volatile uint8_t usart1_rx_flag;

int fputc(int ch, FILE *f)
{

    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 100);

    return ch;
}

uint8_t USART1_Start_DmaTx(void)
{
    uint32_t primask;
    uint8_t started = 0;
    
    primask = __get_PRIMASK();
    __disable_irq();

    if (usart1_tx_dma_current_len == 0
            && (usart1_tx_dma_current_len = lwrb_get_linear_block_read_length(&usart1_tx_rb)) > 0) 
    {
        __HAL_DMA_DISABLE(&hdma_usart1_tx);

        __HAL_DMA_CLEAR_FLAG(&hdma_usart1_tx
            , __HAL_DMA_GET_TC_FLAG_INDEX(&hdma_usart1_tx));
        __HAL_DMA_CLEAR_FLAG(&hdma_usart1_tx
            , __HAL_DMA_GET_HT_FLAG_INDEX(&hdma_usart1_tx));
        __HAL_DMA_CLEAR_FLAG(&hdma_usart1_tx
            , __HAL_DMA_GET_TE_FLAG_INDEX(&hdma_usart1_tx));
        __HAL_DMA_CLEAR_FLAG(&hdma_usart1_tx
            , __HAL_DMA_GET_GI_FLAG_INDEX(&hdma_usart1_tx));

        HAL_UART_Transmit_DMA(&huart1
            , (uint8_t*)lwrb_get_linear_block_read_address(&usart1_tx_rb)
            , (uint16_t)usart1_tx_dma_current_len);

        started = 1;
    }
    __set_PRIMASK(primask);
    
    return started;
}

void USART1_DMA_RxHtCb( DMA_HandleTypeDef * p_hdma)
{
    UNUSED(p_hdma);
    
    USART1_RxEventCheck();
}

//接收完成回调函数
void USART1_DMA_RxTcCb( DMA_HandleTypeDef * p_hdma)
{
    UNUSED(p_hdma);
    
    USART1_RxEventCheck();
	usart1_rx_flag = 1;
}

void USART1_RxEventCb(struct __UART_HandleTypeDef *huart, uint16_t pos)
{
    UNUSED(huart);
    UNUSED(pos);

    USART1_RxEventCheck();
}

// 串口1发送完成回调
void USART1_TxTcCb(UART_HandleTypeDef *huart)
{
        lwrb_skip(&usart1_tx_rb, usart1_tx_dma_current_len);	/* Skip sent data, mark as read */
        usart1_tx_dma_current_len = 0;          			   /* Clear length variable */
        USART1_Start_DmaTx();         					       /* Start sending more data */
}

void USART1_Init(void)
{
    lwrb_init(&usart1_tx_rb, usart1_tx_rb_data, ARRAY_LEN(usart1_tx_rb_data));
    lwrb_init(&usart1_rx_rb, usart1_rx_rb_data, ARRAY_LEN(usart1_rx_rb_data));

    HAL_UARTEx_ReceiveToIdle_DMA(&huart1, usart1_rx_dma_buffer, ARRAY_LEN(usart1_rx_dma_buffer));
    HAL_UART_RegisterRxEventCallback(&huart1, USART1_RxEventCb);
    HAL_UART_RegisterCallback(&huart1, HAL_UART_TX_COMPLETE_CB_ID, USART1_TxTcCb);
}

// void USART1_RxEventCheck(uint16_t pos)
void USART1_RxEventCheck(void)
{
    static uint16_t old_pos;
    uint16_t pos;
    
    /* Calculate current position in buffer and check for new data available */
    //检查缓冲区中已用长度
    pos = ARRAY_LEN(usart1_rx_dma_buffer) - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
    // printf("old_pos = %d, pos = %d\r\n", old_pos, pos);
    if (pos != old_pos) 
    {    /* Check change in received data */
        if (pos > old_pos) 
        { /* Current position is over previous one */
            /*
             * Processing is done in "linear" mode.
             *
             * Application processing is fast with single data block,
             * length is simply calculated by subtracting pointers
             *
             * [   0   ]
             * [   1   ] <- old_pos |------------------------------------|
             * [   2   ]            |                                    |
             * [   3   ]            | Single block (len = pos - old_pos) |
             * [   4   ]            |                                    |
             * [   5   ]            |------------------------------------|
             * [   6   ] <- pos
             * [   7   ]
             * [ N - 1 ]
             */

            lwrb_write(&usart1_rx_rb, &usart1_rx_dma_buffer[old_pos], pos - old_pos);
        } 
        else 
        {
            /*
             * Processing is done in "overflow" mode..
             *
             * Application must process data twice,
             * since there are 2 linear memory blocks to handle
             *
             * [   0   ]            |---------------------------------|
             * [   1   ]            | Second block (len = pos)        |
             * [   2   ]            |---------------------------------|
             * [   3   ] <- pos
             * [   4   ] <- old_pos |---------------------------------|
             * [   5   ]            |                                 |
             * [   6   ]            | First block (len = N - old_pos) |
             * [   7   ]            |                                 |
             * [ N - 1 ]            |---------------------------------|
             */

            lwrb_write(&usart1_rx_rb, &usart1_rx_dma_buffer[old_pos], ARRAY_LEN(usart1_rx_dma_buffer) - old_pos);
            
            if (pos > 0) 
            {
            
                lwrb_write(&usart1_rx_rb, &usart1_rx_dma_buffer[0], pos);
            }
        }
        old_pos = pos; /* Save current position as old for next transfers */
	    usart1_rx_flag = 1;
    }
}

void USART1_ProcessData(void)
{
    uint8_t data[UART1_RX_RB_LEN];
    uint16_t len1 = lwrb_get_linear_block_read_length(&usart1_rx_rb);
    printf("len1 = %d\r\n", len1);
    if (len1 > 0) 
    {
        printf("lwrb_read(&usart1_tx_rb, data, len1) = %d\r\n"
            , lwrb_read(&usart1_rx_rb, data, len1));
        uint16_t len2 = lwrb_get_linear_block_read_length(&usart1_rx_rb);
        printf("len2 = %d\r\n", len2);
        if (len2 > 0)
        {
            printf("lwrb_read(&usart1_tx_rb, &data[len1], len2) = %d\r\n"
                , lwrb_read(&usart1_rx_rb, &data[len1], len2));
        }
        // 进行data进行处理

        // 处理usart1_rx_rb的一些东西
        lwrb_write(&usart1_tx_rb
            , data
            , len1 + len2); /* Write data to TX buffer for loopback */  

        USART1_Start_DmaTx();
    }
}

void USART1_SendData(const uint8_t *p_data, uint16_t len)
{
    lwrb_write(&usart1_tx_rb, p_data, len); /* Write data to TX buffer for loopback */
    USART1_Start_DmaTx();
}

void USART1_Sendstring(const char *str)
{

    lwrb_write(&usart1_tx_rb, str, strlen(str)); /* Write data to TX buffer for loopback */
    USART1_Start_DmaTx();

}



BSP_USART_H文件

#ifndef __BSP_USART_H__
#define __BSP_USART_H__

#include "main.h"
#include "stdio.h"
#include "lwrb.h"

#define ARRAY_LEN(x)            (sizeof(x) / sizeof((x)[0]))


extern UART_HandleTypeDef huart1;
extern DMA_HandleTypeDef hdma_usart1_rx;
extern DMA_HandleTypeDef hdma_usart1_tx;
extern volatile size_t usart1_tx_dma_current_len;
extern volatile uint8_t usart1_rx_flag;

void USART1_Init(void);
void USART1_ProcessData(void);
void USART1_SendData(const uint8_t *p_data, uint16_t len);
void USART1_Sendstring(const char* str);










#endif // ! __BSP_USART_H__

lwrb文件链接文章来源地址https://www.toymoban.com/news/detail-693584.html

#ifndef __BSP_USART_H__
#define __BSP_USART_H__

#include "main.h"
#include "stdio.h"
#include "lwrb.h"

#define ARRAY_LEN(x)            (sizeof(x) / sizeof((x)[0]))


extern UART_HandleTypeDef huart1;
extern DMA_HandleTypeDef hdma_usart1_rx;
extern DMA_HandleTypeDef hdma_usart1_tx;
extern volatile size_t usart1_tx_dma_current_len;
extern volatile uint8_t usart1_rx_flag;

void USART1_Init(void);
void USART1_ProcessData(void);
void USART1_SendData(const uint8_t *p_data, uint16_t len);
void USART1_Sendstring(const char* str);


#endif // ! __BSP_USART_H__

lwrb文件[链接](https://github.com/MaJerle/lwrb)

git[下载链接](https://github.com/MaJerle/lwrb.git)

到了这里,关于stm32串口+DMA环形缓冲收发保姆级的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • stm32和python实现DMA+串口数据收发

    1-0 串口配置 1-1 DMA发送模式配置 1-2 通过DMA传输数据到USART1的发送寄存器 1-3 串口数据发送 将usart1_dma_tx_data()函数放在main函数中或者中断处理函数中即可,如下所示: 2-1 DMA接收模式配置 2-2 串口结束中断 2-3 对串口接收的数据进行处理 3 完整程序

    2024年02月14日
    浏览(33)
  • 【STM32笔记】STM32的串口数据收发基础(四)(USART DMA模式)

         在STM32中编写串口通信数据收发有三种方式: 轮询模式 (阻塞方式), 中断模式 (非阻塞方式)以及 DMA模式 。      打开STM32CubeMX,前部分配置流程如串口数据收发基础(三)节里一样。配置好USART1的基本参数,开启定时器中断后,接下来就要开启USART1的DMA。

    2024年02月03日
    浏览(31)
  • STM32 串口DMA接收数据(高效接收数据)

    极度不推荐在使用DMA的时候按照传统的方式进行重定义!!! 非常简单,轮询方式整个CPU 在串口发送时处于等待状态,但是使用DMA时无法确保当前DMA已经传输完成。 有同学可能会认为可以通过判断DMA的传输标志位来进行等待,但如果这样的话就丧失了DMA的设计意图: 再次使

    2024年02月16日
    浏览(42)
  • 【STM32】HAL库 STM32CubeMX——DMA (串口DMA发送接收)

    软件: STM32CubeMX KEIL5 mcuisp 串口通信助手 硬件: STM32F103C8Tx 杜邦线,面包板,USB转TTL DMA,全称Direct Memory Access,即直接存储器访问。 DMA传输将数据从一个地址空间复制到另一个地址空间,提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。 我们知道系统的运

    2024年02月12日
    浏览(57)
  • STM32实现DMA接收串口数据

    一..首先我们得配置DMA和USARAT,我们的原理是DMA1的通道5为USART1的RX引脚。  1.USART1的配置 2.DMA的配置 二.中断进行数据处理(stm32f10x_it.c) 我们可以串口打印出数组中的数据,验证DMA是否正常工作。可以到数据处理那个地方进行处理。USART1在初始化中就已经波特率为115200.我们可以

    2024年02月16日
    浏览(36)
  • STM32 串口 DMA 接收任意长度数据

    DMA 传输完成会产生中断告知 CPU,这对于固定长度的数据是没什么问题的。但是对于不定长的数据就不行了,DMA 一定要接收到足够多(设定的长度)的数据时才产生完成中断,如果接收到的数据量小于设定的长度,这个时候 CPU 就无法通过中断方式取处理这点数据了。那 CPU

    2024年02月11日
    浏览(37)
  • 使用环形缓冲区ringbuffer实现串口数据接收

    环形缓冲区(ringbuffer),实际上就是一种队列数据结构,只不过它不是线性队列,而是环形队列。 关于环形缓冲区(ringbuffer)的详细介绍,网上一搜一大把,这里不重复介绍了,我这里直接上代码。 详细介绍可以参考下面链接里面的介绍: https://en.wikipedia.org/wiki/Circular_b

    2023年04月19日
    浏览(37)
  • STM32学习笔记(五)串口空闲中断+DMA实现不定长收发(stm32c8t6)

    记录一下学习过程 DMA DMA,全称为: Direct Memory Access,即直接存储器访问, DMA 传输将数据从一个 地址空间复制到另外一个地址空间。 这一过程无需cpu的参与,从而提高cpu使用的效率 DMA相关的参数:1 数据的源地址、2 数据传输的目标地址 、3 传输宽度,4 传输多少字节,5 传

    2024年02月14日
    浏览(39)
  • 环形队列+DMA空闲中断+接收串口数据

    本次实验利用环形队列+DMA空闲中断+串口。。通过这个实验可以非常深入的理解队列,DMA,串口的知识。如果你能自己实现掌握这个实验,那么你应该基本掌握了队列,DMA,串口的知识。 本次使用的是用环形队列当缓冲器区接收串口数据。我们可以先区了解DMA的空闲中断。本次

    2024年02月13日
    浏览(32)
  • STM32 LL库 串口DMA发送接收配置教程

    本文详细介绍了如何在STM32中使用LL库进行串口DMA发送和接收的配置,包括STM32CubeMX的配置、代码初始化、发送功能和接收功能。通过本教程,您将学会如何正确配置串口DMA,并实现高效的数据传输。

    2024年02月10日
    浏览(63)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包