/* SFF Minilab PDU Project Current Sensing & Display Driver Board Author: tobychui */ #include #include #include /* 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); }