(三)stm32之串口通信DMA传输完成中断
扫描二维码
随时随地手机看文章
一、DMA功能简介
首先唠叨一下DMA的基本概念,DMA的出现大大减轻了CPU的工作量。在硬件系统中,主要由CPU(内核)、外设、内存(SRAM)、总线等结构组成,数据经常要在内存和外设之间,外设和外设之间转移。例如:CPU需要处理从外设采集回来的数据,CPU需要先将数据从ADC外设的寄存器读取到内存中(变量)去,然后进行运算处理,这是一般的解决方法。CPU的资源是非常宝贵的,我们可以设法把转移的工作交给其他部件来完成,CPU把更多的资源用于数据运算和中断响应上,如此DMA便登场了。DMA正是为CPU分担数据转移工作,因为DMA的存在,CPU才被解放出来,它可以在数据转移的同时进行数据运算,相应中断,大大提高了效率。
二、DMA的主要特性
三、DMA中断特性
四、DMA之串口通信
我们实现一个简单的功能,在DMA中处理串口通信,把数据转移的工作交给DMA,DMA把数据从内存(数组)到外设(串口)的转移,在main函数中不断进行闪灯操作,这样我们可以看到DMA在工作的时候CPU也在工作。非常有必要复习一下DMA的对应关系,我们知道stm32总共有2个DMA控制器(DMA1有7个通道,DMA2有5个通道),每个通道专门用来管理来自一个或多个外设对存储器访问的请求,还有一个仲裁器来协调DMA请求的优先级(优先级分:很高、高、中等、低),这可不是随便对应的。
1、LED初始化程序如下:
1234567891011121314151617voidLED_GPIO_Config(void){/*定义一个GPIO_InitTypeDef类型的结构体*/GPIO_InitTypeDef GPIO_InitStructure;/*开启LED的外设时钟*/RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE);/*选择要控制的GPIOB引脚*/GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;/*设置引脚模式为通用推挽输出*/GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;/*设置引脚速率为50MHz */GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;/*调用库函数,初始化GPIOB0*/GPIO_Init(GPIOB, &GPIO_InitStructure);/* 关闭所有led灯 */GPIO_SetBits(GPIOB, GPIO_Pin_14);}这个地方地方没什么要注意的,唯一要注意的就是输入输出模式,我们按需求这样配就好了。
2、串口初始化
123456789101112131415161718192021222324252627voidUSART3_Config(void){GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;/* config USART3 clock */RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB , ENABLE);RCC_APB1PeriphClockCmd( RCC_APB1Periph_USART3, ENABLE);/* USART1 GPIO config *//* Configure USART1 Tx (PA.09) as alternate function push-pull */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);/* Configure USART1 Rx (PA.10) as input floating */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOB, &GPIO_InitStructure);/* USART1 mode config */USART_InitStructure.USART_BaudRate = 38400;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_Init(USART3, &USART_InitStructure);USART_Cmd(USART3, ENABLE);}3、DMA初始化
123456789101112131415161718192021222324252627282930313233343536voidUSART3_DMA_Config(void){DMA_InitTypeDef DMA_InitStructure;/*开启DMA时钟*/RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//NVIC_Config(); //配置DMA中断//NVIC_Configuration();/*设置DMA源:串口数据寄存器地址*/DMA_InitStructure.DMA_PeripheralBaseAddr = USART3_DR_Base;/*内存地址(要传输的变量的指针)*/DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff;/*方向:从内存到外设*/DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;/*传输大小DMA_BufferSize=SENDBUFF_SIZE*/DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;/*外设地址不增*/DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;/*内存地址自增*/DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;/*外设数据单位*/DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;/*内存数据单位 8bit*/DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;/*DMA模式:不断循环*/DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ;//DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;/*优先级:中*/DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;/*禁止内存到内存的传输 */DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;/*配置DMA1的2通道*/DMA_Init(DMA1_Channel2, &DMA_InitStructure);//DMA_ITConfig(DMA1_Channel2,DMA_IT_TC,ENABLE); //配置DMA发送完成后产生中断/*使能DMA*/DMA_Cmd (DMA1_Channel2,ENABLE);}在这里我们要注意以下几点:
(1)DMA_InitStructure.DMA_PeripheralBaseAddr = USART3_DR_Base;这里对应USART数据寄存器地址,这个地址我们是这样定义的:#define USART3_DR_Base 0x40004804,这个值是怎么算出来的呢?我们可以查看stm32存储器映射表:
USART3的起始地址是0x40004800,我们查看stm32串口数据寄存器偏移地址为0x04
因此我们可以计算到USART3数据寄存器地址为0x40004804
(2)我们数据传输方向内存(变量)到外设(串口),所以DMA方向为内存到外设
(3)DMA传输模式有两种:DMA_Mode_Normal(普通模式),DMA只传输一次;DMA_Mode_Circular(循环模式),DMA循环传输,比如在AD采集时要配置成循环模式。
4、主函数
123456789101112131415161718192021222324252627intmain(void){/* USART1 config 115200 8-N-1 */USART3_Config();USART3_DMA_Config();LED_GPIO_Config();printf("rn usart3 DMA TX 测试 rn");{ ui