123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- /*
- SFF Minilab PDU Project
- Current Sensing & Display Driver Board
- Author: tobychui
- */
- #include <Wire.h>
- #include <Adafruit_GFX.h>
- #include <Adafruit_SSD1306.h>
- /* Hardware Pin Definations */
- #define SDA 23 //0.91 inch OLED SDA pin
- #define SCK 19 //0.91 inch OLED SCK pin
- #define I_sense_A 32
- #define I_sense_B 33
- #define I_sense_C 34
- #define I_sense_D 35
- #define ZERO_CURRENT_V 2.55 //Calibrated voltage of no current flow
- #define OLED_ADDR 0x3C
- #define SCREEN_WIDTH 128
- #define SCREEN_HEIGHT 32
- // Create display object
- Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
- // Number of current samples
- #define NUM_SAMPLES 10
- const float Rt = 5100.0; // top resistor (ohms)
- const float Rb = 10000.0; // bottom resistor (ohms)
- // --- Utility functions ---
- String formatUptime(unsigned long ms) {
- unsigned long totalSec = ms / 1000;
- unsigned int days = totalSec / 86400;
- totalSec %= 86400;
- unsigned int hours = totalSec / 3600;
- totalSec %= 3600;
- unsigned int minutes = totalSec / 60;
- unsigned int seconds = totalSec % 60;
- char buf[32];
- if (days > 0) {
- snprintf(buf, sizeof(buf), "%dd %02dh", days, hours);
- } else if (hours > 0) {
- snprintf(buf, sizeof(buf), "%02dh %02dm", hours, minutes);
- } else if (minutes > 0) {
- snprintf(buf, sizeof(buf), "%02dm %02ds", minutes, seconds);
- } else {
- snprintf(buf, sizeof(buf), "%ds", seconds);
- }
- return String(buf);
- }
- void clear_display() {
- display.clearDisplay();
- display.display();
- }
- void print_text(const char* text, int x = 0, int y = 0, int size = 1) {
- display.clearDisplay();
- display.setTextSize(size);
- display.setTextColor(SSD1306_WHITE);
- display.setCursor(x, y);
- display.println(text);
- display.display();
- }
- void setup() {
- Serial.begin(115200);
- //ADC_11db set ADC to ~0–3.3 V range
- analogSetPinAttenuation(I_sense_A, ADC_11db);
- analogSetPinAttenuation(I_sense_B, ADC_11db);
- analogSetPinAttenuation(I_sense_C, ADC_11db);
- analogSetPinAttenuation(I_sense_D, ADC_11db);
- // Init I2C
- Wire.begin(SDA, SCK);
- // Init OLED
- if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
- Serial.println(F("SSD1306 allocation failed"));
- for (;;); // Don’t proceed, loop forever
- }
- clear_display();
- print_text("imuslab prototype", 0, 0, 1);
- delay(2000);
- }
- // get_current_sensor_voltage() gets the sensor raw output voltage from the given pin number
- // The sensor output is passed through a voltage divider of 5.1k - 10k that
- // convert the 5V signal output of ACS712 to 3.3v logic level readable by ESP32 3.3v ADC
- float get_current_sensor_voltage(int pin_number) {
- long sum_mV = 0;
- // take multiple samples
- for (int i = 0; i < NUM_SAMPLES; i++) {
- sum_mV += analogReadMilliVolts(pin_number);
- delayMicroseconds(200); // short delay to stabilize readings
- }
- // average the readings
- int avg_mV = sum_mV / NUM_SAMPLES;
- // Convert to float volts
- float vout = avg_mV / 1000.0f;
- // Reconstruct original pre-divider voltage
- float vin = vout * (Rt + Rb) / Rb;
- //Serial.printf("Pin %d -> Vout=%.3f V Vin=%.3f V\n", pin_number, vout, vin);
- return vin;
- }
- // get_current_from_voltage_reading() gets the actual current
- // flowing throught the current sensor given the voltage read
- // from ESP32 ADC pins
- float get_current_from_voltage_reading(float voltage) {
- const float sensitivity = 0.100; // V/A for ACS712-20A
- float current = (voltage - ZERO_CURRENT_V) / sensitivity;
- return current;
- }
- void loop() {
- float vinA = get_current_sensor_voltage(I_sense_A);
- float vinB = get_current_sensor_voltage(I_sense_B);
- float vinC = get_current_sensor_voltage(I_sense_C);
- float vinD = get_current_sensor_voltage(I_sense_D);
- float curA = get_current_from_voltage_reading(vinA);
- float curB = get_current_from_voltage_reading(vinB);
- float curC = get_current_from_voltage_reading(vinC);
- float curD = get_current_from_voltage_reading(vinD);
- // Keep current reading above 0
- curA = (curA < 0.0) ? 0.0 : curA;
- curB = (curB < 0.0) ? 0.0 : curB;
- curC = (curC < 0.0) ? 0.0 : curC;
- curD = (curD < 0.0) ? 0.0 : curD;
- display.clearDisplay();
- display.setTextSize(1);
- display.setTextColor(SSD1306_WHITE);
- display.setCursor(0, 0);
- display.printf("A: %.2fA", curA);
- display.setCursor(64, 0);
- display.printf("B: %.2fA", curB);
- display.setCursor(0, 12);
- display.printf("C: %.2fA", curC);
- display.setCursor(64, 12);
- display.printf("D: %.2fA", curD);
- display.setCursor(0, 24);
- display.print("Uptime: ");
- display.print(formatUptime(millis()));
- display.display();
- // --- JSON printout ---
- Serial.printf(
- "{"
- "\"voltage\":{"
- "\"A\":%.3f,"
- "\"B\":%.3f,"
- "\"C\":%.3f,"
- "\"D\":%.3f"
- "},"
- "\"current\":{"
- "\"A\":%.3f,"
- "\"B\":%.3f,"
- "\"C\":%.3f,"
- "\"D\":%.3f"
- "},"
- "\"uptime\":%lu"
- "}\n",
- vinA, vinB, vinC, vinD,
- curA, curB, curC, curD,
- millis() / 1000 // uptime in seconds
- );
- delay(100);
- }
|