ESP32用ADC1即36引脚analogRead读取模拟量,读数为12位数值,即1111 1111 1111,最大值为4095, 资料 传送门 上说读取的最大的电压为3.3V,实测3V就满量程了。也就是说当读数为4095时,模拟电压为3V,可能存在万用表测量误差,就当他满量程是3.3V吧。
demo如下:
void setup() {
Serial.begin(115200);
}
void loop() {
int vtmp=analogRead(36); //ADC获取电压
Serial.printf("采样值为:%d\n", vtmp);
Serial.printf("电压为:%.3fV\n", vtmp * 3.3 / 4095);
delay(1000);
}
ACS712霍尔互感器,5A量程的输出为185mV/A,20A量程的输出为100mV/A,30A量程的输出为66mV/A,我买的是20A的。
接线如下
ESP32 | ACS712 |
5V | VCC |
G | GND |
36 | OUT |
在空载的情况下,ACS712输出的理论上为2.5V,2.5V即为0点。如果测的是直流电,数量则在2.5+;如果测的是交流电,数值则在2.5+ 2.5-上。实测后发现几个问题:
- 空载输出并非2.5V稳定的,而是在2.7±0.2V浮动。
解决方法:采用50次测量取均值,这样数值相对会稳定点。有资料说要在硬件上加低通滤波,不会搞T_T。 - 就算是零点2.5V稳定,按20A量程的输出为100mV/A来计算,如果电流为测量20A,那ACS712的输出电压测为2.5+0.120=4.5V,而ESP32的测量模拟量为3.3V,已经超过了ESP32的量程。怎么办?
解决方法:想了想,是不是工作电压为5V,零点为2.5V,那工作电压为3.3V,零点是不是也到1.65V了呢?循着这个思路测了一下,确实如此。就是不知道是否还是100mV/A,待测量。如果还是这个标准的话,满量程输出电压为1.65+0.120=3.75V,马马虎虎还能测得上。假设工作电压下降了,输出标准也同比下降的话,那20A的标准就变为66mV/A,那满测量输出为:4.5*0.66=2.97V,那就在ESP32的测量范围内了,不过只只是猜测,待实测证实。
注:github搜索ACS712会出来很多别人已经写好的arduino库。都是针对arduino模拟测量程5V ,采样10位即1023写的。需要把程序里的参数进行调整,例如下面的我根据ESP32的参数进行了些改良:
ACS712.h
#ifndef ACS712_h
#define ACS712_h
#include <Arduino.h>
#define ADC_SCALE 4095.0//采样值 arduino为1023
#define VREF 3.3 //参考电压,即满量程模拟电压,arduino为5
#define DEFAULT_FREQUENCY 50//交流电频率
enum ACS712_type {ACS712_05B, ACS712_20A, ACS712_30A};
class ACS712 {
public:
ACS712(ACS712_type type, uint8_t _pin);
int calibrate(); // 零点校准值
void setZeroPoint(int _zero);
void setSensitivity(float sens);
float getCurrentDC(); // 测直流电
float getCurrentAC(uint16_t frequency = 50); // 测交流电
private:
int zero = 2048;//零点模拟值
float sensitivity;
uint8_t pin;
};
#endif
ACS712.cpp
#include "ACS712.h"
ACS712::ACS712(ACS712_type type, uint8_t _pin) {
pin = _pin;
// 不同量程模块的灵敏度,工作电压变了,这里的灵敏度值估计也要同比调整
switch (type) {
case ACS712_05B: // 5A
sensitivity = 0.185;
break;
case ACS712_20A: // 20A
sensitivity = 0.100;
break;
case ACS712_30A: // 30A
sensitivity = 0.066;
break;
}
}
// 零点校准
int ACS712::calibrate() {
uint16_t acc = 0;
for (int i = 0; i < 50; i++) {// 50次取样平均,原版10次
acc += analogRead(pin);
}
zero = acc / 50;
return zero;
}
// 设置零点值
void ACS712::setZeroPoint(int _zero) {
zero = _zero;
}
// 设置灵敏度值
void ACS712::setSensitivity(float sens) {
sensitivity = sens;
}
// 测量直流电,单位:mA 毫安
float ACS712::getCurrentDC() {
int16_t acc = 0;
for (int i = 0; i < 50; i++) {//50次采样,原版10次
acc += analogRead(pin) - zero;
}
float I = (float)acc / 50.0 / ADC_SCALE * VREF / sensitivity * 1000 ;
return I;
}
// 测量交流电,单位:mA 毫安
float ACS712::getCurrentAC(uint16_t frequency) {
uint32_t period = 1000000 / frequency;
uint32_t t_start = micros();
uint32_t Isum = 0, measurements_count = 0;
int32_t Inow;
while (micros() - t_start < period) {
Inow = analogRead(pin) - zero;
Isum += Inow*Inow;
measurements_count++;
}
float Irms = sqrt(Isum / measurements_count) / ADC_SCALE * VREF / sensitivity * 1000;
return Irms;
}
测量直流电DEMO
#include "ACS712.h"
/*
This example shows how to measure DC current
*/
// We have 30 amps version sensor connected to A0 pin of arduino
// Replace with your version if necessary
ACS712 sensor(ACS712_30A, A0);
void setup() {
Serial.begin(115200);
// calibrate() method calibrates zero point of sensor,
// It is not necessary, but may positively affect the accuracy
// Ensure that no current flows through the sensor at this moment
// If you are not sure that the current through the sensor will not leak during calibration - comment out this method
Serial.println("Calibrating... Ensure that no current flows through the sensor at this moment");
int zero = sensor.calibrate();
Serial.println("Done!");
Serial.println("Zero point for this sensor = " + zero);
}
void loop() {
// Read current from sensor
float I = sensor.getCurrentDC();
// Send it to serial
Serial.println(String("I = ") + I + " mA");
// Wait a second before the new measurement
delay(1000);
}
测量交流电DEMO
#include "ACS712.h"
/*
This example shows how to measure the power consumption
of devices in 230V electrical system
or any other system with alternative current
*/
// We have 30 amps version sensor connected to A0 pin of arduino
// Replace with your version if necessary
ACS712 sensor(ACS712_30A, A0);
void setup() {
Serial.begin(9600);
// calibrate() method calibrates zero point of sensor,
// It is not necessary, but may positively affect the accuracy
// Ensure that no current flows through the sensor at this moment
// If you are not sure that the current through the sensor will not leak during calibration - comment out this method
Serial.println("Calibrating... Ensure that no current flows through the sensor at this moment");
sensor.calibrate();
Serial.println("Done!");
}
void loop() {
// We use 230V because it is the common standard in European countries
// Change to your local, if necessary
float U = 230;
// To measure current we need to know the frequency of current
// By default 50Hz is used, but you can specify desired frequency
// as first argument to getCurrentAC() method, if necessary
float I = sensor.getCurrentAC();
// To calculate the power we need voltage multiplied by current
float P = U * I;
Serial.println(String("I = ") + I + " mA");
Serial.println(String("P = ") + P + " Watts");
delay(1000);
}