STM32F405--ADC多通道(单次转换、扫描模式、软件触发)

文章介绍了如何使用STM32F405RGT6的ADC1的通道4和5采集模拟电压,通过DMA传输至内存,并在OLED上实时显示采样值和电压值。详细描述了ADC的配置和初始化过程以及主函数中的数据处理和OLED显示部分。
摘要由CSDN通过智能技术生成

功能描述:使用STM32F405RGT6的ADC1的通道4和通道5分别对输入到PA4和PA5上的模拟电压进行模数转换,同时通过DMA将转换的值搬运到内存中,最后在OLED上显示ADC的原始采样值和实际电压值。ADC配置为独立模式、多通道、单次转换、扫描模式、软件触发。

  • main.c文件内容如下
#include "stm32f4xx.h"                  // Device header
#include "OLED.h"
#include "MyADC.h"

uint16_t* ADC_Value;
double Voltage[2];

int main(void)
{
	MyADC_Init();
	OLED_Init();
	
	OLED_Clear();	//清屏OLED
	OLED_Refresh();	//刷新OLED
	
	while(1)
	{
		ADC_Value = MyADC_GetValue();						//获取ADC1的采样值
		Voltage[0] = ((double)ADC_Value[0]/4096)*3.3;		//计算对应的电压
		OLED_Printf(0,0,8,"ADC_Value = %d",ADC_Value[0]);	//显示ADC1通道4采样值
		OLED_Printf(0,16,8,"Voltage = %.2lfV",Voltage[0]);	//显示对应的电压值
		Voltage[1] = ((double)ADC_Value[1]/4096)*3.3;		//计算对应的电压
		OLED_Printf(0,32,8,"ADC_Value = %d",ADC_Value[1]);	//显示ADC1通道5采样值
		OLED_Printf(0,48,8,"Voltage = %.2lfV",Voltage[1]);	//显示对应的电压值
		
		OLED_Refresh();										//刷新OLED
	}
}

  • MyADC.c文件内容如下
#include "MyADC.h"           

uint16_t MyADC_Buff[2];

/**
  * @摘要  		初始化ADC和相应的GPIO
  * @参数  		无
  * @返回值  	无
  * @说明  		无
  */
void MyADC_Init(void)
{
	//开启GPIOA的时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
	
	//定义GPIO初始化结构体
	GPIO_InitTypeDef GPIO_InitStructure;
	//初始化上述结构体
	GPIO_StructInit(&GPIO_InitStructure);
	//配置GPIO模式为模拟输入模式
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	//配置GPIO输出类型为推挽输出(此处无用)
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	//指定GPIO引脚为Pin4hePin5
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
	//配置GPIO输入类型为浮空输入(此处无用)
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
	//配置GPIO的速度为快速50MHZ
	GPIO_InitStructure.GPIO_Speed = GPIO_Fast_Speed;
	//初始化对应的GPIO
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	//开启ADC1的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	
	//定义所有ADC共用配置的初始化结构体
	ADC_CommonInitTypeDef ADC_CommonInitStructure;
	//初始化上述结构体
	ADC_CommonStructInit(&ADC_CommonInitStructure);
	//配置为独立模式
	ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
	//配置ADC时钟的预分频器的值为4,即21MHZ(<30MHZ)
	ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;
	//失能DMA(这是多ADC模式下的DMA,不是这里要用的DMA)
	ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
	//配置多ADC模式下的两个ADC采样间隔(此处无用)
	ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_8Cycles;
	//初始化所有ADC共用配置
	ADC_CommonInit(&ADC_CommonInitStructure);
	
	//定义ADC初始化结构体
	ADC_InitTypeDef ADC_InitStructure;
	//初始化上述结构体
	ADC_StructInit(&ADC_InitStructure);
	//配置ADC分辨率为12位
	ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
	//配置ADC为单次转换模式
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
	//配置ADC为扫描模式
	ADC_InitStructure.ADC_ScanConvMode = ENABLE;
	//配置ADC数据对齐方式为右对齐
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
	//配置ADC外部触发为无,即关闭外部触发
	ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
	//配置ADC外部触发源为TIM2的TRGO输出(此处无用)
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO;
	//配置ADC转换通道数为2
	ADC_InitStructure.ADC_NbrOfConversion = 2;
	//初始化对应的ADC
	ADC_Init(ADC1, &ADC_InitStructure);
	
	//配置每一个规则通道的排序和采样周期
	ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 1, ADC_SampleTime_56Cycles);
	ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 2, ADC_SampleTime_56Cycles);
	
	//开启ADC1的DMA通道
	ADC_DMACmd(ADC1, ENABLE);
	//允许ADC一次传输后发出新的DMA请求
	ADC_DMARequestAfterLastTransferCmd(ADC1,ENABLE);
	
	//初始化DMA
	MyDMA_Init((uint32_t)&(ADC1->DR), (uint32_t)MyADC_Buff, 2);
	
	
	//开启ADC1,此时ADC1进入等待触发的状态
	ADC_Cmd(ADC1, ENABLE);
}

/**
  * @摘要  		软件触发ADC并读取采样值
  * @参数  		无
  * @返回值  	指向ADC采样值的指针
  * @说明  		无
  */
