本文展示了STM32 DMA程序串口的
内容涉及 :
DMA 内存传输 DMA外设内存传输
USART串口的识别
IO口输入输出
按键的外部中断处理
32位数据通讯,字符串通讯,单字符通讯
完整代码
文章目录
- 前言
- 一、 编程要点
- 二、使用步骤
-
- 1.理解原理图
- 2.建立DMA传输的 头文件 DMA_book.h
- 3.建立DMA传输的 头文件 DMA_book.c
- 4.建立USART串口的 头文件 USART_book.h
- 5.建立USART串口的 头文件 USART_book.c
- 6.利用之前的Systick 定时输出的 头文件 Systick_book.h
- 7.利用之前的Systick 输出的 头文件 Systick_book.c
- 8.利用之前的RCC_book输出的 头文件 RCC_book.h
- 9.利用之前的RCC_book输出的 头文件 RCC_book.c
- 10.利用之前的LED输出的 头文件 Led_book.h
- 11.利用之前的LED输出的 头文件 Led_book.c
- 12.利用Key输出的程序 Key_book.h
- 13.利用Key输出的程序 Key_book.c
- 14.利用复习Exit中断的程序 Exit_book.h
- 15.利用复习Exit中断的程序 Exit_book.c
- 16.建立USART 输出的 主程序 main.c
- 总结
前言
STM32 的 DMA简介 DMA(Direct Memory Access)—直接存储器存取,是单片机的一个外设,它的主要功能是用来搬数据,但是不需要占用 CPU,即在传输数据的时候,CPU 可以干其他的事情,好像是多线程一样。数据传输支持从外设到存储器或者存储器到存储器,这里的存储器可以是 SRAM 或者是 FLASH。DMA 控制器包含了 DMA1 和 DMA2,其中 DMA1 有 7 个通道,DMA2 有 5 个通道,这里的通道可以理解为传输数据的一种管道。要注意的是 DMA2 只存 在于大容量的单片机中。DMA 传输数据的方向有三个:从外设到存储器,从存储器到外设,从存储 器到存储器。
一、 编程要点
USART:1) 使能 DMA 时钟;
2) 配置 DMA 数据参数;
3) 使能 DMA,进行传输;
4) 等待传输完成,并对源数据和目标地址数据进行比较。
5) 配置 USART 通信功能;
6) 设置串口 DMA 工作参数;
7) 使能 DMA;
8) DMA 传输同时 CPU 可以运行其他任务。
二、使用步骤
1.理解原理图
代码如下:
: STM32F103ZET6 串口引脚位PA9 ,10
: STM32F103ZET6 输出口为PB5低电平点有效
: STM32F103ZET6 Key检测脚为PA8
2.建立DMA传输的 头文件 DMA_book.h
代码如下(示例):
#ifndef __DMA_BOOK_H_
#define __DMA_BOOK_H_
#include "stm32f10x.h"
#define DMA_CLOCK RCC_AHBPeriph_DMA1 //DMA 时钟
/****** A ****************** ROM 到 RAM 的DMA输出 *******************************/
#define Map_DMA_CHANNEL DMA1_Channel6 // 当使用存储器到存储器模式时候,通道可以随便选,没有硬性的规定
#define Map_BUFFER_SIZE 32 // 要发送的数据大小
#define DMA_FLAG_TC DMA1_FLAG_TC6 // 传输完成标志
/* 定义 aSRC_Const_Buffer 数组作为 DMA 传输数据源
* const 关键字将 aSRC_Const_Buffer 数组变量定义为常量类型
* 表示数据存储在内部的 FLASH 中*/
extern const uint32_t aSRC_Cont_Buffer[Map_BUFFER_SIZE] ;
/* 定义 DMA 传输目标存储器存储在内部的 SRAM 中*/
extern uint32_t aDST_Buffer[Map_BUFFER_SIZE];
/*************************************************************************************/
/******** B **************** USART 到 RAM 的DMA输出 *******************************/
#define USART_DMA_CHANNEL DMA1_Channel4 //串口对应的 DMA 请求通道
#define USART_Source_ADDR (USART1_BASE+0x04) //串口数据的地址
#define USART_BUFFER_SIZE 9000 // 要发送的数据大小
extern uint32_t USART_DMA_Buffer[USART_BUFFER_SIZE];
/************************************************************************************/
void _DMA_Config(DMA_Channel_TypeDef* _DMAy_Channelx , uint32_t _BUFFER_SIZE , uint32_t _DMA_OutSource_ADDR, uint32_t _DMA_InSource_ADDR , uint32_t _DMA_DIR);
uint8_t Buffercmp(const uint32_t *pBuffer, uint32_t * pBuffer1 , uint16_t BufferLength);
void _USART_DMA_Config(DMA_Channel_TypeDef* _DMAy_Channelx , uint32_t _BUFFER_SIZE , uint32_t _DMA_OutSource_ADDR, uint32_t _DMA_InSource_ADDR , uint32_t _DMA_DIR);
#define _Map_DMA_Config_ _DMA_Config(Map_DMA_CHANNEL ,Map_BUFFER_SIZE ,aSRC_Cont_Buffer , aDST_Buffer , DMA_DIR_PeripheralSRC)
// ROM 到 RAM 的DMA输出 的程序初始化 DMA_DIR_PeripheralSRC:为方向外设到内存
#define _DMA_InnerChange_ Buffercmp(aSRC_Cont_Buffer , aDST_Buffer, Map_BUFFER_SIZE)
// ROM 到 RAM 的DMA输出 的数据验证
#define _USART_DMA_Config_ _USART_DMA_Config(USART_DMA_CHANNEL ,USART_BUFFER_SIZE ,USART_Source_ADDR , USART_DMA_Buffer , DMA_DIR_PeripheralDST)
// ROM 到 RAM 的DMA输出 的程序初始化 DMA_DIR_PeripheralDST:为方向外设到内存
#endif
3.建立DMA传输的 头文件 DMA_book.c
代码如下(示例):
#include "DMA_book.h"
#include "USART_book.h"
const uint32_t aSRC_Cont_Buffer [Map_BUFFER_SIZE]={
'A','B','C','D',
'E','F','B','C',
'A','X','B','C',
'A','D','B','C',
'A','C','B','C',
'A','V','B','C',
'A','B','W','C',
' A','R','B','C'
};
uint32_t aDST_Buffer[Map_BUFFER_SIZE] ;
uint32_t USART_DMA_Buffer[USART_BUFFER_SIZE];
void _DMA_Config(DMA_Channel_TypeDef* _DMAy_Channelx , uint32_t _BUFFER_SIZE , uint32_t _DMA_Source_ADDR, uint32_t _DMA_AIM_ADDR , uint32_t _DMA_DIR){
DMA_InitTypeDef DMA_InitStructure ;
//开启DMA时钟
RCC_AHBPeriphClockCmd(DMA_CLOCK,ENABLE);
//源数据缓存地址(外设地址)
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)_DMA_Source_ADDR ;
//转换缓存地址地址(内存地址)
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)_DMA_AIM_ADDR;
//方向:外设到存储器(这里的外设是内部的FLASH)DMA_DIR_PeripheralSRC:为方向外设到内存 DMA_DIR_PeripheralDST:为方向外设到内存
DMA_InitStructure.DMA_DIR = _DMA_DIR ;
//传输大小
DMA_InitStructure.DMA_BufferSize = _BUFFER_SIZE;
//外设(内部的FLASH)地址递增
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
//内存地址递增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
//外设数据单位
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
//内存数据单位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
//DMA模式,一次或者循环模式
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
//DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
//优先级:高
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
//使能内存到内存的传输
DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;
//配置DMA通道
DMA_Init(_DMAy_Channelx , &DMA_InitStructure);
//使能DMA
DMA_Cmd(_DMAy_Channelx , ENABLE);
}
uint8_t Buffercmp(const uint32_t *pBuffer, uint32_t * pBuffer1 , uint16_t BufferLength){
/*数据长度递减*/
while(BufferLength--){
Usart_SendHalf_32_Word(_DEBUG_USARTx,*pBuffer);
Usart_SendHalf_32_Word(_DEBUG_USARTx,*pBuffer1);
/*判断两个数据源是否相等*/
if(*pBuffer != *pBuffer1){
/* 对应数据源不相等马上退出函数,并返回 0 */
return 0;
}
/* 递增两个数据源的地址指针 */
pBuffer++;
pBuffer1++;
}
/* 完成判断并且对应数据相对 */
return 1;
}
void _USART_DMA_Config(DMA_Channel_TypeDef* _DMAy_Channelx , uint32_t _BUFFER_SIZE , uint32_t _DMA_Source_ADDR, uint32_t _DMA_AIM_ADDR , uint32_t _DMA_DIR){
DMA_InitTypeDef DMA_InitStructure ;
//开启DMA时钟
RCC_AHBPeriphClockCmd(DMA_CLOCK,ENABLE);
//源数据缓存地址(外设地址)
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)_DMA_Source_ADDR ;
//转换缓存地址地址(内存地址)
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)_DMA_AIM_ADDR;
//方向:外设到存储器(这里的外设是内部的FLASH)DMA_DIR_PeripheralSRC:为方向外设到内存 DMA_DIR_PeripheralDST:为方向外设到内存
DMA_InitStructure.DMA_DIR = _DMA_DIR ;
//传输大小
DMA_InitStructure.DMA_BufferSize = _BUFFER_SIZE;
//外设(内部的FLASH)地址递增
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
//内存地址递增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
//外设数据单位
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
//内存数据单位
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;
//配置DMA通道
DMA_Init(_DMAy_Channelx , &DMA_InitStructure);
//使能DMA
DMA_Cmd(_DMAy_Channelx , ENABLE);
}
4.建立USART串口的 头文件 USART_book.h
代码如下(示例):
#ifndef __USART_BOOK_H_
#define __USART_BOOK_H_
#include "stm32f10x.h"
#include "stm32f10x_usart.h"
#include "stm32f10x_rcc.h"
//串口的宏定义 不同的串口挂在的总线和IO不一样
//串口1
#define _DEBUG_USARTx USART1
#define _DEBUG_USART_CLK RCC_APB2Periph_USART1
#define _DEBUG_USART_APBxClkCmd RCC_APB2PeriphClockCmd
#define _DEBUG_USART_BAUDRATE 115200
// USART GPIO 引脚定义
#define _DEBUG_USART_GPIO_CLK RCC_APB2Periph_GPIOA
#define _DEBUG_USART_GPIO_APBxCLKCmd RCC_APB2PeriphClockCmd
#define _DEBUG_USART_TX_GPIO_PORT GPIOA
#define _DEBUG_USART_TX_GPIO_PIN GPIO_Pin_9
#define _DEBUG_USART_TX_GPIO_MODE GPIO_Mode_AF_PP
#define _DEBUG_USART_RX_GPIO_PORT GPIOA
#define _DEBUG_USART_RX_GPIO_PIN GPIO_Pin_10
#define _DEBUG_USART_RX_GPIO_MODE GPIO_Mode_IN_FLOATING
#define _DEBUG_NVIC_USART_IRQ USART1_IRQn
#define _DRBUG_USART_IRQHandler USART1_IRQHandler
void fn_USART_IO_Config(void);
void fn_USART_Config(void);
void fn_USART_Init(void);
void fn_Usart_Send_Byte(USART_TypeDef * pUSARTx , uint8_t ch );
void fn_Usart_SendString(USART_TypeDef *pUSARTx , char * str);
void Usart_SendHalf_32_Word( USART_TypeDef * pUSARTx, uint32_t ch);
void _DRBUG_USART_IRQHandler(void);
#endif
5.建立USART串口的 头文件 USART_book.c
代码如下(示例):
#include "USART_book.h"
/**************************************************************
* @brief
* void fn_LED_Corporate(GPIO_TypeDef* _GPIO_x , uint16_t _GPIO_Pin_x ,
* LED_Corporate_state_t _LED_Corporate_state_t );
* &