风筝
发表于: 2020-12-17 10:35:13 | 显示全部楼层

我们都知道基本的电压表、电流表和功率表,这是测量任何电子项目或电路上的值所需的三个基本设备。借助万用表测量电压和电流是一个很好的方法,但是我在测试电路时面临的最大问题之一就是测量电源效率。因此,今天我们将通过搭建一个基于Arduino和ESP32的功率计来解决该问题,该功率计可以测量输入电压、输入电流、输出电压和输出电流。因此,它可以同时测量输入功率和输出功率,利用这些值,我们可以轻松地测量效率。


搭建数字表不仅可以降低成本,而且还为您提供了升级和改进的空间。由于我们使用ESP32来构建此项目,因此我们可以轻松地使此仪表具有IoT功能并通过Web记录数据,现在让我们开始吧。


ESP32功率计所需的材料

下图显示了用于构建电路的材料。由于这是由非常通用的组件组成的。

ESP32-Based-Efficiency-meter-Components.jpg


我还列出了以下组件以及所需数量。如果您自己构建电路,强烈建议从下面的列表中所有材料。

●    ESP32开发板-1

●    128X64 OLED-1

●    ACS712-20 IC-2

●    DC电源插头-1

●    100uF电容-2

●    104pF电容-2

●    102pF电容-2

●    10K,1%-4

●    68K,1%-2

●    6.8K,1%-2


基于Arduino和ESP32的功率计 - 电路图

基于Arduino和ESP32的功率计的原理图如下所示。创建此电路非常简单,使用通用组件。

ESP32-Based-Efficiency-meter-Circuit-Diagram.png


电路的操作非常简单。我们将以一种独特的方式来测量该项目中的电压和电流。我们同时测量输入和输出的电压和电流,因此我们可以实时看到电路的效率。对于某些项目,这非常方便。这些电路的工作方式如下所述。


ACS712电流传感器

ACS712-Current-Sensor-IC.png

如上图所示,我们使用ACS712电流传感器来测量电流。这是一个非常有趣的IC,因为它使用霍尔效应来测量电流。我们使用的是20A的型号,具体为ACS712-20。


ACS712数据表建议在4.5-5.5的电压范围内正常运行。当我们使用ESP32测量电流时,它只能承受3.3V的电压,这就是为什么我使用带有两个10K电阻的分压器来降低ACS712 IC的输出电压的原因。当没有电流流过IC时,它会输出2.5V,而当有电流流过IC时,它会根据电流的流向降低电压或提高电压。


分压电路

Voltage-Divider.png

为了测量输入和输出电压,我们在电路的输入和输出侧有两个分压器。该电路可以测量的最大电压为35V,但可以通过更改分压器的电阻值轻松地对其进行更改。


稳压器

Voltage-Regulator.png

使用通用LM7805稳压器为ESP32、OLED和ACS712 IC供电。当我们使用非常干净的电源为其供电时,可以不使用任何去耦电容器,但我们在输入和输出端均使用了100uF电容来稳定IC。


ESP32 IC和OLED显示屏

ESP32-IC-with-OLED.png

我们使用ESP32作为主处理器,负责所有的读数、计算、输入和输出。另外,我们使用了128X64 OLED显示屏来显示这些值。


基于Arduino和ESP32的功率计的PCB设计

我们的基于Arduino和ESP32的效率计的PCB设计在单面板上。使用Eagle来设计PCB,但是您可以使用任何选择的设计软件。电路板设计的2D图像如下所示。

ESP32-Based-Efficiency-Meter-PCB.png


足够的接地线用于在所有组件之间进行正确的接地连接。此外,我们确保使用正确的5V和3.3V走线以减少噪声并提高效率。


Arduino代码

现在,我们对硬件方面有了很好的了解之后,可以打开Arduino IDE并开始编写代码。该代码的目的是从ESP32开封板的引脚35和33读取模拟电压。另外,我们从32引脚读取电压和34引脚读取电流值。完成此操作后,我们可以将它们相乘以获得输入功率和输出功率,并将其放在效率公式中,就可以得出效率。最后,我们将其显示在LCD屏幕上。


