Advertisement
learnelectronics

Mike P's Power Logger

Aug 14th, 2018
483
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 13.25 KB | None | 0 0
  1. /*
  2.  * Written by M. Padovani in Jan 2018, adapting Arduino Mega Sketch for the ESP32 with additional features
  3.  * Monitor high side voltage/current/power via TWO INA219, TWO OLED, LEDs, and SD card reader
  4.  * One INA219 (0x40) will be to measure up to 32V/2000mA while the second (0x41) will measure up to 16V/400mA
  5.  * One OLED (0x3C) will display VCP while the second (0x3D) will display the refresh interval
  6.  * Refresh interval will be determined from feedback via a Pot connected to A2
  7.  * Refresh interval will range from "0ms" (as fast as the program will run, which is ~140ms) to 60000ms
  8.  * See "SGS3_VCP_allTimers.xls" for more details concerning timing
  9.  * Recommend resisitor values: 220 Red, 220 Green, 220 Blue (3.3V supply)
  10.  * Serial Print has been omitted (not needed) to increase speed of sketch
  11.  * SD card file is "VCP.txt" (Voltage, Current, Power)
  12.  * Can log data as CSV to Serial Monitor as well (currently commented out)
  13.  * Sketch uses 304655 bytes (23%) program space, 29232 bytes (9%) dynamic memory  
  14. */
  15.  
  16. #include <Wire.h>
  17. #include <Adafruit_INA219.h>
  18. #include <Adafruit_SSD1306.h>
  19. #include <SPI.h>
  20. #include "SdFat.h"
  21. SdFat SD;
  22.  
  23. #define OLED_RESET 4
  24. Adafruit_SSD1306 VCP_display(OLED_RESET);  //displays Voltage(V), Current(mA), and Power(mW)
  25. Adafruit_SSD1306 Refresh_display(OLED_RESET);  //displayed refresh interval(ms)
  26.  
  27. Adafruit_INA219 ina219_A(0x40);  //on red sense LED pin, 32V/2000mA, default address
  28. Adafruit_INA219 ina219_B(0x41);  //on blue sense LED pin, 16V/400mA
  29.  
  30. #define red1_pin 14  //GPIO 14
  31. #define green1_pin 33  //GPIO 33
  32. #define blue1_pin 15  //GPIO 27
  33. #define red2_sensePin 27  //GPIO 27
  34. #define blue2_sensePin 21  //GPIO 21
  35. #define refresh_PotPin A2
  36. #define white1_pin 13  //GPIO 13
  37. #define white2_sensePin A5  //A5 or GPIO 4
  38.  
  39. int bluePinState;  //holds value of blue button state (0 or 1 / LOW or HIGH)
  40. int redPinState;  //holds value of red button state (0 or 1 / LOW or HIGH)
  41.  
  42. //Timer function
  43.   unsigned long currentMillis;  //subtract out so the program updates at 250ms
  44.   unsigned long previousMillis = 0;
  45.   unsigned long refreshInterval;  //depends on Pot value on A2
  46.  
  47. //SPI SD Card Pins
  48.   int SDpin = 32;  //SD card cs pin
  49.  
  50. //Store ID # of data record
  51.   unsigned long id = 1;
  52.  
  53. //Create files to store on SD card  
  54.   File VolCurPowFile;
  55.  
  56. //Variables needed to get refresh interval
  57.   int refreshValue;
  58.   int newPotValue;  //depends on Pot value on A2
  59.   int previousPotValue = 0;
  60.   int rawRefreshValue;  //raw analogRead on A2
  61.   int refreshRate;
  62.  
  63.  
  64. void setup() {
  65.  
  66.   Serial.begin(115200);
  67.  
  68.   pinMode(red1_pin, OUTPUT);
  69.   pinMode(green1_pin, OUTPUT);
  70.   pinMode(blue1_pin, OUTPUT);
  71.   pinMode(red2_sensePin, INPUT);
  72.   pinMode(blue2_sensePin, INPUT);
  73.   digitalWrite(red1_pin, LOW);
  74.   digitalWrite(green1_pin, LOW);
  75.   digitalWrite(blue1_pin, LOW);
  76.   pinMode(white1_pin, OUTPUT);
  77.   pinMode(white2_sensePin, INPUT);
  78.   digitalWrite(white1_pin, LOW);
  79.  
  80.   VCP_display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  81.   VCP_display.clearDisplay();
  82.   VCP_display.display();
  83.   Refresh_display.begin(SSD1306_SWITCHCAPVCC, 0x3D);
  84.   Refresh_display.clearDisplay();
  85.   Refresh_display.display();
  86.  
  87.   pinMode(SDpin, OUTPUT);  //defined as global variable, set as output
  88.   SD.begin(SDpin);
  89.  
  90.   uint32_t currentFrequency;
  91.   ina219_A.begin();
  92.   ina219_B.begin();
  93.  
  94.   /*********** NOT USED -- DID NOT SHOW A NOTICABLE DIFFERENCE COMPARED TO 32V/2A ***********/
  95.   //ina219.setCalibration_32V_1A();
  96.  
  97.   ina219_A.setCalibration_32V_2A();  //red LED
  98.   ina219_B.setCalibration_16V_400mA();  //blue LED
  99.  
  100.   Serial.println("Time(ms),Gain(mA),id(#),BusVolt(V),ShuntVolt(mV),LoadVolt(V),Current(mA),LoadPower(mW)");
  101.   VolCurPowFile = SD.open("VCP.txt",FILE_WRITE);
  102.     if (VolCurPowFile) {
  103.       VolCurPowFile.println("Time(ms),Gain(mA),id(#),BusVolt(V),ShuntVolt(mV),LoadVolt(V),Current(mA),LoadPower(mW)");
  104.       VolCurPowFile.close();
  105.     }
  106.  
  107.   /*********** GET THE REFRESH RATE FROM POT CONNECTED TO A2 ***********/
  108.   getRefreshRate();
  109.  
  110.   refreshRateDisplay();
  111.  
  112. }
  113.  
  114.  
  115. void loop() {
  116.  
  117.   /******* ZERO CLOCK STARTS HERE *******/
  118.   currentMillis = millis();
  119.  
  120.   //set variable refresh rate (0ms to 60000ms).  0ms will go as fast as the program can run.
  121.   if (currentMillis - previousMillis >= refreshInterval) {
  122.  
  123.     /***** SAVE THE "CURRENT" TIME *****/
  124.     previousMillis = currentMillis;
  125.    
  126.     /***** SAVE THE STATE OF THE RED AND BLUE LED *****/
  127.     redPinState = digitalRead(red2_sensePin);
  128.     bluePinState = digitalRead(blue2_sensePin);
  129.        
  130.     /***** CHECK STATE OF RED LED AND CALCULATE VIA 36V/2000mA *****/
  131.     if (redPinState == HIGH && bluePinState == LOW) {
  132.    
  133.       digitalWrite(red1_pin, HIGH);
  134.       digitalWrite(blue1_pin, LOW);
  135.      
  136.       float shuntvoltage = 0;
  137.       float busvoltage = 0;
  138.       float current_mA = 0;
  139.       float loadvoltage = 0;
  140.       float loadpower = 0;
  141.    
  142.       shuntvoltage = ina219_A.getShuntVoltage_mV();
  143.       busvoltage = ina219_A.getBusVoltage_V();
  144.       current_mA = ina219_A.getCurrent_mA();
  145.       loadvoltage = busvoltage + (shuntvoltage / 1000);
  146.       loadpower = ((loadvoltage)*(current_mA/1000))*1000;
  147.  
  148.     /****** SERIAL PRINT NOT NEEDED *******/
  149. //    Serial.print(currentMillis);
  150. //    Serial.print(',');
  151. //    Serial.print("32V_2000mA");
  152. //    Serial.print(',');
  153. //    Serial.print(id);
  154. //    Serial.print(',');
  155. //    Serial.print(busvoltage);
  156. //    Serial.print(',');
  157. //    Serial.print(shuntvoltage);
  158. //    Serial.print(',');
  159. //    Serial.print(loadvoltage);
  160. //    Serial.print(',');
  161. //    Serial.print(current_mA);
  162. //    Serial.print(',');
  163. //    Serial.println(loadpower);
  164.  
  165.       VolCurPowFile = SD.open("VCP.txt",FILE_WRITE);
  166.         if (VolCurPowFile) {
  167.             digitalWrite(green1_pin, HIGH);
  168.             VolCurPowFile.print(currentMillis);
  169.             VolCurPowFile.print(',');
  170.             VolCurPowFile.print("32V_2000mA");
  171.             VolCurPowFile.print(',');
  172.             VolCurPowFile.print(id++);
  173.             VolCurPowFile.print(',');
  174.             VolCurPowFile.print(busvoltage);
  175.             VolCurPowFile.print(',');
  176.             VolCurPowFile.print(shuntvoltage);
  177.             VolCurPowFile.print(',');
  178.             VolCurPowFile.print(loadvoltage);
  179.             VolCurPowFile.print(',');
  180.             VolCurPowFile.print(current_mA);
  181.             VolCurPowFile.print(',');
  182.             VolCurPowFile.println(loadpower);
  183.             VolCurPowFile.close();
  184.             digitalWrite(green1_pin, LOW);
  185.         }
  186.  
  187.       VCP_display.setTextColor(WHITE);
  188.       VCP_display.clearDisplay();
  189.       VCP_display.setTextSize(2);
  190.       VCP_display.setCursor(0, 0);
  191.       VCP_display.println(loadvoltage);
  192.       VCP_display.setCursor(100, 0);
  193.       VCP_display.println("V");
  194.       VCP_display.setCursor(0, 20);
  195.       VCP_display.println(current_mA);
  196.       VCP_display.setCursor(100, 20);
  197.       VCP_display.println("mA");
  198.       VCP_display.setCursor(0, 40);
  199.       VCP_display.println(loadpower);
  200.       VCP_display.setCursor(100, 40);
  201.       VCP_display.println("mW");
  202.       VCP_display.display();
  203.  
  204.       }
  205.    
  206.     /***** CHECK STATE OF BLUE LED AND CALCULATE VIA 16V/400mA *****/
  207.     if (redPinState == LOW && bluePinState == HIGH) {
  208.  
  209.       digitalWrite(blue1_pin, HIGH);
  210.       digitalWrite(red1_pin, LOW);
  211.      
  212.       float shuntvoltage = 0;
  213.       float busvoltage = 0;
  214.       float current_mA = 0;
  215.       float loadvoltage = 0;
  216.       float loadpower = 0;
  217.    
  218.       shuntvoltage = ina219_B.getShuntVoltage_mV();
  219.       busvoltage = ina219_B.getBusVoltage_V();
  220.       current_mA = ina219_B.getCurrent_mA();
  221.       loadvoltage = busvoltage + (shuntvoltage / 1000);
  222.       loadpower = ((loadvoltage)*(current_mA/1000))*1000;
  223.  
  224.    
  225.    
  226.    /****** SERIAL PRINT NOT NEEDED *******/
  227. //    Serial.print(currentMillis);
  228. //    Serial.print(',');
  229. //    Serial.print("16V_400mA");
  230. //    Serial.print(',');
  231. //    Serial.print(id);
  232. //    Serial.print(',');
  233. //    Serial.print(busvoltage);
  234. //    Serial.print(',');
  235. //    Serial.print(shuntvoltage);
  236. //    Serial.print(',');
  237. //    Serial.print(loadvoltage);
  238. //    Serial.print(',');
  239. //    Serial.print(current_mA);
  240. //    Serial.print(',');
  241. //    Serial.println(loadpower);
  242.  
  243.       VolCurPowFile = SD.open("VCP.txt",FILE_WRITE);
  244.         if (VolCurPowFile) {
  245.             digitalWrite(green1_pin, HIGH);
  246.             VolCurPowFile.print(currentMillis);
  247.             VolCurPowFile.print(',');
  248.             VolCurPowFile.print("16V_400mA");
  249.             VolCurPowFile.print(',');
  250.             VolCurPowFile.print(id++);
  251.             VolCurPowFile.print(',');
  252.             VolCurPowFile.print(busvoltage);
  253.             VolCurPowFile.print(',');
  254.             VolCurPowFile.print(shuntvoltage);
  255.             VolCurPowFile.print(',');
  256.             VolCurPowFile.print(loadvoltage);
  257.             VolCurPowFile.print(',');
  258.             VolCurPowFile.print(current_mA);
  259.             VolCurPowFile.print(',');
  260.             VolCurPowFile.println(loadpower);
  261.             VolCurPowFile.close();
  262.             digitalWrite(green1_pin, LOW);
  263.         }
  264.  
  265.       VCP_display.setTextColor(WHITE);
  266.       VCP_display.clearDisplay();
  267.       VCP_display.setTextSize(2);
  268.       VCP_display.setCursor(0, 0);
  269.       VCP_display.println(loadvoltage);
  270.       VCP_display.setCursor(100, 0);
  271.       VCP_display.println("V");
  272.       VCP_display.setCursor(0, 20);
  273.       VCP_display.println(current_mA);
  274.       VCP_display.setCursor(100, 20);
  275.       VCP_display.println("mA");
  276.       VCP_display.setCursor(0, 40);
  277.       VCP_display.println(loadpower);
  278.       VCP_display.setCursor(100, 40);
  279.       VCP_display.println("mW");
  280.       VCP_display.display();
  281.  
  282.       }
  283.    
  284.     /***** IF RED AND BLUE LED SENSE PINS ARE LOW, THEN DO NOTHING *****/
  285.     if (bluePinState == LOW && redPinState == LOW) {
  286.    
  287.       digitalWrite(red1_pin, LOW);
  288.       digitalWrite(blue1_pin, LOW);
  289.  
  290.       VCP_display.clearDisplay();
  291.       VCP_display.display();
  292.        
  293.     }
  294.   }
  295. }
  296.  
  297.  
  298. int getRefreshRate() {
  299.  
  300.   /****** ADC really stinks on the ESP32!  Did not want to use ADS1115, so I tweaked these threshold numbers appropriately ******/
  301.  
  302.   newPotValue = map(analogRead(refresh_PotPin), 0, 4095, 65000, 0);
  303.  
  304.   if (newPotValue != previousPotValue) {
  305.  
  306.     if (newPotValue <=400) {
  307.       return(0);
  308.       //Serial.println(0);
  309.     }
  310.     if (newPotValue >400 && newPotValue <=8000) {
  311.       return(250);
  312.       //Serial.println(250);
  313.     }
  314.     if (newPotValue >8000 && newPotValue <=18000) {
  315.       return(500);
  316.       //Serial.println(500);
  317.     }
  318.     if (newPotValue >18000 && newPotValue <=26000) {
  319.       return(1000);
  320.       //Serial.println(1000);
  321.     }
  322.     if (newPotValue >26000 && newPotValue <=32000) {
  323.       return(5000);
  324.       //Serial.println(5000);
  325.     }
  326.     if (newPotValue >32000 && newPotValue <=38000) {
  327.       return(10000);
  328.       //Serial.println(10000);
  329.     }
  330.     if (newPotValue >38000 && newPotValue <=44000) {
  331.       return(20000);
  332.       //Serial.println(20000);
  333.     }
  334.     if (newPotValue >44000 && newPotValue <=50000) {
  335.       return(30000);
  336.       //Serial.println(30000);
  337.     }
  338.     if (newPotValue >50000 && newPotValue <=56000) {
  339.       return(40000);
  340.       //Serial.println(40000);
  341.     }
  342.     if (newPotValue >56000 && newPotValue <=62000) {
  343.       return(50000);
  344.       //Serial.println(50000);
  345.     }
  346.     if (newPotValue >62000 && newPotValue <=65000) {
  347.       return(60000);
  348.       //Serial.println(60000);
  349.     }
  350.     else {return(00000);  //Serial.println(00000);}
  351.   }
  352.  
  353.     previousPotValue = newPotValue;
  354.  }
  355. }
  356.  
  357.  
  358. void refreshRateDisplay() {
  359.  
  360.   /****** Had problems with floating ground...instead of reading 0 it read 0-120.  May be fixed once connections are soldered *****/
  361.   //while (white2_sensePin == LOW);  
  362.    
  363.   /***** USED THIS INSTEAD TO RAISE THE GROUND LEVEL FOR BETTER CODE STABILITY *****/
  364.   while (analogRead(white2_sensePin) <= 200) {
  365.  
  366.     refreshRate = getRefreshRate();
  367.  
  368.     digitalWrite(white1_pin, HIGH);
  369.     Refresh_display.setTextColor(WHITE);
  370.     Refresh_display.clearDisplay();
  371.     Refresh_display.setTextSize(2);
  372.     Refresh_display.setCursor(0, 0);
  373.     Refresh_display.println("SetRefresh");
  374.     Refresh_display.setCursor(40, 20);
  375.     Refresh_display.println("Rate!");
  376.     Refresh_display.setCursor(100, 40);
  377.     Refresh_display.println("ms");
  378.     Refresh_display.setCursor(30, 40);
  379.     Refresh_display.println(refreshRate);
  380.     Refresh_display.display();
  381.     digitalWrite(white1_pin, LOW);
  382.  
  383.     //Serial.print("Set Refresh Rate! "); Serial.println(refreshRate);
  384.  
  385.     delay(50);  //Needed to blink white LED
  386.  
  387.   }
  388.    
  389.   /***** BUTTON IS PRESSED AT THIS POINT ("white2_sensePin" GOES HIGH) *****/
  390.  
  391.   digitalWrite(white1_pin, HIGH);  //keep white LED lit
  392.  
  393.   refreshInterval = getRefreshRate();
  394.  
  395.   /***** KEEP DISPLAY ON *****/
  396.   Refresh_display.setTextColor(WHITE);
  397.   Refresh_display.clearDisplay();
  398.   Refresh_display.setTextSize(2);
  399.   Refresh_display.setCursor(20, 0);
  400.   Refresh_display.println("Refresh");
  401.   Refresh_display.setCursor(15, 20);
  402.   Refresh_display.println("Rate Set");
  403.   Refresh_display.setCursor(100, 40);
  404.   Refresh_display.println("ms");
  405.   Refresh_display.setCursor(30, 40);
  406.   Refresh_display.println(refreshRate);
  407.   Refresh_display.display();
  408.  
  409.   //Serial.print("Refresh Rate Set! "); Serial.println(refreshRate);
  410.  
  411.   delay(50);  //Needed to blink white LED
  412.  
  413. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement