STM32CubeMX第八篇之DMA

Posted 海洋想想

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STM32CubeMX第八篇之DMA相关的知识,希望对你有一定的参考价值。

前言

本文主要讲解自己实现DMA串口实验。

本实验主要实现以下功能:

  1. 按键0按下,则8000Byte数据通过由DMA控制的串口发出去
  2. 在LCD屏幕上显示数据发送的进度。
  3. 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循环部分,采用分块处理的方法:

  1. 尽量减少延时函数的使用
  2. 将每个模块集中处理,中间通信通过标志位实现。

此处唯一需要注意的是, DMA在每次传输完成,会自动关闭使能标志。所以每次重新启动DMA,都需要做以下几个工作:

  1. 重新指定内存发送的起始地址和发送数据的大小。
  2. 使能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的主要内容,如果未能解决你的问题,请参考以下文章

STM32F429第二十八篇之ADC

STM32F429第二十八篇之ADC

STM32F429第二十八篇之ADC

STM32F429第二十八篇之ADC

STM32CubeMX第七篇之MCU屏

STM32CubeMX第七篇之MCU屏