ADC模数转换在stm32上的应用

ADC模数转换在stm32上的应用

1. 什么是ADC?

ADC是"Analog-to-Digital Converter"(模数转换器)的缩写。它是一种电子器件或电路,用于将连续变化的模拟信号(如电压或电流)转换为数字信号(通常是二进制码),这样计算机和数字设备就可以处理这些信号。

在许多电子系统中,比如音频设备、通信系统、测量仪器等,ADC都是一个关键组件。通过ADC,真实世界的物理信号(如声音、温度、压力等)可以被转换成数字形式,进而被微处理器或计算机分析和处理。

ADC的主要参数包括:

  • 分辨率:表示转换后的数字信号能表示多少个离散值,通常以位数表示(例如8位、12位、16位等)。
  • 采样率:单位时间内能够完成的转换次数,通常用Hz(赫兹)来表示。
  • 量化误差:由于数字信号只能近似表示模拟信号,这种近似带来的误差称为量化误差。
  • 信噪比(SNR):信号功率与噪声功率的比值,反映了ADC输出信号的质量。
  • 动态范围:ADC能有效转换的最大信号幅度与最小可检测信号幅度之比。

ADC的类型有很多种,常见的有逐次逼近型(SAR)、积分型(Sigma-Delta)、并行比较型(Flash)等。每种类型的ADC都有其特定的应用场景和技术优势。

2. stm32中的ADC

STM32 微控制器中的 ADC(Analog-to-Digital Converter)是一种模拟到数字转换器,用于将模拟信号转换为数字信号,以便微控制器可以处理这些信号。STM32 系列微控制器提供了多种型号,而不同的型号可能拥有不同数量和特性的 ADC。

以下是一些关于 STM32 中 ADC 的主要特点:

  1. 类型

    • STM32 的 ADC 通常采用 12 位逐次逼近型设计,这意味着它可以提供 4096 (2^12) 个不同的数字输出值,对应于输入电压的变化。
  2. 分辨率

    • 12 位的分辨率意味着 ADC 可以区分出输入电压的微小变化,最小分辨率为 VREF / 4096。
  3. 通道数

    • 不同型号的 STM32 可能有不同的通道数。例如,STM32F10X 系列支持最多 18 个通道,其中 16 个可以连接到外部信号源,另外 2 个用于内部信号源。
    • STM32F4 系列支持多达 19 个复用通道,可以测量来自 16 个外部源和 2 个内部源的信号。
  4. 转换模式

    • 单次转换模式:每次只进行一次转换。
    • 连续转换模式:在连续模式下,ADC 会连续不断地进行转换,直到被软件停止。
    • 扫描模式:此模式下,ADC 会在指定的多个通道上依次进行转换。
    • 间断模式:允许在多个连续转换之间插入空闲周期,以减少功耗。
  5. 触发源

    • ADC 可以通过硬件触发启动转换,例如定时器的中断输出或外部中断线。
  6. 数据对齐

    • ADC 结果可以左对齐或右对齐在 16 位的数据寄存器中。左对齐意味着最低有效位 (LSB) 在寄存器的最低位位置;右对齐则意味着最高有效位 (MSB) 在寄存器的最高位位置。
  7. 供电要求

    • 通常,ADC 的供电范围为 2.4V 至 3.6V,而输入电压范围由参考电压 VREF 决定,即 VREF- ≤ VIN ≤ VREF+。
  8. 校准

    • ADC 提供了校准功能,以确保转换精度。校准可以通过软件命令启动。
  9. 中断和事件

    • ADC 支持中断机制,在转换结束、注入转换结束以及模拟看门狗事件时可以产生中断。
  10. 多 ADC 模式

    • 一些 STM32 型号配备了多个 ADC,它们可以独立工作,也可以在双重或三重模式下协同工作,以实现更高的采样率。

3. 12位逐次逼近型ADC

12位逐次逼近型ADC(Analog-to-Digital Converter)是一种常用的模数转换器类型,广泛应用于各种电子设备中。

1. 工作原理

逐次逼近型ADC的工作原理基于比较器和数字-模拟转换器(DAC)。其基本过程如下:

  1. 初始化:将DAC的输出设为中间值,此时DAC输出为参考电压的一半。
  2. 比较:将输入模拟电压与DAC输出进行比较。
  3. 调整:根据比较结果,调整DAC的输出以接近输入电压。
  4. 重复:重复上述步骤,每次改变DAC输出的一个位,直到所有位都被确定为止。

