STM32F10x 学习笔记之USART实现串口通讯 DMA 方式

2020-07-04来源: eefocus关键字:STM32F10x  USART  串口通讯  DMA  方式

STM32F10x 的USART 支持DMA 方式,并且在DMA完成后可以产生中断。这对于需要接收或发送大量数据的应用情景是很有帮助的。


在普通的8位或16位单片机中很少有包含DMA控制器的,所以可能许多嵌入式程序员对DMA方式并不熟悉。简单的说,直接存储器存取(DMA)用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。由于无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源来做其他操作。


STM32F10x 上具有两个DMA控制器,共有12个通道(DMA1有7个通道,DMA2有5个通道),每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁器来协调各个DMA请求的优先权。


按照STM32参考手册上的说法:“DMA控制器和Cortex™-M3核心共享系统数据总线,执行直接存储器数据传输。当CPU和DMA同时访问相同的目标(RAM或外设)时,DMA请求会暂停CPU访问系统总线达若干个周期,总线仲裁器执行循环调度,以保证CPU至少可以得到一半的系统总线(存储器或外设)带宽。”所以我们不必担心DMA控制器霸占总线资源。CPU总是可以得到一般的总线时间的。


下面我们以USART2 的数据发送为例来介绍DMA。首先由STM32 参考手册的图22可知。USART2 的发送功能可以使用DMA1 的第7 个通道。


利用的DMA 传输的设置工作大体可以分为6步:

1. 在DMA1_CPAR7寄存器中设置外设寄存器的地址。发生外设数据传输请求时,这个地址将是数据传输的源或目标。 

2. 在DMA1_CMAR7寄存器中设置数据存储器的地址。发生外设数据传输请求时,传输的数据将从这个地址读出或写入这个地址。 

3. 在DMA1_CNDTR7寄存器中设置要传输的数据量。在每个数据传输后,这个数值递减。 

4. 在DMA1_CCR7寄存器的PL[1:0]位中设置通道的优先级。 

5. 在DMA1_CCR7寄存器中设置数据传输的方向、循环模式、外设和存储器的增量模式、外设和存储器的数据宽度、传输一半产生中断或传输完成产生中断。 

6. 设置DMA1_CCR7寄存器的ENABLE位,启动该通道。 


第1步对应的代码为:

  1. DMA1_Channel7->CPAR = (uint32_t) &(USART2->DR);  

第2步对应的代码如下,其中p_str 是一个指针,指向要传输的数据的首地址:


  1. DMA1_Channel7->CMAR = (uint32_t) p_str;  

第3步对应的代码如下,cnt 为要传输的数据量,串口数据是以字节为传输单位的,所以这里cnt就是要传输数据的字节数。


  1. DMA1_Channel7->CNDTR = cnt;  

第4步对应的代码如下,DMA 通道的优先级分为4级,分别是:DMA_Priority_VeryHigh、DMA_Priority_High、DMA_Priority_Medium、DMA_Priority_Low。这里设为最低。


  1. DMA1_Channel7->CCR |= DMA_Priority_Low;  

第5步对应的代码如下:


  1. DMA1_Channel7->CCR |= DMA_DIR_PeripheralDST |   

  2. DMA_Mode_Normal |   

  3. DMA_PeripheralInc_Disable |  

  4. DMA_MemoryInc_Enable |  

  5. DMA_PeripheralDataSize_Byte |  

  6. DMA_MemoryDataSize_Byte |   

  7. DMA_M2M_Disable;  

第6步对应的代码如下:


  1. DMA1_Channel7->CCR |= DMA_CCR1_EN;  


实际上在这6步之前应该还有2步操作。首先设置DMA之前,要打开DMA的时钟:


  1. RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);  

其次,也要设置USART使其支持DMA方式:


  1. USARTx->CR3 |= USART_DMAReq_Tx;  


或者用下面的函数:


  1. USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE);   


