STM32基础设计(4)---DMA通信

发布者:PeacefulOasis最新更新时间:2019-01-29 来源: eefocus关键字:STM32  DMA通信 手机看文章 扫描二维码
随时随地手机看文章

前面几篇文章介绍了STM32 F103C8的 GPIO口操作,串口的操作,中断的操作,今天这篇文章简单介绍STM32的DMA操作。


本文通过一个小的设计来进行讲解,将STM32内部存储的一个数组中的数据,通过DMA操作复制到第二个数组里,并用USART1串口将第二个数组中的数据输出到电脑端,进行检查,看是否复制成功。


首先总结全文,,使用STM32进行DMA操作的主要过程如下:


1,初始化GPIO


2,初始化串口


3,初始化DMA


4,编写主函数


下面介绍详细步骤:


(步骤1,2前几篇博客有详细讲,请读者翻阅。)


1,初始化GPIO

void IO_Init()

{

GPIO_InitTypeDef Uart_A; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

Uart_A.GPIO_Pin = GPIO_Pin_9;

Uart_A.GPIO_Speed = GPIO_Speed_50MHz;

Uart_A.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_Init(GPIOA,&Uart_A);

Uart_A.GPIO_Pin = GPIO_Pin_10;

Uart_A.GPIO_Speed = GPIO_Speed_50MHz;

Uart_A.GPIO_Mode = GPIO_Mode_IN_FLOATING; //page 110

GPIO_Init(GPIOA,&Uart_A);

}

2,初始化USART1

void Usart1_Init()

{

USART_InitTypeDef Uart;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);

Uart.USART_BaudRate = 115200;

Uart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;

Uart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

Uart.USART_Parity = USART_Parity_No;

Uart.USART_StopBits = USART_StopBits_1;

Uart.USART_WordLength = USART_WordLength_8b;

USART_Init(USART1,&Uart);

USART_Cmd(USART1,ENABLE);

USART_ClearFlag(USART1,USART_FLAG_TC); //page 540

}


3,初始化DMA

库函数中DMA的结构体如下:


typedef struct

{

  uint32_t DMA_PeripheralBaseAddr; /*!< Specifies the peripheral base address for DMAy Channelx. */

 

  uint32_t DMA_MemoryBaseAddr;     /*!< Specifies the memory base address for DMAy Channelx. */

 

  uint32_t DMA_DIR;                /*!< Specifies if the peripheral is the source or destination.

                                        This parameter can be a value of @ref DMA_data_transfer_direction */

 

  uint32_t DMA_BufferSize;         /*!< Specifies the buffer size, in data unit, of the specified Channel. 

                                        The data unit is equal to the configuration set in DMA_PeripheralDataSize

                                        or DMA_MemoryDataSize members depending in the transfer direction. */

 

  uint32_t DMA_PeripheralInc;      /*!< Specifies whether the Peripheral address register is incremented or not.

                                        This parameter can be a value of @ref DMA_peripheral_incremented_mode */

 

  uint32_t DMA_MemoryInc;          /*!< Specifies whether the memory address register is incremented or not.

                                        This parameter can be a value of @ref DMA_memory_incremented_mode */

 

  uint32_t DMA_PeripheralDataSize; /*!< Specifies the Peripheral data width.

                                        This parameter can be a value of @ref DMA_peripheral_data_size */

 

  uint32_t DMA_MemoryDataSize;     /*!< Specifies the Memory data width.

                                        This parameter can be a value of @ref DMA_memory_data_size */

 

  uint32_t DMA_Mode;               /*!< Specifies the operation mode of the DMAy Channelx.

                                        This parameter can be a value of @ref DMA_circular_normal_mode.

                                        @note: The circular buffer mode cannot be used if the memory-to-memory

                                              data transfer is configured on the selected Channel */

 

  uint32_t DMA_Priority;           /*!< Specifies the software priority for the DMAy Channelx.

                                        This parameter can be a value of @ref DMA_priority_level */

 

  uint32_t DMA_M2M;                /*!< Specifies if the DMAy Channelx will be used in memory-to-memory transfer.

                                        This parameter can be a value of @ref DMA_memory_to_memory */

}DMA_InitTypeDef;

DMA_DIR

这个是定义DMA的传输方向,DMA传输总共有三个方向,外设到内存,内存到外设,内存到内存(关于外设和内存可以这样简单理解,相当于一条路的两头)


库函数中有两个定义:


#define DMA_DIR_PeripheralDST              ((uint32_t)0x00000010)

#define DMA_DIR_PeripheralSRC              ((uint32_t)0x00000000)

以DST结尾的那个,表示,以外设为目的地,以SRC结尾的那个,表示,以外设为起始点。


 uint32_t DMA_PeripheralBaseAddr;这个是用来定义外设地址的

uint32_t DMA_MemoryBaseAddr;这个是用来定义内存地址的

uint32_t DMA_BufferSize;这个是指DMA通道的DMA 缓存的大小,这是为了照顾,两边的速率不一致。

uint32_t DMA_PeripheralInc;这个是用来定义外设地址是否要自增

uint32_t DMA_MemoryInc; 这个是用来定义内存地址是否要自增

uint32_t DMA_PeripheralDataSize;用来制定外设的数据宽度

uint32_t DMA_MemoryDataSize;

这个是用来制定内存的数据宽度,当外设和存储器之间传数据时,两边的数据宽度应该设置为一样大小


uint32_t DMA_Mode; 

这个是用来指定DMA的工作模式,有一次传输和循环传输模式,两种。

uint32_t DMA_Priority;

这个是用来指定DMA的优先级,有非常高,高,中,低四种。


uint32_t DMA_M2M; 这个是用来设置是否进行 内存到内存传输

初始化函数如下:


void Dma_Init()

{

DMA_InitTypeDef dma;

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);//老规矩,先开心脏

dma.DMA_MemoryBaseAddr = (u32)zimu;内存地址

dma.DMA_PeripheralBaseAddr = (u32)zimu_1;外设地址

dma.DMA_DIR = DMA_DIR_PeripheralDST;外设为目的地,即zimu_1数组为目的地

dma.DMA_BufferSize = 26;缓冲区大小

dma.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;数据宽度

dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;同上

dma.DMA_MemoryInc = DMA_MemoryInc_Enabl;内存地址自增

dma.DMA_PeripheralInc = DMA_PeripheralInc_Enable;外设地址自增

dma.DMA_Mode = DMA_Mode_Normal;单次模式

dma.DMA_Priority = DMA_Priority_High;优先级为高

dma.DMA_M2M = DMA_M2M_Enable;设置为内存到内存传输

DMA_Init(DMA1_Channel6,&dma);寄存器初始化

DMA_Cmd(DMA1_Channel6,ENABLE);DMA使能

}


4,编写主函数

int main()

{

void printf_string(char* a);

IO_Init();GPIO初始化

Usart1_Init();USART1初始化

Dma_Init();DMA初始化

while(DMA_GetFlagStatus(DMA1_FLAG_TC6) == RESET){}//等待DMA操作完成,在参考手册的149页可以仔细看这个寄存器

while(1){

    if(USART_GetFlagStatus(USART1,USART_FLAG_TXE))判断是否能用串口输出

        {

    printf_string(zimu_1);输出zimu_1数组

    delay(3000);延时

        }

}

}

void printf_string(char* a)

{

while(*a != '\0')直到数组末尾

{

USART1->DR = *a;赋值给USART的数据寄存器

while(!USART_GetFlagStatus(USART1,USART_FLAG_TC));等待发送成功

a++;地址加一

}

}

本文到此结束,因博主水平有限,如有错误,敬请指出,不胜感激!


亲测,可运行。详细代码如下:


#include

#define uint unsigned int

#define uchar unsigned char

char zimu[]={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};

char zimu_1[32]={'.'};

void delay(uint n)

{

int i,j;

for(i=0;i

for(j=0;j<8500;j++);

}

 

void IO_Init()

{

GPIO_InitTypeDef Uart_A;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

Uart_A.GPIO_Pin = GPIO_Pin_9;

Uart_A.GPIO_Speed = GPIO_Speed_50MHz;

Uart_A.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_Init(GPIOA,&Uart_A);

Uart_A.GPIO_Pin = GPIO_Pin_10;

Uart_A.GPIO_Speed = GPIO_Speed_50MHz;

Uart_A.GPIO_Mode = GPIO_Mode_IN_FLOATING; //page 110

GPIO_Init(GPIOA,&Uart_A);

}

void Usart1_Init()

{

USART_InitTypeDef Uart;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);

Uart.USART_BaudRate = 115200;

Uart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;

Uart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

Uart.USART_Parity = USART_Parity_No;

Uart.USART_StopBits = USART_StopBits_1;

Uart.USART_WordLength = USART_WordLength_8b;

USART_Init(USART1,&Uart);

USART_Cmd(USART1,ENABLE);

USART_ClearFlag(USART1,USART_FLAG_TC); //page 540

}

 