具体来说,对于12位ADC,这个过程需要进行12次迭代,每次迭代确定一位的值。每次迭代后,DAC输出值都会向输入电压靠近,最终得到最接近输入电压的12位数字值。

2. 主要特性

  • 分辨率:12位ADC可以分辨出输入电压的4096个不同级别((2^{12} = 4096))。
  • 量化误差:量化误差是指ADC输出的数字值与实际模拟输入之间的最大偏差。对于12位ADC,量化误差通常为满量程电压的1/4096。
  • 转换时间:转换时间取决于时钟频率和所需的位数。对于12位ADC,如果每个比特需要一个时钟周期,则转换时间大约为12个时钟周期加上一些额外的时间(如建立时间和稳定时间)。

3. 关键部件

  • 比较器:用于比较输入电压与DAC输出。
  • 数字-模拟转换器(DAC):用于生成模拟电压供比较器比较。
  • 逐次逼近寄存器(SAR):存储每次迭代中确定的比特位。
  • 控制逻辑:控制整个转换过程,包括时序和位的更新。

4. 优点

  • 速度快:逐次逼近型ADC通常比其他类型的ADC(如积分型ADC)更快。
  • 易于实现:硬件结构简单,便于集成。
  • 成本效益高:适用于大多数中低速应用,具有良好的性价比。

5. 缺点

  • 功耗:由于需要快速转换,逐次逼近型ADC相对于积分型ADC而言功耗较高。
  • 精度限制:虽然12位分辨率已经足够高,但在需要更高精度的情况下可能不是最佳选择。

6. 应用

  • 数据采集系统:用于测量传感器输出的模拟信号。
  • 音频处理:用于将麦克风等音频源的模拟信号转换为数字信号。
  • 通信系统:用于接收端的信号处理。
  • 工业自动化:用于监控和控制系统的信号采集。

7. 配置和使用

配置12位逐次逼近型ADC通常涉及以下几个步骤:

  • 设置参考电压:确定ADC的参考电压范围。
  • 选择时钟频率:根据转换速度需求选择合适的时钟频率。
  • 配置分辨率:尽管是12位ADC,但某些情况下可能需要降低分辨率以提高转换速度。
  • 设置触发源:选择硬件触发还是软件触发。
  • 配置中断:设置中断使能,以便在转换完成后接收中断通知。

4. stm32的ADC转换模式

STM32 微控制器系列提供了多种 ADC(Analog-to-Digital Converter)转换模式来适应不同的应用场景。

1. 单次转换模式 (Single Conversion Mode)

  • 描述:在这种模式下,每次启动转换后,ADC 将执行一次转换,然后进入待机状态等待下一次启动。
  • 用途:适合不需要连续采样的场合,比如测量按键状态或温度等。

2. 连续转换模式 (Continuous Conversion Mode)

  • 描述:在这种模式下,一旦启动转换,ADC 将连续不断地执行转换,直到通过软件停止或硬件事件自动停止。
  • 用途:适合需要连续采集数据的应用场景,例如实时信号采集。

3. 扫描模式 (Scan Mode)

  • 描述:在扫描模式下,ADC 可以依次转换一组通道,每个通道转换结束后会自动切换到下一个通道,直到完成所有指定通道的转换。
  • 用途:当需要对多个通道进行连续采样时非常有用,比如多路传感器数据采集。

4. 多ADC同步模式 (Dual/Multi-ADC Synchronization Mode)

  • 描述:STM32 的一些型号支持两个或更多 ADC 的同步操作,可以实现多个 ADC 在相同时间点开始转换,这对于需要同步采集多路信号的应用非常有用。
  • 用途:例如在电机控制中,需要同时读取三相电流或电压。

5. 触发和外部事件管理

  • 描述:STM32 ADC 支持由内部或外部事件触发转换开始。这些触发可以来自定时器的输出比较单元、外部引脚变化或其他 ADC 的转换结束。
  • 用途:可以用来实现精确的采样时机控制,比如与 PWM 输出同步采集信号。

