STM32 DMA+AD多通道

接线图

代码配置

ADC单次扫描+DMA单次转运模式

cs 复制代码
uint16_t AD_Value[4];
//DMA+AD多通道
void DMA_Config(void)
{
		
//定义结构体变量
GPIO_InitTypeDef GPIO_InitStructure;//定义GPIO结构体变量
ADC_InitTypeDef ADC_InitStructure;  //定义ADC结构体变量
DMA_InitTypeDef DMA_InitStructure;//定义DMA结构体变量
	
//开启RCC时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);//开启ADC1的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启GPIO A族时钟
RCC_ADCCLKConfig(RCC_PCLK2_Div6);                   //配置分频器 选择6分频 分频之后ADCCLK = 72MHz/6 = 12MHz
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);//开启DMA1的时钟
//配置GPIO
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//选择模拟输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;    //配置引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速率
	
GPIO_Init(GPIOA, &GPIO_InitStructure);   //GPIO初始化
	
//配置多路开关
	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转换器
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//选择连续转换模式还是单次转换 本次单次转换
ADC_InitStructure.ADC_DataAlign =ADC_DataAlign_Right; //指定ADC数据是左对齐还是右对齐 这次选择右对齐
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//触发控制的触发源 本次使用软件触发
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//配置独立模式还是双ADC模式 这里选独立模式
ADC_InitStructure.ADC_NbrOfChannel = 4;//在扫描模式下,总共会用到几个通道 
ADC_InitStructure.ADC_ScanConvMode = ENABLE;//选择扫描模式还是非扫描模式 本次扫描模式
ADC_Init(ADC1, &ADC_InitStructure);
	

	
//配置DMA
//外设站点
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;//外设站点的基地址,这里要写一个32位的地址
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//数据宽度 半字16位来转运
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//地址是否自增
//存储器站点
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AD_Value;//存储器站点的及地址
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//数据宽度
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器站点地址自增
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//传输方向 选择外设站点到存储器站点
DMA_InitStructure.DMA_BufferSize = 4;//传输次数
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//传输计数器是否自动重装 这里选择正常模式不自动重装
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//选择触发源,这里选择软件触发
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//通道优先级
	
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
	
	
//使能
DMA_Cmd(DMA1_Channel1,ENABLE);//使能DMA
	
//开启ADC到DMA的输出
ADC_DMACmd(ADC1, ENABLE);
	
//开关控制 开启ADC
ADC_Cmd(ADC1,ENABLE);//开启ADC电源
	
//校准
ADC_ResetCalibration(ADC1);//复位校准
while(ADC_GetResetCalibrationStatus(ADC1) == SET);//返回复位校准状态
ADC_StartCalibration(ADC1);//开始校准
while(ADC_GetCalibrationStatus(ADC1) == SET);//获取校准状态
	
	
	
}

功能函数

cs 复制代码
void DMA_GetValue(void)
{
	DMA_Cmd(DMA1_Channel1,DISABLE);//失能DMA
	DMA_SetCurrDataCounter(DMA1_Channel1, 4);//转运数据
	DMA_Cmd(DMA1_Channel1,ENABLE);//使能DMA
	
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);//软件触发
	//等待转运完成
	while(DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);
	DMA_ClearFlag(DMA1_FLAG_TC1);//清除标志位
	
}

主函数

需要在头函数将AD_Value extern引用一下才能在主函数里使用

cs 复制代码
#include "MyDMA.h"
int main(void)
{
   OLED_Init();
	 DMA_Config();
	OLED_ShowString(1, 1, "AD0:");
	OLED_ShowString(2, 1, "AD1:");
	OLED_ShowString(3, 1, "AD2:");
	OLED_ShowString(4, 1, "AD3:");
	while(1)
	{
		
		DMA_GetValue();
		OLED_ShowNum(1, 6, AD_Value[0], 4);
		OLED_ShowNum(2, 6, AD_Value[1], 4);
		OLED_ShowNum(3, 6, AD_Value[2], 4);
		OLED_ShowNum(4, 6, AD_Value[3], 4);
		
	}
	
	
}

ADC连续扫描+DMA循环模式

在上一个函数的基础上修改几个参数,将ADC单次扫描改为连续扫描,DMA模式选择位循环模式,这种模式就不需要写功能函数了,主函数里直接可以用

将ADC触发放到最后

