STM32F4单片机上实现双路ADC的同步采样(超详细,手把手教学)
在嵌入式开发中,STM32F4系列单片机由于其性能优越、资源丰富,广泛应用于各类工业和消费电子项目中。在许多应用场景中,ADC(模数转换器)功能至关重要,尤其是需要对多路信号进行采样时。本文将介绍如何在STM32F4单片机上实现双路ADC的同步采样,并详细解释代码的关键点。
前言
STM32F4系列微控制器具备多个ADC模块,每个模块支持多个通道的模拟输入。本例子中,我们将使用STM32F407微控制器的两个ADC模块(ADC1和ADC2),并通过DMA实现双路ADC的同步采样。这样可以有效减少CPU负载,并且确保ADC采样的实时性。
硬件和软件环境
硬件:STM32F407开发板,两个模拟输入信号源(如电位器或传感器)
软件:Keil MDK或IAR等IDE,STM32固件库
系统架构
系统架构如下:
1、使用两个ADC模块(ADC1和ADC2)来进行双路模拟信号的采样。
2、通过DMA(Direct Memory Access)将采样结果传输到内存,减轻CPU负载。
3、ADC在循环模式下工作,不断进行采样和数据传输。
ADC采样基本原理
STM32F4的ADC具备以下特点:
1.分辨率最高为12位
2.支持多通道采样
3.支持DMA,极大提升数据传输效率
4.支持双ADC同步模式
在本项目中,我们使用双路ADC同步采样模式,并结合DMA实现数据自动传输。通过DMA,数据将直接存入内存,避免CPU占用,提升系统效率。
代码实现
- 配置系统时钟和外设时钟
在STM32开发中,首先需要配置系统时钟和外设时钟,以确保ADC模块和DMA模块能够正确工作。可以通过以下代码来配置时钟:
void RCC_Configuration(void)
{
/* 启用ADC1、ADC2和DMA时钟 */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); // DMA2时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); // ADC1时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE); // ADC2时钟
}
- 配置GPIO引脚
ADC的输入通常需要配置对应的GPIO引脚为模拟模式。以下是示例代码,假设我们使用的是PA0和PA1作为ADC的输入引脚:
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* 启用GPIOA时钟 */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
/* 配置PA0和PA1为模拟输入模式 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
- 配置DMA
DMA用于自动将ADC采样结果传输到内存。以下代码配置了DMA,以支持从ADC1和ADC2传输数据到存储器中。
void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
/* 配置DMA2流0用于ADC1 */
DMA_DeInit(DMA2_Stream0);
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&adcValues[0];
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = 2;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_Init(DMA2_Stream0, &DMA_InitStructure);
/* 启用DMA2流0 */
DMA_Cmd(DMA2_Stream0, ENABLE);
}
- 配置ADC
ADC模块配置包括通道选择、分辨率、采样时间等。以下示例展示了如何配置ADC1和ADC2。
void ADC_Configuration(void)
{
ADC_InitTypeDef ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
/* 配置ADC通用配置 */
ADC_CommonInitStructure.ADC_Mode = ADC_DualMode_RegSimult;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&ADC_CommonInitStructure);
/* 配置ADC1 */
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_Init(ADC1, &ADC_InitStructure);
/* 配置ADC1的通道0(PA0) */
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_3Cycles);
/* 配置ADC2 */
ADC_Init(ADC2, &ADC_InitStructure);
/* 配置ADC2的通道1(PA1) */
ADC_RegularChannelConfig(ADC2, ADC_Channel_1, 1, ADC_SampleTime_3Cycles);
/* 启用ADC DMA请求 */
ADC_DMACmd(ADC1, ENABLE);
ADC_DMACmd(ADC2, ENABLE);
/* 启用ADC */
ADC_Cmd(ADC1, ENABLE);
ADC_Cmd(ADC2, ENABLE);
}
- 启动ADC和DMA
当配置完所有外设后,可以通过启动ADC和DMA进行采样:
void Start_ADC_DMA(void)
{
/* 启动ADC1的DMA */
ADC_SoftwareStartConv(ADC1);
}
- 主循环
在主循环中,可以定期读取存储在内存中的ADC采样结果:
int main(void)
{
RCC_Configuration(); // 时钟配置
GPIO_Configuration(); // GPIO配置
DMA_Configuration(); // DMA配置
ADC_Configuration(); // ADC配置
/* 启动ADC和DMA */
Start_ADC_DMA();
while (1)
{
// 此处可以读取 adcValues[] 数组中的数据
uint32_t adc1_value = adcValues[0];
uint32_t adc2_value = adcValues[1];
// 处理采样数据
}
}
代码解释
1、时钟配置:使用RCC_Configuration函数启用了ADC和DMA的时钟。
2、GPIO配置:将PA0和PA1配置为模拟输入模式,分别连接到ADC1的通道0和ADC2的通道1。
3、DMA配置:通过DMA_Configuration函数设置了DMA,以便将ADC采样结果传输到内存。
4、ADC配置:ADC_Configuration函数配置了ADC1和ADC2,并设置了同步模式。
5、数据采集:Start_ADC_DMA函数启动ADC和DMA的采样过程,主循环中通过访问adcValues[]来获取采样结果。
结论
本文详细介绍了如何使用STM32固件库开发双路ADC采样程序,并通过DMA实现数据的高效传输。在实际项目中,这种方式可以有效减轻CPU负担,适用于需要高效处理多路模拟信号的场景。通过STM32固件库的配置,我们能够更加精细地控制硬件资源,实现高效的嵌入式应用。
作者:一万个W