#第八章 DMA数据转存器#基于江科大的stm32单片机学习笔记

本文详细介绍了STM32F103c8t6单片机中DMA(DirectMemoryAccess)的使用,包括引脚定义、DMA库函数如初始化、命令控制、中断配置等,并展示了如何在任务中利用DMA进行数据搬运和ADC多通道采集的应用示例。
摘要由CSDN通过智能技术生成

视频链接:[1-1] 课程简介_哔哩哔哩_bilibili

STM32F103c8t6引脚定义表:(橙色是电源相关的引脚,蓝色是最小系统相关的引脚。绿色的是IO口和功能引脚,FT意为能容忍5V电压,主功能是上电默认的功能,默认复用功能是IO口上连接的外设功能引脚,加粗的引脚是能直接用的,没加粗的引脚可能要进行其他配置才能使用)

8-1 DMA直接存储器取存

DMA库函数:


//恢复初始化DMA
void DMA_DeInit(DMA_Channel_TypeDef* DMAy_Channelx);

//初始化DMA
void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct);

//DMA结构体赋默认值
void DMA_StructInit(DMA_InitTypeDef* DMA_InitStruct);

//DMA是否启动
void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalState NewState);

//DMA中断配置
void DMA_ITConfig(DMA_Channel_TypeDef* DMAy_Channelx, uint32_t DMA_IT, FunctionalState NewState);

//DMA设置当前数据寄存器,即设置传输计数器
void DMA_SetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx, uint16_t DataNumber); 

//DMA获取当前数据寄存器
uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx);

//获取标志位
FlagStatus DMA_GetFlagStatus(uint32_t DMAy_FLAG);

//清除标志位
void DMA_ClearFlag(uint32_t DMAy_FLAG);

//获取中断标志位
ITStatus DMA_GetITStatus(uint32_t DMAy_IT);

//清除中断标志位
void DMA_ClearITPendingBit(uint32_t DMAy_IT);

8-2 DMA数据转运&DMA+AD多通道

配置DMA的步骤:

1.启动RCC时钟

2.调用DMA初始化函数DMA_Init,配置参数

3.开启DMA,调用DMA_Cmd

4.(如果要硬件触发,要调用XXX_MDACmd,开启触发信号的输出)

5.(如果要DMA中断,调用DMA_ITConfig,开启中断输出)

 main.c

#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "task01.h"
#include "task02.h"
#include "delay.h"


//任务1 软件触发DMA转运数据
uint8_t DataA[] = {0x01,0x02,0x03,0x04};
uint8_t DataB[] = {00,00,00,00};

void Task01()
{
    OLED_Init();
    Task01_Init((uint32_t)DataA,(uint32_t)DataB,4);
    OLED_ShowHexNum(1,1,DataA[0],2);
    OLED_ShowHexNum(1,5,DataA[1],2);
    OLED_ShowHexNum(1,9,DataA[2],2);
    OLED_ShowHexNum(1,14,DataA[3],2);
    while(1)
    {
    OLED_ShowHexNum(4,1,DataB[0],2);
    OLED_ShowHexNum(4,5,DataB[1],2);
    OLED_ShowHexNum(4,9,DataB[2],2);
    OLED_ShowHexNum(4,14,DataB[3],2);
    
    for(uint16_t i = 0;i < 4;i++)
        {
            DataA[i] += 0x02;
        }
        
    Task01_DMA_Transfer();
    Delay_ms(100);
    
    }
}


//ADC作为外设多通道DMA运输
//PA0接电位器  PA1接光温传感器  PA2接温度传感器  PA3接红外传感器

void Task02()
{
    OLED_Init();
    Task02_Init();
    while(1)
    {
        Task02_AD_GetValue();
//        AD_Value[0] = Task02_AD_GetValue(ADC_Channel_0);
//        AD_Value[1] = Task02_AD_GetValue(ADC_Channel_1);
//        AD_Value[2] = Task02_AD_GetValue(ADC_Channel_2);
//        AD_Value[3] = Task02_AD_GetValue(ADC_Channel_3);
        
//        Task02_DMA_Transfer();
        
        OLED_ShowNum(1,1,AD_Value[0],4);
        OLED_ShowNum(1,6,AD_Value[1],4);
        OLED_ShowNum(2,1,AD_Value[2],4);
        OLED_ShowNum(2,6,AD_Value[3],4);
                     
//        OLED_ShowNum(3,1,Value[0],4);
//        OLED_ShowNum(3,6,Value[1],4);
//        OLED_ShowNum(4,1,Value[2],4);
//        OLED_ShowNum(4,6,Value[3],4);
        Delay_ms(300);
    }
}

int main(void)
{
//    Task02();
	while (1)
	{
		
	}
}

 task01.c

#include "task01.h"

uint16_t My_Size;

