STM32F103C8T6 HAL库 printf重定向 USART1 DMA方式发送数据

2024-06-09 15:04

本文主要是介绍STM32F103C8T6 HAL库 printf重定向 USART1 DMA方式发送数据,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言:

        在上一篇文章里,我采用printf重定向为usart1,但是这样发送,对于MPU的负载比较大,所以本篇文章采用DMA方式,解放MPU资源,去做其他的事情,这里仅做为自己的记录。

正文开始:

        Cubemx配置

        先是在Cubemx里对单片机进行配置,跟上一篇文章同样的配置

        增加DMA通道,并且将RX引脚置为上拉模式,因为本次只是作为发送,所以,这里也可以不把RX置为上拉模式,

        配置DMA,保持默认配置即可,可以根据自己的项目需求,将自己的优先级进行调整。

                这里已经是默认勾选了DMA中断,这里只将USART1的中断使能勾选上

        并且将RX引脚设置为上拉模式,因为在选择异步通信后,CubeMX会自动配置引脚的工作模式。这时的默认配置是不打开上下拉。这可能会使引脚在悬空状态时电平不确定,产生误接收。我们把RX接收引脚,修改为:上拉(Pull-up),给引脚固定一个弱上拉,以避免悬空时产生误接收。

        有些同学第一次会找不到如何将RX设置为上拉模式,按照我的箭头指示即可。

        至此,我们的配置部分基本完成,点击生辰代码即可。

        代码部分:

        在KEIL中新建文件夹USART_DMA.c和USAR_DMA.h文件。代码如下

        USART_DMA.c

#include "USART_DMA.h"
#include "stdio.h"
#include "stdarg.h"volatile uint8_t  usart_dma_tx_over = 1;int myprintf(const char *format,...)
{va_list arg;static char SendBuff[200] = {0};int rv;while(!usart_dma_tx_over);//等待前一次DMA发送完成va_start(arg,format);rv = vsnprintf((char*)SendBuff,sizeof(SendBuff)+1,(char*)format,arg);va_end(arg);HAL_UART_Transmit_DMA(&huart1,(uint8_t *)SendBuff,rv);usart_dma_tx_over = 0;//清0全局标志,发送完成后重新置1return rv;
}void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{if(huart->Instance==USART1){usart_dma_tx_over = 1;}
}//要用的时候,直接可以
//myprintf("num:%d\r\n",i++);	
//HAL_Delay(1000);

        USART_DMA.h

#ifndef __USART_DMA_H
#define __USART_DMA_H#include "main.h"
#include "usart.h"int myprintf(const char *format,...);
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart);#endif

        使用的话,只要在while循环里添加myprintf即可。

        代码解释:

        这里我用到的是DMA传输,用到的函数是

HAL_UART_Transmit_DMA (&huart1, uint8_t *pData, uint16_t Num); 

        参数分别是选用的串口,数据地址(字符串数字形式的内容),发送的字节数。

        与HAL_UART_Transmit_IT (&huart1,  uint8_t *pData,  uint16_t Num);(中断发送)的区别在于100个字节,会产生100次中断。这个DMA发送函数,全程只产生一次中断。

        与HAL_UART_Transmit (&huart1,  uint8_t *pData,  uint16_t Num,  超时值);(阻塞式发送)区别在于阻塞式发送每发送一个字节,死等,好了继续发下一个,再死等,不断重复。就是以前标准库种那最普通的死等法,只是它增加了一个超时值。其中超时值的功能:如果指定时间内没发送完毕,就直接返回,防止卡死。数据发送通信需时间:1秒 ÷ 波特率 × 字节数 × 10 × 1000ms。举例:115200波特率,100字节,大约用时 9ms

        调用后,函数给DMA数据地址,DMA就自动开始搬砖,它会把数据逐字节搬运到串口的DR寄存器上,等串口发送完这个字节了,再自动搬运下一个,过程完全不占用程序运行资源。搬完了,就产生一个中断,给程序打个招呼。通常,我们程序上,把这个“招呼”也省略了,不用理会它。

        我们在串口的中断回调函数中,直接将标志位清零,然后等待下次将数据发送出去。

这篇关于STM32F103C8T6 HAL库 printf重定向 USART1 DMA方式发送数据的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1045518

相关文章

C++中零拷贝的多种实现方式

《C++中零拷贝的多种实现方式》本文主要介绍了C++中零拷贝的实现示例,旨在在减少数据在内存中的不必要复制,从而提高程序性能、降低内存使用并减少CPU消耗,零拷贝技术通过多种方式实现,下面就来了解一下... 目录一、C++中零拷贝技术的核心概念二、std::string_view 简介三、std::stri

Linux脚本(shell)的使用方式

《Linux脚本(shell)的使用方式》:本文主要介绍Linux脚本(shell)的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录概述语法详解数学运算表达式Shell变量变量分类环境变量Shell内部变量自定义变量:定义、赋值自定义变量:引用、修改、删

python判断文件是否存在常用的几种方式

《python判断文件是否存在常用的几种方式》在Python中我们在读写文件之前,首先要做的事情就是判断文件是否存在,否则很容易发生错误的情况,:本文主要介绍python判断文件是否存在常用的几种... 目录1. 使用 os.path.exists()2. 使用 os.path.isfile()3. 使用

Mybatis的分页实现方式

《Mybatis的分页实现方式》MyBatis的分页实现方式主要有以下几种,每种方式适用于不同的场景,且在性能、灵活性和代码侵入性上有所差异,对Mybatis的分页实现方式感兴趣的朋友一起看看吧... 目录​1. 原生 SQL 分页(物理分页)​​2. RowBounds 分页(逻辑分页)​​3. Page

Linux链表操作方式

《Linux链表操作方式》:本文主要介绍Linux链表操作方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、链表基础概念与内核链表优势二、内核链表结构与宏解析三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势六、典型应用场景七、调试技巧与

Linux实现线程同步的多种方式汇总

《Linux实现线程同步的多种方式汇总》本文详细介绍了Linux下线程同步的多种方法,包括互斥锁、自旋锁、信号量以及它们的使用示例,通过这些同步机制,可以解决线程安全问题,防止资源竞争导致的错误,示例... 目录什么是线程同步?一、互斥锁(单人洗手间规则)适用场景:特点:二、条件变量(咖啡厅取餐系统)工作流

RedisTemplate默认序列化方式显示中文乱码的解决

《RedisTemplate默认序列化方式显示中文乱码的解决》本文主要介绍了SpringDataRedis默认使用JdkSerializationRedisSerializer导致数据乱码,文中通过示... 目录1. 问题原因2. 解决方案3. 配置类示例4. 配置说明5. 使用示例6. 验证存储结果7.

Python程序打包exe,单文件和多文件方式

《Python程序打包exe,单文件和多文件方式》:本文主要介绍Python程序打包exe,单文件和多文件方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录python 脚本打成exe文件安装Pyinstaller准备一个ico图标打包方式一(适用于文件较少的程

Python验证码识别方式(使用pytesseract库)

《Python验证码识别方式(使用pytesseract库)》:本文主要介绍Python验证码识别方式(使用pytesseract库),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全... 目录1、安装Tesseract-OCR2、在python中使用3、本地图片识别4、结合playwrigh

Spring中管理bean对象的方式(专业级说明)

《Spring中管理bean对象的方式(专业级说明)》在Spring框架中,Bean的管理是核心功能,主要通过IoC(控制反转)容器实现,下面给大家介绍Spring中管理bean对象的方式,感兴趣的朋... 目录1.Bean的声明与注册1.1 基于XML配置1.2 基于注解(主流方式)1.3 基于Java