最初来源:https://youtu.be/lrugreN2K4w
这个项目适合测试一些普通设备,虽然可以测手机,但并不建议对手机充电测量,现在市面上的手机需要的充电协议太多了,而且我也不会,不知道怎么整合进去.这里先把方法和结果共享出来,有兴趣的话大家可以试试把充电协议整合进去.
本文例子做的比较适合测量一些比较非主流的负责检查,例如12.6v锂电池充电,笔记本能耗等这些5.5DC插头插座的设备测量,总的来说适合远程或者短暂测量与观测使用.
其中来源视频是可以通过TF卡记录数据的,原品只是个单机版本,也不计算和显示电池容量,这里我使用了BLYNK,所以我是放弃了这个原有TF卡存储数据记录的功能的相关代码段,并加上了电池容量计算和显示,需要的可以点击上面的来源连接.
(点击图片放大)
通过接入blynk后使用手机客户端查看信息的版本,当时的手机是iPhone 6s 电池容量大概是1350 mAh,当时实际充满电后,模块测出大概差不多的容量,精度还算是可以的
(点击图片放大)
这是做成单机版即仅可以现场观察的用量,输入电压已经做成恒流充电的模块,专门用量测试电池容量
关于为啥不发交流版本的教程原因
- 220V带电测试具有危险性
- 新手容易接错线导致意外
- 个人感觉用途不大
具体看下图
(点击图片放大)
图1是在电脑上通过串口测试并观察交流负载电压等信息的图,图3是意外碰线被晒坏的模块
实现功能
- 实时显示电流/电压/功率/已用电量/电池容量(接入blynk后可以异地远程查看)
- 通过OLED屏实施显示(可选,并和远程客户端实时同步显示,OLED的数据延时少一点)
- 数值精确到5位小数
- 可以通过电子邮件地址发送记录数据到手机(需要谷歌邮箱)
演示视频(待审核,占位)
软件环境
- Arduino库(点击进入下载或者在IDE内直接搜索相关关键字下载):
- Blynk(站内搜索Blynk有教程,或者直接去官网看文档)
- Adafruit INA219
- Adafruit SSD1306
材料
名称 | 数量 | 单位 | 备注 |
---|---|---|---|
ESP8266 | 1 | 个 | 最好使用NodeMCU,本文单机版用的是Arduino nano |
INA219电流检测模块 | 1 | 个 | 先看官方资料:https://www.adafruit.com/product/904 |
OLED模块 | 1 | 个 | 0.96寸,SSD1306主控,可以用SPI接口,这里用的是IIC接口 |
负载用电源 | 1 | 个 | 0-26V,0-3.2A |
单片机用电源 | 1 | 个 | 3.3-5v,专门供单片机和模块使用 |
测试用负载 | 1 | 个 | 新手别用手机什么的,烧了你就惨了,先找个5V LED灯板或者风扇当做负载,熟悉了再用手机什么的测试,注意安全,免得烧了你的设备 |
杜邦线 | 若干 | ||
导线 | 若干 | 测试用的0.3平方左右就行,其他功率需要的请看下面补充资料 |
另外,建议手头有一个现成的电量表,以用作参考调整
材料的补充事项
- 不熟练的别用手机之类贵的负载做测试
- 事前记得现在清楚INA219的相关参数,不然过压什么烧东西就不好了
- 关于电源输入/负载的导线选择必须选足够粗的,以免发生烧线之类情况,又或者出现降压之类情况,导线过流的话可是会引起发热甚至起火的哦,详细参考下面公式:
再三强调:操作必须规范!
接线
声明:事前请先确定你自己会使用万用表的电流档测电流再继续下一步,因为INA219上的四个VIN+和VIN-的端口并不是表示输入,而是表示电流的方向,VIN+表示为:电流的输入端,VIN-表示电流的输出端,即VIN+接入负载电源端的VCC,然后VIN-接到负载端的VIN(正极输入).
- 先接电流模块和负载部分
ESP8266 | INA219 | 单片机用电源 (3.3-5V) | 负载用电源 | 负载 |
---|---|---|---|---|
SDA | SDA | |||
SCL | SCL | |||
VCC | VCC | VCC | ||
GND | GND | GND | GND | GND |
VIN+ | VIN+ | |||
VIN- | VIN- |
- 单片机和OLED部分
ESP8266 | OLED | 单片机用电源 (3.3-5V) |
---|---|---|
SDA | SDA | |
SCL | SCL | |
VCC | VCC | VCC |
GND | GND | GND |
代码
这里都是以英文显示的,我就懒得做字库了,没那个精力,有兴趣的朋友可以自己做做字库用中文显示.
单机版
#include <Wire.h>
#include <Adafruit_INA219.h>
#include <Adafruit_SSD1306.h>
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);
Adafruit_INA219 ina219;
unsigned long previousMillis = 0;
unsigned long interval = 100;
const int chipSelect = 10;
float shuntvoltage = 0;
float busvoltage = 0;
float current_mA = 0;
float loadvoltage = 0;
float energy = 0;
float mAh = 0;
void setup() {
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
ina219.begin();
}
void loop() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval)
{
previousMillis = currentMillis;
ina219values();
}
displaydata();
}
void displaydata() {
display.clearDisplay();
display.setTextColor(WHITE);
display.setTextSize(1);
display.setCursor(0, 0);
display.println(loadvoltage, 3);
display.setCursor(35, 0);
display.println("V");
display.setCursor(0, 10);
display.println(current_mA, 1);
display.setCursor(45, 10);
display.println("mA");
display.setCursor(63, 10);
display.println("=");
display.setCursor(75, 10);
display.println(current_mA / 1000, 4);
display.setCursor(120, 10);
display.println("A");
display.setCursor(63, 20);
display.println("=");
display.setCursor(0, 20);
display.println(loadvoltage * current_mA, 1);
display.setCursor(45, 20);
display.println("mW");
display.setCursor(75, 20);
display.println(loadvoltage * current_mA / 1000, 4);
display.setCursor(120, 20);
display.println("W");
display.setCursor(0, 30);
display.println(energy, 5);
display.setCursor(110, 30);
display.println("mWh");
display.setCursor(0, 40);
display.println(mAh, 5);
display.setCursor(110, 40);
display.println("mAh");
display.setTextColor(WHITE);
display.setTextSize(2);
display.setCursor(5, 50);
display.println("PowerMeter");
display.display();
}
void ina219values() {
shuntvoltage = ina219.getShuntVoltage_mV();
busvoltage = ina219.getBusVoltage_V();
current_mA = ina219.getCurrent_mA();
loadvoltage = busvoltage + (shuntvoltage / 1000);
energy = energy + loadvoltage * current_mA / 3600;
mAh = energy / loadvoltage /10;
}
Blynk版
#define BLYNK_PRINT Serial
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include<SPI.h>
#include <Wire.h>
#include <Adafruit_INA219.h>
#include <Adafruit_SSD1306.h>
char auth[] = "你的设备 KEY ";
char ssid[] = "你的 WIFI SSID";
char pass[] = "你的 WIFI 密码";
#define OLED_RESET LED_BUILTIN //4
Adafruit_SSD1306 display(OLED_RESET);
#if (SSD1306_LCDHEIGHT != 64)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif
Adafruit_INA219 ina219;
BlynkTimer timer;
unsigned long previousMillis = 0;
unsigned long interval = 100;
const int chipSelect = D8;
float shuntvoltage = 0;
float busvoltage = 0;
float current_mA = 0;
float loadvoltage = 0;
float energy = 0;
float mAh = 0;
void sendSensor() {
float mW = loadvoltage * current_mA;
Blynk.virtualWrite(V1, loadvoltage);//负载电压
Blynk.virtualWrite(V2, current_mA);//电流
Blynk.virtualWrite(V3, mW);//功率
Blynk.virtualWrite(V4, energy);//电量
Blynk.virtualWrite(V5, mAh);//电池容量
}
void setup() {
Serial.begin(9600);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
ina219.begin();
Blynk.begin(auth, ssid, pass);
timer.setInterval(1000L, sendSensor);
}
void loop() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval)
{
previousMillis = currentMillis;
ina219values();
}
displaydata();
Blynk.run();
timer.run();
}
//OLED显示的自定义函数
void displaydata() {
display.clearDisplay();
display.setTextColor(WHITE);
display.setTextSize(1);
display.setCursor(0, 0);
display.println(loadvoltage, 3);
display.setCursor(35, 0);
display.println("V");
display.setCursor(0, 10);
display.println(current_mA, 1);
display.setCursor(45, 10);
display.println("mA");
display.setCursor(63, 10);
display.println("=");
display.setCursor(75, 10);
display.println(current_mA / 1000, 4);
display.setCursor(120, 10);
display.println("A");
display.setCursor(63, 20);
display.println("=");
display.setCursor(0, 20);
display.println(loadvoltage * current_mA, 1);
display.setCursor(45, 20);
display.println("mW");
display.setCursor(75, 20);
display.println(loadvoltage * current_mA / 1000, 4);
display.setCursor(120, 20);
display.println("W");
display.setCursor(0, 30);
display.println(energy, 5);
display.setCursor(110, 30);
display.println("mWh");
display.setCursor(0, 40);
display.println(mAh, 5);
display.setCursor(110, 40);
display.println("mAh");
//显示一个大大的LOGO
display.setTextColor(WHITE);
display.setTextSize(2);
display.setCursor(5, 50);
display.println("PowerMeter");
display.display();
}
void ina219values() {
shuntvoltage = ina219.getShuntVoltage_mV(); //分流电压
busvoltage = ina219.getBusVoltage_V(); //母线电压
current_mA = ina219.getCurrent_mA(); //电流,单位为毫安
loadvoltage = busvoltage + (shuntvoltage / 1000); //负载电压
energy = energy + loadvoltage * current_mA / 3600; //电能
mAh = energy / loadvoltage / 10; //毫安时
}
补充
- 如果发现数据不太对,请用万用表检查线的降压情况,导线不用太细.
- 导线不建议太长太细,尽量用铜线,不然你要花点时间去把电压调准确.
- 至于曲线图功能,可以开启Blynk APP里头的super chart,服务器端设置好邮箱的话可以把数据发到你邮箱,只是官方文档写的是要求必须谷歌邮箱.
- 如果是Blynk版,那么手机端收到的数值对比OLED端的数值来说,会稍有延迟.
- INA219最大支持监测的电压为直流0-26V,这一点要注意.
- 源代码作者来源里头用的是NANO,可是我亲测是会因为单片机内存空间不足而导致无法编译的,后来改用mega可以.要是你喜欢的话可以直接用ESP8266一个带TF卡记录的单机版 .
- 如果你打算做成可以随时重置WIFI的功能,可以参考我之前做的小时钟的这编文章,可以自己试试在代码里头整合一下,这里我就不再啰嗦了.