模拟信号与数字信号转换 - ADC实验
一、 模拟信号与数字信号
在学习 ADC 之前,我们要首先学习什么是模拟信号,什么是数字信号。
特性 | 模拟信号 | 数字信号 |
时间 | 连续 | 离散 |
幅值 | 连续 | 离散 |
示例 | 温度变化、天体运动等 | 网络传输数据、电子钟表 |
我们举个简单的例子:
- 指针时钟显示的就是时间的模拟信号,他表示时间是连续变化的;
- 数字时钟显示的就是时间的数字信号,时间的显示是按照固定增量变化的,他可以显示 1、2、3,但是无法显示 1.1、2.1、等,所以在数字电路中使用的数字信号一般只能取 0 或 1,把 0 对应为低电平,把 1 对应为高电平,所以有或者没有数字信号是在模拟信号的基础上依次经过
采样
、量化
、编码
而形成的;
采样
就是把输入的模拟信号按适当的时间间隔得到各个时刻的样本值;
量化
是把经采样测得的各个时刻的值用二进制码来表示;
编码
则是把量化生成的二进制数排列在一起形成顺序脉冲序列。
二、模数转换器 (ADC)
(一)ADC 的功能
- 定义:ADC(Analog to Digital Converter)将模拟信号转换为数字信号。
- 应用:将变化的电压转成数字信号供单片机处理。
(二)输入电压范围
- 默认配置下,ADC 引脚输入电压必须在 0.0V 和 1.0V 之间。
- 超过 1.0V 的值将读为 4095。
- 可通过配置衰减器增加测量范围。
三、硬件电路设计
(一)电位器
电位器相当于一个滑动变阻器,两端引脚阻值是固定的,中间引脚对任何一端的引脚阻值是可变的,他等效于从中间把电位器分成两个串联的电阻,串联总阻值是确定的,一端接输入电源,一端接地。
(二)物料清单 (BOM)
材料名称 | 数量 |
NanoE 单片机 | 1 |
电位器 | 1 |
杜邦线(跳线) | 若干 |
面包板 | 1 |
(三)电路连接
- 将材料按照下图相连:电位器一端接 3V3 引脚,中间引脚接 D7,另一端引脚接地。
- 另外可再将电位器中间引脚接D13,通过LED灯亮度反应模拟值的输入。
四、软件程序设计
(一)使用 analogRead()
和 analogWrite()
实现模拟值打印和LED灯亮度控制
示例代码
#define POT 7 // 定义引脚7为电位器输入引脚
int pot_value; // 用于存储电位器的值
void setup() {
// 初始化设置,运行一次
Serial.begin(115200); // 初始化串口通信,波特率115200
pinMode(POT, INPUT); // 设置引脚7为输入模式
}
void loop() {
// 主循环,重复运行的代码
pot_value = analogRead(POT); // 从引脚7读取电位器的模拟值
Serial.println(pot_value); // 打印读取的电位器值
delay(50); // 延迟50毫秒,以稳定读取
}
1. 代码编译成功并上传后,在工具中查找,或直接点击页面右上方小图标,打开内置的串口监视器;
2. 在其窗口设置波特率为115200,并点击切换自动滚动;
3. 旋转电位器,通过串口监视器窗口观察模拟值输入变化以及LED灯亮暗变化;
4. 这样我们就实现了利用电位器实现模拟值的打印和LED灯亮度控制。
- 我们可以修改代码, 引入
analogWrite()
函数:
#define POT 7 // 定义引脚7为电位器输入引脚
#define LED 13
int pot_value; // 用于存储电位器的值
int led_value;
void setup() {
pinMode(POT, INPUT); // 设置引脚7为输入模式
pinMode(LED, OUTPUT);
}
void loop() {
// 主循环,重复运行的代码
pot_value = analogRead(POT); // 从引脚7读取电位器的模拟值
led_value = pot_value / 16;
analogWrite(LED, led_value);
delay(50); // 延迟50毫秒,以稳定读取
}
(二)ADC 方法使用说明
1. 上述实验和我们这一节要讲的数模转换器并不是一件事,我们查看esp32-hal.h文件,可以看到ADC的所有控制函数:
#ifndef MAIN_ESP32_HAL_ADC_H_
#define MAIN_ESP32_HAL_ADC_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "esp32-hal.h"
typedef enum {
ADC_0db,
ADC_2_5db,
ADC_6db,
ADC_11db
} adc_attenuation_t;
/*。
*获取引脚的ADC值。
**/
uint16_t analogRead(uint8_t pin);
/*。
*设置aliogRead返回值的分辨率。默认值为12位(范围从0到4096)
*如果在9和12之间,它将等于设置的硬件分辨率,否则值将移位
*范围为1-16
*注:与Arduino SAM兼容
*/
void analogReadResolution(uint8_t bits);
/*。
*设置采样位和读取分辨率
*默认值为12位(0-4095)
*范围为9-12
*/
void analogSetWidth(uint8_t bits);
/*。
*设置每个样本的周期数
*默认为8,似乎表现不错
*范围为1-255
*/
void analogSetCycles(uint8_t cycles);
/*。
*设置范围内的样本数
*默认值为1
*范围为1-255
*此设置将范围拆分为
*“样本”件,可能看起来
*就像敏感度成倍增长
*那么多次
*/
void analogSetSamples(uint8_t samples);
/*。
*设置ADC时钟的分频器
*默认值为1
*范围为1-255
*/
void analogSetClockDiv(uint8_t clockDiv);
/*
* Set the attenuation for all channels
* Default is 11db
* */
void analogSetAttenuation(adc_attenuation_t attenuation);
/*
*设置所有通道的衰减
*默认值为11db
**/
void analogSetPinAttenuation(uint8_t pin, adc_attenuation_t attenuation);
/*。
*获取霍尔传感器的值(不带LNA)
*连接到引脚36(SVP)和39(SVN)
**/
int hallRead();
/*。
*非阻塞接口(差不多)
*
*注:ADC转换一次只能针对单个管脚运行。
*这意味着如果要在同一总线的两个引脚上运行ADC
*需陆续运行。或许最好的用法是。
*在两辆巴士上并行开始转换
**/
/*。
*将引脚连接到ADC(还将清除任何其他可能开启的模拟模式)
**/
bool adcAttachPin(uint8_t pin);
/*
*在连接的引脚总线上开始ADC转换
**/
bool adcStart(uint8_t pin);
/*
*检查引脚的ADC总线上的转换当前是否正在运行
**/
bool adcBusy(uint8_t pin);
/*
*获取转换结果(未完成将等待)
**/
uint16_t adcEnd(uint8_t pin);
#ifdef __cplusplus
}
#endif
#endif /* MAIN_ESP32_HAL_ADC_H_ */
2. ADC 函数说明
analogReadResolution(resolution)
设置样本大小位和分辨率。它可以是一个介于 9(0 - 511)和 12 位(0 - 4095)之间的值,默认是 12 位分辨率(最大)。这与NanoC不同
adcAttachPin(pin)
添加一个引脚到 ADC(也请确保其他模式可以是 on)。返回 TRUE 或 FALSE 结果。
analogSetAttenuation(attenuation)
设置所有 ADC 引脚的输入衰减。默认是 ADC_11db。其他取值:
ADC_0db: 集没有衰减。 ADC 可以测量最大约 800mV(1V 输入 = ADC 读取 1088)。
ADC_2_5db: ADC 的输入电压将被衰减,扩展测量范围至约 1100mV(1V 输入 = ADC 读取 3722)。
ADC_6_db: ADC 的输入电压将被衰减,扩展测量范围至约 1300mV(1V 输入 = ADC 读取 3033)。
ADC_11db: ADC 的输入电压将被衰减,扩展测量范围至约 2600mV(1V 输入 = ADC 读取 1575)。
analogSetPinAttenuation(pin, attenuation)
设置指定引脚的输入衰减。默认是 ADC_11db。衰减值与前一个函数相同。
3. 示例代码
这一次我们使用LEDC模块来控制灯的亮度,而非 analogWrite()
函数:
#define POT 7 // 定义电位器连接的引脚为 7
#define LED 13 // 定义LED连接的引脚为 13
#define CHANNEL 0 // 定义PWM通道为 0
#define RESOLUTION 12 // 定义ADC分辨率为 12 位(最大值为 4095)
#define FREQ 1000 // 定义PWM信号的频率为 1000 Hz
int pot_value;
void setup() {
analogReadResolution(RESOLUTION); // 设置模拟读取的分辨率为 12 位
analogSetAttenuation(ADC_11db); // 设置ADC的衰减为 11dB,以支持更高的输入电压范围
ledcSetup(CHANNEL, FREQ, RESOLUTION); // 初始化LEDC通道,设置频率和分辨率
ledcAttachPin(LED, CHANNEL); // 将LED引脚附加到LEDC通道,以便后续控制
}
void loop() {
pot_value = analogRead(POT);
ledcWrite(CHANNEL, pot_value); // 将电位器的值作为 PWM 信号写入 LED,引脚控制 LED 亮度
delay(50);
}
这就是使用ADC,将电位器输入的模拟信号转化为LEDC输出的PWM数字信号,从而实现电位器控制 LED 的亮度变化。