数模转换器 - ADC 实验

罗大富 BigRich大约 6 分钟ESP32Arduino

前面我们介绍使用 PWM 输出不同电压值,类似于模拟信号输出。如果需要 ESP32 检测外部输入的模拟信号该怎么办?这就是本节课要学习的 ADC,通过 ADC 将模拟信号转换为数字信号给 ESP32 处理。

实验原理

在学习 ADC 之前,我们要首先学习什么是模拟信号,什么是数字信号。

模拟信号(Analog Signal):模拟信号是连续变化的量或者信号,生活中接触到的信号基本都是模拟信号,温度变化,天体运动等等,这些都是连续的信息,都是模拟信号。模拟信号,简单的说就是用电信号模拟出其他的信号,比如用电信号模拟出图像,模拟出声音的声波。

数字信号(Digital Signal):数字信号是时间离散、数值离散的信号,数字信号存在采样,还存在量化,只能取到一些不连续的固定值,这也是数字信号和模拟信号之间可以进行相互转换的原因。

所以,总结就是模拟信号时间连续,幅值连续,数字信号时间离散,幅值离散。模拟电路就是使用、处理模拟信号的电路;数字电路就是使用、处理数字信号的电路。

我们举个简单的例子:

  1. 指针时钟显示的就是时间的模拟信号,他表示时间是连续变化的,
  2. 数字时钟显示的就是时间的数字信号,时间的显示是按照固定增量变化的,他可以显示 1、2、3,但是无法显示 1.1、2.1、等,所以在数字电路中使用的数字信号一般只能取 0 或 1,把 0 对应为低电平,把 1 对应为高电平,说白了就是有或者没有

数字信号是在模拟信号的基础上依次经过 采样量化编码而形成的。具体地说,采样 就是把输入的模拟信号按适当的时间间隔得到各个时刻的样本值;量化 是把经采样测得的各个时刻的值用二进制码来表示;编码 则是把量化生成的二进制数排列在一起形成顺序脉冲序列。

ADC(Analog to Digital Converter)即模数转换器,它可以将模拟信号转换为数字信号。由于单片机只能识别二进制数字,所以外界模拟信号常常会通过 ADC 转换成其可以识别的数字信号。常见的应用就是将变化的电压转成数字信号。

注意

使用默认配置时,ADC 引脚上的输入电压必须介于 0.0V 和 1.0V 之间(任何高于 1.0V 的值都将读为 4095)。如果需要增加测量范围,需要配置衰减器。

硬件电路设计

物料清单(BOM 表):

材料名称数量
LED1
1kΩ 电阻1
电位器1
面包板1
杜邦线若干

电位器相当于一个滑动变阻器,两端引脚阻值是固定的,中间引脚对任何一端的引脚阻值是可变的,他等效于从中间把电位器分成两个串联的电阻,串联总阻值是确定的,一端接输入电源,一端接地

软件程序设计

1. 在串口监视器显示 analogRead() 模拟输入

我们可以先在串口监视器中,打印一下读取到的 analogRead() 的值,这里需要使用到 Arduino 内置的串口函数:

  • Serial.begin():设置通信波特率,一般使用 9600,这样就可以在串口监视器中直接打印出来内容;
  • Serial.println():在串口屏中打印内容。

因此,我们的代码可以这么写:

#define POT 26

 
// 初始化电位计输入信号
int pot_value;

 
void setup() {
    // 设置串口通信波特率 9600
    Serial.begin(9600);
    pinMode(POT, INPUT);
}
 
void loop() {
    // 读取电位计模拟输入值
    pot_value = analogRead(POT);
    // 打印模拟值在串口屏上
    Serial.println(pot_value);
    delay(50);
}

2. 使用 analogRead() 调节 LED 亮度

我们可以使用 analogRead() 来读取电位计传入的模拟值,范围是在 0 ~ 4023,而我们想要输入 analogWrite() 的参数范围是在 0 ~ 255,因此,我们还需要把读取到的模拟值范围转换成输出范围,代码如下:

#define POT 26
#define LED 13
 
// variable for storing the potentiometer value
int pot_value;
int led_value;
 
void setup() {
    Serial.begin(9600);
    pinMode(POT, INPUT);
    pinMode(LED, OUTPUT);
}
 
void loop() {
    // 读取电位计模拟输入值
    pot_value = analogRead(POT);
    // 把电位计模拟输入值转换为 LED 的模拟输出值。
    led_value = pot_value / 16;
    analogWrite(LED, led_value);
    delay(50);
}

3. 使用 ADC 模拟通道输入

打开 esp32_hal_adc.h 文件之后,我们可以看到 ADC 的所有控制函数:

  • analogReadResolution(resolution):设置样本位和分辨率。它可以是一个介于 9(0 - 511)和 12 位(0 - 4095)之间的值。默认是 12 位分辨率。
  • analogSetWidth(width):设置样本位和分辨率。它可以是一个介于 9(0 - 511)和 12 位(0 - 4095)之间的值。默认是 12 位分辨率。
  • analogSetCycles(cycles):设置每个样本的循环次数。默认是 8。取值范围:1 ~ 255。
  • analogSetSamples(samples):设置范围内的样本数量。默认为 1 个样本。它有增加灵敏度的作用。
  • analogSetClockDiv(attenuation):设置ADC时钟的分压器。默认值为1。取值范围:1 ~ 255。
  • adcAttachPin(pin):附加一个引脚到 ADC(也清除任何其他模拟模式可能是 on)。返回TRUE或FALSE结果。
  • analogSetAttenuation(attenuation):设置所有 ADC 引脚的输入衰减。默认是 ADC_11db。其他取值:
    1. ADC_0db: 集没有衰减。ADC 可以测量大约 800mv (1V 输入 = ADC 读数 1088)。
    2. ADC_2_5db: ADC 的输入电压将被衰减,扩展测量范围至约。1100 mV。(1V 输入 = ADC 读数 3722)。
    3. ADC_6db: ADC 的输入电压将被衰减,扩展测量范围至约。1350 mV。(1V 输入= ADC 读数 3033)。
    4. ADC_11db: ADC 的输入电压将被衰减,扩展测量范围至约。2600 mV。(1V 输入= ADC 读数 1575)。
  • analogSetPinAttenuation(pin, attenuation):设置指定引脚的输入衰减。默认是 ADC_11db。衰减值与前一个函数相同。

因此,代码可以这么写:

#define POT       26
#define LED       13
#define CHANNEL   0


// 初始化模拟输入值
int pot_value;

 
void setup() {
  Serial.begin(9600);
  // 设置 ADC 分辨率
  analogReadResolution(12);
  // 配置衰减器
  analogSetAttenuation(ADC_11db);
  // 建立 LEDC 通道,配置 LEDC 分辨率
  ledcSetup(CHANNEL, 1000, 12);
  // 关联 GPIO 口与 LEDC 通道
  ledcAttachPin(LED, CHANNEL);
}


void loop() {
  // 获取模拟输入值
  pot_value = analogRead(POT);
  // 输出 PWM
  ledcWrite(CHANNEL, pot_value);
  delay(50);
}
上次编辑于:
贡献者: Luo