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-上。实测后发现几个问题:

  1. 空载输出并非2.5V稳定的,而是在2.7±0.2V浮动。
    解决方法:采用50次测量取均值,这样数值相对会稳定点。有资料说要在硬件上加低通滤波,不会搞T_T。
  2. 就算是零点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.1
    20=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);
}