uint16_t* MyADC_GetValue(void)
{
	//软件触发ADC1,此时ADC1进入采样转换状态
	ADC_SoftwareStartConv(ADC1);
	
	//ADC采样完成后会硬件自动触发DMA进行数据转运
	
	//等待DMA转运完成,DMA转运完成则ADC转换一定完成了
	while(DMA_GetFlagStatus(DMA2_Stream0, DMA_FLAG_TCIF0) == RESET);
	//清除DMA转运完成标志
	DMA_ClearFlag(DMA2_Stream0, DMA_FLAG_TCIF0);
	//重新开启DMA,此时DMA等待硬件触发
	DMA_Cmd(DMA2_Stream0, ENABLE);
	
	//返回ADC1的采样值
	return MyADC_Buff;
}

  • MyADC.h文件内容如下
#ifndef __MYADC_H
#define __MYADC_H

#include "stm32f4xx.h"                  // Device header
#include "MyDMA.h"

void MyADC_Init(void);
uint16_t* MyADC_GetValue(void);

#endif

  • MyDMA.c文件内容如下
#include "MyDMA.h"

/**
  * @摘要  		初始化DMA
  * @参数  		SAddress: 源地址
  * @参数  		DAddress: 目的地址
  * @参数  		Size: 要传输的数据个数
  * @返回值  	无
  * @说明  		无
  */
void MyDMA_Init(uint32_t SAddress, uint32_t DAddress,uint16_t Size)
{
	//开启DMA2的时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
	
	//定义DMA初始化结构体
	DMA_InitTypeDef DMA_InitStructure;
	//初始化上述结构体
	DMA_StructInit(&DMA_InitStructure);
	//配置DMA通道为通道0
	DMA_InitStructure.DMA_Channel = DMA_Channel_0;
	//配置DMA传输的存储器地址(即目的地址)
	DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)DAddress;
	//配置存储器接收数据的单位为半字
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
	//配置存储器地址指针为自增模式
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	//配置DMA传输的外设(即源地址)
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)SAddress;
	//配置外设发送数据的单位为半字
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
	//配置外设地址指针为非自增模式
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	//配置存储器突发传输配置为单次传输
	DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
	//配置外设突发传输配置为单次传输
	DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
	//配置DMA传输方向为外设到存储器
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
	//配置DMA要传输的数据个数
	DMA_InitStructure.DMA_BufferSize = Size;
	//配置DMA为非循环模式
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
	//配置DMA为非直接模式
	DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
	//配置FIFO阈值为全满
	DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
	//配置该通道的DMA优先级为中
	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
	
	//等待DMA失能,以确保初始化可以成功
	while(DMA_GetCmdStatus(DMA2_Stream0) == ENABLE);
	//初始化DMA
	DMA_Init(DMA2_Stream0, &DMA_InitStructure);
	
	//开启DMA,此时DMA等待硬件触发
	DMA_Cmd(DMA2_Stream0, ENABLE);
}

  • MyDMA.h文件内容如下
#ifndef __MYDMA_H
#define __MYDMA_H

#include "stm32f4xx.h"                  // Device header

void MyDMA_Init(uint32_t SAddress, uint32_t DAddress, uint16_t Size);

#endif

  • 6
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是使用HAL库在STM32F405上配置ADC1多通道单次转换DMA方式的代码: 首先,需要在CubeMX中启用ADC和DMA,并将ADC配置为多通道单次转换模式。在ADC设置中,选择“多通道”并选择要转换的通道。在DMA设置中,选择“循环模式”和“内存递增模式”,并将数据大小设置为16位。 然后,在主函数中初始化ADC和DMA,并启动转换: ```c /* ADC and DMA initialization */ ADC_HandleTypeDef hadc1; DMA_HandleTypeDef hdma_adc1; void MX_ADC1_Init(void) { hadc1.Instance = ADC1; hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; hadc1.Init.Resolution = ADC_RESOLUTION_12B; hadc1.Init.ScanConvMode = ENABLE; hadc1.Init.ContinuousConvMode = DISABLE; hadc1.Init.DiscontinuousConvMode = DISABLE; hadc1.Init.NbrOfDiscConversion = 0; hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc1.Init.NbrOfConversion = 2; hadc1.Init.DMAContinuousRequests = ENABLE; hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV; if (HAL_ADC_Init(&hadc1) != HAL_OK) { Error_Handler(); } ADC_ChannelConfTypeDef sConfig = {0}; sConfig.Channel = ADC_CHANNEL_0; sConfig.Rank = 1; sConfig.SamplingTime = ADC_SAMPLETIME_84CYCLES; if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { Error_Handler(); } sConfig.Channel = ADC_CHANNEL_1; sConfig.Rank = 2; if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { Error_Handler(); } } void MX_DMA_Init(void) { /* DMA controller clock enable */ __HAL_RCC_DMA2_CLK_ENABLE(); /* DMA interrupt init */ /* DMA2_Stream0_IRQn interrupt configuration */ HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0); HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn); } int main(void) { /* Initialize peripherals */ HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_ADC1_Init(); MX_DMA_Init(); /* Start ADC conversion */ HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_values, 2); while (1) { /* Main loop */ } } ``` 在转换完成后,DMA中断将被触发。在该中断处理程序中,可以读取ADC值并进行进一步处理: ```c /* DMA interrupt handler */ void DMA2_Stream0_IRQHandler(void) { HAL_DMA_IRQHandler(&hdma_adc1); /* Process ADC values */ uint16_t value0 = adc_values[0]; uint16_t value1 = adc_values[1]; /* ... */ } ``` 这里的“adc_values”是一个uint16_t类型的数组,大小为2,用于存储ADC转换结果。在ADC转换完成后,DMA将这些值存储在该数组中。可以使用这些值进行进一步的处理,例如将它们发送到计算机或用于控制外设。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值