void Dma_Init()

{

DMA_InitTypeDef dma;

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);

dma.DMA_MemoryBaseAddr = (u32)zimu;

dma.DMA_PeripheralBaseAddr = (u32)zimu_1;

dma.DMA_DIR = DMA_DIR_PeripheralDST;

dma.DMA_BufferSize = 26;

dma.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;

dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

dma.DMA_MemoryInc = DMA_MemoryInc_Enable;

dma.DMA_PeripheralInc = DMA_PeripheralInc_Enable;

dma.DMA_Mode = DMA_Mode_Normal;

dma.DMA_Priority = DMA_Priority_High;

dma.DMA_M2M = DMA_M2M_Enable;

DMA_Init(DMA1_Channel6,&dma);

DMA_Cmd(DMA1_Channel6,ENABLE);

}

int main()

{

void printf_string(char* a);

IO_Init();

Usart1_Init();

Dma_Init();

GPIOC->BSRR = GPIO_Pin_13;

while(DMA_GetFlagStatus(DMA1_FLAG_TC6) == RESET){}

while(1){

if(USART_GetFlagStatus(USART1,USART_FLAG_TXE))

{

printf_string(zimu_1);

delay(3000);

}

}

}

void printf_string(char* a)

{

//USART1->CR1 &= ~USART_CR1_TXEIE;

USART1->CR1 |= USART_CR1_TXEIE;

while(*a != '\0')

{

USART1->DR = *a;

while(!USART_GetFlagStatus(USART1,USART_FLAG_TC));

a++;

}

}


关键字:STM32  DMA通信 引用地址:STM32基础设计(4)---DMA通信

上一篇:STM32基础设计(5)---ADC转换(中断方式)
下一篇:STM32基础设计(3)---中断串口通信

推荐阅读最新更新时间:2024-03-16 16:23

