STM32CubeMX第八篇之DMA
Posted 海洋想想
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STM32CubeMX第八篇之DMA相关的知识,希望对你有一定的参考价值。
前言
本文主要讲解自己实现DMA串口实验。
本实验主要实现以下功能:
- 按键0按下,则8000Byte数据通过由DMA控制的串口发出去
- 在LCD屏幕上显示数据发送的进度。
- LED0每1s闪烁一次,证明程序正确运行
本实验使用的HAL库的版本为:STM32Cube_FW_F4_V1.25.0
本实验使用的STM32CubeMX版本为:6.1.1
该工程的下载地址为:
本实验主要参考了正点原子的实验例程,关于正点原子程序的讲解,参考博客<STM32F429第二十七篇之DMA实验详解>。
关于 按键处理,LED灯,还有LCD屏相关知识,请参考之前的博客。
程序讲解
/**
******************************************************************************
* @file main.c
* @author zhy
* @version 1.0
* @date 2021-05-26
* @brief DMA实验
******************************************************************************
*/
#include "stm32f4xx_hal.h"
#include "sys.h"
#include "fmc.h"
#include "gpio.h"
#include "dma.h"
#include "lcd.h"
#include "key.h"
#include "led.h"
#include "usart.h"
#include "stdio.h"
#define LENGTH 8000
static uint8_t testTxDma[LENGTH] = 0; //因为数组过长,所以放置在此处
int main()
/* 1.变量初始化 */
unsigned int i = 0;
unsigned int j = 0;
uint32_t timer = 0;
uint32_t timerLed = 0;
uint32_t timerKey = 0;
uint8_t keyEdge = 0;
const LcdCoordinate focusTips = 64, 0;
const LcdCoordinate focusPercent = 80, 0;
const uint8_t *temp = "hello, word!\\n";
DmaType flagDma = DMA_NONE;
/* 2.硬件初始化 */
HAL_Init();
SystemClock_Config();
SramInit();
GpioInit();
LcdInit();
Uart1Init();
KeyInit();
LedInit();
DmaInit();
/* 3.发送内容初始化 */
for (i = 0; i < LENGTH; i++)
if (temp[j] == 0)
j = 0;
testTxDma[i] = temp[j];
j++;
/* 4.lcd显示初始化 */
LcdSetColor(LCD_RED, LCD_WHITE);
LcdShowString("Demo9 DMA\\n");
LcdShowString("Zhen Haiyang\\n");
LcdShowString("2021/05/27\\n");
LcdShowString("--KEY0:Start--\\n");
LcdSetColor(LCD_BLUE, LCD_WHITE);
/* 5.while循环 */
while (1)
timer = HAL_GetTick();
/* key */
keyEdge = 0; //将有效边沿清0
if (timer - timerKey >= 10)
timerKey = timer; //时间复位
KeyScan(); //按键扫描
keyEdge = KeyGetEdgeActive(); //获得有效按键边沿
/* usart */
if (keyEdge & KEY_0) //key0按下
DmaStart((uint32_t)&testTxDma, LENGTH);
flagDma = DMA_ONGOING;
if (DMA2->HISR & DMA_HISR_TCIF7) //传输完成
flagDma = DMA_FINISH;
DMA2->HIFCR |= DMA_HIFCR_CTCIF7;
/* lcd */
if (flagDma == DMA_FINISH)
flagDma = DMA_NONE;
LcdSetFocus(focusTips);
LcdShowString("Trassmit Finish!");
LcdSetFocus(focusPercent);
LcdShowNumber(100, 3);
LcdShowString("%");
else if (flagDma == DMA_ONGOING)
uint16_t temp = LENGTH - DMA2_Stream7->NDTR;
temp = temp * 100 / LENGTH;
LcdSetFocus(focusTips);
LcdShowString("Trassmiting... ");
LcdSetFocus(focusPercent);
LcdShowNumber(temp, 3);
LcdShowString("%");
/* led */
if (timer - timerLed >= 500) //500ms
timerLed = timer;
set_led_0 = !set_led_0;
if (keyEdge & KEY_1)
set_led_1 = !set_led_1;
该程序初始化部分和之前讲解的基本一致。不再详述。
while循环部分,采用分块处理的方法:
- 尽量减少延时函数的使用
- 将每个模块集中处理,中间通信通过标志位实现。
此处唯一需要注意的是, DMA在每次传输完成,会自动关闭使能标志。所以每次重新启动DMA,都需要做以下几个工作:
- 重新指定内存发送的起始地址和发送数据的大小。
- 使能DMA。
具体通过以下函数实验:
/**
* @brief DMA
* @note 无
* @param uint32_t memory 内存的地址
* @param uint32_t length 发送数据的长度
* @retval 无
*/
void DmaStart(uint32_t memory, uint32_t length)
DMA2_Stream7->M0AR = memory;
DMA2_Stream7->NDTR = length;
DMA2_Stream7->CR |= DMA_SxCR_EN;
Cube功能和上文讲解基本一致,不再详细讲解。
以上是关于STM32CubeMX第八篇之DMA的主要内容,如果未能解决你的问题,请参考以下文章