void Task01_Init(uint32_t ADDrA,uint32_t ADDrB,uint16_t Size)//数据从ADDrA->ADDrB,A是外设,B是存储器
{
    My_Size = Size;
    //初始化DMA
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);//开启RCC时钟
    
    DMA_Cmd(DMA1_Channel1,DISABLE);//先失能DMA
    
    DMA_InitTypeDef My_DMA_InitStructure;
    My_DMA_InitStructure.DMA_BufferSize = Size;//缓存区大小,即传输计数器 0~65535
    My_DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//传输方向
    //DST是指外设站点作为目的地,SRC是指外设站点作为源头
    My_DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;//是否使用存储器到存储器,即选择软件触发还是硬件触发
    My_DMA_InitStructure.DMA_MemoryBaseAddr = ADDrB;//存储器站点的起始地址
    My_DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//存储器站点的数据宽度
    My_DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器站点地址是否递增
    My_DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//传输模式,选择是否使用自动重装
    //DMA的软件触发和自动重装不能同时启用,否则无法停下
    My_DMA_InitStructure.DMA_PeripheralBaseAddr = ADDrA;//外设站点的起始地址
    My_DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设站点的数据宽度
    My_DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;//外设外设站点地址是否递增。
    My_DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//优先级配置。
    DMA_Init(DMA1_Channel1,&My_DMA_InitStructure);
    
    DMA_Cmd(DMA1_Channel1,ENABLE);
}

void Task01_DMA_Transfer(void)
{
    
    DMA_Cmd(DMA1_Channel1,DISABLE);
    DMA_SetCurrDataCounter(DMA1_Channel1,My_Size);
    DMA_Cmd(DMA1_Channel1,ENABLE);
    
    //等待转运完成
    while(DMA_GetFlagStatus(DMA1_FLAG_GL1) == RESET);
    DMA_ClearFlag(DMA1_FLAG_GL1);
}

task02.c 

#include "task02.h"

uint16_t AD_Value[4];

void Task02_Init()
{
    
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);//开启DMA时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);//开启ADC1时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启GPIOA时钟
    
    //配置ADC
    GPIO_InitTypeDef My_GPIO_InitStructure;
    My_GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 ;
    My_GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    My_GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&My_GPIO_InitStructure);    //配置GPIO
    
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);    //ADC预分频
    
    ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);
    ADC_RegularChannelConfig(ADC1,ADC_Channel_1,2,ADC_SampleTime_55Cycles5);
    ADC_RegularChannelConfig(ADC1,ADC_Channel_2,3,ADC_SampleTime_55Cycles5);
    ADC_RegularChannelConfig(ADC1,ADC_Channel_3,4,ADC_SampleTime_55Cycles5);
    
    ADC_InitTypeDef My_ADC_InitStructure;
    My_ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//是否连续转换模式
    My_ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//数据右对齐
    My_ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//不接触发源
    My_ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//ADC为独立模式
    My_ADC_InitStructure.ADC_NbrOfChannel = 4;
    My_ADC_InitStructure.ADC_ScanConvMode = ENABLE;//配置多通道模式
    ADC_Init(ADC1,&My_ADC_InitStructure);//初始化ADC
     
    
    DMA_Cmd(DMA1_Channel1,DISABLE);//先失能DMA
    
    DMA_InitTypeDef My_DMA_InitStructure;
    My_DMA_InitStructure.DMA_BufferSize = 4;//缓存区大小,即传输计数器 0~65535
    My_DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//传输方向
    //DST是指外设站点作为目的地,SRC是指外设站点作为源头
    My_DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//是否使用存储器到存储器,即选择软件触发还是硬件触发
    My_DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AD_Value;//存储器站点的起始地址
    My_DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_HalfWord;//存储器站点的数据宽度
    My_DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器站点地址是否递增
    My_DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//传输模式,选择是否使用自动重装
    //DMA的软件触发和自动重装不能同时启用,否则无法停下
    My_DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;//外设站点的起始地址
    My_DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//外设站点的数据宽度
    My_DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设外设站点地址是否递增。
    My_DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//优先级配置。
    DMA_Init(DMA1_Channel1,&My_DMA_InitStructure);
    
    DMA_Cmd(DMA1_Channel1,ENABLE);//使能DMA    
    ADC_DMACmd(ADC1,ENABLE);//将ADC触发DMA开启
    ADC_Cmd(ADC1,ENABLE);//开启ADC
    
    //因使用多通道的ADC,要检验数据
    //复位校准
    ADC_ResetCalibration(ADC1);
    //等待校准复位完毕
    while(ADC_GetResetCalibrationStatus(ADC1) == SET);
    //开启校准
    ADC_StartCalibration(ADC1);
    //等待校准完毕
    while(ADC_GetCalibrationStatus(ADC1) == SET);
}


void Task02_AD_GetValue(void)
{ 
    DMA_Cmd(DMA1_Channel1,DISABLE);
    DMA_SetCurrDataCounter(DMA1_Channel1,4);
    DMA_Cmd(DMA1_Channel1,ENABLE);
    
    ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件触发转换
    
    //等待转运完成
    while(DMA_GetFlagStatus(DMA1_FLAG_GL1) == RESET);
    DMA_ClearFlag(DMA1_FLAG_GL1);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值