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功能和上文讲解基本一致,不再详细讲解。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值