在之前的文章,我们介绍了模拟信号,在本章中,我们用实例来详细介绍如何用ESP32来读取一个电压信号。
模拟信号的读取对于很多传感器来说是十分重要的知识点,在之前的文章也介绍了,模拟信号存在一些缺点,如容易受到外界的干扰,信号传输的质量难以控制等。ESP32内置的ADC功能在官方文档中,也明确说明了该功能在精度和防干扰方面是比较差的。所以,ESP32的模拟信号读取功能在硬件和软件上都存在一定的问题,我们需要一定的了解才能正确地解决这个问题,所以,本篇会分成几章来介绍。
我们首先需要了解读取模拟值的函数:
函数格式:
analogRead(pin);
参数:
pin - 引脚号码
读取pin引脚的模拟值。
ESP32的ADC通道的分辨率一般为12位,因为每个位可以对应2个值,所以,可以计算出,它的分辨率转换为十进制数值可以用2的12次方(2^12)来计算,结果就是2^12 = 4096。范围为0~4095。
我们也可以用analogReadResolution(bits)函数来定义ADC的分辨率。参数bits范围为9-12(默认为12),对应的分辨率如下:
参数为9时:2^9 = 512,范围为0~511
参数为10时:2^10 = 1024,范围为0~1023
参数为11时:2^11 = 2048,范围为0~2047
参数为12时:2^12 = 4096,范围为0~4095
就是说,在默认设置下,当该引脚接收到的电压为3.3V时,该引脚接收到的值为4095,当接收到的电压为0时,接收到的值为0。
该文,我们用分压电阻的原理来测试读取一个电压的值,我们先介绍一下分压电阻的原理。
分压电阻的原理是指与某一电路串联的导体的电阻,在总电压不变的情况下,在某一电路上串联一个分压电阻,将能起分压的作用,一部分电压将降在分压电阻上,使该部分电路两端的电压减小。
我们来看上面的三个电路,三个电路中,都有一个电源,两个电阻,两个电压计。在这三个电路中,所有电源都设置为5V,但电阻各有区别,我们分别看这三个电路:
电路一:两个电阻的阻值相同。
电阻1 = 1K,电阻两端电压为2.5V
电阻2 = 1K,电阻两端电压为2.5V
电路二:电阻1阻值>电阻2阻值。
电阻1 = 3K,电阻两端电压为3V
电阻2 = 2K,电阻两端电压为2V
电路三:电阻1阻值<电阻2阻值。
电阻1 = 1K,电阻两端电压为1V
电阻2 = 4K,电阻两端电压为4V
我们可以用一个公式来计算出某个电阻两端的电压值。
电阻1电压
U1 = R1/(R1+R2)XU
我们尝试计算一下电路二中电阻一的电压是否如图所示:
3000Ω/(3000Ω+2000Ω)*5V = 3V
下面,我们尝试用ESP32来测试分压电阻原理是否正确。
电路:
程序代码:
void setup() {
Serial.begin(115200);
}
void loop() {
int value = analogRead(4); //读取4号引脚的模拟值
Serial.println(value);
delay(1000);
}
串口监视器查看运行结果:
结果十分奇怪,因为如果按照分压电阻原理,正常的结果应该为4096/2=2048附近的值。
我们用analogSetAttenuation()函数给引脚设置衰减值,引脚会对输入的电压进行一定的减弱,以防止电压过大造成单片机损坏,衰减程度越大,测量的电压范围越大。
void setup() {
Serial.begin(115200);
analogSetAttenuation(ADC_11db);
}
void loop() {
int value = analogRead(4); //读取4号引脚的模拟值
Serial.println(value);
delay(1000);
}
就结果来看,是没有任何效果的,因为引脚衰减设置的默认值,就是11db。
目前为止,我们可以读取到引脚的模拟值,但读取到的数据与现实有一定的误差,我们会在之后的章节中慢慢了解出现这种情况的原因。
虽然结果有所误差,但很多情况下,我们并不需要过于精确的数据,比如下面要介绍的一个实例,在这个实例中,我们将设计一个以模拟值来控制一个LED亮度的实例:
在这个实例中,我们先用pwm模式(pwm的介绍可以在之前的文章中找到:ESP32入门三(ESP32的引脚(GPIO)信号)_esp32 gpio-CSDN博客)来控制LED的亮度,所以我们首先要做的是把接收到的模拟信号精度和pwm的精度设置为相同的2^8=256。
analogReadResolution(8); //模拟信号分辨率设为2^8=256
ledcSetup(0,1000,8); //设置pwm频道,频率,精度2^8=256
我们选择的是用4号脚来接收模拟信号,25号脚来输出pwm信号,下面是完整代码:
void setup() {
analogReadResolution(8); //模拟信号分辨率设为2^8=256
ledcSetup(0,1000,8); //设置pwm频道,频率,精度2^8=256
ledcAttachPin(25,0); //25号引脚与0号pwm频道绑定
}
void loop() {
int adc_value = analogRead(4); //读取4号引脚的模拟值
ledcWrite(0,adc_value); //0号pwm频道绑定的25号引脚pwm输出
delay(1000);
}
上传代码后,可以观察到,25号引脚上的LED会随着电位器的扭动改变LED的亮度。
在下一章中,我们将详细测试和介绍模拟信号出现误差的原因,尝试消除出现的误差。