一旦启动了DMA通道,它既可响应连到该通道上的外设的DMA请求。 完成一次DMA传输后如何开启下一次传输呢,这个问题困扰了我好几天,最后在STM32参考手册上发现如下的一句话:

当通道配置为非循环模式时,传输结束后(即传输计数变为0)将不再产生DMA操作。要开始新的DMA传输,需要在关闭DMA通道的情况下,在DMA_CNDTRx寄存器中重新写入传输数目。


下面先给一个简单的示例程序:


  1. void USART2_Init(void)  

  2. {  

  3.     GPIO_InitTypeDef GPIO_InitStructure;  

  4.     USART_InitTypeDef USART_InitStructure;  

  5.     NVIC_InitTypeDef NVIC_InitStructure;  

  6.   

  7.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_AFIO, ENABLE);  

  8.   

  9.     /* Configure USART Tx as alternate function push-pull */  

  10.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  

  11.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;  

  12.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  

  13.     GPIO_Init(GPIOD, &GPIO_InitStructure);  

  14.   

  15.     /* Configure USART Rx as input floating */  

  16.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  

  17.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;  

  18.     GPIO_Init(GPIOD, &GPIO_InitStructure);  

  19.   

  20.     GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE);  

  21.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);  

  22.   

  23.     USART_InitStructure.USART_BaudRate = 9600;  

  24.     USART_InitStructure.USART_WordLength = USART_WordLength_8b;  

  25.     USART_InitStructure.USART_StopBits = USART_StopBits_1;  

  26.     USART_InitStructure.USART_Parity = USART_Parity_No;  

  27.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  

  28.     USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;  

  29.     USART_Init(USART2, &USART_InitStructure);  

  30.   

  31.     USART_Cmd(USART2, ENABLE);  

  32. }  

  33.   

  34. void UART2_TX_DMA_Init(uint8_t *p_str, uint16_t cnt)  

  35. {  

  36. //    DMA_InitTypeDef    DMA_InitStructure;  

  37. //    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(USART2->DR);      

  38. //    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) str;  

  39. //    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;  

  40. //    DMA_InitStructure.DMA_BufferSize = 14;  

  41. //    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  

  42. //    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  

  43. //    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;  

  44. //    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;  

  45. //    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;  

  46. //    DMA_InitStructure.DMA_Priority = DMA_Priority_Low;  

  47. //    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  

  48.   

  49.     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);  

  50. //    DMA_Init(DMA1_Channel7, &DMA_InitStructure);  

  51.   

  52.     DMA1_Channel7->CPAR = (uint32_t) &(USART2->DR);  

  53.     DMA1_Channel7->CMAR = (uint32_t) p_str;  

  54.     DMA1_Channel7->CNDTR = cnt;  

  55.     DMA1_Channel7->CCR = DMA_DIR_PeripheralDST | DMA_Priority_Low |   

  56.                 DMA_Mode_Normal | DMA_PeripheralInc_Disable    |  

  57.                 DMA_MemoryInc_Enable | DMA_PeripheralDataSize_Byte |  

  58.                 DMA_MemoryDataSize_Byte    | DMA_M2M_Disable;  

  59. }  

  60.   

  61. uint8_t str[] = "Hello World!!!";  

  62. void TaskStart(void *pdata)  

  63. {  

  64.     SysTick_Config(SystemCoreClock/10);  

  65.     USART2_Init();  

  66.     UART2_TX_DMA_Init(str, 14);  

  67.     for(;;)  

  68.     {  

  69.         LED_Spark();  

  70.         //DMA_Cmd(DMA1_Channel7, DISABLE);  

  71. DMA1_Channel7->CCR &= (uint16_t)(~DMA_CCR1_EN);

[1] [2] [3]
关键字:STM32F10x  USART  串口通讯  DMA  方式 编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/ic502130.html 本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:串口DMA方式发送&接收
下一篇:STM32学习------SPI笔记【寄存器版】

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

STM32F10X ADC原理详解(STM32F103ZET6)
STM32ADC的工作原理模/数转换器STM32F10x  ADC特点12位逐次逼近型的模拟数字转换器。最多带3个ADC控制器最多支持18个通道,可最多测量16个外部和2个内部信号源。支持单次和连续转换模式转换结束,注入转换结束,和发生模拟看门狗事件时产生中断。通道0到通道n的自动扫描模式自动校准采样间隔可以按通道编程规则通道和注入通道均有外部触发选项转换结果支持左对齐或右对齐方式存储在16位数据寄存器ADC转换时间:最大转换速率 1us。(最大转换速度为1MHz,在ADCCLK=14M,采样周期为1.5个ADC时钟下得到。)ADC供电要求:2.4V-3.6VADC输入范围:VREF- ≤  VIN 
发表于 2020-07-25
<font color='red'>STM32F10X</font> ADC原理详解(<font color='red'>STM32F</font>103ZET6)
STM32启动文件初探之startup_stm32f10x_hd.s(Reset_Handler函数)
用别处的地址进行链接,如果其它地方没有定义,编译器也不报错,以此处地址进行链接。第四行和第五行IMPORT 说明SystemInit 和__main 这两个标号在其他文件,在链接的时候需要到其他文件去寻找。SystemInit在库文件system_stm32f10x.c 实现,用来初始化STM32的一系列时钟,把系统时钟设置为72MHZ。STM32的时钟比51 单片机复杂,需要经过一系列的配置才能达到稳定运行的状态。__main 其实不是我们定义的,当编译器编译时,只要遇到这个标号就会定义这个函数,该函数的主要功能是:负责初始化栈、堆,配置系统境,并在最后跳转到用户自定义的main函数,从此来到C的世界。第六行把Syst
发表于 2020-03-24
STM32F10x 利用环形缓冲区的串口驱动程序
;**/    #include "stm32f10x_usart.h"  #include "com_buffered.h"    #define OS_ENTER_CRITICAL()     __set_PRIMASK(1)  #define OS_EXIT_CRITICAL()      __set_PRIMASK(0)           
发表于 2020-01-19
<font color='red'>STM32F10x</font> 利用环形缓冲区的串口驱动程序
STM32F10x_硬件I2C读写EEPROM(标准外设库版本)
Ⅰ、写在前面上一篇文章是“STM32F10x_模拟I2C读写EEPROM”,讲述使用IO口模拟I2C总线通信,对EEPROM(AT24Xxx)进行读写操作的过程。上一篇文章主要内容:I2C协议、模拟I2C底层驱动、EEPROM(AT24Xxx)单字节读写操作。本文主要内容:STM32硬件I2C详细配置、EEPROM(AT24Xxx)多字节读写操作、ST官方I2C存在问题。实例实验效果:1、多字节读写:任意地址(66), 写入任意长度(129)、读取并打印出来2、单字节读写:任意地址(0),写入1字节数据、 读取并打印出来实验说明:1.多字节读写实验为什么是从66地址写? 为什么是写入129字节?答案:验证对EEPROM多字
发表于 2020-01-09
<font color='red'>STM32F10x</font>_硬件I2C读写EEPROM(标准外设库版本)
详细分析stm32f10x.h
/**这里是STM32比较重要的头文件   ******************************************************************************  * @file    stm32f10x.h                  ST 标准的头文件  * @author  MCD Application Team 
发表于 2019-11-28
ATMEGA16单片机usart通信(主从多机通信)proteus仿真与源码
Stack size         : 256*****************************************************/#include <mega16.h>flash unsigned char led_7[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};unsigned char point=0;// External Interrupt 0 service routineinterrupt [USART_RXC] void usart_rx_isr(void) 
发表于 2020-07-12
ATMEGA16单片机<font color='red'>usart</font>通信(主从多机通信)proteus仿真与源码
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2020 EEWORLD.com.cn, Inc. All rights reserved