由于我们使用的是128X64 OLED显示器,因此我们需要Adafruit_GFX库和Adafruit_SSD1306库与显示屏进行通信。您可以从Arduino的默认板管理器中下载;也可以从与其关联的GitHub存储库中下载并包含库,如下所示。

●    下载Adafruit_GFX库

●    下载Adafruit_SSD1306库


与往常一样,首先我们包含所有必需的库。然后,我们定义所有的引脚和变量,如下所示。

  1. #include <Wire.h>
  2. #include <Adafruit_GFX.h>
  3. #include <Adafruit_SSD1306.h>
  4. #include <math.h>
  5. #define SCREEN_WIDTH 128 // OLED display width, in pixels
  6. #define SCREEN_HEIGHT 64 // OLED display height, in pixels
  7. #define INPUT_VOLTAGE_SENSE_PIN 33
  8. #define OUTPUT_VOLTAGE_SENSE_PIN 35
  9. #define INPUT_CURRENT_SENSE_PIN 32
  10. #define OUTPUT_CURRENT_SENSE_PIN 34
  11. double  R1_VOLTAGE = 68000; //68K
  12. double  R2_VOLTAGE = 6800; // 6.8K
  13. double  R1_Current 10000 //10K
  14. double  R2_Current 22000 //22K
  15. //We have used 50 as mVperp value; please refer to the documentation for further information
  16. double mVperAmp = 50; // use 100 for 20A Module and 66 for 30A Module
  17. double ACSoffset = /*1130*/ 1136;
  18. // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
  19. Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
复制代码

SCREEN_WIDTH和SCREEN_HEIGHT定义用于定义屏幕尺寸。接下来,我们定义了所有必需的引脚,通过这些引脚我们将测量电压和电流。接下来,我们定义了电阻值,这些电阻值在硬件中使用,如从原理图中可以看到的。如果您没有这些值,或者想要更改仪表的范围,则可以更改这些值,代码就可以正常工作。


当我们使用ACS712测量电流时,我们需要mVperAmp值来根据电压计算电流。当我使用20A ACS712模块时,数据表中给出的mV / A值为100。但是由于使用的是ESP32和分压器,因此只有一半的值(即50)。


ACSoffset是从电压计算电流所需的偏移量。由于ACS712 IC由5V供电,因此偏移电压为2.5V。但是,当我们使用分压器时,它会降至1.25V。如果遇到校准问题,可以调整这些值并补偿ADC。


最后,我们使用Adafruit_SSD1306类创建一个显示对象,并传递屏幕宽度、高度、I2C配置和最后一个-1参数来定义函数。如果您的显示屏没有外部复位引脚,那么最后一个参数必须使用-1。

  1. void setup() {
  2.   Serial.begin(115200);
  3.   if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
  4.     Serial.println(F("SSD1306 allocation failed"));
  5.     for (;;);
  6.   }
  7.   display.clearDisplay();
  8.   display.setRotation(2);
  9.   display.setTextSize(1);
  10.   delay(100);
  11. }
复制代码

接下来,我们介绍setup()部分。在本节中,我们将启用串行调试功能,并借助显示对象的begin方法来检查I2C显示是否可用。另外,我们设置I2C地址。接下来,我们使用clearDisplay()清除显示内容。另外,我们使用setRotation函数旋转显示屏。接下来,我们为使函数生效设置了100 ms的延迟。完成后,我们现在可以继续loop函数。但是在这之前,我们需要讨论另外两个函数,分别是return_voltage_value()return_current_value()

  1. double return_voltage_value(int pin_no)
  2. {
  3.   double tmp = 0;
  4.   double ADCVoltage = 0;
  5.   double inputVoltage = 0;
  6.   double avg = 0;
  7.   for (int i = 0; i < 150; i++)
  8.   {
  9.     tmp = tmp + analogRead(pin_no);
  10.   }
  11.   avg = tmp / 150;
  12.   ADCVoltage = ((avg * 3.3) / (4095)) + 0.138;
  13.   inputVoltage = ADCVoltage / (R2_VOLTAGE / (R1_VOLTAGE + R2_VOLTAGE)); // formula for calculating voltage in i.e. GND
  14.   return inputVoltage;
  15. }
复制代码

