(三)stm32之串口通信DMA传输完成中断

您所在的位置:网站首页 sci发送中断如何触发 (三)stm32之串口通信DMA传输完成中断

(三)stm32之串口通信DMA传输完成中断

2024-07-17 10:59| 来源: 网络整理| 查看: 265

一、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初始化程序如下:

void LED_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、串口初始化

void USART3_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初始化

void USART3_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、主函数

int main(void) { /* USART1 config 115200 8-N-1 */ USART3_Config(); USART3_DMA_Config(); LED_GPIO_Config(); printf("\r\n usart3 DMA TX 测试 \r\n"); { uint16_t i; /*填充将要发送的数据*/ for(i=0;i


【本文地址】


今日新闻


推荐新闻


    CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3