本帖最后由 tomy113900173 于 2020-5-11 15:25 编辑
一、方案概述
目前市场上的USB电压电流表很多,但是数据的测量精度和采样频率都是固定的,本着DIY的精神设计了基于BLINKER的无线USB电压电流表,实现电流的精度和采样频率都可调节。 总体方案如下,用ESP8266作为主控芯片,通过IIC跟电压电流传感器INA226进行通信,同时将测量的数据显示在SSD1306上,其中SSD1306通过模拟IIC进行通信,同时将测量的数据通过BLINKER发送到手机APP显示,可以实现远程查看电压、电流、功率、容量。
二、详细方案 2.1电压电流检测 TI INA226是一个具备IIC功能的双向高/低端的电流、功率检测器件,电流检测精度是2.5uV。电路图如右所示,SCL连接到ESP8266的D1,SDA连接到ESP8266的D2,通过设定采样电阻为0.01欧姆则可以检测出1mA的电流。
2.2 SSD1306显示模块 SSD1306通过IO口跟ESP8266的D5、D6连接,用U8G2显示库驱动
2.3程序设计
#define BLINKER_WIFI
#include <Blinker.h>
char auth[] = "9958e36fd79c";
char ssid[] = "TP-LINK_0430";
char pswd[] = "07743935112";
#define Number_1 "BusVoltage"
#define Number_2 "ShuntCurrent"
#define Number_3 "BusPower"
#define Number_4 "CapaPower"
#define Number_5 "BlinkerTime"
BlinkerNumber Number1(Number_1);
BlinkerNumber Number2(Number_2);
BlinkerNumber Number3(Number_3);
BlinkerNumber Number4(Number_4);
BlinkerNumber Number5(Number_5);
/*****************/
#include <Arduino.h>
#include <INA226.h>
#include <U8g2lib.h>
#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif
float BusVoltage ;
float ShuntCurrent ;
float BusPower ;
float CapaPower ;
U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ 14, /* data=*/ 12, /* reset=*/ U8X8_PIN_NONE); // ESP32 Thing, pure SW emulated I2C
INA226 ina;
void checkConfig()
{
Serial.print("Mode: ");
switch (ina.getMode())
{
case INA226_MODE_POWER_DOWN: Serial.println("Power-Down"); break;
case INA226_MODE_SHUNT_TRIG: Serial.println("Shunt Voltage, Triggered"); break;
case INA226_MODE_BUS_TRIG: Serial.println("Bus Voltage, Triggered"); break;
case INA226_MODE_SHUNT_BUS_TRIG: Serial.println("Shunt and Bus, Triggered"); break;
case INA226_MODE_ADC_OFF: Serial.println("ADC Off"); break;
case INA226_MODE_SHUNT_CONT: Serial.println("Shunt Voltage, Continuous"); break;
case INA226_MODE_BUS_CONT: Serial.println("Bus Voltage, Continuous"); break;
case INA226_MODE_SHUNT_BUS_CONT: Serial.println("Shunt and Bus, Continuous"); break;
default: Serial.println("unknown");
}
Serial.print("Samples average: ");
switch (ina.getAverages())
{
case INA226_AVERAGES_1: Serial.println("1 sample"); break;
case INA226_AVERAGES_4: Serial.println("4 samples"); break;
case INA226_AVERAGES_16: Serial.println("16 samples"); break;
case INA226_AVERAGES_64: Serial.println("64 samples"); break;
case INA226_AVERAGES_128: Serial.println("128 samples"); break;
case INA226_AVERAGES_256: Serial.println("256 samples"); break;
case INA226_AVERAGES_512: Serial.println("512 samples"); break;
case INA226_AVERAGES_1024: Serial.println("1024 samples"); break;
default: Serial.println("unknown");
}
Serial.print("Bus conversion time: ");
switch (ina.getBusConversionTime())
{
case INA226_BUS_CONV_TIME_140US: Serial.println("140uS"); break;
case INA226_BUS_CONV_TIME_204US: Serial.println("204uS"); break;
case INA226_BUS_CONV_TIME_332US: Serial.println("332uS"); break;
case INA226_BUS_CONV_TIME_588US: Serial.println("558uS"); break;
case INA226_BUS_CONV_TIME_1100US: Serial.println("1.100ms"); break;
case INA226_BUS_CONV_TIME_2116US: Serial.println("2.116ms"); break;
case INA226_BUS_CONV_TIME_4156US: Serial.println("4.156ms"); break;
case INA226_BUS_CONV_TIME_8244US: Serial.println("8.244ms"); break;
default: Serial.println("unknown");
}
Serial.print("Shunt conversion time: ");
switch (ina.getShuntConversionTime())
{
case INA226_SHUNT_CONV_TIME_140US: Serial.println("140uS"); break;
case INA226_SHUNT_CONV_TIME_204US: Serial.println("204uS"); break;
case INA226_SHUNT_CONV_TIME_332US: Serial.println("332uS"); break;
case INA226_SHUNT_CONV_TIME_588US: Serial.println("558uS"); break;
case INA226_SHUNT_CONV_TIME_1100US: Serial.println("1.100ms"); break;
case INA226_SHUNT_CONV_TIME_2116US: Serial.println("2.116ms"); break;
case INA226_SHUNT_CONV_TIME_4156US: Serial.println("4.156ms"); break;
case INA226_SHUNT_CONV_TIME_8244US: Serial.println("8.244ms"); break;
default: Serial.println("unknown");
}
Serial.print("Max possible current: ");
Serial.print(ina.getMaxPossibleCurrent());
Serial.println(" A");
Serial.print("Max current: ");
Serial.print(ina.getMaxCurrent());
Serial.println(" A");
Serial.print("Max shunt voltage: ");
Serial.print(ina.getMaxShuntVoltage());
Serial.println(" V");
Serial.print("Max power: ");
Serial.print(ina.getMaxPower());
Serial.println(" W");
}
/*****************/
void dataRead(const String & data)
{
BLINKER_LOG("Blinker readString: ", data);
Blinker.vibrate();
uint32_t BlinkerTime = millis();
Blinker.print("V", BusVoltage);
Number1.icon("icon_1");
Number1.color("#FFFFFF");
Number1.unit("mV");
Number1.print(BusVoltage*1000);
Blinker.print("A", ShuntCurrent);
Number2.icon("icon_1");
Number2.color("#FFFFFF");
Number2.unit("mA");
Number2.print(ShuntCurrent*1000);
Blinker.print("W", BusPower);
Number3.icon("icon_1");
Number3.color("#FFFFFF");
Number3.unit("W");
Number3.print(BusPower);
Blinker.print("mAh", CapaPower);
Number4.icon("icon_1");
Number4.color("#FFFFFF");
Number4.unit("mAh");
Number4.print(CapaPower);
Blinker.print("millis", BlinkerTime);
Number5.icon("icon_1");
Number5.color("#FFFFFF");
Number5.unit("minute");
Number5.print(BlinkerTime/1000/60);
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
}
void setup()
{
Serial.begin(115200);
BLINKER_DEBUG.stream(Serial);
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
Blinker.attachData(dataRead);
Blinker.begin(auth, ssid, pswd);
delay(500);
/*****************************************************/
Serial.println("Initialize INA226");
Serial.println("-----------------------------------------------");
// Default INA226 address is 0x40
ina.begin();
// Configure INA226
ina.configure(INA226_AVERAGES_128, INA226_BUS_CONV_TIME_1100US, INA226_SHUNT_CONV_TIME_1100US, INA226_MODE_SHUNT_BUS_CONT);
// Calibrate INA226. Rshunt = 0.01 ohm, Max excepted current = 4A
ina.calibrate(0.01, 3);
// Display configuration
checkConfig();
Serial.println("-----------------------------------------------");
u8g2.begin();
u8g2.setFont(u8g2_font_ncenB14_tf ); // choose a suitable font
/*****************************************************/
}
void loop()
{
Blinker.run();
/******************************************/
static unsigned long time1 = millis();
static unsigned long time3 = millis();
static unsigned long time2 = 0, time4 = 0;
time2 = millis();
if ((time2 - time1) >= 10)//10m测量一次参数,并进行容量测量
{
BusVoltage = ina.readBusVoltage();
ShuntCurrent = ina.readShuntCurrent();
BusPower = ina.readBusPower();
CapaPower + = ShuntCurrent * (time2 - time1) / 3600;
time1 = time2;
}
time4 = millis();
if ((time4 - time3) >= 500)//50mS刷新一次SSD1306
{
time3 = time4;
u8g2.clearBuffer(); // clear the internal memory
u8g2.setCursor(108, 14);
u8g2.print(" V");
u8g2.setCursor(113, 30);
u8g2.print("A");
u8g2.setCursor(110, 46);
u8g2.print("W");
u8g2.setCursor(83, 64);
u8g2.print("mAh");
u8g2.setCursor(0, 14);
u8g2.print(BusVoltage, 3);
u8g2.setCursor(0, 30);
u8g2.print(ShuntCurrent, 3);
u8g2.setCursor(0, 46);
u8g2.print(BusPower, 3);
u8g2.setCursor(0, 64);
u8g2.print(CapaPower);
u8g2.sendBuffer();
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
}
}
2.4调试
串口结果如下面所示证明esp8266已经跟INA226通信成功而且已经连接上网络了,网址是192.168.1.103,good news!!!
再看看SSD1306显示,good news again!因为显示屏尺寸比较小,现在只显示了电压、电流、功率、容量这几个参数,后面再考虑分屏显示!!!目前看到的这个图片内容是USB风扇作为负载的数据!!!
2.5 手机APP设计
打开“点灯BLINKER”app,简单几个拖拽就可以设计好符合自己的APP了,这点要为点灯科技点32个赞:D :D :D
我的这个界面显示接单了点,没有做优化~~~,点击一下刷新一下数据,比SSD1306显示的内容多了一个运行的时间!!!
三、未来展望
到目前为止,已基本完成了本项目的设定目标了!!!
但是我们要不断前进!前进!前进!
后面再考虑给这个项目添加新能的功能,比如加大数据采集的频率,然后再讲数据保存到U盘或者SD卡,就是一个简单的数据记录仪了!
好吧,YY太多了,到这里为止吧!!!
PS:INA226的驱动我也是网上找的,忘了在哪里下载了,对于原作者说声SORRY!!!
另外可以调节到采样电阻可以实现采样微安级别的电流,有需要的可以自行调节!!!
电流和容量的精度也不做保证,误差肯定有的,因为采样电阻也是有一定的误差的!!!
|