return_voltage_value()函数用于测量进入ADC的电压,它以引脚编号作为参数。在此函数中,我们首先声明一些变量,它们是tmp、ADCVoltage、inputVoltage和avg。 tmp变量用于存储从analogRead()函数获得的临时ADC值,然后在for循环中将其取平均值150次,然后将该值存储到一个称为avg的变量中。然后,根据给定的公式计算ADCVoltage,最后,计算输入电压并返回值。您看到的+0.138值是我用来校准电压电平的校准值。

  1. double return_current_value(int pin_no)
  2. {
  3.   double tmp = 0;
  4.   double avg = 0;
  5.   double ADCVoltage = 0;
  6.   double Amps = 0;
  7.   for (int z = 0; z < 150; z++)
  8.   {
  9.     tmp = tmp + analogRead(pin_no);
  10.   }
  11.   avg = tmp / 150;
  12.   ADCVoltage = ((avg / 4095.0) * 3300); // Gets you mV
  13.   Amps = ((ADCVoltage - ACSoffset) / mVperAmp);
  14.   return Amps;
  15. }
复制代码

接下来,我们介绍return_current_value()函数。此函数也使用引脚编号作为参数。在该函数中,我们还有四个变量viz、tmp、avg、ADCVoltage和Amps。接下来,我们使用analogRead()函数读取该引脚并将其取平均值150次,然后使用公式计算ADC电压,然后计算电流并返回该值。


  1. void loop()
  2. {  
  3.   float input_voltage = abs(return_voltage_value(INPUT_VOLTAGE_SENSE_PIN)) ;
  4.   float input_current = abs(return_current_value(INPUT_CURRENT_SENSE_PIN)) ;
  5.   float output_voltage = abs(return_voltage_value(OUTPUT_VOLTAGE_SENSE_PIN)) ;
  6.   float output_current =  abs((return_current_value(OUTPUT_CURRENT_SENSE_PIN))) ;
  7.   input_current = input_current - 0.025;
  8.   Serial.print("Input Voltage: ");
  9.   Serial.print(input_voltage);
  10.   Serial.print(" | Input Current: ");
  11.   Serial.print(input_current);
  12.   Serial.print(" | Output Voltage: ");
  13.   Serial.print(output_voltage);
  14.   Serial.print(" | Output Current: ");
  15.   Serial.println(output_current);
  16.   delay(300);
  17.   display.clearDisplay();
  18.   display.setCursor(0, 0);
  19.   display.print("I/P V: ");
  20.   display.setCursor(37, 0);
  21.   display.print(input_voltage);
  22.   display.setCursor(70, 0);
  23.   display.print("V");
  24. }
复制代码

首先我们声明并定义4个float变量。我们调用相应的函数,将引脚编号作为参数传递,因为ACS712模块可以返回负的当前值。我们使用数学库的abs()函数将负值设为正。接下来,我们串口打印所有值以进行调试。接下来,我们清除显示、设置光标,然后打印值。


测试基于Arduino和ESP32的功率计

ESP32-Based-Efficiency-Meter-Testing.jpg


您可以在上图中看到我的测试设置。我将30V变压器作为输入,并将仪表连接到测试板。我使用的是基于LM2596的降压转换器板,并且用于负载,并且使用了三个并联的10欧姆电阻。

ESP32-Based-Efficiency-Meter-Working.jpg


如上图所示,我已连接到万用表以检查输入和输出电压。变压器产生大约32V的电压,降压转换器的输出为3.95V。

Working-of-ESP32-Based-Efficiency-Meter.jpg


上图显示了由功率计和万用表测得的输出电流。万用表显示为0.97安培,这是由于ACS712模块中存在非线性而略有偏离,但这符合我们的目的。


希望您喜欢本文并从中学到新东西。如有任何疑问,请随时在本贴下面进行回复。

跳转到指定楼层
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

主题 54 | 回复: 107



手机版|

GMT+8, 2024-3-29 23:46 , Processed in 0.103162 second(s), 6 queries , Gzip On, MemCache On. Powered by Discuz! X3.5

YiBoard一板网 © 2015-2022 地址:河北省石家庄市长安区高营大街 ( 冀ICP备18020117号 )

快速回复 返回顶部 返回列表