ADC简介
ADC,即模数转换器(Analog-to-Digital Converter),是一种在微控制器(如STM32)中常见的设备,它能够将模拟信号转换为数字信号。简单来说,我们的现实世界中大部分的信号都是模拟的,比如声音、光线强度、温度等,它们的变化是连续的。而微控制器是数字设备,它处理的是0和1的数字信号。 ADC让我们可以读取模拟信号的值,然后将这个连续变化的信号转换成一系列数字,微控制器就可以读取这些数字进行进一步的处理了。举个例子,如果你有一个测量温度的传感器,它输出的是电压变化,你可以用ADC读取这些电压变化,然后转换成温度值。 在STM32等微控制器中,ADC的分辨率通常是12位的,这意味着它可以将模拟信号转换为0到4095之间的数字值(2的12次方等于4096个不同的值)。如果ADC是10位的,它就可以输出0到1023之间的值(2的10次方等于1024个不同的值)
ADC可以读取哪些模拟信号?
- 电压信号:直接测量通过电阻分压器或其他电压源产生的电压。
- 电流信号:通过电流传感器如霍尔效应传感器产生的模拟输出。
- 压力信号:使用压力传感器将压力变化转换为电压信号读取。
- 光强信号:例如利用光敏电阻或光敏二极管测量环境的光线强度。
- 湿度信号:通过湿度传感器,将环境的湿度变化转换为可读的电压信号。
- 声音信号:通过麦克风传感器将环境中的声波转换为电压信号。
ADC的分辨率和采样速率有什么关系?
ADC的分辨率和采样速率是两个不同的概念,它们描述了模数转换器的不同特性:
- 分辨率:分辨率决定了ADC可以区分的最小电压差值。由ADC的位数决定,位数越高,分辨率越高,能够检测到的最小电压变化就越小。例如,一个12位的ADC具有2^12(4096)个不同的可能的输出值。
- 采样速率:采样速率(或采样频率)是ADC单位时间内可以执行的采样次数。它通常以赫兹(Hz)为单位。采样率越高,ADC就能够更频繁地采集数据,更好地跟踪快速变化的信号。
两者之间的关系是,在保持一定的分辨率的条件下,增加采样速率可能需要更强大的ADC性能和更高的处理能力。同时,根据奈奎斯特定理,为了准确地重建一个模拟信号,采样频率需要至少是信号最高频率的两倍。 总的来说,分辨率描述了ADC测量精度的能力,而采样速率描述了ADC测量频率的能力。在实际应用中,两者需要根据具体的测量需求和性能要求来平衡选择。
STM32中ADC的工作原理
在STM32微控制器中,ADC(模数转换器)的工作原理基于将模拟信号(如电压)转化为数字值的过程。以下是ADC在STM32中的基本工作方式:
- 采样 - ADC首先对模拟信号进行采样,即在特定的时刻捕获信号的值。STM32的ADC可以配置为手动触发采样或通过定时器等外部事件自动触发。
- 保持 - 模拟信号被ADC的采样保持电路捕获并保持在一定时间内,这样便于转换电路准确读取到这个值。保持时间需要足够长,以确保转换的准确性。
- 量化 - 模拟信号通过ADC内的量化电路转换成数字值。量化过程是将采样的模拟信号划分到一定数量的离散区间内,并将这个模拟信号转换为代表这个区间的数字值。在STM32的ADC通常可以是12位的,即4096个区间。
- 转换 - 量化后的数字信号是模拟信号的近似数字表示。这个数字最终通过ADC寄存器可以被微控制器读取和处理。
- 输出 - 微控制器通过读取ADC数据寄存器,获取转换结果。这个结果通常是以二进制或十六进制的格式表示,但可以根据需要,通过软件算法转换成相应的物理单位(比如温度、压力等)。
在STM32中,通过配置ADC寄存器,开发者可以定制化ADC工作方式,例如选择不同的采样时间、分辨率、通道,以及是否启用连续采样或单次采样等。每个STM32系列的微控制器可能有多个ADC模块,并且每个ADC模块可能有多个通道。基于具体的应用需求,开发者可以选择合适的ADC以及相应的配置来进行数据的采集和处理。
重要寄存器
- ADC_CommonInitTypeDef:这不是一个单独的寄存器,但它是一个结构体,用于初始化ADC的通用设置,适用于包含多个ADC模块的STM32芯片。
- ADC_CR1 和 ADC_CR2(控制寄存器1和2):这些寄存器用于控制ADC的主要功能,如转换分辨率、连续转换模式、触发源选择等。
- ADC_SMPR1 和 ADC_SMPR2(采样时间寄存器1和2):这些寄存器用于配置各个ADC通道的采样时间。
- ADC_HTR 和 ADC_LTR(看门狗高阈值和低阈值寄存器):如果使用模拟看门狗功能,将会用到这些寄存器来设置高低阈值。
- ADC_SQR1 、ADC_SQR2 和 ADC_SQR3(规则序列寄存器):用于设置规则转换序列和每次序列要转换的通道数量。
- ADC_JSQR(注入序列寄存器):如果使用注入通道功能,用于设置注入序列和转换的通道。
- ADC_DR(数据寄存器):用于读取转换结果的电压值。
- ADC_CCR(公共控制寄存器):适用于一些特定的STM32芯片,用于控制与多个ADC模块相关的某些特性,如温度传感器、Vrefint引用电压等。
如何配置这些寄存器
在程序中配置STM32的ADC寄存器,一般需要以下步骤:
-
启用ADC和GPIO时钟 :使用
RCC_APB2PeriphClockCmd()
函数启用ADC和与ADC输入通道相对应的GPIO端口的时钟。cppRCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOx, ENABLE);
-
配置ADC使用的GPIO为模拟输入模式 :将GPIO端口配置为模拟输入模式以用于ADC。
cppGPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_x; // 替换x为实际的引脚 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOx, &GPIO_InitStructure); // 替换x为实际的端口
-
复位并初始化ADC :创建
ADC_InitTypeDef
结构体并使用ADC_StructInit()
函数进行初始化。cppADC_InitTypeDef ADC_InitStructure; ADC_StructInit(&ADC_InitStructure);
-
配置特定于ADC的寄存器 :
-
使用
ADC_Init()
函数配置ADC_CR1和ADC_CR2。 -
根据ADC通道数配置ADC_SMPR1和ADC_SMPR2。
-
设定ADC转换序列与转换次数(ADC_SQR1, ADC_SQR2和ADC_SQR3)。
cppADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 或 ENABLE,取决于是单通道还是多通道 ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // 或 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_RegularChannelConfig(ADC1, ADC_Channel_x, 1, ADC_SampleTime_55Cycles5); // x是通道号
-
-
校准并启用ADC :在诸如ADC_CR2这样的寄存器中启用ADC然后启动校准过程。
cppADC_Cmd(ADC1, ENABLE); ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1));
-
启动ADC转换 :软件启动ADC或配置触发器自动启动转换。
cppADC_SoftwareStartConvCmd(ADC1, ENABLE);
-
读取ADC值 :从ADC_DR寄存器读取转换结果。
cppuint16_t ADC_Value = ADC_GetConversionValue(ADC1);
请根据具体的STM32型号和库函数版本查看参考手册和标准外设库,因为不同的型号和库函数版本有一些差异。这些设置应作为指导,应根据你实际使用的STM32系列进行调整。
完整示例代码
cpp
#include "stm32f10x.h"
#include "stm32f10x_adc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
void ADC1_Init(void) {
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
// 1. 使能ADC1和GPIO端口时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOC, ENABLE);
// 2. 配置PC.04 作为模拟输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOC, &GPIO_InitStructure);
// 3. ADC结构体初始化
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
// 4. 配置ADC1的通道11为顺序进行规则转换的第一个转换
ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 1, ADC_SampleTime_55Cycles5);
// 5. 使能 ADC1
ADC_Cmd(ADC1, ENABLE);
// 6. 初始化ADC1的校准寄存器,并开始校准
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
// 7. 开始转换
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
int main(void) {
// 初始化ADC
ADC1_Init();
while (1) {
// 检测转换结束
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
// 读取ADC转换结果
uint16_t ADC_Value = ADC_GetConversionValue(ADC1);
// ... 使用ADC_Value进行其他操作
}
}
这份代码是非常基础的STM32使用ADC的例子,使用标准外设库函数进行简单的ADC配置和读取。步骤如下:
- 使能GPIO和ADC时钟。
- 设置ADC使用的GPIO口为模拟输入模式。
- 对ADC进行基础配置,如工作模式,数据对齐方式等。
- 设置ADC通道,这里以通道14为例。
- 使能ADC并校准。
- 开始ADC转换。