cs 复制代码
//DMA+AD多通道
void DMA_Config(void)
{
		
	//定义结构体变量
	GPIO_InitTypeDef GPIO_InitStructure;//定义GPIO结构体变量
	ADC_InitTypeDef ADC_InitStructure;  //定义ADC结构体变量
	DMA_InitTypeDef DMA_InitStructure;//定义DMA结构体变量
	
	//开启RCC时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);//开启ADC1的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启GPIO A族时钟
  RCC_ADCCLKConfig(RCC_PCLK2_Div6);                   //配置分频器 选择6分频 分频之后ADCCLK = 72MHz/6 = 12MHz
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);//开启DMA1的时钟
	//配置GPIO
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//选择模拟输入
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;    //配置引脚
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速率
	
	GPIO_Init(GPIOA, &GPIO_InitStructure);   //GPIO初始化
	
	//配置多路开关
		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转换器
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//选择连续转换模式还是单次转换 本次连续转换
	ADC_InitStructure.ADC_DataAlign =ADC_DataAlign_Right; //指定ADC数据是左对齐还是右对齐 这次选择右对齐
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//触发控制的触发源 本次使用软件触发
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//配置独立模式还是双ADC模式 这里选独立模式
	ADC_InitStructure.ADC_NbrOfChannel = 4;//在扫描模式下,总共会用到几个通道 
	ADC_InitStructure.ADC_ScanConvMode = ENABLE;//选择扫描模式还是非扫描模式 本次扫描模式
	ADC_Init(ADC1, &ADC_InitStructure);
	

	
	//配置DMA
	//外设站点
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;//外设站点的基地址,这里要写一个32位的地址
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//数据宽度 半字16位来转运
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//地址是否自增
	//存储器站点
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AD_Value;//存储器站点的及地址
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//数据宽度
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器站点地址自增
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//传输方向 选择外设站点到存储器站点
	DMA_InitStructure.DMA_BufferSize = 4;//传输次数
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//传输计数器是否自动重装 这里选择循环模式
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//选择触发源,这里选择软件触发
	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//通道优先级
	
	DMA_Init(DMA1_Channel1, &DMA_InitStructure);
	
	
	//使能
	DMA_Cmd(DMA1_Channel1,ENABLE);//使能DMA
	
	//开启ADC到DMA的输出
	ADC_DMACmd(ADC1, ENABLE);
	
	//开关控制 开启ADC
	ADC_Cmd(ADC1,ENABLE);//开启ADC电源
	
	//校准
	ADC_ResetCalibration(ADC1);//复位校准
	while(ADC_GetResetCalibrationStatus(ADC1) == SET);//返回复位校准状态
	ADC_StartCalibration(ADC1);//开始校准
	while(ADC_GetCalibrationStatus(ADC1) == SET);//获取校准状态
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);//软件触发
	
	
}

主函数

cs 复制代码
#include "MyDMA.h"
int main(void)
{
   OLED_Init();
	 DMA_Config();
	OLED_ShowString(1, 1, "AD0:");
	OLED_ShowString(2, 1, "AD1:");
	OLED_ShowString(3, 1, "AD2:");
	OLED_ShowString(4, 1, "AD3:");
	while(1)
	{
		OLED_ShowNum(1, 6, AD_Value[0], 4);
		OLED_ShowNum(2, 6, AD_Value[1], 4);
		OLED_ShowNum(3, 6, AD_Value[2], 4);
		OLED_ShowNum(4, 6, AD_Value[3], 4);
		
	}
	
	
}
相关推荐
小亮亮虫4 小时前
16.3.STM32F407ZGT6-CAN波特率配置
stm32
cherry_rainyyy6 小时前
51单片机 01 LED
stm32·单片机·嵌入式硬件
嘿嘿嘿x37 小时前
联合体(union)
网络·单片机·嵌入式软件
color_leo8 小时前
zephyr devicetree
单片机·嵌入式硬件·mcu
宣宣猪的小花园.8 小时前
STM32单片机学习记录(2.2)
stm32·单片机·嵌入式硬件·无人机·空气动力学
exp_add310 小时前
四、GPIO中断实现按键功能
单片机·嵌入式硬件
exp_add311 小时前
五、定时器实现呼吸灯
单片机·嵌入式硬件
文科比理科更擅长的工科男15 小时前
013-51单片机红外遥控器模拟控制空调,自动制冷制热定时开关
单片机·嵌入式硬件·51单片机
Ching·1 天前
物联网 STM32【源代码形式-ESP8266透传】连接OneNet IOT从云产品开发到底层MQTT实现,APP控制 【保姆级零基础搭建】
stm32·嵌入式硬件·物联网