STM32-串口通讯工作原理
STM32 USART 简介 STM32芯片具有多个USART外设用于串口通讯,USART(通用同步异步收发器)能够灵活地与外部设备进行全双工通讯。USART的全称“通用同步异步收发器”,也就是说他可以同步通信也可以异步通信。但是我们实现串口打印调试信息到电脑,其实只用到了他的异步通信的功能。 USART除了有串口功能,它满足外部设备对工业标准NRZ 异步串行数据格式的要求,并且使用了小数波特率发生器提供了多种波特率,使得它的应用更加广泛。它还支持同步单向通信和半双工单线通信;还支持 LIN(局域互连网络)、智能卡协议与 IrDA(红外线数据协会) SIR ENDEC 规范,以及调制解调器操作 (CTS/RTS)。而且,它还支
[单片机]
STM32-串口通讯工作原理
STM32-SPI的NSS详解
区分开内部NSS和NSS外部引脚的区别,内部NSS的电平状态决定了设备的主从模式,内部NSS状态可以由NSS外部引脚控制,也可以由控制寄存器的SSI位控制。 内部NSS决定了主模式还是从模式,它可以通过设置SSM位选择硬件管理或是软件管理,如下图。 NSS外部引脚,主要作为输入引脚。如果是硬件管理(SSM=0),则当NSS引脚为低电平的时候,NSS状态为从模式,否则为主模式;如果是软件管理(SSM=1),内部NSS则由SSI位决定,STM设置NSS引脚的软件管理是为了可以将NSS引脚空出来,像普通IO引脚运用。 外部NSS引脚可以作为主设备的输出引脚(SSOE=1),此时主设备拉低外部NSS引脚,使其连接上的硬件模式(
[单片机]
STM32-SPI的NSS详解
STM32 编译指令 #pragma pack 的配对使用
#pragma pack 可以用来指定数据结构的成员变量的内存对齐数值。 可选值为: 1、2、4、8、16。 使用 pack 指令要配对使用,以避免意外影响项目中其他源文件的结构成员的内存对齐。 如果影响了其他源文件的结构成员内存对齐,那么在你按照默认对齐来计算那些结构成员占用内存大小或者使用指针移动计算结构成员偏移位置的时候,就可能会出现意料之外的异常。 主要可能的异常是内存定位错误或非法内存访问,结果可能导致错误的定位或数值,极端的情况下可能导致程序崩溃。 下面的例子用来展示基本的配对使用方式。 1)#pragma pack(n)的配对使用 #pragma pack(1) //内存对齐设置为1个字节
[单片机]
STM32使用PWM控制LED呼吸灯效果
实验的STM32型号: STM32F103C8T6 48引脚 涉及到的知识: RCC,GPIO,TIMER,PWM 设置 *RCC需打开外部时钟 *GPIO查表得知 PA3 默认复用引脚 TIM2_CH4 *TIMER使用默认的TIM2_CH4 *PWM的控制使用了动态的占空比来达到呼吸效果 下面给出代码: #include stm32f10x.h void RCC_cfg(void); void GPIO_cfg(void); void TIMER_cfg(void); void PWM_cfg(void); int led_fx=1; int led_dt=0;
[单片机]
STM32学习体会
学习STM32也有一段时间了,周围的人也在学习这款单片机,感觉它是越来越流行,没办法,功能强大,又便宜,谁不愿意用呢。搞不懂AVR,现在都快被挤兑成诺基亚了,还是死守价格不便宜!没学的就跳过啊,STM32,MSP430都是不错的选择 因为暑假的时候学了MSP430,所以现在学STM32让我感觉很容易就上手了,相比51,主要是初始化更加繁琐了,没办法嘛,功能强大,寄存器就多,多了配置起来就复杂一些。 个人感觉一开始还是走寄存器路线,因为只有学懂了底层的东西才能更好的理解它的功能是怎么实现的,才能从中找出来捷径。以后的话貌似还可以走库函数路线,那样可以大大的缩短开发周期。 几乎所有的单片机开始都是在介绍IO口,但是我感觉在
[单片机]
STM32通过USB实现Bootloader/IAP功能
前沿: 最近在做STM32的USB Bootlader/IAP功能,也就是通过USB实现固件升级,本文介绍下实现的基本思路,希望对实现IAP的同学一个参考,改方法已经在产品中得到实际应用并验证是比较合理,稳定可靠的。 程序空间划分: 在单片机的程序Flash中分两个区,分别存储Bootloader代码和App代码,Bootloader放到代码起始地址,也就是0x08000000,App放到0x8020000地址,中间预留了很多的地址空间,主要是为了用来存储一些需要掉电保存的数据,比如我在0x0800C000地址就存放了App程序运行后写入该地址的标志数据。 启动流程: 上电后自然是运行Bootloader程序,Bootloader
[单片机]
<font color='red'>STM32</font>通过USB实现Bootloader/IAP功能
STM32:STM32学习记录3:按键输入
1:IO配置:。上拉输入模式:区别在于没有输入信号的时候默认输入高电平(因为 有弱上拉)。下拉输入模式:区别在于没有输入信号的时候默认输入低电平(因为有弱下拉)。对于浮空输入模式顾名思义也就是输入什么信号才是什么信号,对于浮空输入要保证有明确的输入信号。 2:stm32的GPIO既可以设置为输出也可以设置为输入,当设置为输入时,输出还是可以有效的,当设为上拉时,可以把输出设为高电平,而设为下拉输入时,把输出设为低电平,这样就有了上拉和下拉。 3:STM32 支持 JTAG 和 SWD 两种仿真接口,他们和普通的 IO 口共用,当需要使用普通 IO口的时候,则必须先禁止 JTAG/SWD。STM32 在默认状态下是开启 JT
[单片机]
STM32 V3.4库函数使用建立工程方法
清晰地记得刚从51单片机过度到STM32,那种一头雾水的感觉。使用的STM32开发板是非常不适合初学者使用的开发板,它是硬件看上去华丽的神舟开发板。在这里我不评论神舟开发板如何如何,如果你是初学者,建议你不要使用神舟开发板。 拿到神舟开发板的教程,坑爹啊,如何使用STM32库的说明都没有,这对初学者也太不公平了吧。鄙人一个STM32菜鸟在网上花了半天时间才弄明白如何使用这个库,如何建立工程。今天分享我当初是如何使用STM32库文件建立工程的,非常适合初学者。 少废话,上图:
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
热门活动
换一批
更多
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

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

更多精选电路图
换一换 更多 相关热搜器件
更多每日新闻
随便看看
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved