minilab-pdu.ino 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. /*
  2. SFF Minilab PDU Project
  3. Current Sensing & Display Driver Board
  4. Author: tobychui
  5. */
  6. #include <Wire.h>
  7. #include <Adafruit_GFX.h>
  8. #include <Adafruit_SSD1306.h>
  9. /* Hardware Pin Definations */
  10. #define SDA 23 //0.91 inch OLED SDA pin
  11. #define SCK 19 //0.91 inch OLED SCK pin
  12. #define I_sense_A 32
  13. #define I_sense_B 33
  14. #define I_sense_C 34
  15. #define I_sense_D 35
  16. #define ZERO_CURRENT_V 2.55 //Calibrated voltage of no current flow
  17. #define OLED_ADDR 0x3C
  18. #define SCREEN_WIDTH 128
  19. #define SCREEN_HEIGHT 32
  20. // Create display object
  21. Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
  22. // Number of current samples
  23. #define NUM_SAMPLES 10
  24. const float Rt = 5100.0; // top resistor (ohms)
  25. const float Rb = 10000.0; // bottom resistor (ohms)
  26. // --- Utility functions ---
  27. String formatUptime(unsigned long ms) {
  28. unsigned long totalSec = ms / 1000;
  29. unsigned int days = totalSec / 86400;
  30. totalSec %= 86400;
  31. unsigned int hours = totalSec / 3600;
  32. totalSec %= 3600;
  33. unsigned int minutes = totalSec / 60;
  34. unsigned int seconds = totalSec % 60;
  35. char buf[32];
  36. if (days > 0) {
  37. snprintf(buf, sizeof(buf), "%dd %02dh", days, hours);
  38. } else if (hours > 0) {
  39. snprintf(buf, sizeof(buf), "%02dh %02dm", hours, minutes);
  40. } else if (minutes > 0) {
  41. snprintf(buf, sizeof(buf), "%02dm %02ds", minutes, seconds);
  42. } else {
  43. snprintf(buf, sizeof(buf), "%ds", seconds);
  44. }
  45. return String(buf);
  46. }
  47. void clear_display() {
  48. display.clearDisplay();
  49. display.display();
  50. }
  51. void print_text(const char* text, int x = 0, int y = 0, int size = 1) {
  52. display.clearDisplay();
  53. display.setTextSize(size);
  54. display.setTextColor(SSD1306_WHITE);
  55. display.setCursor(x, y);
  56. display.println(text);
  57. display.display();
  58. }
  59. void setup() {
  60. Serial.begin(115200);
  61. //ADC_11db set ADC to ~0–3.3 V range
  62. analogSetPinAttenuation(I_sense_A, ADC_11db);
  63. analogSetPinAttenuation(I_sense_B, ADC_11db);
  64. analogSetPinAttenuation(I_sense_C, ADC_11db);
  65. analogSetPinAttenuation(I_sense_D, ADC_11db);
  66. // Init I2C
  67. Wire.begin(SDA, SCK);
  68. // Init OLED
  69. if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
  70. Serial.println(F("SSD1306 allocation failed"));
  71. for (;;); // Don’t proceed, loop forever
  72. }
  73. clear_display();
  74. print_text("imuslab prototype", 0, 0, 1);
  75. delay(2000);
  76. }
  77. // get_current_sensor_voltage() gets the sensor raw output voltage from the given pin number
  78. // The sensor output is passed through a voltage divider of 5.1k - 10k that
  79. // convert the 5V signal output of ACS712 to 3.3v logic level readable by ESP32 3.3v ADC
  80. float get_current_sensor_voltage(int pin_number) {
  81. long sum_mV = 0;
  82. // take multiple samples
  83. for (int i = 0; i < NUM_SAMPLES; i++) {
  84. sum_mV += analogReadMilliVolts(pin_number);
  85. delayMicroseconds(200); // short delay to stabilize readings
  86. }
  87. // average the readings
  88. int avg_mV = sum_mV / NUM_SAMPLES;
  89. // Convert to float volts
  90. float vout = avg_mV / 1000.0f;
  91. // Reconstruct original pre-divider voltage
  92. float vin = vout * (Rt + Rb) / Rb;
  93. //Serial.printf("Pin %d -> Vout=%.3f V Vin=%.3f V\n", pin_number, vout, vin);
  94. return vin;
  95. }
  96. // get_current_from_voltage_reading() gets the actual current
  97. // flowing throught the current sensor given the voltage read
  98. // from ESP32 ADC pins
  99. float get_current_from_voltage_reading(float voltage) {
  100. const float sensitivity = 0.100; // V/A for ACS712-20A
  101. float current = (voltage - ZERO_CURRENT_V) / sensitivity;
  102. return current;
  103. }
  104. void loop() {
  105. float vinA = get_current_sensor_voltage(I_sense_A);
  106. float vinB = get_current_sensor_voltage(I_sense_B);
  107. float vinC = get_current_sensor_voltage(I_sense_C);
  108. float vinD = get_current_sensor_voltage(I_sense_D);
  109. float curA = get_current_from_voltage_reading(vinA);
  110. float curB = get_current_from_voltage_reading(vinB);
  111. float curC = get_current_from_voltage_reading(vinC);
  112. float curD = get_current_from_voltage_reading(vinD);
  113. // Keep current reading above 0
  114. curA = (curA < 0.0) ? 0.0 : curA;
  115. curB = (curB < 0.0) ? 0.0 : curB;
  116. curC = (curC < 0.0) ? 0.0 : curC;
  117. curD = (curD < 0.0) ? 0.0 : curD;
  118. display.clearDisplay();
  119. display.setTextSize(1);
  120. display.setTextColor(SSD1306_WHITE);
  121. display.setCursor(0, 0);
  122. display.printf("A: %.2fA", curA);
  123. display.setCursor(64, 0);
  124. display.printf("B: %.2fA", curB);
  125. display.setCursor(0, 12);
  126. display.printf("C: %.2fA", curC);
  127. display.setCursor(64, 12);
  128. display.printf("D: %.2fA", curD);
  129. display.setCursor(0, 24);
  130. display.print("Uptime: ");
  131. display.print(formatUptime(millis()));
  132. display.display();
  133. // --- JSON printout ---
  134. Serial.printf(
  135. "{"
  136. "\"voltage\":{"
  137. "\"A\":%.3f,"
  138. "\"B\":%.3f,"
  139. "\"C\":%.3f,"
  140. "\"D\":%.3f"
  141. "},"
  142. "\"current\":{"
  143. "\"A\":%.3f,"
  144. "\"B\":%.3f,"
  145. "\"C\":%.3f,"
  146. "\"D\":%.3f"
  147. "},"
  148. "\"uptime\":%lu"
  149. "}\n",
  150. vinA, vinB, vinC, vinD,
  151. curA, curB, curC, curD,
  152. millis() / 1000 // uptime in seconds
  153. );
  154. delay(100);
  155. }