STM32使用DMA发送串口数据
1、概述
上一篇文章《STM32使用DMA接收串口数据》讲解了如何使用DMA接收数据,使用DMA外设和串口外设,使用的中断是串口空闲中断。本篇文章主要讲解使用DMA发送数据,不会讲解基础的串口和DMA知识,直接上代码,如果有同学对DMA和串口都不熟悉,建议看一下上篇文章《STM32使用DMA接收串口数据》。
使用DMA发送数据,首先我们要确认使用的串口有没有DMA。
我们使用USART1串口外设,从数据手册中可以查到,USART1的发送和接收都是支持DMA的,使用的是DMA2.

接下来就是撸代码的时刻了
02、代码
DMA串口发送的代码是在上一篇文章DMA串口接收的基础上修改的。
void UART_Init(void)
{
USART_InitTypeDef USART_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure; /* Enable GPIO clock */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
/* Enable UART1 clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
/* Connect PXx to USARTx_Tx*/
GPIO_PinAFConfig(GPIOA, 9, GPIO_AF_USART1); /* Connect PXx to USARTx_Rx*/
GPIO_PinAFConfig(GPIOA, 10, GPIO_AF_USART1); /* Configure USART Tx as alternate function */
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure); /* Configure USART Rx as alternate function */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_Init(GPIOA, &GPIO_InitStructure); USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; /* USART configuration */
USART_Init(USART1, &USART_InitStructure); USART_ITConfig(USART1, USART_IT_IDLE, ENABLE); /* Enable the USARTx Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure); /*使能串口DMA接收*/
USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
/*使能串口DMA发送*/
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE); /* Enable USART */
USART_Cmd(USART1, ENABLE);
}
在这里除了常规的串口配置,我们需要配置串口的DMA发送,和串口DMA接收一样的API函数,参数修改为USART_DMAReq_Tx即可。
串口DMA发送配置
void Uart_Send_DMA_Config(void)
{
DMA_InitTypeDef DMA_InitStructure; /* Enable DMA clock */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); /* Reset DMA Stream registers (for debug purpose) */
DMA_DeInit(DMA2_Stream7); /* Check if the DMA Stream is disabled before enabling it.
Note that this step is useful when the same Stream is used multiple times:
enabled, then disabled then re-enabled... In this case, the DMA Stream disable
will be effective only at the end of the ongoing data transfer and it will
not be possible to re-configure it before making sure that the Enable bit
has been cleared by hardware. If the Stream is used only once, this step might
be bypassed. */
while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE)
{
} /* Configure DMA Stream */
DMA_InitStructure.DMA_Channel = DMA_Channel_4; //DMA请求发出通道
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;//配置外设地址
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)UART_Buffer;//配置存储器地址
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;//传输方向配置
DMA_InitStructure.DMA_BufferSize = (uint32_t)UART_RX_LEN;//传输大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址不变
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//memory地址自增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设地址数据单位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//memory地址数据单位
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//DMA模式:正常模式
DMA_InitStructure.DMA_Priority = DMA_Priority_High;//优先级:高
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;//FIFO 模式不使能.
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;// FIFO 阈值选择
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//存储器突发模式选择,可选单次模式、 4 节拍的增量突发模式、 8 节拍的增量突发模式或 16 节拍的增量突发模式。
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//外设突发模式选择,可选单次模式、 4 节拍的增量突发模式、 8 节拍的增量突发模式或 16 节拍的增量突发模式。
DMA_Init(DMA2_Stream7, &DMA_InitStructure); /* DMA Stream enable */
// DMA_Cmd(DMA2_Stream7, ENABLE);
}
这里也是常规的DMA配置流程,不明白的同学请看文章《STM32DMA详解》,这里值得注意的是,配置完成并没有使能DMA2_Stream7,使能了就会立即将UART_Buffer的数据发送出去。
其他代码处理
void USART1_IRQHandler(void)
{
uint8_t temp;
if(USART_GetFlagStatus(USART1, USART_FLAG_IDLE) == SET)
{
DealWith_UartData();
// USART_ClearFlag(USART1, USART_FLAG_IDLE);
temp = USART1->SR;
temp = USART1->DR; //清USART_IT_IDLE标志
}
} void DealWith_UartData()
{
DMA_Cmd(DMA2_Stream2, DISABLE);
UART_Receive_flg = 1;
UART_Receive_len = UART_RX_LEN - DMA_GetCurrDataCounter(DMA2_Stream2);
UART_Buffer[UART_Receive_len] = 0;
DMA_SetCurrDataCounter(DMA2_Stream2,UART_RX_LEN);
DMA_ClearFlag(DMA2_Stream2, DMA_FLAG_TCIF2);
DMA_Cmd(DMA2_Stream2, ENABLE);
} int main(void)
{
UART_Receive_flg = 0; Uart_Reveice_DMA_Config();
Uart_Send_DMA_Config();
UART_Init(); while (1)
{
if(UART_Receive_flg)
{
UART_Receive_flg = 0;
Uart_Send_DMA_Start();
}
}
}
上面3个函数,简单逻辑就是,当串口使用DMA接收了一定量的数据,就会通过串口DMA发送出去,串口DMA发送的代码如下:
void Uart_Send_DMA_Start(void)
{
DMA_SetCurrDataCounter(DMA2_Stream7,UART_Receive_len);
DMA_ClearFlag(DMA2_Stream7, DMA_FLAG_TCIF7);
/* DMA Stream enable */
DMA_Cmd(DMA2_Stream7, ENABLE);
}
03、后记
这一篇很简单,就是DMA使用的一个延伸,上面说了这么多,也贴了很多代码,不可能将所有代码全部贴出来,作为软件工程师,还是在IDE里看代码方便,如果感兴趣的话,可以到下面github链接下载代码,Keil和IAR的工程文件都有。
PCB和工程代码开源地址:
https://github.com/strongercjd/STM32F207VCT6
点击查看本文所在的专辑,STM32F207教程
STM32使用DMA发送串口数据的更多相关文章
- STM32 UART DMA实现未知数据长度接收
串口通信是经常使用到的功能,在STM32中UART具有DMA功能,并且收发都可以使用DMA,使用DMA发送基本上大家不会遇到什么问题,因为发送的时候会告知DMA发送的数据长度,DMA按照发送的长度直接 ...
- STM32—无需中断来实现使用DMA接收串口数据
本节目标: 通过DMA,无需中断,接收不定时长的串口数据 描述:当在串口多数据传输下,CPU会产生多次中断来接收串口数据,这样会大大地降低CPU效率,同时又需要CPU去做其它更重要的事情,我们应该如何 ...
- 使用DMA方式发送串口数据
一.初始化部分代码 //串口接收DMA缓存 uint8_t Uart_Rx[UART_RX_LEN] = {}; uint32_t Uart_Send_Buffer[] = {}; void USAR ...
- STM32 串口USART DMA方式发送接收数据
硬件:stm32f103cbt6 软件:STM32F10x_StdPeriph_Lib_V3.5.0 文章目录 头文件 USART3_DR的地址 DMA的通道 DMA的中断 USART接收回调函数 头 ...
- STM32 使用 printf 发送数据配置方法 -- 串口 UART, JTAG SWO, JLINK RTT
STM32串口通信中使用printf发送数据配置方法(开发环境 Keil RVMDK) http://home.eeworld.com.cn/my/space-uid-338727-blogid-47 ...
- 为何串口dma发送数据可能不完整
串口dma数据发送不完整, 1. 通过打印log说明数据合成,送给dma buff都是正常的. 2. 数据通过硬件串口直接配置,是正常的 3. 数据通过单片机dma转发后数据异常,通过检查发现 dma ...
- stm32_DMA采集一个AD数据_并通过DMA向串口发送
这是以前学32的时候写的,那时候学了32之后感觉32真是太强大了,比51强的没影.关于dma网上有许多的资料,关于dma采集ad网上也有很多.亲们搜搜,这里只贴代码了,其实我也想详详细细地叙述一番,但 ...
- STM32移植RT-Thread的串口只能接收一个字节数据的问题
打开设备的函数参数要与注册设备函数参数要一致, 注册设备的函数及其参数如下: /* register UART1 device */ rt_hw_serial_register(&serial ...
- 换晶振导致stm32串口数据飞码的解决办法
一般来说,stm32f107都是用标配的晶振,比如8MHz. 但是,如果用别的晶振,比如13.56M的晶振,那串口接收还正常吗? 根据试验结果,很可能会飞码.比如说用串口助手发送的是0x35,但是在串 ...
随机推荐
- Android Dex文件格式解析
Dex文件是Android虚拟机下的可执行文件,包含了应用程序所用到所有操作指令和运行时数据.在程序编译过程中,java源文件先被编译成class文件,然后通过dx工具将多个class文件整合为一个d ...
- PHP基础-数组
一.数组的概述 * 1. 数组的本质:管理和操作一组变量,成批处理 * 2. 数组是复合类型 * 3. 数组中可以存储任意长度的数据,也可以存储任意类型的数据 * 4. 数组就可以完成其它语言数据结构 ...
- SecureCRT 基本设置
1:字体与大小 Lucida Console 四号 2:声音关闭 Terminal-->Audio bell不勾选 默认网络工程师常用: Terminal-->Emulation--& ...
- Blazor实现未登录重定向到登录页的方法
今天研究了一下blazor,发现他默认启动就是类似于后台管理系统的界面,看到这个页面我就想给他写个登录,有登录就涉及到未登录重定向的问题,但是我没有找到blazor全局路由的设置,知道的老哥可以告诉我 ...
- 图扑软件正式加入腾讯智维生态发展计划,智能 IDC 开启数字经济新征程
4 月 23 日,主题为<智汇科技,维新至善>的腾讯数据中心智维技术研讨会在深圳胜利召开,发布了腾讯智维 2.0 技术体系,深度揭秘了智维 2.0 新产品战略和技术规划.图扑软件(High ...
- 《Spring 手撸专栏》第 2 章:小试牛刀(让新手能懂),实现一个简单的Bean容器
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 上学时,老师总说:不会你就问,但多数时候都不知道要问什么! 你总会在小傅哥的文章前言 ...
- 【开源技术分享】无需流媒体服务,让浏览器直接播放rtsp/rtmp的神器:EasyMedia
不同于市面上其他需要各种转发到流媒体服务的中间件来说,EasyMedia不需要依赖任何nginx-rtmp,srs,zlmediakit等等第三方流媒体服务,只需要你有rtsp或者rtmp等等协议的视 ...
- linux下符号链接和硬链接的区别
存在2众不同类型的链接,软链接和硬链接,修改其中一个,硬链接指向的是节点(inode),软链接指向的是路径(path) 软连接文件 软连接文件也叫符号连接,这个文件包含了另一个文件的路径名,类似于wi ...
- 使用find_if算法搜寻map的value
// // main.cpp // map_find // // Created by PKU on 14-9-8. // Copyright (c) 2014年 PKU. All rights re ...
- OCR横向评测 -- 软工案例分析
目录 第一部分 调研&评测 使用感受 1. 使用门槛 2. 界面设计 3. 数据标注 4. 模型训练 5. 模型预测 6. 体验评价与改进建议 好的方面: 可能需要改进的方面: 7. BUG反 ...