5. ADC单通道&多通道转换

  1. 启用ADC和GPIO时钟:

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    • 这两行代码启用了ADC1外设和GPIOA端口的时钟,这是配置它们之前必须做的步骤。
  2. 配置ADC时钟分频:

    RCC_ADCCLKConfig(RCC_PCLK2_Div6);
    
    • 这行设置了ADC时钟为APB2总线时钟(PCLK2)的六分之一。ADC时钟频率不应超过其最大限制,通常约为14 MHz。
  3. 配置GPIO作为模拟输入:

    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    • 初始化GPIOA的第0号引脚为模拟输入模式。GPIO的速度设置为50 MHz,这虽然与ADC操作不直接相关,但需要正确配置。
  4. 配置常规通道:

    ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
    
    • ADC1: 指定要配置的ADC实例,在这个例子中是ADC1。
    • ADC_Channel_0: 指定要配置的ADC通道,这里是ADC通道0。
    • 1: 这个参数指定了在常规序列中的通道位置。在这个例子中,通道0被设置为序列中的第一个通道。
    • ADC_SampleTime_55Cycles5: 指定了采样时间,即ADC采集模拟信号的时间长度。在这个例子中,采样时间为55.5个ADC时钟周期。
  5. 初始化ADC:

    ADC_InitTypeDef ADC_InitStructure;
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;
    ADC_InitStructure.ADC_NbrOfChannel = 1;
    ADC_Init(ADC1, &ADC_InitStructure);
    
    • 这段代码初始化ADC1:
      • 设置ADC工作模式为独立模式。
      • 数据对齐方式设置为右对齐。
      • 外部触发转换禁用。
      • 连续转换模式禁用。
      • 扫描模式禁用。
      • 通道数量设置为1个。
  6. 使能ADC并开始校准:

    ADC_Cmd(ADC1, ENABLE);
    
    ADC_ResetCalibration(ADC1);
    while (ADC_GetResetCalibrationStatus(ADC1) == SET);
    ADC_StartCalibration(ADC1);
    while (ADC_GetCalibrationStatus(ADC1) == SET);
    
    • 使能ADC1。
    • 开始重置校准,等待校准重置完成。
    • 开始校准过程,等待校准完成。

这个函数用于获取ADC转换后的数值。

  1. 启动软件触发的转换:

    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
    
    • 启动ADC的软件触发转换。
  2. 等待转换完成:

    while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
    
    • 等待直到转换结束标志位被置位。
  3. 读取转换结果:

    return ADC_GetConversionValue(ADC1);
    
    • 返回ADC转换得到的数值。

单通道转换完整代码

void AD_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
	
	ADC_InitTypeDef ADC_InitStructure;
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;
	ADC_InitStructure.ADC_NbrOfChannel = 1;
	ADC_Init(ADC1, &ADC_InitStructure);
	
	ADC_Cmd(ADC1, ENABLE);
	
	ADC_ResetCalibration(ADC1);
	while (ADC_GetResetCalibrationStatus(ADC1) == SET);
	ADC_StartCalibration(ADC1);
	while (ADC_GetCalibrationStatus(ADC1) == SET);
}

uint16_t AD_GetValue(void)
{
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);
	while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
	return ADC_GetConversionValue(ADC1);
}

多通道转换配置流程

与单通道不同的是只需要在部分地方进行改动即可:

  1. 配置多个GPIO作为模拟输入:

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
    
    • 这里配置了GPIOA的引脚0、1、2和3为模拟输入,而不是只配置引脚0。
  2. AD_GetValue函数接受一个参数:

    uint16_t AD_GetValue(uint8_t ADC_Channel)
    
    • 这个函数现在接受一个uint8_t类型的参数ADC_Channel,表示要读取哪个ADC通道的数据。
  3. 配置指定的ADC通道:

    ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5);
    
    • AD_GetValue函数中,使用传递进来的ADC_Channel参数来配置ADC通道,而不是固定配置通道0。
  4. 其他部分保持不变:

    • 其他部分如ADC的初始化、使能、校准等没有变化。

完整

#include "stm32f10x.h"                  // Device header

void AD_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	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);
		
	ADC_InitTypeDef ADC_InitStructure;
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;
	ADC_InitStructure.ADC_NbrOfChannel = 1;
	ADC_Init(ADC1, &ADC_InitStructure);
	
	ADC_Cmd(ADC1, ENABLE);
	
	ADC_ResetCalibration(ADC1);
	while (ADC_GetResetCalibrationStatus(ADC1) == SET);
	ADC_StartCalibration(ADC1);
	while (ADC_GetCalibrationStatus(ADC1) == SET);
}

uint16_t AD_GetValue(uint8_t ADC_Channel)
{
	ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5);
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);
	while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
	return ADC_GetConversionValue(ADC1);
}
  • 18
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FightingLod

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值