前面几篇文章介绍了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基础设计(5)---ADC转换(中断方式)
下一篇:STM32基础设计(3)---中断串口通信
推荐阅读最新更新时间:2024-03-16 16:23