STM32-HAL库(快速入门)-4-UART-不定长收发最终解决版(DMA)

一、DMA实现不定长接收字符串原理

DMA,可以看作一个CPU的秘书,可以在程序配置好后,不经过CPU的干预,直接做数据搬移的操作,来大大节省CPU的资源消耗

原理:

我们知道,串口通信开始为空闲位,然后发送方先发送起始位,再发送字符,最后发送校验位和停止位,最后再变为空闲位,那么当数据连续收发时,如果我们像上一篇文章一样,接收一个字符就触发一次中断,那是不是中断的太频繁了呢?就像你对妹子说I love you,可是你每说一个字母就摇动对方一下,确认对方听清了没,我估计你没说到第5个字符对方就扭头走了吧。所以,这篇文章实现了DMA+串口ilde中断(空闲中断)的方式来实现不定长接收,类似于,你一次性说出i love you然后再确认对方有没有听到。

空闲中断:当串口连续通信时,每发送两个字符之间是没有空闲位的,只有当全部字符发送完毕才进入空闲位,然后触发空闲中断。

同样,我们先定义一个数组,如rx_buffer[100],已知,当触发DMA接收时,DMA计数器自动设置为100,每收到一个字节,计数器减1,所以,我们可以获取这个计数器数a,然后100-a,就是已经接收到的字符了。再把数据从数组中拿出来,这样就实现了不定长收发功能。

二、cubemx配置

第一步:打开串口,设置为异步模式

第二步:配置串口参数

第三步:打开串口中断 

第四步:打开DMA 

三、keil代码编写

    #define MAX_Size_rx_buffer 100
    uint8_t rx_buffer[MAX_Size_rx_buffer];
    uint8_t rx_error[] = "The data is too long\r\n";

    HAL_UART_Receive_DMA(&huart1,rx_buffer,MAX_Size_rx_buffer);//开启串口DMA接收
    __HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);//开启空闲中断

    extern uint8_t rx_buffer[MAX_Size_rx_buffer];
    uint16_t len = 0;

    void USART1_IRQHandler(void)
    {
       /* USER CODE BEGIN USART1_IRQn 0 */
    if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE)!=RESET)
    {
        __HAL_UART_CLEAR_IDLEFLAG(&huart1);
        HAL_UART_DMAStop(&huart1);
        len = MAX_Size_rx_buffer - __HAL_DMA_GET_COUNTER(huart1.hdmarx);
        if(len>=MAX_Size_rx_buffer)
        {
            HAL_UART_Transmit_DMA(&huart1,rx_error,22);
        }
        else
        {   
            HAL_UART_Transmit_DMA(&huart1,rx_buffer,len);
        }
        
        HAL_UART_Receive_DMA(&huart1,rx_buffer,100);
    }

第一步:定义接收缓存区

main.h

main.c

第二步:while前开启DMA接收和空闲中断

第三步:由于工程没有空闲中断的回调函数,所以我们要在串口1的中断服务函数来编写

先外部声明一下主函数用到的接收缓存区数组,再定义一下用来记录接收数据长度的变量len

stm32f4_it.c

第四步:在串口1中断服务函数编写不定长收发代码

先获取空闲中断标志位是否发生了,若发生则先清楚标志位再停止DMA,然后判断出来接受了多少字符串,判断长度是否大于等于最大数量,100个字符的最大数量,若点击了发送新行,则还会有\R和\N,最后,重新开启DMA接收

四、现象

注意:

由于hal库bug,第一次发送时候不要超过max_size,因为程序第一次启动后,第一次暂停DMA之后,使用dma模式发出字符串

有任何bug请直接发在评论区我会第一时间更改

 

### STM32 HAL UART接收功能详解 #### 介绍 STM32微控制器系列广泛应用于嵌入式开发项目中,其硬件抽象层(HAL)简化了许多外设的操作。对于UART接口而言,HAL提供了丰富的API函数来配置和操作该模块。 #### 配置UART接收模式 为了设置UART进入DMA接收模式,在初始化结构体`UART_HandleTypeDef`内需指定相应的参数并调用初始化函数[^1]: ```c UART_HandleTypeDef huart1; void MX_USART1_UART_Init(void) { /* USART1 parameter configuration */ huart1.Instance = USART1; huart1.Init.BaudRate = 115200; // 波特率设定为115200bps huart1.Init.WordLength = UART_WORDLENGTH_8B;// 字符长度为8位 huart1.Init.StopBits = UART_STOPBITS_1; // 停止位数为1 huart1.Init.Parity = UART_PARITY_NONE; // 不使用奇偶校验 huart1.Init.Mode = UART_MODE_TX_RX; // 发送加接收模式 huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;// 关闭硬件流控制 huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; if (HAL_UART_Init(&huart1) != HAL_OK){ Error_Handler(); } } ``` #### 启动DMA接收过程 当完成上述基本配置之后,则可通过如下方式开启基于DMA机制的数据读取流程[^2]: ```c uint8_t aRxBuffer[RXBUFFERSIZE]; // 开启DMA传输,等待空闲线程触发回调处理接收到的数据包. if (HAL_UARTEx_ReceiveToIdle_DMA(&huart1, (uint8_t *)aRxBuffer, RXBUFFERSIZE)!= HAL_OK){ Error_Handler(); } /* At this stage the microcontroller will receive any communication from another device, * store it into 'aRxBuffer' until an idle line is detected or buffer gets full. Once done, * callback function will be called to process received data.*/ ``` #### 处理接收到的数据 每当检测到线路处于闲置状态时(`IDLE`事件),会自动激活预定义好的回调函数来进行后续动作,比如解析消息内容或是转发给其他组件继续工作: ```c void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart,uint16_t Size) { if(huart->Instance==USART1){ // Process your incoming message here using 'Size' bytes stored inside 'aRxBuffer' // Reset DMA pointer back to start of buffer after processing complete packet __HAL_UART_FLUSH_DRREGISTER(huart); HAL_UARTEx_ReceiveToIdle_DMA(huart,(uint8_t*)aRxBuffer,RXBUFFERSIZE); } } ``` 通过这种方式能够有效地管理异步到达的信息片段,并确保不会因为缓冲区溢出而导致丢失重要指令或数据帧。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值