STM32F4系列微控制器ADC功能详解及编程实现
STM32F4系列微控制器ADC功能详解及编程实现
STM32F4系列微控制器内置的ADC(模拟-数字转换器)功能,能够将模拟电压信号转换为数字信号,广泛应用于各种测量和控制系统中。本文将详细介绍STM32F4的ADC工作原理、硬件特性以及具体的编程实现步骤,帮助读者掌握这一重要功能的使用方法。
基本原理
当需要测量和记录外部电压的变化,或者根据外部电压的变化量来决定是否触发某个动作时,我们可以使用ADC(模拟—数字转换器)功能。这个功能可以将模拟的电压信号转换为数字信号,方便我们进行测量、记录或判断。例如,假设有一个温度传感器,它的输出是一个与温度成正比的模拟电压信号,可将这个模拟信号连接到F4的ADC输入端,然后通过ADC功能将这个模拟信号转换为数字信号,并读取这个数字信号获取温度的信息。进一步的可根据这个数字信号的变化,来决定是否要触发某个动作,例如温度超过了设定的阈值,即会触发一个报警动作。
STM32F4内置的ADC简介:
- 转换类型:STM32F4的ADC是基于逐次逼近原理工作的,这是一种常用的模数转换方法,它通过逐次比较来逼近输入信号的电压值。
- 通道数量:STM32F4微控制器配备有3个ADC,每个ADC都可以独立使用,或者可以配置为双重或三重模式以提高采样率。它们提供多达19个复用通道,这意味着可以同时测量来自多个源的信号,包括16个外部源、2个内部源以及Vbat通道。
- 转换模式:这些通道的A/D转换支持多种模式,包括单次转换、连续转换、扫描转换和间断转换,使微控制器能够灵活应对不同的应用场景。
- 数据存储:转换结果可以以左对齐(4-15位)或右对齐(0-11位)的方式存储在16位的数据寄存器中,这为用户提供了不同的数据存储选项。
- 分辨率设置:STM32F4的ADC可以设置为6位、8位或12位的模式,位数越高,分辨率越高,从而能够更精确地表示模拟信号的细节。
- 保护机制:STM32F4的ADC还具有模拟看门狗特性,允许应用程序检测输入电压是否超出了用户自定义的阈值上限或下限,这为系统提供了额外的保护机制。
- 电源供应:ADC模块的输入电压范围是由VREF-(参考负电压)和VREF+(参考正电压)这两个外部引脚决定的。在设计电路时,通常会将VSSA(模拟电源负端)和VREF-接地,而将VREF+和VDDA(数字电源正端)连接到3.3V,这样就得到了ADC的输入电压范围为0-3.3V。此外,12位的ADC意味着有4096个(0-4095)不同的数值可以表示0-3.3V之间的电压,可以理解为把3.3V分成了4096份,因此每个单位(ADC转换值0-4095)的增加代表着3.3V/4096的电压增加。
转换公式:
ADC的通道选择很重要,在STM32F4的ADC19个通道中,外部16个通道对应着不同的IO口(见表1.1)。这些通道可以用来测量外部的模拟信号,通过采样并将其转换为数字值供微控制器处理。
要注意的是,为了保证转换结果准确性,不要让ADC的时钟超过36MHz,而STM32F4ADC模块的时钟频率取决于APB2总线的基础时钟和分频系数。例如,APB2总线的基础时钟是84MHz,选择分频系数为4(分频系数有2、4、6、8),则ADC时钟频率为21MHz。
采样时间是根据实际需要设置的,它表示ADC采集模拟信号的时间长度。理论上,采样时间越长,得到的结果越精确,但同时也会增加转换时间。转换时间等于采样时间加上12个ADC时钟周期(也称固定时钟周期),其中12个固定时钟周期是因为12位ADC需要12个时钟周期来完成一次完整的模拟信号到数字信号的转换过程。为了确保信号能够被准确地采集,在转换开始之前通常会有一个最小的采样时间要求,这就意味着最少的转换周期数为15个ADC周期,其中包括了12个转换周期和3个可编程的采样周期。可编程采样时间可设置为3、15、28、56、84、112、144、480个周期。
例如,当选择分频系数为4、时钟周期为3时,根据转换时间(TCONV)计算公式:
得到此时转换速率为1.4MHz,转换时间为0.71μs,即每秒可以进行最多140万次采样。STM32F4的ADC最大转换速率为2.4MHz,转换时间为0.41us(这是在ADC的时钟等于36MHz,没有算12个固定时钟周期,采样周期为3个周期下得到的)。
如果被测的电压大于ADC输入电压,例如,要用STM32F4测量0~12V外部电压,可以在外部电压输入ADC引脚之前,加入电阻分压模块使其最大输入值控制在3.3V以内。STM32F4还具有模拟看门狗特性,允许应用程序检测输入电压是否超出定义的高/低阀值,这可以为系统提供额外的保护,防止由于输入电压异常而导致的潜在问题。
具体编程步骤
步骤一:结构体介绍
//ADC初始化结构体
typedef struct
{
uint32_t ADC_Resolution; //定义ADC分辨率,单位为位
FunctionalState ADC_ScanConvMode; //定义ADC扫描转换模式,启用或禁用
FunctionalState ADC_ContinuousConvMode; //定义ADC连续转换模式,启用或禁用
uint32_t ADC_ExternalTrigConvEdge; //定义外部触发转换的边沿类型
uint32_t ADC_ExternalTrigConv; //定义外部触发转换源
uint32_t ADC_DataAlign; //定义ADC数据对齐方式
uint8_t ADC_NbrOfConversion; //定义ADC转换通道的数量
} ADC_InitTypeDef;
步骤二:ADC程序配置
//ADC初始化配置
void ADC_ControlIO_Init(void)
{
// 初始化ADC相关寄存器
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
// 使能GPIO和ADC时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE);
// 配置GPIO为模拟输入模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // 选择PA0作为ADC输入通道
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 初始化ADC
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
// 配置ADC采样时间
ADC_SampleTimeConfig(ADC1, ADC_Channel_0, ADC_SampleTime_55Cycles5);
// 使能ADC
ADC_Cmd(ADC1, ENABLE);
// 等待ADC准备好
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_ADRDY) == RESET);
}
//读取ADC值
u16 Read_ADC(void)
{
// 开始转换
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
// 等待转换完成
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
// 读取转换结果
return ADC_GetConversionValue(ADC1);
}
//定义一个函数,用于计算ADC的平均值
float Average_ADC(u8 t)
{
u32 sum = 0;
u8 i;
for (i = 0; i < t; i++)
{
sum += Read_ADC();
delay_ms(1); // 等待一段时间,避免连续读取影响精度
}
return (float)sum / t;
}
步骤三:主程序
int main(void)
{
float Adc_value;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断分组
LED_Init(); //初始化LED
usart1_Init(); //初始化USART1串口通信
ADC_ControlIO_Init(); //初始化ADC控制IO
while (1)
{
Adc_value = Average_ADC(10); //读取ADC值,并计算平均值,参数10表示连续读取10次ADC值后取平均
printf("%.3f\r\n", Adc_value); //打印出ADC的平均值,保留三位小数
if (Adc_value < 2)
LED1 = 0; //如果ADC平均值小于3,开启LED1
else
LED1 = 1; //如果ADC平均值大于等于3,关闭LED1
delay_ms(100);
}
}
本文详细介绍了STM32F4微控制器的ADC功能及其编程实现,涵盖了从硬件原理到具体代码实现的全过程。通过本文的学习,读者可以掌握如何使用STM32F4的ADC功能进行模拟信号的采集和处理,为嵌入式系统开发提供有力的技术支持。