From a743759fd7367470d7bab5299f9c29f7ed3d1b6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=85=95=E7=82=8E?= <29385962@qq.com> Date: Tue, 19 Jul 2022 02:57:13 +0000 Subject: [PATCH] for INA226 --- ARDUINO_MPPT_FIRMWARE_V2.1/2_Read_Sensors.ino | 203 ++++ .../3_Device_Protection.ino | 86 ++ .../4_Charging_Algorithm.ino | 73 ++ .../5_System_Processes.ino | 123 ++ .../6_Onboard_Telemetry.ino | 86 ++ .../7_Wireless_Telemetry.ino | 149 +++ ARDUINO_MPPT_FIRMWARE_V2.1/8_LCD_Menu.ino | 1018 +++++++++++++++++ .../ARDUINO_MPPT_FIRMWARE_V2.1.ino | 637 +++++++++++ ARDUINO_MPPT_FIRMWARE_V2.1/blinker_UI.txt | 1 + 9 files changed, 2376 insertions(+) create mode 100644 ARDUINO_MPPT_FIRMWARE_V2.1/2_Read_Sensors.ino create mode 100644 ARDUINO_MPPT_FIRMWARE_V2.1/3_Device_Protection.ino create mode 100644 ARDUINO_MPPT_FIRMWARE_V2.1/4_Charging_Algorithm.ino create mode 100644 ARDUINO_MPPT_FIRMWARE_V2.1/5_System_Processes.ino create mode 100644 ARDUINO_MPPT_FIRMWARE_V2.1/6_Onboard_Telemetry.ino create mode 100644 ARDUINO_MPPT_FIRMWARE_V2.1/7_Wireless_Telemetry.ino create mode 100644 ARDUINO_MPPT_FIRMWARE_V2.1/8_LCD_Menu.ino create mode 100644 ARDUINO_MPPT_FIRMWARE_V2.1/ARDUINO_MPPT_FIRMWARE_V2.1.ino create mode 100644 ARDUINO_MPPT_FIRMWARE_V2.1/blinker_UI.txt diff --git a/ARDUINO_MPPT_FIRMWARE_V2.1/2_Read_Sensors.ino b/ARDUINO_MPPT_FIRMWARE_V2.1/2_Read_Sensors.ino new file mode 100644 index 0000000..3ccc6d8 --- /dev/null +++ b/ARDUINO_MPPT_FIRMWARE_V2.1/2_Read_Sensors.ino @@ -0,0 +1,203 @@ +/* + void ADC_SetGain(){ + if(ADS1015_Mode==true){ //FOR ADS1015 12-BIT ADC MODEL + if(ADC_GainSelect==0){ads.setGain(GAIN_TWOTHIRDS);ADC_BitReso=3.0000;} // Gain: 2/3x Range: +/- 6.144V + else if(ADC_GainSelect==1){ads.setGain(GAIN_ONE);ADC_BitReso=2.0000;} // Gain: 1x Range: +/- 4.096V + else if(ADC_GainSelect==2){ads.setGain(GAIN_TWO);ADC_BitReso=1.0000;} // Gain: 2x Range: +/- 2.048V + } + else{ //FOR ADS1115 16-BIT ADC MODEL + if(ADC_GainSelect==0){ads.setGain(GAIN_TWOTHIRDS);ADC_BitReso= 0.1875;} // Gain: 2/3x Range: +/- 6.144V + else if(ADC_GainSelect==1){ads.setGain(GAIN_ONE);ADC_BitReso= 0.125;} // Gain: 1x Range: +/- 4.096V + else if(ADC_GainSelect==2){ads.setGain(GAIN_TWO);ADC_BitReso= 0.0625;} // Gain: 2x Range: +/- 2.048V + } + } +*/ + +void checkConfig(INA226 &ina) +{ + 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 resetVariables() { + secondsElapsed = 0; + energySavings = 0; + daysRunning = 0; + timeOn = 0; +} +void Read_Sensors() { + + /////////// TEMPERATURE SENSOR ///////////// + if (sampleStoreTS <= avgCountTS) { //TEMPERATURE SENSOR - Lite Averaging + TS = TS + analogRead(TempSensor); + sampleStoreTS++; + } else { + TS = TS / sampleStoreTS; + TSlog = log(ntcResistance * (4095.00 / TS - 1.00)); + temperature = (1.0 / (1.009249522e-03 + 2.378405444e-04 * TSlog + 2.019202697e-07 * TSlog * TSlog * TSlog)) - 273.15+10; + sampleStoreTS = 0; + TS = 0; + } + + /////////// VOLTAGE & CURRENT SENSORS ///////////// + VSI = 0.0000; //Clear Previous Input Voltage + VSO = 0.0000; //Clear Previous Output Voltage + CSI = 0.0000; //Clear Previous Input Current + CSO = 0.0000; //Clear Previous Output Current + + //VOLTAGE SENSOR - Instantenous Averaging + /* + for (int i = 0; i < avgCountVS; i++) { + VSI = VSI + ads.computeVolts(ads.readADC_SingleEnded(3)); + VSO = VSO + ads.computeVolts(ads.readADC_SingleEnded(1)); + VSI = VSI + ina1.readBusVoltage()*(R1_VOLTAGE1+R2_VOLTAGE1)/R1_VOLTAGE1; + VSO = VSO + ina2.readBusVoltage()*(R1_VOLTAGE2+R2_VOLTAGE2)/R1_VOLTAGE2; + } + voltageInput = (VSI/avgCountVS)*inVoltageDivRatio; + voltageOutput = (VSO/avgCountVS)*outVoltageDivRatio; + voltageInput = VSI/avgCountVS; + voltageOutput = VSO/avgCountVS; + */ + voltageInput = ina1.readBusVoltage() * inVoltageDivRatio; + voltageOutput = ina2.readBusVoltage() * outVoltageDivRatio; + + + //CURRENT SENSOR - Instantenous Averaging + /* + for (int i = 0; i < avgCountCS; i++) { + CSI = CSI + ads.computeVolts(ads.readADC_SingleEnded(2)); + CSI = CSI + ina1.readShuntCurrent(); + CSO = CSO + ina2.readShuntCurrent(); + } + CSI_converted = (CSI/avgCountCS)*1.3300; + currentInput = ((CSI_converted-currentMidPoint)*-1)/currentSensV; + CSI_converted = (CSI/avgCountCS); + CSO_converted = (CSO/avgCountCS); + */ + CSI_converted = ina1.readShuntCurrent(); + CSO_converted = ina2.readShuntCurrent(); + currentInput = CSI_converted; + + if (currentInput < 0) { + currentInput = 0.0000; + } + if (voltageOutput <= 0) { + currentOutput = 0.0000; + } + //else{currentOutput = (voltageInput*currentInput)/voltageOutput;} + else { + currentOutput = CSO_converted; + } + + //POWER SOURCE DETECTION + if (voltageInput <= 3 && voltageOutput <= 3) { + inputSource = 0; //System is only powered by USB port + } + else if (voltageInput > voltageOutput) { + inputSource = 1; //System is running on solar as power source + } + else if (voltageInput < voltageOutput) { + inputSource = 2; //System is running on batteries as power source + } + + //////// AUTOMATIC CURRENT SENSOR CALIBRATION //////// + if (buckEnable == 0 && FLV == 0 && OOV == 0) { + //currentMidPoint = ((CSI/avgCountCS)*1.3300)-0.003; + currentMidPoint = (CSI / avgCountCS) - 0.003; + } + + //POWER COMPUTATION - Through computation + //powerInput = voltageInput*currentInput; + powerInput = ina1.readBusPower(); + //powerOutput = voltageInput*currentInput*efficiencyRate; + powerOutput = ina2.readBusPower(); + outputDeviation = (voltageOutput / voltageBatteryMax) * 100.000; + + //STATE OF CHARGE - Battery Percentage + batteryPercent = ((voltageOutput - voltageBatteryMin) / (voltageBatteryMax - voltageBatteryMin)) * 101; + batteryPercent = constrain(batteryPercent, 0, 100); + + //TIME DEPENDENT SENSOR DATA COMPUTATION + currentRoutineMillis = millis(); + if (currentRoutineMillis - prevRoutineMillis >= millisRoutineInterval) { //Run routine every millisRoutineInterval (ms) + prevRoutineMillis = currentRoutineMillis; //Store previous time + Wh = Wh + (powerInput / (3600.000 * (1000.000 / millisRoutineInterval))); //Accumulate and compute energy harvested (3600s*(1000/interval)) + kWh = Wh / 1000.000; + MWh = Wh / 1000000.000; + daysRunning = timeOn / (86400.000 * (1000.000 / millisRoutineInterval)); //Compute for days running (86400s*(1000/interval)) + timeOn++; //Increment time counter + } + + //OTHER DATA + secondsElapsed = millis() / 1000; //Gets the time in seconds since the was turned on and active + energySavings = electricalPrice * (Wh / 1000.0000); //Computes the solar energy saving in terms of money (electricity flag rate) +} diff --git a/ARDUINO_MPPT_FIRMWARE_V2.1/3_Device_Protection.ino b/ARDUINO_MPPT_FIRMWARE_V2.1/3_Device_Protection.ino new file mode 100644 index 0000000..3f43312 --- /dev/null +++ b/ARDUINO_MPPT_FIRMWARE_V2.1/3_Device_Protection.ino @@ -0,0 +1,86 @@ +void backflowControl() { //PV BACKFLOW CONTROL (INPUT MOSFET) + if (output_Mode == 0) { + bypassEnable = 1; //PSU MODE: Force backflow MOSFET on + } + else { //CHARGER MODE: Force backflow MOSFET on + if (voltageInput > voltageOutput + voltageDropout) { + bypassEnable = 1; //CHARGER MODE: Normal Condition - Turn on Backflow MOSFET (on by default when not in MPPT charger mode) + } + else { + bypassEnable = 0; //CHARGER MODE: Input Undervoltage - Turn off bypass MOSFET and prevent PV Backflow (SS) + } + } + digitalWrite(backflow_MOSFET, bypassEnable); //Signal backflow MOSFET GPIO pin +} + +void Device_Protection() { + //ERROR COUNTER RESET + currentRoutineMillis = millis(); + if (currentErrorMillis - prevErrorMillis >= errorTimeLimit) { //Run routine every millisErrorInterval (ms) + prevErrorMillis = currentErrorMillis; //Store previous time + if (errorCount < errorCountLimit) { + errorCount = 0; //Reset error count if it is below the limit before x milliseconds + } + else {} // TO ADD: sleep and charging pause if too many errors persists + } + //FAULT DETECTION + ERR = 0; //Reset local error counter + backflowControl(); //Run backflow current protection protocol + if (temperature > temperatureMax) { + OTE = 1; //OTE - OVERTEMPERATURE: System overheat detected + ERR++; + errorCount++; + } else { + OTE = 0; + } + if (currentInput > currentInAbsolute) { + IOC = 1; //IOC - INPUT OVERCURRENT: Input current has reached absolute limit + ERR++; + errorCount++; + } else { + IOC = 0; + } + if (currentOutput > currentOutAbsolute) { + OOC = 1; //OOC - OUTPUT OVERCURRENT: Output current has reached absolute limit + ERR++; + errorCount++; + } else { + OOC = 0; + } + if (voltageOutput > voltageBatteryMax + voltageBatteryThresh) { + OOV = 1; //OOV - OUTPUT OVERVOLTAGE: Output voltage has reached absolute limit + ERR++; + errorCount++; + } else { + OOV = 0; + } + if (voltageInput < vInSystemMin && voltageOutput < vInSystemMin) { + FLV = 1; //FLV - Fatally low system voltage (unable to resume operation) + ERR++; + errorCount++; + } else { + FLV = 0; + } + + if (output_Mode == 0) { //PSU MODE specific protection protocol + REC = 0; BNC = 0; //Clear recovery and battery not connected boolean identifiers + if (voltageInput < voltageBatteryMax + voltageDropout) { + IUV = 1; //IUV - INPUT UNDERVOLTAGE: Input voltage is below battery voltage (for psu mode only) + ERR++; + errorCount++; + } else { + IUV = 0; + } + } + else { //Charger MODE specific protection protocol + backflowControl(); //Enable backflow current detection & control + if(voltageOutputvoltageBatteryMax){PPWM =(PPWM_margin*pwmMax*voltageBatteryMax)/(100.00*voltageInput)*0.98;} //计算预测 PWM Floor 并存储在变量中 + else{PPWM =(PPWM_margin*pwmMax*voltageOutput)/(100.00*voltageInput);} //计算预测 PWM Floor 并存储在变量中 + PPWM = constrain(PPWM,0,pwmMaxLimited); +} + +void PWM_Modulation(){ + if(output_Mode==0){PWM = constrain(PWM,0,pwmMaxLimited);} //PSU MODE PWM = PWM OVERFLOW PROTECTION(将下限限制为 0%,上限限制为最大允许占空比) + else{ + predictivePWM(); //运行和计算预测 pwm floor + PWM = constrain(PWM,PPWM,pwmMaxLimited); //CHARGER MODE PWM - 将下限限制为 PPWM,上限限制为最大允许占空比) + } + ledcWrite(pwmChannel,PWM); //设置 PWM 占空比并在启用降压时写入 GPIO + buck_Enable(); //开启 MPPT 降压 (IR2104) +} + +void Charging_Algorithm(){ + if(ERR>0||chargingPause==1){buck_Disable();} //当出现错误或充电暂停用于暂停覆盖时关闭 MPPT 降压 + else{ + if(REC==1){ // IUV RECOVERY - (仅对充电模式有效) + REC=0; //重置 IUV 恢复布尔标识符 + buck_Disable(); //在 PPWM 初始化之前禁用降压 + lcd.setCursor(0,0);lcd.print("POWER SOURCE "); //显示液晶信息 + lcd.setCursor(0,1);lcd.print("DETECTED "); //显示液晶信息 + Serial.println("> Solar Panel Detected"); //显示串口信息 + Serial.print("> Computing For Predictive PWM "); //显示串口信息 + for(int i = 0; i<40; i++){Serial.print(".");delay(30);} //For loop "loading... 效果 + Serial.println(""); //在串行上显示下一行的换行符 + Read_Sensors(); + predictivePWM(); + PWM = PPWM; + lcd.clear(); + } + else{ //NO ERROR PRESENT - 继续电源转换 + /////////////////////// CC-CV BUCK PSU ALGORITHM ////////////////////////////// + if(MPPT_Mode==0){ // CC-CV PSU 模式 + if(currentOutput>currentCharging) {PWM--;} //电流高于 → 降低占空比 + else if(voltageOutput>voltageBatteryMax){PWM--;} //电压高于 → 降低占空比 + else if(voltageOutputcurrentCharging){PWM--;} //电流高于 → 降低占空比 + else if(voltageOutput>voltageBatteryMax){PWM--;} //电压高于 → 降低占空比 + else{ //MPPT 算法 + if(powerInput>powerInputPrev && voltageInput>voltageInputPrev) {PWM--;} // ↑P ↑V ; →MPP //D-- + else if(powerInput>powerInputPrev && voltageInputvoltageInputPrev){PWM++;} // ↓P ↑V ; MPP→ //D++ + else if(powerInputvoltageBatteryMax) {PWM--;} // MP MV ; 达到 MPP + else if(voltageOutput= temperatureFan) { + fanStatus = 1; //Turn on fan when set fan temp reached + } + else if (temperature < temperatureFan) { + fanStatus = 0; //Turn off fan when set fan temp reached + } + digitalWrite(FAN, fanStatus); //Send a digital signal to the fan MOSFET + } + else {} //DYNAMIC PWM COOLING MODE (3-PIN FAN - coming soon) + } + else { + digitalWrite(FAN, LOW); //Fan Disabled + } + + //////////// LOOP TIME STOPWATCH //////////// + loopTimeStart = micros(); //Record Start Time + loopTime = (loopTimeStart - loopTimeEnd) / 1000.000; //Compute Loop Cycle Speed (mS) + loopTimeEnd = micros(); //Record End Time + + ///////////// AUTO DATA RESET ///////////// + if (telemCounterReset == 0) {} //Never Reset + else if (telemCounterReset == 1 && daysRunning > 1) { + resetVariables(); //Daily Reset + } + else if (telemCounterReset == 2 && daysRunning > 7) { + resetVariables(); //Weekly Reset + } + else if (telemCounterReset == 3 && daysRunning > 30) { + resetVariables(); //Monthly Reset + } + else if (telemCounterReset == 4 && daysRunning > 365) { + resetVariables(); //Yearly Reset + } + + ///////////// LOW POWER MODE ///////////// + if (lowPowerMode == 1) {} + else {} +} + +void factoryReset() { + EEPROM.begin(eeprom_size); + EEPROM.write(MPPT_Mode_add, 1); //STORE: Charging Algorithm (1 = MPPT Mode) + EEPROM.write(voltageBatteryMax_add, 12); //STORE: Max Battery Voltage (whole) + EEPROM.write(voltageBatteryMax2_add, 0); //STORE: Max Battery Voltage (decimal) + EEPROM.write(voltageBatteryMin_add, 9); //STORE: Min Battery Voltage (whole) + EEPROM.write(voltageBatteryMin2_add, 0); //STORE: Min Battery Voltage (decimal) + EEPROM.write(currentCharging_add, 1); //STORE: Charging Current (whole) + EEPROM.write(currentCharging2_add, 0); //STORE: Charging Current (decimal) + EEPROM.write(enableFan_add, 1); //STORE: Fan Enable (Bool) + EEPROM.write(temperatureFan_add, 60); //STORE: Fan Temp (Integer) + EEPROM.write(temperatureMax_add, 90); //STORE: Shutdown Temp (Integer) + EEPROM.write(enableWiFi_add, 1); //STORE: Enable WiFi (Boolean) + EEPROM.write(flashMemLoad_add, 1); //STORE: Enable autoload (on by default) + EEPROM.write(output_Mode_add, 1); //STORE: Charger/PSU Mode Selection (1 = Charger Mode) + EEPROM.write(backlightSleepMode_add, 0); //STORE: LCD backlight sleep timer (default: 0 = never) + EEPROM.commit(); + loadSettings(); + EEPROM.end(); +} + +void loadSettings() { + MPPT_Mode = EEPROM.read(MPPT_Mode_add); // Load saved charging mode setting + voltageBatteryMax = EEPROM.read(voltageBatteryMax_add) + (EEPROM.read(voltageBatteryMax2_add) * .01); // Load saved maximum battery voltage setting + voltageBatteryMin = EEPROM.read(voltageBatteryMin_add) + (EEPROM.read(voltageBatteryMin2_add) * .01); // Load saved minimum battery voltage setting + currentCharging = EEPROM.read(currentCharging_add) + (EEPROM.read(currentCharging2_add) * .01); // Load saved charging current setting + enableFan = EEPROM.read(enableFan_add); // Load saved fan enable settings + temperatureFan = EEPROM.read(temperatureFan_add); // Load saved fan temperature settings + temperatureMax = EEPROM.read(temperatureMax_add); // Load saved shutdown temperature settings + enableWiFi = EEPROM.read(enableWiFi_add); // Load saved WiFi enable settings + flashMemLoad = EEPROM.read(flashMemLoad_add); // Load saved flash memory autoload feature + output_Mode = EEPROM.read(output_Mode_add); // Load saved charging mode setting + backlightSleepMode = EEPROM.read(backlightSleepMode_add); // Load saved lcd backlight sleep timer +} + +void saveSettings() { + EEPROM.begin(eeprom_size); + EEPROM.write(MPPT_Mode_add, MPPT_Mode); //STORE: Algorithm + conv1 = voltageBatteryMax * 100; //STORE: Maximum Battery Voltage (gets whole number) + conv2 = conv1 % 100; //STORE: Maximum Battery Voltage (gets decimal number and converts to a whole number) + EEPROM.write(voltageBatteryMax_add, voltageBatteryMax); + EEPROM.write(voltageBatteryMax2_add, conv2); + conv1 = voltageBatteryMin * 100; //STORE: Minimum Battery Voltage (gets whole number) + conv2 = conv1 % 100; //STORE: Minimum Battery Voltage (gets decimal number and converts to a whole number) + EEPROM.write(voltageBatteryMin_add, voltageBatteryMin); + EEPROM.write(voltageBatteryMin2_add, conv2); + conv1 = currentCharging * 100; //STORE: Charging Current + conv2 = conv1 % 100; + EEPROM.write(currentCharging_add, currentCharging); + EEPROM.write(currentCharging2_add, conv2); + EEPROM.write(enableFan_add, enableFan); //STORE: Fan Enable + EEPROM.write(temperatureFan_add, temperatureFan); //STORE: Fan Temp + EEPROM.write(temperatureMax_add, temperatureMax); //STORE: Shutdown Temp + EEPROM.write(enableWiFi_add, enableWiFi); //STORE: Enable WiFi + //EEPROM.write(flashMemLoad_add, flashMemLoad); //STORE: Enable autoload (must be excluded from bulk save, uncomment under discretion) + EEPROM.write(output_Mode_add, output_Mode); //STORE: Charge/PSU Mode Selection + EEPROM.write(backlightSleepMode_add, backlightSleepMode); //STORE: LCD backlight sleep timer + EEPROM.commit(); //Saves setting changes to flash memory + EEPROM.end(); + +} +void saveAutoloadSettings() { + EEPROM.begin(eeprom_size); + EEPROM.write(flashMemLoad_add, flashMemLoad); //STORE: Enable autoload + EEPROM.commit(); //Saves setting changes to flash memory + EEPROM.end(); + Serial.println("Saves setting changes"); +} +void initializeFlashAutoload() { + if (disableFlashAutoLoad == 0) { + flashMemLoad = EEPROM.read(flashMemLoad_add); //Load saved autoload (must be excluded from bulk save, uncomment under discretion) + if (flashMemLoad == 1) { + loadSettings(); //Load stored settings from flash memory + } + EEPROM.end(); + } +} diff --git a/ARDUINO_MPPT_FIRMWARE_V2.1/6_Onboard_Telemetry.ino b/ARDUINO_MPPT_FIRMWARE_V2.1/6_Onboard_Telemetry.ino new file mode 100644 index 0000000..93629af --- /dev/null +++ b/ARDUINO_MPPT_FIRMWARE_V2.1/6_Onboard_Telemetry.ino @@ -0,0 +1,86 @@ +void Onboard_Telemetry() { + + /////////////////////// USB SERIAL DATA TELEMETRY //////////////////////// + // 0 - Disable Serial + // 1 - Display All + // 2 - Display Essential Data + // 3 - Display Numbers Only + + currentSerialMillis = millis(); + if (currentSerialMillis - prevSerialMillis >= millisSerialInterval) { //Run routine every millisRoutineInterval (ms) + prevSerialMillis = currentSerialMillis; //Store previous time + + if (serialTelemMode == 0) {} + // else if(chargingPause==1){Serial.println("CHARGING PAUSED");} // Charging paused message + else if (serialTelemMode == 1) { // 1 - Display All + Serial.print(" ERR:"); Serial.print(ERR); + Serial.print(" FLV:"); Serial.print(FLV); + Serial.print(" BNC:"); Serial.print(BNC); + Serial.print(" IUV:"); Serial.print(IUV); + Serial.print(" IOC:"); Serial.print(IOC); + Serial.print(" OOV:"); Serial.print(OOV); + Serial.print(" OOC:"); Serial.print(OOC); + Serial.print(" OTE:"); Serial.print(OTE); + Serial.print(" REC:"); Serial.print(REC); + Serial.print(" MPPTA:"); Serial.print(MPPT_Mode); + Serial.print(" CM:"); Serial.print(output_Mode); //Charging Mode + + Serial.print(" "); + Serial.print(" BYP:"); Serial.print(bypassEnable); + Serial.print(" EN:"); Serial.print(buckEnable); + Serial.print(" FAN:"); Serial.print(fanStatus); + Serial.print(" WiFi:"); Serial.print(WIFI); + Serial.print(" "); + Serial.print(" PI:"); Serial.print(powerInput, 3); + Serial.print(" PWM:"); Serial.print(PWM); + Serial.print(" PPWM:"); Serial.print(PPWM); + Serial.print(" VI:"); Serial.print(voltageInput, 3); + Serial.print(" VO:"); Serial.print(voltageOutput, 3); + Serial.print(" CI:"); Serial.print(currentInput, 3); + Serial.print(" CO:"); Serial.print(currentOutput, 3); + Serial.print(" Wh:"); Serial.print(Wh, 3); + Serial.print(" Temp:"); Serial.print(temperature, 1); + Serial.print(" "); + Serial.print(" CSMPV:"); Serial.print(currentMidPoint, 3); + Serial.print(" CSV:"); Serial.print(CSI_converted, 3); + Serial.print(" VO%Dev:"); Serial.print(outputDeviation, 1); + Serial.print(" SOC:"); Serial.print(batteryPercent); Serial.print("%"); + Serial.print(" T:"); Serial.print(secondsElapsed); + Serial.print(" LoopT:"); Serial.print(loopTime, 3); Serial.print("ms"); + Serial.println(""); + } + else if (serialTelemMode == 2) { // 2 - Display Essential Data + Serial.print(" PI:"); Serial.print(powerInput, 3); + Serial.print(" PWM:"); Serial.print(PWM); + Serial.print(" PPWM:"); Serial.print(PPWM); + Serial.print(" VI:"); Serial.print(voltageInput, 3); + Serial.print(" VO:"); Serial.print(voltageOutput, 3); + Serial.print(" CI:"); Serial.print(currentInput, 3); + Serial.print(" CO:"); Serial.print(currentOutput, 3); + Serial.print(" Wh:"); Serial.print(Wh, 3); + Serial.print(" Temp:"); Serial.print(temperature, 1); + Serial.print(" EN:"); Serial.print(buckEnable); + Serial.print(" FAN:"); Serial.print(fanStatus); + Serial.print(" SOC:"); Serial.print(batteryPercent); Serial.print("%"); + Serial.print(" T:"); Serial.print(secondsElapsed); + Serial.print(" LoopT:"); Serial.print(loopTime, 3); Serial.print("ms"); + Serial.println(""); + } + else if (serialTelemMode == 3) { // 3 - Display Numbers Only + Serial.print(" "); Serial.print(powerInput, 3); + Serial.print(" "); Serial.print(voltageInput, 3); + Serial.print(" "); Serial.print(voltageOutput, 3); + Serial.print(" "); Serial.print(currentInput, 3); + Serial.print(" "); Serial.print(currentOutput, 3); + Serial.print(" "); Serial.print(Wh, 3); + Serial.print(" "); Serial.print(temperature, 1); + Serial.print(" "); Serial.print(buckEnable); + Serial.print(" "); Serial.print(fanStatus); + Serial.print(" "); Serial.print(batteryPercent); + Serial.print(" "); Serial.print(secondsElapsed); + Serial.print(" "); Serial.print(loopTime, 3); + Serial.print(" "); Serial.println(""); + } + + } +} diff --git a/ARDUINO_MPPT_FIRMWARE_V2.1/7_Wireless_Telemetry.ino b/ARDUINO_MPPT_FIRMWARE_V2.1/7_Wireless_Telemetry.ino new file mode 100644 index 0000000..23cfa37 --- /dev/null +++ b/ARDUINO_MPPT_FIRMWARE_V2.1/7_Wireless_Telemetry.ino @@ -0,0 +1,149 @@ +void setupWiFi() { + if (enableWiFi == 1) { + //Blynk.begin(auth,ssid,pass); + if (blinker_id == "") { + if (!AutoWifiConfig()) + { + SmartConfig(); + } + } else { + // 初始化blinker + Blinker.begin(blinker_id, ssid, pass); + + Blinker.attachData(dataRead); + Blinker.attachHeartbeat(heartbeat); + Blinker.attachDataStorage(dataStorage); + } + WIFI = 1; + } +} + +bool AutoWifiConfig() +{ + + //设置固定IP地址 + //IPAddress staticIP(192, 168, 5, 24); //ESP static ip + //IPAddress gateway(192, 168, 5, 1); //IP Address of your WiFi Router (Gateway) + //IPAddress subnet(255, 255, 255, 0); //Subnet mask + //IPAddress dns(192, 168, 5, 1); //DNS + //WiFi.config(staticIP, gateway, subnet, dns); + WiFi.begin(ssid, pass); //Wifi接入到网络 + //WiFi.begin(); //Wifi接入到网络 + //如果觉得时间太长可改 + for (int i = 0; i < 20; i++) + { + int wstatus = WiFi.status(); + if (wstatus == WL_CONNECTED) + { + Serial.println("WIFI AutoConfig Success"); + Serial.print("LocalIP:"); + Serial.print(WiFi.localIP()); + Serial.print(" ,GateIP:"); + Serial.println(WiFi.gatewayIP()); + return true; + } + else + { + Serial.print("WIFI AutoConfig Waiting......"); + Serial.println(wstatus); + delay(1000); + } + } + Serial.println("WIFI AutoConfig Faild!" ); + return false; +} + +void SmartConfig() +{ + int delay_times = 0; + // WiFi.mode(WIFI_AP_STA); + WiFi.mode(WIFI_STA); + Serial.println("\r\n wait for smartconfig...."); + WiFi.beginSmartConfig(); + while (1) + { + if (delay_times > 60) { + ESP.restart(); + } + Serial.print("."); + delay(500); + if ( WiFi.smartConfigDone()) + { + Serial.println("SmartConfig Success"); + //Serial.printf("SSID:%s\r\n", WiFi.SSID().c_str()); + //Serial.printf("PSW:%s\r\n", WiFi.psk().c_str()); + break; + } + delay_times++; + } +} + + +void Wireless_Telemetry() { + + ////////// WIFI TELEMETRY ////////// + if (enableWiFi == 1) { + int LED1, LED2, LED3, LED4; //Declare LED brightness variable + if (buckEnable == 1) { + LED1 = 200; //BATTERY CHARGING STATUS + } else { + LED1 = 0; + } + if (batteryPercent >= 99 ) { + LED2 = 200; //FULL CHARGE STATUS + } else { + LED2 = 0; + } + if (batteryPercent <= 10) { + LED3 = 200; //LOW BATTERY STATUS + } else { + LED3 = 0; + } + if (IUV == 0) { + LED4 = 200; //PV INPUT PRESENCE STATUS + } else { + LED4 = 0; + } + + if (blinker_id == "") { + while (WiFi.status() != WL_CONNECTED) { + delay(500); + AutoWifiConfig(); + Serial.print("."); + } + } else { + if (WiFi.status() == WL_CONNECTED) { + Blinker.run(); + } else { + AutoWifiConfig(); + } + } + + /* + Blynk.run(); + Blynk.virtualWrite(1,powerInput); + Blynk.virtualWrite(2,batteryPercent); + Blynk.virtualWrite(3,voltageInput); + Blynk.virtualWrite(4,currentInput); + Blynk.virtualWrite(5,voltageOutput); + Blynk.virtualWrite(6,currentOutput); + Blynk.virtualWrite(7,temperature); + Blynk.virtualWrite(8,Wh/1000); + Blynk.virtualWrite(9,energySavings); + Blynk.virtualWrite(10,LED1); //LED - Battery Charging Status + Blynk.virtualWrite(11,LED2); //LED - Full Battery Charge Status + Blynk.virtualWrite(12,LED3); //LED - Low Battery Charge Status + Blynk.virtualWrite(13,LED4); //LED - PV Harvesting + + Blynk.virtualWrite(14,voltageBatteryMin); //Minimum Battery Voltage (Read & Write) + Blynk.virtualWrite(15,voltageBatteryMax); //Maximum Battery Voltage (Read & Write) + Blynk.virtualWrite(16,currentCharging); //Charging Current (Read & Write) + Blynk.virtualWrite(17,electricalPrice); //Electrical Price (Write) + */ + } + ////////// WIFI TELEMETRY ////////// + if (enableBluetooth == 1) { + //ADD BLUETOOTH CODE + } + +} diff --git a/ARDUINO_MPPT_FIRMWARE_V2.1/8_LCD_Menu.ino b/ARDUINO_MPPT_FIRMWARE_V2.1/8_LCD_Menu.ino new file mode 100644 index 0000000..9e0df70 --- /dev/null +++ b/ARDUINO_MPPT_FIRMWARE_V2.1/8_LCD_Menu.ino @@ -0,0 +1,1018 @@ +void lcdBacklight_Wake() { + lcd.setBacklight(HIGH); + prevLCDBackLMillis = millis(); +} +void lcdBacklight() { + unsigned long backLightInterval; + if (backlightSleepMode == 0) { + prevLCDBackLMillis = millis(); //Set backlight var to sleep never + } + else if (backlightSleepMode == 1) { + backLightInterval = 10000; //Set backlight var to sleep after 10 seconds without keypress + } + else if (backlightSleepMode == 2) { + backLightInterval = 300000; //Set backlight var to sleep after 5 minutes without keypress + } + else if (backlightSleepMode == 3) { + backLightInterval = 3600000; //Set backlight var to sleep after 1 hour without keypress + } + else if (backlightSleepMode == 4) { + backLightInterval = 21600000; //Set backlight var to sleep after 6 hours without keypress + } + else if (backlightSleepMode == 5) { + backLightInterval = 43200000; //Set backlight var to sleep after 12 hours without keypress + } + else if (backlightSleepMode == 6) { + backLightInterval = 86400000; //Set backlight var to sleep after 1 day without keypress + } + else if (backlightSleepMode == 7) { + backLightInterval = 259200000; //Set backlight var to sleep after 3 days without keypress + } + else if (backlightSleepMode == 8) { + backLightInterval = 604800000; //Set backlight var to sleep after 1 week without keypress + } + else if (backlightSleepMode == 9) { + backLightInterval = 2419200000; //Set backlight var to sleep after 1 month without keypress + } + + if (backlightSleepMode > 0 && settingMode == 0) { + currentLCDBackLMillis = millis(); + if (currentLCDBackLMillis - prevLCDBackLMillis >= backLightInterval) { //Run routine every millisRoutineInterval (ms) + prevLCDBackLMillis = currentLCDBackLMillis; //Store previous time + lcd.setBacklight(LOW); //Increment time counter + } + } +} +void padding100(int padVar) { + if (padVar < 10) { + lcd.print(" "); + } + else if (padVar < 100) { + lcd.print(" "); + } +} +void padding10(int padVar) { + if (padVar < 10) { + lcd.print(" "); + } +} +void displayConfig1() { + lcd.setCursor(0, 0); lcd.print(powerInput, 2); lcd.print("W"); padding100(powerInput); + lcd.setCursor(7, 0); + if (Wh < 10) { + lcd.print(Wh, 3); //9.999Wh_ + lcd.print("Wh "); + } + else if (Wh < 100) { + lcd.print(Wh, 2); //99.99Wh_ + lcd.print("Wh "); + } + else if (Wh < 1000) { + lcd.print(Wh, 1); //999.9Wh_ + lcd.print("Wh "); + } + else if (Wh < 10000) { + lcd.print(kWh, 2); //9.99kWh_ + lcd.print("kWh "); + } + else if (Wh < 100000) { + lcd.print(kWh, 1); //99.9kWh_ + lcd.print("kWh "); + } + else if (Wh < 1000000) { + lcd.print(kWh, 0); //999kWh__ + lcd.print("kWh "); + } + else if (Wh < 10000000) { + lcd.print(MWh, 2); //9.99MWh_ + lcd.print("MWh "); + } + else if (Wh < 100000000) { + lcd.print(MWh, 1); //99.9MWh_ + lcd.print("MWh "); + } + else if (Wh < 1000000000) { + lcd.print(MWh, 0); //999MWh__ + lcd.print("MWh "); + } + lcd.setCursor(15, 0); lcd.print(daysRunning, 0); + lcd.setCursor(0, 1); lcd.print(batteryPercent); lcd.print("%"); padding100(batteryPercent); + if (BNC == 0) { + lcd.setCursor(5, 1); + lcd.print(voltageOutput, 2); + lcd.print("V"); + padding10(voltageOutput); + } + else { + lcd.setCursor(5, 1); + lcd.print("NOBAT "); + } + lcd.setCursor(11, 1); lcd.print(currentOutput, 2); lcd.print("A"); padding10(currentOutput); +} +void displayConfig2() { + lcd.setCursor(0, 0); lcd.print(powerInput, 2); lcd.print("W"); padding100(powerInput); + lcd.setCursor(7, 0); lcd.print(voltageInput, 2); lcd.print("V"); padding10(voltageInput); + lcd.setCursor(14, 0); lcd.print(currentInput, 2); lcd.print("A"); padding10(currentInput); + lcd.setCursor(0, 1); lcd.print(powerOutput, 2); lcd.print("W"); padding100(powerOutput); + if (BNC == 0) { + lcd.setCursor(7, 1); + lcd.print(voltageOutput, 2); + lcd.print("V"); + padding10(voltageOutput); + } + else { + lcd.setCursor(7, 1); + lcd.print("NOBAT"); + } + lcd.setCursor(14, 1); lcd.print(currentOutput, 2); lcd.print("A"); padding10(currentOutput); +} +void displayConfig3() { + lcd.setCursor(0, 0); lcd.print(powerInput, 2); lcd.print("W"); padding100(powerInput); + lcd.setCursor(7, 0); + if (Wh < 10) { + lcd.print(Wh, 2); //9.99Wh_ + lcd.print("Wh "); + } + else if (Wh < 100) { + lcd.print(Wh, 1); //99.9Wh_ + lcd.print("Wh "); + } + else if (Wh < 1000) { + lcd.print(Wh, 0); //999Wh__ + lcd.print("Wh "); + } + else if (Wh < 10000) { + lcd.print(kWh, 1); //9.9kWh_ + lcd.print("kWh "); + } + else if (Wh < 100000) { + lcd.print(kWh, 0); //99kWh__ + lcd.print("kWh "); + } + else if (Wh < 1000000) { + lcd.print(kWh, 0); //999kWh_ + lcd.print("kWh "); + } + else if (Wh < 10000000) { + lcd.print(MWh, 1); //9.9MWh_ + lcd.print("MWh "); + } + else if (Wh < 100000000) { + lcd.print(MWh, 0); //99MWh__ + lcd.print("MWh "); + } + else if (Wh < 1000000000) { + lcd.print(MWh, 0); //999Mwh_ + lcd.print("MWh "); + } + lcd.setCursor(15, 0); lcd.print(batteryPercent); lcd.print("%"); padding100(batteryPercent); + int batteryPercentBars; + batteryPercentBars = batteryPercent / 6.18; //6.25 proper value + lcd.setCursor(0, 1); + for (int i = 0; i < batteryPercentBars; i++) { + lcd.print((char)255); //Battery Bar Blocks + } + for (int i = 0; i < 16 - batteryPercentBars; i++) { + lcd.print(" "); //Battery Blanks + } +} +void displayConfig4() { + lcd.setCursor(0, 0); lcd.print("TEMPERATURE STAT"); + lcd.setCursor(0, 1); lcd.print(temperature); lcd.print((char)223); lcd.print("C"); padding100(temperature); + lcd.setCursor(8, 1); lcd.print("FAN"); + lcd.setCursor(12, 1); + if (fanStatus == 1) { + lcd.print("ON "); + } + else { + lcd.print("OFF"); + } +} +void displayConfig5() { + lcd.setCursor(0, 0); lcd.print(" SETTINGS MENU "); + lcd.setCursor(0, 1); lcd.print("--PRESS SELECT--"); +} + +void factoryResetMessageLCD() { + lcd.setCursor(0, 0); lcd.print(" FACTORY RESET "); + lcd.setCursor(0, 1); lcd.print(" SUCCESSFUL "); + delay(1000); +} +void savedMessageLCD() { + // lcd.setCursor(0,0);lcd.print(" SETTINGS SAVED "); + // lcd.setCursor(0,1);lcd.print(" SUCCESSFULLY "); + // delay(500); + // lcd.clear(); +} +void cancelledMessageLCD() { + // lcd.setCursor(0,0);lcd.print(" SETTINGS "); + // lcd.setCursor(0,1);lcd.print(" CANCELLED "); + // delay(500); + // lcd.clear(); +} + +//////////////////////////////////////////// MAIN LCD MENU CODE ///////////////////////////////////////////// +void LCD_Menu() { + int + menuPages = 4, + subMenuPages = 12, + longPressTime = 3000, + longPressInterval = 500, + shortPressInterval = 100; + + //SETTINGS MENU + if (settingMode == 1) { + chargingPause = 1; + + //BUTTON KEYPRESS + if (setMenuPage == 0) { + if (digitalRead(buttonRight) == 1) { + subMenuPage++; + } + if (digitalRead(buttonLeft) == 1) { + subMenuPage--; + } + if (digitalRead(buttonBack) == 1) { + settingMode = 0; //bool engage, main menu int page + subMenuPage = 0; + } + if (digitalRead(buttonSelect) == 1) { + setMenuPage = 1; //enter sub menu settings - bool engage + } + lcdBacklight_Wake(); + while (digitalRead(buttonRight) == 1 || digitalRead(buttonLeft) == 1 + || digitalRead(buttonBack) == 1 || digitalRead(buttonSelect) == 1) {} + } + //SUB MENU PAGE CYCLING + if (subMenuPage > subMenuPages) { + subMenuPage = 0; + } + else if (subMenuPage < 0) { + subMenuPage = subMenuPages; + } + //--------------------------- SETTINGS MENU PAGES: ---------------------------// + ///// SETTINGS MENU ITEM: SUPPLY ALGORITHM SELECT ///// + if (subMenuPage == 0) { + lcd.setCursor(0, 0); lcd.print("SUPPLY ALGORITHM"); + if (setMenuPage == 1) { + lcd.setCursor(0, 1); + lcd.print(" >"); + } + else { + lcd.setCursor(0, 1); + lcd.print("= "); + } + if (MPPT_Mode == 1) { + lcd.print("MPPT + CC-CV "); + } + else { + lcd.print("CC-CV ONLY "); + } + + //SET MENU - BOOLTYPE + if (setMenuPage == 0) { + boolTemp = MPPT_Mode; + } + else { + if (digitalRead(buttonRight) == 1 || digitalRead(buttonLeft) == 1) { + while (digitalRead(buttonRight) == 1 || digitalRead(buttonLeft) == 1) {} + if (MPPT_Mode == 1) { + MPPT_Mode = 0; + } else { + MPPT_Mode = 1; + } + } + if (digitalRead(buttonBack) == 1) { + while (digitalRead(buttonBack) == 1) {} MPPT_Mode = boolTemp; + cancelledMessageLCD(); + setMenuPage = 0; + } + if (digitalRead(buttonSelect) == 1) { + while (digitalRead(buttonSelect) == 1) {} saveSettings(); + setMenuPage = 0; + savedMessageLCD(); + } + } + } + + ///// SETTINGS MENU ITEM: CHARER/PSU MODE ///// + else if (subMenuPage == 1) { + lcd.setCursor(0, 0); lcd.print("CHARGER/PSU MODE"); + if (setMenuPage == 1) { + lcd.setCursor(0, 1); + lcd.print(" >"); + } + else { + lcd.setCursor(0, 1); + lcd.print("= "); + } + if (output_Mode == 1) { + lcd.print("CHARGER MODE "); + } + else { + lcd.print("PSU MODE "); + } + + //SET MENU - BOOLTYPE + if (setMenuPage == 0) { + boolTemp = output_Mode; + } + else { + if (digitalRead(buttonRight) == 1 || digitalRead(buttonLeft) == 1) { + while (digitalRead(buttonRight) == 1 || digitalRead(buttonLeft) == 1) {} + if (output_Mode == 1) { + output_Mode = 0; + } else { + output_Mode = 1; + } + } + if (digitalRead(buttonBack) == 1) { + while (digitalRead(buttonBack) == 1) {} output_Mode = boolTemp; + cancelledMessageLCD(); + setMenuPage = 0; + } + if (digitalRead(buttonSelect) == 1) { + while (digitalRead(buttonSelect) == 1) {} saveSettings(); + setMenuPage = 0; + savedMessageLCD(); + } + } + } + + + ///// SETTINGS MENU ITEM: MAX BATTERY V ///// + else if (subMenuPage == 2) { + lcd.setCursor(0, 0); lcd.print("MAX BATTERY V "); + if (setMenuPage == 1) { + lcd.setCursor(0, 1); + lcd.print(" >"); + } + else { + lcd.setCursor(0, 1); + lcd.print("= "); + } + lcd.setCursor(2, 1); lcd.print(voltageBatteryMax, 2); lcd.print("V"); + lcd.print(" "); + + //SET MENU - FLOATTYPE + if (setMenuPage == 0) { + floatTemp = voltageBatteryMax; + } + else { + if (digitalRead(buttonBack) == 1) { + while (digitalRead(buttonBack) == 1) {} voltageBatteryMax = floatTemp; + cancelledMessageLCD(); + setMenuPage = 0; + } + if (digitalRead(buttonSelect) == 1) { + while (digitalRead(buttonSelect) == 1) {} saveSettings(); + setMenuPage = 0; + savedMessageLCD(); + } + currentMenuSetMillis = millis(); + if (digitalRead(buttonRight) == 1) { //Right button press (increments setting values) + while (digitalRead(buttonRight) == 1) { + if (millis() - currentMenuSetMillis > longPressTime) { //Long Press + voltageBatteryMax += 1.00; //Increment by 1 + voltageBatteryMax = constrain(voltageBatteryMax, vOutSystemMin, vOutSystemMax); //Limit settings values to a range + lcd.setCursor(2, 1); lcd.print(voltageBatteryMax, 2); delay(longPressInterval); //Display settings data + } + else { //Short Press + voltageBatteryMax += 0.01; //Increment by 0.01 + voltageBatteryMax = constrain(voltageBatteryMax, vOutSystemMin, vOutSystemMax); //Limit settings values to a range + lcd.setCursor(2, 1); lcd.print(voltageBatteryMax, 2); delay(shortPressInterval); //Display settings data + } + lcd.print("V "); //Display unit + } + } + else if (digitalRead(buttonLeft) == 1) { //Left button press (decrements setting values) + while (digitalRead(buttonLeft) == 1) { + if (millis() - currentMenuSetMillis > longPressTime) { //Long Press + voltageBatteryMax -= 1.00; //Increment by 1 + voltageBatteryMax = constrain(voltageBatteryMax, vOutSystemMin, vOutSystemMax); //Limit settings values to a range + lcd.setCursor(2, 1); lcd.print(voltageBatteryMax, 2); delay(longPressInterval); //Display settings data + } + else { //Short Press + voltageBatteryMax -= 0.01; //Increment by 0.01 + voltageBatteryMax = constrain(voltageBatteryMax, vOutSystemMin, vOutSystemMax); //Limit settings values to a range + lcd.setCursor(2, 1); lcd.print(voltageBatteryMax, 2); delay(shortPressInterval); //Display settings data + } + lcd.print("V "); //Display unit + } + } + } + } + ///// SETTINGS MENU ITEM: MIN BATTERY V ///// + else if (subMenuPage == 3) { + lcd.setCursor(0, 0); lcd.print("MIN BATTERY V "); + if (setMenuPage == 1) { + lcd.setCursor(0, 1); + lcd.print(" >"); + } + else { + lcd.setCursor(0, 1); + lcd.print("= "); + } + lcd.setCursor(2, 1); lcd.print(voltageBatteryMin, 2); lcd.print("V"); + lcd.print(" "); + + //SET MENU - FLOATTYPE + if (setMenuPage == 0) { + floatTemp = voltageBatteryMin; + } + else { + if (digitalRead(buttonBack) == 1) { + while (digitalRead(buttonBack) == 1) {} voltageBatteryMin = floatTemp; + cancelledMessageLCD(); + setMenuPage = 0; + } + if (digitalRead(buttonSelect) == 1) { + while (digitalRead(buttonSelect) == 1) {} saveSettings(); + setMenuPage = 0; + savedMessageLCD(); + } + currentMenuSetMillis = millis(); + if (digitalRead(buttonRight) == 1) { //Right button press (increments setting values) + while (digitalRead(buttonRight) == 1) { + if (millis() - currentMenuSetMillis > longPressTime) { //Long Press + voltageBatteryMin += 1.00; //Increment by 1 + voltageBatteryMin = constrain(voltageBatteryMin, vOutSystemMin, vOutSystemMax); //Limit settings values to a range + lcd.setCursor(2, 1); lcd.print(voltageBatteryMin, 2); delay(longPressInterval); //Display settings data + } + else { //Short Press + voltageBatteryMin += 0.01; //Increment by 0.01 + voltageBatteryMin = constrain(voltageBatteryMin, vOutSystemMin, vOutSystemMax); //Limit settings values to a range + lcd.setCursor(2, 1); lcd.print(voltageBatteryMin, 2); delay(shortPressInterval); //Display settings data + } + lcd.print("V "); //Display unit + } + } + else if (digitalRead(buttonLeft) == 1) { //Left button press (decrements setting values) + while (digitalRead(buttonLeft) == 1) { + if (millis() - currentMenuSetMillis > longPressTime) { //Long Press + voltageBatteryMin -= 1.00; //Increment by 1 + voltageBatteryMin = constrain(voltageBatteryMin, vOutSystemMin, vOutSystemMax); //Limit settings values to a range + lcd.setCursor(2, 1); lcd.print(voltageBatteryMin, 2); delay(longPressInterval); //Display settings data + } + else { //Short Press + voltageBatteryMin -= 0.01; //Increment by 0.01 + voltageBatteryMin = constrain(voltageBatteryMin, vOutSystemMin, vOutSystemMax); //Limit settings values to a range + lcd.setCursor(2, 1); lcd.print(voltageBatteryMin, 2); delay(shortPressInterval); //Display settings data + } + lcd.print("V "); //Display unit + } + } + } + } + ///// SETTINGS MENU ITEM: CHARGING CURRENT ///// + else if (subMenuPage == 4) { + lcd.setCursor(0, 0); lcd.print("CHARGING CURRENT"); + if (setMenuPage == 1) { + lcd.setCursor(0, 1); + lcd.print(" >"); + } + else { + lcd.setCursor(0, 1); + lcd.print("= "); + } + lcd.setCursor(2, 1); lcd.print(currentCharging, 2); lcd.print("A"); + lcd.print(" "); + + //SET MENU - FLOATTYPE + if (setMenuPage == 0) { + floatTemp = currentCharging; + } + else { + if (digitalRead(buttonBack) == 1) { + while (digitalRead(buttonBack) == 1) {} currentCharging = floatTemp; + cancelledMessageLCD(); + setMenuPage = 0; + } + if (digitalRead(buttonSelect) == 1) { + while (digitalRead(buttonSelect) == 1) {} saveSettings(); + setMenuPage = 0; + savedMessageLCD(); + } + currentMenuSetMillis = millis(); + if (digitalRead(buttonRight) == 1) { //Right button press (increments setting values) + while (digitalRead(buttonRight) == 1) { + if (millis() - currentMenuSetMillis > longPressTime) { //Long Press + currentCharging += 1.00; //Increment by 1 + currentCharging = constrain(currentCharging, 0.0, cOutSystemMax); //Limit settings values to a range + lcd.setCursor(2, 1); lcd.print(currentCharging, 2); delay(longPressInterval); //Display settings data + } + else { //Short Press + currentCharging += 0.01; //Increment by 0.01 + currentCharging = constrain(currentCharging, 0.0, cOutSystemMax); //Limit settings values to a range + lcd.setCursor(2, 1); lcd.print(currentCharging, 2); delay(shortPressInterval); //Display settings data + } + lcd.print("A "); //Display unit + } + } + else if (digitalRead(buttonLeft) == 1) { //Left button press (decrements setting values) + while (digitalRead(buttonLeft) == 1) { + if (millis() - currentMenuSetMillis > longPressTime) { //Long Press + currentCharging -= 1.00; //Increment by 1 + currentCharging = constrain(currentCharging, 0.0, cOutSystemMax); //Limit settings values to a range + lcd.setCursor(2, 1); lcd.print(currentCharging, 2); delay(longPressInterval); //Display settings data + } + else { //Short Press + currentCharging -= 0.01; //Increment by 0.01 + currentCharging = constrain(currentCharging, 0.0, cOutSystemMax); //Limit settings values to a range + lcd.setCursor(2, 1); lcd.print(currentCharging, 2); delay(shortPressInterval); //Display settings data + } + lcd.print("A "); //Display unit + } + } + } + } + ///// SETTINGS MENU ITEM: COOLING FAN ///// + else if (subMenuPage == 5) { + lcd.setCursor(0, 0); lcd.print("COOLING FAN "); + if (setMenuPage == 1) { + lcd.setCursor(0, 1); + lcd.print(" >"); + } + else { + lcd.setCursor(0, 1); + lcd.print("= "); + } + if (enableFan == 1) { + lcd.print("ENABLED "); + } + else { + lcd.print("DISABLE "); + } + + //SET MENU - BOOLTYPE + if (setMenuPage == 0) { + boolTemp = enableFan; + } + else { + if (digitalRead(buttonRight) == 1 || digitalRead(buttonLeft) == 1) { + while (digitalRead(buttonRight) == 1 || digitalRead(buttonLeft) == 1) {} + if (enableFan == 1) { + enableFan = 0; + } else { + enableFan = 1; + } + } + if (digitalRead(buttonBack) == 1) { + while (digitalRead(buttonBack) == 1) {} enableFan = boolTemp; + cancelledMessageLCD(); + setMenuPage = 0; + } + if (digitalRead(buttonSelect) == 1) { + while (digitalRead(buttonSelect) == 1) {} saveSettings(); + setMenuPage = 0; + savedMessageLCD(); + } + } + } + ///// SETTINGS MENU ITEM: FAN TRIG TEMP ///// + else if (subMenuPage == 6) { + lcd.setCursor(0, 0); lcd.print("FAN TRIGGER TEMP"); + if (setMenuPage == 1) { + lcd.setCursor(0, 1); + lcd.print(" >"); + } + else { + lcd.setCursor(0, 1); + lcd.print("= "); + } + lcd.setCursor(2, 1); lcd.print(temperatureFan); + lcd.print((char)223); lcd.print("C"); lcd.print(" "); + + //SET MENU - INTTYPE + if (setMenuPage == 0) { + intTemp = temperatureFan; + } + else { + if (digitalRead(buttonBack) == 1) { + while (digitalRead(buttonBack) == 1) {} temperatureFan = intTemp; + cancelledMessageLCD(); + setMenuPage = 0; + } + if (digitalRead(buttonSelect) == 1) { + while (digitalRead(buttonSelect) == 1) {} saveSettings(); + setMenuPage = 0; + savedMessageLCD(); + } + if (digitalRead(buttonRight) == 1) { //Right button press (increments setting values) + while (digitalRead(buttonRight) == 1) { + temperatureFan++; //Increment by 1 + temperatureFan = constrain(temperatureFan, 0, 100); //Limit settings values to a range + lcd.setCursor(2, 1); lcd.print(temperatureFan); delay(shortPressInterval); //Display settings data + lcd.print((char)223); lcd.print("C "); //Display unit + } + } + else if (digitalRead(buttonLeft) == 1) { //Left button press (decrements setting values) + while (digitalRead(buttonLeft) == 1) { + temperatureFan--; //Increment by 1 + temperatureFan = constrain(temperatureFan, 0, 100); //Limit settings values to a range + lcd.setCursor(2, 1); lcd.print(temperatureFan); delay(shortPressInterval); //Display settings data + lcd.print((char)223); lcd.print("C "); //Display unit + } + } + } + } + ///// SETTINGS MENU ITEM: SHUTDOWN TEMP ///// + else if (subMenuPage == 7) { + lcd.setCursor(0, 0); lcd.print("SHUTDOWN TEMP "); + if (setMenuPage == 1) { + lcd.setCursor(0, 1); + lcd.print(" >"); + } + else { + lcd.setCursor(0, 1); + lcd.print("= "); + } + lcd.setCursor(2, 1); lcd.print(temperatureMax); + lcd.print((char)223); lcd.print("C"); lcd.print(" "); + + //SET MENU - INTTYPE + if (setMenuPage == 0) { + intTemp = temperatureMax; + } + else { + if (digitalRead(buttonBack) == 1) { + while (digitalRead(buttonBack) == 1) {} temperatureMax = intTemp; + cancelledMessageLCD(); + setMenuPage = 0; + } + if (digitalRead(buttonSelect) == 1) { + while (digitalRead(buttonSelect) == 1) {} saveSettings(); + setMenuPage = 0; + savedMessageLCD(); + } + if (digitalRead(buttonRight) == 1) { //Right button press (increments setting values) + while (digitalRead(buttonRight) == 1) { + temperatureMax++; //Increment by 1 + temperatureMax = constrain(temperatureMax, 0, 120); //Limit settings values to a range + lcd.setCursor(2, 1); lcd.print(temperatureMax); delay(shortPressInterval); //Display settings data + lcd.print((char)223); lcd.print("C "); //Display unit + } + } + else if (digitalRead(buttonLeft) == 1) { //Left button press (decrements setting values) + while (digitalRead(buttonLeft) == 1) { + temperatureMax--; //Increment by 1 + temperatureMax = constrain(temperatureMax, 0, 120); //Limit settings values to a range + lcd.setCursor(2, 1); lcd.print(temperatureMax); delay(shortPressInterval); //Display settings data + lcd.print((char)223); lcd.print("C "); //Display unit + } + } + } + } + ///// SETTINGS MENU ITEM: WIFI FEATURE ///// + else if (subMenuPage == 8) { + lcd.setCursor(0, 0); lcd.print("WIFI FEATURE "); + if (setMenuPage == 1) { + lcd.setCursor(0, 1); + lcd.print(" >"); + } + else { + lcd.setCursor(0, 1); + lcd.print("= "); + } + if (enableWiFi == 1) { + lcd.print("ENABLED "); + } + else { + lcd.print("DISABLED "); + } + + //SET MENU - BOOLTYPE + if (setMenuPage == 0) { + boolTemp = enableWiFi; + } + else { + if (digitalRead(buttonRight) == 1 || digitalRead(buttonLeft) == 1) { + while (digitalRead(buttonRight) == 1 || digitalRead(buttonLeft) == 1) {} + if (enableWiFi == 1) { + enableWiFi = 0; + } else { + enableWiFi = 1; + } + } + if (digitalRead(buttonBack) == 1) { + while (digitalRead(buttonBack) == 1) {} enableWiFi = boolTemp; + cancelledMessageLCD(); + setMenuPage = 0; + } + if (digitalRead(buttonSelect) == 1) { + while (digitalRead(buttonSelect) == 1) {} saveSettings(); + setMenuPage = 0; + savedMessageLCD(); + } + } + } + + ///// SETTINGS MENU ITEM: AUTOLOAD ///// + else if (subMenuPage == 9) { + lcd.setCursor(0, 0); lcd.print("AUTOLOAD FEATURE"); + if (setMenuPage == 1) { + lcd.setCursor(0, 1); + lcd.print(" >"); + } + else { + lcd.setCursor(0, 1); + lcd.print("= "); + } + if (flashMemLoad == 1) { + lcd.print("ENABLED "); + } + else { + lcd.print("DISABLED "); + } + + //SET MENU - BOOLTYPE + if (setMenuPage == 0) { + boolTemp = flashMemLoad; + } + else { + if (digitalRead(buttonRight) == 1 || digitalRead(buttonLeft) == 1) { + while (digitalRead(buttonRight) == 1 || digitalRead(buttonLeft) == 1) {} + if (flashMemLoad == 1) { + flashMemLoad = 0; + } else { + flashMemLoad = 1; + } + } + if (digitalRead(buttonBack) == 1) { + while (digitalRead(buttonBack) == 1) {} flashMemLoad = boolTemp; + cancelledMessageLCD(); + setMenuPage = 0; + } + if (digitalRead(buttonSelect) == 1) { + while (digitalRead(buttonSelect) == 1) {} saveAutoloadSettings(); + setMenuPage = 0; + savedMessageLCD(); + } + } + } + ///// SETTINGS MENU ITEM: BACKLIGHT SLEEP ///// + else if (subMenuPage == 10) { + lcd.setCursor(0, 0); lcd.print("BACKLIGHT SLEEP "); + if (setMenuPage == 1) { + lcd.setCursor(0, 1); + lcd.print(" >"); + } + else { + lcd.setCursor(0, 1); + lcd.print("= "); + } + lcd.setCursor(2, 1); + if (backlightSleepMode == 1) { + lcd.print("10 SECONDS "); + } + else if (backlightSleepMode == 2) { + lcd.print("5 MINUTES "); + } + else if (backlightSleepMode == 3) { + lcd.print("1 HOUR "); + } + else if (backlightSleepMode == 4) { + lcd.print("6 HOURS "); + } + else if (backlightSleepMode == 5) { + lcd.print("12 HOURS "); + } + else if (backlightSleepMode == 6) { + lcd.print("1 DAY "); + } + else if (backlightSleepMode == 7) { + lcd.print("3 DAYS "); + } + else if (backlightSleepMode == 8) { + lcd.print("1 WEEK "); + } + else if (backlightSleepMode == 9) { + lcd.print("1 MONTH "); + } + else { + lcd.print("NEVER "); + } + + //SET MENU - INTMODETYPE + if (setMenuPage == 0) { + intTemp = backlightSleepMode; + } + else { + if (digitalRead(buttonBack) == 1) { + while (digitalRead(buttonBack) == 1) {} backlightSleepMode = intTemp; + cancelledMessageLCD(); + setMenuPage = 0; + } + if (digitalRead(buttonSelect) == 1) { + while (digitalRead(buttonSelect) == 1) {} saveSettings(); + setMenuPage = 0; + savedMessageLCD(); + } + if (digitalRead(buttonRight) == 1) { //Right button press (increments setting values) + backlightSleepMode++; //Increment by 1 + backlightSleepMode = constrain(backlightSleepMode, 0, 9); //Limit settings values to a range + lcd.setCursor(2, 1); + if (backlightSleepMode == 1) { + lcd.print("10 SECONDS "); + } + else if (backlightSleepMode == 2) { + lcd.print("5 MINUTES "); + } + else if (backlightSleepMode == 3) { + lcd.print("1 HOUR "); + } + else if (backlightSleepMode == 4) { + lcd.print("6 HOURS "); + } + else if (backlightSleepMode == 5) { + lcd.print("12 HOURS "); + } + else if (backlightSleepMode == 6) { + lcd.print("1 DAY "); + } + else if (backlightSleepMode == 7) { + lcd.print("3 DAYS "); + } + else if (backlightSleepMode == 8) { + lcd.print("1 WEEK "); + } + else if (backlightSleepMode == 9) { + lcd.print("1 MONTH "); + } + else { + lcd.print("NEVER "); + } + while (digitalRead(buttonRight) == 1) {} + } + else if (digitalRead(buttonLeft) == 1) { //Left button press (decrements setting values) + backlightSleepMode--; //Increment by 1 + backlightSleepMode = constrain(backlightSleepMode, 0, 9); //Limit settings values to a range + lcd.setCursor(2, 1); + if (backlightSleepMode == 1) { + lcd.print("10 SECONDS "); + } + else if (backlightSleepMode == 2) { + lcd.print("5 MINUTES "); + } + else if (backlightSleepMode == 3) { + lcd.print("1 HOUR "); + } + else if (backlightSleepMode == 4) { + lcd.print("6 HOURS "); + } + else if (backlightSleepMode == 5) { + lcd.print("12 HOURS "); + } + else if (backlightSleepMode == 6) { + lcd.print("1 DAY "); + } + else if (backlightSleepMode == 7) { + lcd.print("3 DAYS "); + } + else if (backlightSleepMode == 8) { + lcd.print("1 WEEK "); + } + else if (backlightSleepMode == 9) { + lcd.print("1 MONTH "); + } + else { + lcd.print("NEVER "); + } + while (digitalRead(buttonLeft) == 1) {} + } + } + } + ///// SETTINGS MENU ITEM: FACTORY RESET ///// + else if (subMenuPage == 11) { + if (setMenuPage == 0) { + lcd.setCursor(0, 0); lcd.print("FACTORY RESET "); + lcd.setCursor(0, 1); lcd.print("> PRESS SELECT "); + } + else { + if (confirmationMenu == 0) { + lcd.setCursor(0, 0); // Display ">No" + lcd.print(" ARE YOU SURE? "); + lcd.setCursor(0, 1); + lcd.print(" >NO YES "); + } + else { + lcd.setCursor(0, 0); // Display ">YES" + lcd.print(" ARE YOU SURE? "); + lcd.setCursor(0, 1); + lcd.print(" NO >YES "); + } + if (digitalRead(buttonRight) == 1 || digitalRead(buttonLeft) == 1) { + while (digitalRead(buttonRight) == 1 || digitalRead(buttonLeft) == 1) {} if (confirmationMenu == 0) { + confirmationMenu = 1; //Cycle Yes NO + } else { + confirmationMenu = 0; + } + } + if (digitalRead(buttonBack) == 1) { + while (digitalRead(buttonBack) == 1) {} cancelledMessageLCD(); //Cancel + setMenuPage = 0; + confirmationMenu = 0; + } + if (digitalRead(buttonSelect) == 1) { + while (digitalRead(buttonSelect) == 1) {} if (confirmationMenu == 1) { + factoryReset(); + factoryResetMessageLCD(); + } setMenuPage = 0; + confirmationMenu = 0; + subMenuPage = 0; + } + } + } + ///// SETTINGS MENU ITEM: FIRMWARE VERSION ///// + else if (subMenuPage == 12) { + if (setMenuPage == 0) { + lcd.setCursor(0, 0); lcd.print("FIRMWARE VERSION"); + lcd.setCursor(0, 1); lcd.print(firmwareInfo); + lcd.setCursor(8, 1); lcd.print(firmwareDate); + + + } + else { + lcd.setCursor(0, 0); lcd.print(firmwareContactR1); + lcd.setCursor(0, 1); lcd.print(firmwareContactR2); + if (digitalRead(buttonBack) == 1 || digitalRead(buttonSelect) == 1) { + while (digitalRead(buttonBack) == 1 || digitalRead(buttonSelect) == 1) {} setMenuPage = 0; //Cancel + } + } + } + } + //MAIN MENU + else if (settingMode == 0) { + chargingPause = 0; + + //LCD BACKLIGHT SLEEP + lcdBacklight(); + + //BUTTON KEYPRESS + if (digitalRead(buttonRight) == 1) { + buttonRightCommand = 1; + lcdBacklight_Wake(); + } + if (digitalRead(buttonLeft) == 1) { + buttonLeftCommand = 1; + lcdBacklight_Wake(); + } + if (digitalRead(buttonBack) == 1) { + buttonBackCommand = 1; + lcdBacklight_Wake(); + } + if (digitalRead(buttonSelect) == 1) { + buttonSelectCommand = 1; + lcdBacklight_Wake(); + } + + currentLCDMillis = millis(); + if (currentLCDMillis - prevLCDMillis >= millisLCDInterval && enableLCD == 1) { //Run routine every millisLCDInterval (ms) + prevLCDMillis = currentLCDMillis; + + //MENU PAGE BUTTON ACTION + if (buttonRightCommand == 1) { + buttonRightCommand = 0; + menuPage++; + lcd.clear(); + } + else if (buttonLeftCommand == 1) { + buttonLeftCommand = 0; + menuPage--; + lcd.clear(); + } + else if (buttonBackCommand == 1) { + buttonBackCommand = 0; + menuPage = 0; + lcd.clear(); + } + else if (buttonSelectCommand == 1 && menuPage == 4) { + buttonSelectCommand = 0; + settingMode = 1; + lcd.clear(); + } + if (menuPage > menuPages) { + menuPage = 0; + } + else if (menuPage < 0) { + menuPage = menuPages; + } + + if (menuPage == 0) { + displayConfig1(); + } + else if (menuPage == 1) { + displayConfig2(); + } + else if (menuPage == 2) { + displayConfig3(); + } + else if (menuPage == 3) { + displayConfig4(); + } + else if (menuPage == 4) { + displayConfig5(); + } + } + } +} diff --git a/ARDUINO_MPPT_FIRMWARE_V2.1/ARDUINO_MPPT_FIRMWARE_V2.1.ino b/ARDUINO_MPPT_FIRMWARE_V2.1/ARDUINO_MPPT_FIRMWARE_V2.1.ino new file mode 100644 index 0000000..15c601e --- /dev/null +++ b/ARDUINO_MPPT_FIRMWARE_V2.1/ARDUINO_MPPT_FIRMWARE_V2.1.ino @@ -0,0 +1,637 @@ +/* PROJECT FUGU FIRMWARE V1.10 (DIY 1kW Open Source MPPT Solar Charge Controller) + By: TechBuilder (Angelo Casimiro) + FIRMWARE STATUS: Verified Stable Build Version + (Contact me for the experimental beta versions) + ----------------------------------------------------------------------------------------------------------- + DATE CREATED: 02/07/2021 + DATE MODIFIED: 30/08/2021 + ----------------------------------------------------------------------------------------------------------- + CONTACTS: + GitHub - www.github.com/AngeloCasi (New firmware releases will only be available on GitHub Link) + Email - casithebuilder@gmail.com + YouTube - www.youtube.com/TechBuilder + Facebook - www.facebook.com/AngeloCasii + ----------------------------------------------------------------------------------------------------------- + PROGRAM FEATURES: + - MPPT Perturbed Algorithm With CC-CV + - WiFi & Bluetooth BLE Blynk Phone App Telemetry + - Selectable Charger/PSU Mode (can operate as a programmable buck converter) + - Dual Core ESP32 Unlocked (using xTaskCreatePinnedToCore(); ) + - Precision ADC Tracking Auto ADS1115/ADS1015 Detection (16bit/12bit I2C ADC) + - Automatic ACS712-30A Current Sensor Calibration + - Equipped With Battery Disconnect & Input Disconnect Recovery Protection Protocol + - LCD Menu Interface (with settings & 4 display layouts) + - Flash Memory (non-volatile settings save function) + - Settable PWM Resolution (8bit-16bit) + - Settable PWM Switching Frequency (1.2kHz - 312kHz) + ----------------------------------------------------------------------------------------------------------- + PROGRAM INSTRUCTIONS: + 1.) Watch YouTube video tutorial first before using + 2.) Install the required Arduino libraries for the ICs + 3.) Select Tools > ESP32 Dev Board Board + 4.) Do not modify code unless you know what you are doing + 5.) The MPPT's synchronous buck converter topology is code dependent, messing with the algorithm + and safety protection protocols can be extremely dangerous especially when dealing with HVDC. + 6.) Install Blynk Legacy to access the phone app telemetry feature + 7.) Input the Blynk authentication in this program token sent by Blynk to your email after registration + 8.) Input WiFi SSID and password in this program + 9.) When using WiFi only mode, change "disableFlashAutoLoad = 0" to = 1 (LCD and buttons not installed) + this prevents the MPPT unit to load the Flash Memory saved settings and will load the Arduino variable + declarations set below instead + ----------------------------------------------------------------------------------------------------------- + GOOGLE DRIVE PROJECT LINK: coming soon + INSTRUCTABLE TUTORIAL LINK: coming soon + YOUTUBE TUTORIAL LINK: www.youtube.com/watch?v=ShXNJM6uHLM + GITHUB UPDATED FUGU FIRMWARE LINK: github.com/AngeloCasi/FUGU-ARDUINO-MPPT-FIRMWARE + ----------------------------------------------------------------------------------------------------------- + ACTIVE CHIPS USED IN FIRMWARE: + - ESP32 WROOM32 + - ADS1115/ADS1015 I2C ADC + - ACS712-30A Current Sensor IC + - IR2104 MOSFET Driver + - CH340C USB TO UART IC + - 16X2 I2C Character LCD + + OTHER CHIPS USED IN PROJECT: + - XL7005A 80V 0.4A Buck Regulator (2x) + - AMS1115-3.3 LDO Linear Regulator + - AMS1115-5.0 LDO Linear Regulator + - CSD19505 N-ch MOSFETS (3x) + - B1212 DC-DC Isolated Converter + - SS310 Diodes +*/ +//================================ MPPT FIRMWARE LCD MENU INFO =====================================// +// The lines below are for the Firmware Version info displayed on the MPPT's LCD Menu Interface // +//==================================================================================================// +String +firmwareInfo = "V2.10", +firmwareDate = "23/06/2022", +firmwareContactR1 = "www.youtube.com/", +firmwareContactR2 = "TechBuilder "; + +//====================== ARDUINO LIBRARIES (ESP32 Compatible Libraries) ============================// +// You will have to download and install the following libraries below in order to program the MPPT // +// unit. Visit TechBuilder's YouTube channel for the "MPPT" tutorial. // +//============================================================================================= ====// +#include //SYSTEM PARAMETER - EEPROM Library (By: Arduino) +#include //SYSTEM PARAMETER - WIRE Library (By: Arduino) +#include //SYSTEM PARAMETER - SPI Library (By: Arduino) +#include //SYSTEM PARAMETER - WiFi Library (By: Arduino) +#include //SYSTEM PARAMETER - WiFi Library (By: Arduino) +//#include //SYSTEM PARAMETER - Blynk WiFi Library For Phone App +#define BLINKER_WIFI +#define BLINKER_ALIGENIE_OUTLET +#define BLINKER_WITHOUT_SSL +#define BLINKER_ALIGENIE_SENSOR +#include //#define BLINKER_ESP_SMARTCONFIG +#include //系统参数 - ESP32 LCD 兼容库(作者:Robojax) +#include +//#include //SYSTEM PARAMETER - ADS1115/ADS1015 ADC Library (By: Adafruit) +#include +LiquidCrystal_I2C lcd(0x27, 20, 4); //系统参数 - 配置 LCD RowCol 大小和 I2C 地址 +TaskHandle_t Core2; //SYSTEM PARAMETER - Used for the ESP32 dual core operation +//Adafruit_ADS1015 ads; //SYSTEM PARAMETER - ADS1015 ADC Library (By: Adafruit) Kindly delete this line if you are using ADS1115 +//Adafruit_ADS1115 ads; //SYSTEM PARAMETER - ADS1115 ADC Library (By: Adafruit) Kindly uncomment this if you are using ADS1115 +INA226 ina1; +INA226 ina2; +#include +#define timezone 8 + +BlinkerNumber Num1("num-9y2"); +BlinkerNumber Num2("num-m2k"); +BlinkerNumber Num3("num-5up"); +BlinkerNumber Num4("num-ahb"); +BlinkerNumber Num5("num-l24"); +BlinkerNumber Num6("num-3bm"); +BlinkerNumber Num7("num-rgu"); +BlinkerNumber Num8("num-ao5"); +BlinkerNumber Num9("num-ycz"); + +BlinkerButton Button1("btn-e6n"); +BlinkerButton Button2("btn-e3t"); +BlinkerButton Button3("btn-ogw"); +BlinkerButton Button4("btn-q4l"); + + +//====================================== USER PARAMETERS ===========================================// +//下面的参数是没有MPPT充电器设置时使用的默认参数 // +//通过 LCD 菜单界面或手机 WiFi 应用程序设置或保存。这里的一些参数// +//将允许您覆盖或解锁高级用户的功能(不在 LCD 菜单上的设置)// +//==================================================================================================// +#define backflow_MOSFET 27 //SYSTEM PARAMETER - Backflow MOSFET +#define buck_IN 33 //SYSTEM PARAMETER - Buck MOSFET Driver PWM Pin +#define buck_EN 32 //SYSTEM PARAMETER - Buck MOSFET Driver Enable Pin +#define LED 2 //SYSTEM PARAMETER - LED Indicator GPIO Pin +#define FAN 16 //SYSTEM PARAMETER - Fan GPIO Pin +//#define ADC_ALERT 35 //SYSTEM PARAMETER - ADC_ALERT GPIO Pin +#define INA1_ALERT 35 //SYSTEM PARAMETER - INA226 Alert GPIO Pin +#define INA2_ALERT 34 //SYSTEM PARAMETER - INA226 Alert GPIO Pin +#define TempSensor 39 //SYSTEM PARAMETER - Temperature Sensor GPIO Pin +#define buttonLeft 18 //SYSTEM PARAMETER - +#define buttonRight 19 //SYSTEM PARAMETER - +#define buttonBack 17 //SYSTEM PARAMETER - +#define buttonSelect 23 //SYSTEM PARAMETER - + +#define eeprom_size 4096 + +#define MPPT_Mode_add 2448 // charging mode setting +#define voltageBatteryMax_add 2449 // Max Battery Voltage (whole) +#define voltageBatteryMax2_add 2450 // Max Battery Voltage (decimal) +#define voltageBatteryMin_add 2451 // Min Battery Voltage (whole) +#define voltageBatteryMin2_add 2452 // Min Battery Voltage (decimal) +#define currentCharging_add 2453 // Charging Current (whole) +#define currentCharging2_add 2454 // Charging Current (decimal) +#define enableFan_add 2455 // Fan Enable (Bool) +#define temperatureFan_add 2456 // Fan Temp (Integer) +#define temperatureMax_add 2457 // Shutdown Temp (Integer) +#define enableWiFi_add 2458 // Enable WiFi (Boolean) +#define flashMemLoad_add 2459 // Enable autoload (on by default) +#define output_Mode_add 2460 // Charger/PSU Mode Selection (1 = Charger Mode) +#define backlightSleepMode_add 2461 // LCD backlight sleep timer (default: 0 = never) + +//========================================= WiFi SSID ==============================================// +// This MPPT firmware uses the Blynk phone app and arduino library for controls and data telemetry // +// Fill in your WiFi SSID and password. You will also have to get your own authentication token // +// from email after registering from the Blynk platform. // +//==================================================================================================// +char +auth[] = "InputBlynkAuthenticationToken", // USER PARAMETER - Input Blynk Authentication Token (From email after registration) +ssid[] = "", // USER PARAMETER - Enter Your WiFi SSID +pass[] = ""; // USER PARAMETER - Enter Your WiFi Password +const char *blinker_id = ""; //Blinker ID +//====================================== USER PARAMETERS ==========================================// +//下面的参数是没有MPPT充电器设置时使用的默认参数 // +//通过 LCD 菜单界面或手机 WiFi 应用程序设置或保存。这里的一些参数// +//将允许您覆盖或解锁高级用户的功能(不在 LCD 菜单上的设置)// +//=================================================================================================// +bool +MPPT_Mode = 1, // USER PARAMETER - 启用 MPPT 算法,当禁用充电器时使用 CC-CV 算法 +output_Mode = 1, // USER PARAMETER - 0 = PSU 模式, 1 = 充电器模式 +disableFlashAutoLoad = 0, // USER PARAMETER - 强制 MPPT 不使用闪存保存的设置,启用此“1”默认为已编程的固件设置 +enablePPWM = 1, // USER PARAMETER - 启用预测 PWM,这加快了调节速度(仅适用于电池充电应用) +enableWiFi = 1, // USER PARAMETER - 启用 WiFi 连接 +enableFan = 1, // USER PARAMETER - 启用冷却风扇 +enableBluetooth = 1, // USER PARAMETER - 启用蓝牙连 +enableLCD = 1, // USER PARAMETER - 启用 接LCD 显示 +enableLCDBacklight = 1, // USER PARAMETER - 启用 LCD 显示器的背光 +overrideFan = 0, // USER PARAMETER - 风扇始终开启 +enableDynamicCooling = 0; // USER PARAMETER - 启用 PWM 冷却控制 +int +serialTelemMode = 1, // USER PARAMETER - 选择串行遥测数据馈送(0 - 禁用串行,1 - 显示所有数据,2 - 显示基本,3 - 仅数字) +pwmResolution = 11, // USER PARAMETER - PWM 位分辨率 +pwmFrequency = 39000, // USER PARAMETER - PWM 开关频率 - Hz(用于降压) +temperatureFan = 60, // USER PARAMETER - 风扇开启的温度阈值 +temperatureMax = 90, // USER PARAMETER - 过热,超过时系统关闭(摄氏度) +telemCounterReset = 0, // USER PARAMETER - 每隔一次重置 Telem 数据(0 = 从不,1 = 日,2 = 周,3 = 月,4 = 年) +errorTimeLimit = 1000, // USER PARAMETER - 重置错误计数器的时间间隔(毫秒) +errorCountLimit = 5, // USER PARAMETER - 最大错误数 +millisRoutineInterval = 250, // USER PARAMETER - 例程函数的时间间隔刷新率 (ms) +millisSerialInterval = 5, // USER PARAMETER - USB 串行数据馈送的时间间隔刷新率 (ms) +millisLCDInterval = 1000, // USER PARAMETER - LCD 显示器的时间间隔刷新率 (ms) +millisWiFiInterval = 1000, // USER PARAMETER - WiFi 遥测的时间间隔刷新率 (ms) +millisLCDBackLInterval = 1000, // USER PARAMETER - 用户参数 - WiFi 遥测的时间间隔刷新率 (ms) +backlightSleepMode = 2, // USER PARAMETER - - 0 = 从不, 1 = 10 秒, 2 = 5 分钟, 3 = 1 小时, 4 = 6 小时, 5 = 12 小时, 6 = 1 天, 7 = 3 天, 8 = 1 周, 9 = 1个月 +baudRate = 500000; // 用户参数 - USB 串行波特率 (bps) + +float +voltageBatteryMax = 12.6000, // USER PARAMETER - 最大电池充电电压(输出 V) +voltageBatteryMin = 3.0000, // USER PARAMETER - 最小电池充电电压(输出 V) +currentCharging = 1.0000, // USER PARAMETER - 最大充电电流(A - 输出) +electricalPrice = 0.6000; // USER PARAMETER - 每千瓦时的输入电价 + + +//================================== CALIBRATION PARAMETERS =======================================// +//可以调整以下参数以设计您自己的 MPPT 充电控制器。只修改 // +//如果你知道你在做什么,下面的值。以下值已针对 // 进行了预校准 +// TechBuilder (Angelo S. Casimiro) 设计的 MPPT 充电控制器 // // +//=================================================================================================// +const bool +ADS1015_Mode = 1; // CALIB PARAMETER - Use 1 for ADS1015 ADC model use 0 for ADS1115 ADC model +const int +ADC_GainSelect = 2, // 校准参数 - ADC 增益选择 (0→±6.144V 3mV/bit, 1→±4.096V 2mV/bit, 2→±2.048V 1mV/bit) +avgCountVS = 3, // 校准参数 - 电压传感器平均采样计数(推荐:3) +avgCountCS = 4, // 校准参数 - 电流传感器平均采样计数(推荐:4) +avgCountTS = 500; // 校准参数 - 温度传感器平均采样计数 +float +inVoltageDivRatio = 2.9784, // 校准参数 - 输入分压器传感器比率(更改此值以校准电压传感器) +outVoltageDivRatio = 2.8275, // 校准参数 - 输出分压器传感器比率(更改此值以校准电压传感器) +vOutSystemMax = 80.0000, // 校准参数 - 最大输入电压 +cOutSystemMax = 50.0000, // 校准参数 - 最大输出电压 +ntcResistance = 10000.00, // 校准参数 - NTC 温度传感器的电阻。如果您使用 10k NTC,请更改为 10000.00 +voltageDropout = 1.0000, // 校准参数 - 降压稳压器的压降电压(由于最大占空比限制而存在 DOV) +voltageBatteryThresh = 1.5000, // 校准参数 - 达到此电压时断电(输出 V) +currentInAbsolute = 31.0000, // 校准参数 - 系统可以处理的最大输入电流(A - 输入) +currentOutAbsolute = 50.0000, // 校准参数 - 系统可以处理的最大输出电流(A - 输入) +PPWM_margin = 99.5000, // 校准参数 - 预测 PWM 的最小工作占空比 (%) +PWM_MaxDC = 97.0000, // 校准参数 - 最大工作占空比 (%) 90%-97% 是好的 +efficiencyRate = 1.0000, // 校准参数 - 理论降压效率(十进制百分比) +currentMidPoint = 2.5250, // 校准参数 - 电流传感器中点 (V) +currentSens = 0.0000, // 校准参数 - 电流传感器灵敏度 (V/A) +currentSensV = 0.0330, // 校准参数 - 电流传感器灵敏度 (mV/A) +vInSystemMin = 8.000; // 校准参数 - 系统识别最低电压 + +//===================================== SYSTEM PARAMETERS =========================================// +//不要更改本节中的参数值。下面的值是系统使用的变量 // +//进程。更改值可能会损坏 MPPT 硬件。请保持原样!然而, // +//您可以访问这些变量来获取您的模组所需的数据。// +//=================================================================================================// +bool +buckEnable = 0, // SYSTEM PARAMETER - Buck Enable Status +fanStatus = 0, // SYSTEM PARAMETER - Fan activity status (1 = On, 0 = Off) +bypassEnable = 0, // SYSTEM PARAMETER - +chargingPause = 0, // SYSTEM PARAMETER - +lowPowerMode = 0, // SYSTEM PARAMETER - +buttonRightStatus = 0, // SYSTEM PARAMETER - +buttonLeftStatus = 0, // SYSTEM PARAMETER - +buttonBackStatus = 0, // SYSTEM PARAMETER - +buttonSelectStatus = 0, // SYSTEM PARAMETER - +buttonRightCommand = 0, // SYSTEM PARAMETER - +buttonLeftCommand = 0, // SYSTEM PARAMETER - +buttonBackCommand = 0, // SYSTEM PARAMETER - +buttonSelectCommand = 0, // SYSTEM PARAMETER - +settingMode = 0, // SYSTEM PARAMETER - +setMenuPage = 0, // SYSTEM PARAMETER - +boolTemp = 0, // SYSTEM PARAMETER - +flashMemLoad = 0, // SYSTEM PARAMETER - +confirmationMenu = 0, // SYSTEM PARAMETER - +WIFI = 0, // SYSTEM PARAMETER - +BNC = 0, // SYSTEM PARAMETER - +REC = 0, // SYSTEM PARAMETER - +FLV = 0, // SYSTEM PARAMETER - +IUV = 0, // SYSTEM PARAMETER - +IOV = 0, // SYSTEM PARAMETER - +IOC = 0, // SYSTEM PARAMETER - +OUV = 0, // SYSTEM PARAMETER - +OOV = 0, // SYSTEM PARAMETER - +OOC = 0, // SYSTEM PARAMETER - +OTE = 0; // SYSTEM PARAMETER - +int +inputSource = 0, // SYSTEM PARAMETER - 0 = MPPT 没有电源,1 = MPPT 使用太阳能作为电源,2 = MPPT 使用电池作为电源 +avgStoreTS = 0, // SYSTEM PARAMETER - 温度传感器使用非侵入式平均,这是用于平均平均的累加器 +temperature = 0, // SYSTEM PARAMETER - +sampleStoreTS = 0, // SYSTEM PARAMETER - TS AVG 第 n 个样本 +pwmMax = 0, // SYSTEM PARAMETER - +pwmMaxLimited = 0, // SYSTEM PARAMETER - +PWM = 0, // SYSTEM PARAMETER - +PPWM = 0, // SYSTEM PARAMETER - +pwmChannel = 0, // SYSTEM PARAMETER - +batteryPercent = 0, // SYSTEM PARAMETER - +errorCount = 0, // SYSTEM PARAMETER - +menuPage = 0, // SYSTEM PARAMETER - +subMenuPage = 0, // SYSTEM PARAMETER - +ERR = 0, // SYSTEM PARAMETER - +conv1 = 0, // SYSTEM PARAMETER - +conv2 = 0, // SYSTEM PARAMETER - +intTemp = 0; // SYSTEM PARAMETER - +float +VSI = 0.0000, // SYSTEM PARAMETER - 原始输入电压传感器 ADC 电压 +VSO = 0.0000, // SYSTEM PARAMETER - 原始输出电压传感器 ADC 电压 +CSI = 0.0000, // SYSTEM PARAMETER - 原始电流传感器 ADC 电压 +CSO = 0.0000, // SYSTEM PARAMETER - Raw current sensor ADC voltage +CSI_converted = 0.0000, // SYSTEM PARAMETER - 实际电流传感器 ADC 电压 +CSO_converted = 0.0000, // SYSTEM PARAMETER - Actual current sensor ADC voltage +TS = 0.0000, // SYSTEM PARAMETER - 原始温度传感器 ADC 值 +powerInput = 0.0000, // SYSTEM PARAMETER - 输入功率(太阳能)以瓦特为单位 +powerInputPrev = 0.0000, // SYSTEM PARAMETER - 先前存储的 MPPT 算法的输入功率变量(瓦特) +powerOutput = 0.0000, // SYSTEM PARAMETER - 输出功率(电池或充电功率,以瓦特为单位) +energySavings = 0.0000, // SYSTEM PARAMETER - 法定货币(比索、美元、欧元等)的能源节约 +voltageInput = 0.0000, // SYSTEM PARAMETER - 输入电压(太阳能电压) +voltageInputPrev = 0.0000, // SYSTEM PARAMETER - 先前存储的 MPPT 算法的输入电压变量 +voltageOutput = 0.0000, // SYSTEM PARAMETER - 输入电压(电池电压) +currentInput = 0.0000, // SYSTEM PARAMETER - 输出功率(电池或充电电压) +currentOutput = 0.0000, // SYSTEM PARAMETER - 输出电流(电池或充电电流,以安培为单位) +TSlog = 0.0000, // SYSTEM PARAMETER - NTC 热敏电阻热感应代码的一部分 +ADC_BitReso = 0.0000, // SYSTEM PARAMETER - 系统检测 ADS1015/ADS1115 ADC 的适当位分辨率因子 +daysRunning = 0.0000, // SYSTEM PARAMETER - 存储 MPPT 设备自上次通电以来运行的总天数 +Wh = 0.0000, // SYSTEM PARAMETER - 存储收集到的累积能量(瓦特小时) +kWh = 0.0000, // SYSTEM PARAMETER - 存储收集到的累积能量(千瓦时) +MWh = 0.0000, // SYSTEM PARAMETER - 存储收集到的累积能量(兆瓦时) +loopTime = 0.0000, // SYSTEM PARAMETER - +outputDeviation = 0.0000, // SYSTEM PARAMETER - 输出电压偏差 (%) +buckEfficiency = 0.0000, // SYSTEM PARAMETER - 测量降压转换器功率转换效率(仅适用于我的双电流传感器版本) +floatTemp = 0.0000, +vOutSystemMin = 0.0000; // CALIB PARAMETER - +unsigned long +currentErrorMillis = 0, //SYSTEM PARAMETER - +currentButtonMillis = 0, //SYSTEM PARAMETER - +currentSerialMillis = 0, //SYSTEM PARAMETER - +currentRoutineMillis = 0, //SYSTEM PARAMETER - +currentLCDMillis = 0, //SYSTEM PARAMETER - +currentLCDBackLMillis = 0, //SYSTEM PARAMETER - +currentWiFiMillis = 0, //SYSTEM PARAMETER - +currentMenuSetMillis = 0, //SYSTEM PARAMETER - +prevButtonMillis = 0, //SYSTEM PARAMETER - +prevSerialMillis = 0, //SYSTEM PARAMETER - +prevRoutineMillis = 0, //SYSTEM PARAMETER - +prevErrorMillis = 0, //SYSTEM PARAMETER - +prevWiFiMillis = 0, //SYSTEM PARAMETER - +prevLCDMillis = 0, //SYSTEM PARAMETER - +prevLCDBackLMillis = 0, //SYSTEM PARAMETER - +timeOn = 0, //SYSTEM PARAMETER - +loopTimeStart = 0, //SYSTEM PARAMETER - 用于循环循环秒表,记录循环开始时间 +loopTimeEnd = 0, //SYSTEM PARAMETER - 用于循环循环秒表,记录循环结束时间 +secondsElapsed = 0; //SYSTEM PARAMETER - + +//====================================== MAIN PROGRAM =============================================// +// The codes below contain all the system processes for the MPPT firmware. Most of them are called // +// from the 8 .ino tabs. The codes are too long, Arduino tabs helped me a lot in organizing them. // +// The firmware runs on two cores of the Arduino ESP32 as seen on the two separate pairs of void // +// setups and loops. The xTaskCreatePinnedToCore() freeRTOS function allows you to access the // +// unused ESP32 core through Arduino. Yes it does multicore processes simultaneously! // +//=================================================================================================// + +void dataRead(const String &data) +{ + BLINKER_LOG("Blinker readString: ", data); +} + +void heartbeat() +{ + Num1.print(powerInput); + Num2.print(voltageInput); + Num3.print(currentInput); + Num4.print(batteryPercent); + Num5.print(voltageOutput); + Num6.print(currentOutput); + Num7.print(Wh/1000); + Num8.print(electricalPrice); + Num9.print(temperature); + + if(buckEnable==1){Button1.print("off");}else{Button1.print("on");} + if(batteryPercent >= 99){Button2.print("off");}else{Button2.print("on");} + if(batteryPercent <= 10){Button3.print("off");}else{Button3.print("on");} + if(IUV == 0){Button4.print("off");}else{Button4.print("on");} + +} +void dataStorage() +{ + Blinker.dataStorage("data-1", powerInput); //数据组件名,数据值 + Blinker.dataStorage("data-2", voltageInput); + Blinker.dataStorage("data-3", currentInput); + Blinker.dataStorage("data-4", powerOutput); + Blinker.dataStorage("data-5", voltageOutput); + Blinker.dataStorage("data-6", currentOutput); +} + +//================= CORE0: SETUP (DUAL CORE MODE) =====================// +void coreTwo(void * pvParameters) { + setupWiFi(); //TAB#7 - WiFi Initialization + //================= CORE0: LOOP (DUAL CORE MODE) ======================// + while (1) { + Wireless_Telemetry(); //TAB#7 - Wireless telemetry (WiFi & Bluetooth) + + } +} +//================== CORE1: SETUP (DUAL CORE MODE) ====================// +void setup() { + + //SERIAL INITIALIZATION + Serial.begin(baudRate); //Set serial baud rate + Serial.println("> Serial Initialized"); //Startup message + BLINKER_DEBUG.stream(Serial); + + //GPIO PIN INITIALIZATION + pinMode(backflow_MOSFET, OUTPUT); + pinMode(buck_EN, OUTPUT); + pinMode(LED, OUTPUT); + pinMode(FAN, OUTPUT); + pinMode(TS, INPUT); + //pinMode(ADC_ALERT,INPUT); + pinMode(INA1_ALERT, INPUT); + pinMode(INA2_ALERT, INPUT); + pinMode(buttonLeft, INPUT); + pinMode(buttonRight, INPUT); + pinMode(buttonBack, INPUT); + pinMode(buttonSelect, INPUT); + + //PWM INITIALIZATION + ledcSetup(pwmChannel, pwmFrequency, pwmResolution); //Set PWM Parameters + ledcAttachPin(buck_IN, pwmChannel); //Set pin as PWM + ledcWrite(pwmChannel, PWM); //Write PWM value at startup (duty = 0) + pwmMax = pow(2, pwmResolution) - 1; //Get PWM Max Bit Ceiling + pwmMaxLimited = (PWM_MaxDC * pwmMax) / 100.000; //Get maximum PWM Duty Cycle (pwm limiting protection) + + //ADC INITIALIZATION + //ADC_SetGain(); //Sets ADC Gain & Range + //ads.begin(); //Initialize ADC + Serial.println("Initialize INA226 Slave1 0x40 A1 GND A0 GND"); + Serial.println("-----------------------------------------------"); + + // Default INA226 address is 0x40 + ina1.begin(); + + // Configure INA226 + ina1.configure(INA226_AVERAGES_4, INA226_BUS_CONV_TIME_588US, INA226_SHUNT_CONV_TIME_588US, INA226_MODE_SHUNT_BUS_CONT); + + // Calibrate INA226. Rshunt = 0.01 ohm, Max excepted current = 4A + ina1.calibrate(0.002, 40); + + // Display configuration + checkConfig(ina1); + + Serial.println("-----------------------------------------------"); + + Serial.println("Initialize INA226 Slave2 0x41"); + Serial.println("-----------------------------------------------"); + + // Default INA226 address is 0x40 + ina2.begin(0x41); + + // Configure INA226 + ina2.configure(INA226_AVERAGES_4, INA226_BUS_CONV_TIME_588US, INA226_SHUNT_CONV_TIME_588US, INA226_MODE_SHUNT_BUS_CONT); + + // Calibrate INA226. Rshunt = 0.01 ohm, Max excepted current = 4A + ina2.calibrate(0.002, 40); + + // Display configuration + checkConfig(ina2); + + Serial.println("-----------------------------------------------"); + + //GPIO INITIALIZATION + buck_Disable(); + + //ENABLE DUAL CORE MULTITASKING + xTaskCreatePinnedToCore(coreTwo, "coreTwo", 10000, NULL, 0, &Core2, 0); + + //INITIALIZE AND LIOAD FLASH MEMORY DATA + EEPROM.begin(eeprom_size); + Serial.println("> FLASH MEMORY: STORAGE INITIALIZED"); //Startup message + initializeFlashAutoload(); //Load stored settings from flash memory + Serial.println("> FLASH MEMORY: SAVED DATA LOADED"); //Startup message + + //LCD INITIALIZATION + if (enableLCD == 1) { + lcd.begin(16, 2); + lcd.setBacklight(HIGH); + lcd.setCursor(0, 0); + lcd.print("MPPT INIT"); + lcd.setCursor(0, 1); + lcd.print("FIRMWARE "); + lcd.print(firmwareInfo); + delay(1500); + lcd.clear(); + } + + uint32_t chipId = 0; + for (int i = 0; i < 17; i = i + 8) { + chipId |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i; + } + Serial.printf("Chip ID: %d\r\n", chipId); + + Serial.printf("ESP32 Chip ID = %04X", (uint16_t)(ESP.getEfuseMac() >> 32)); //print High 2 bytes + Serial.printf("%08X\r\n", (uint32_t)ESP.getEfuseMac()); //print Low 4bytes. + + Serial.printf("Chip model = %s Rev %d\r\n", ESP.getChipModel(), ESP.getChipRevision()); + Serial.printf("This chip has %d cores CpuFreqMHz = %u\r\n", ESP.getChipCores(), ESP.getCpuFreqMHz()); + Serial.printf("get Cycle Count = %u\r\n", ESP.getCycleCount()); + Serial.printf("SDK version:%s\r\n", ESP.getSdkVersion()); //获取IDF版本 + + //获取片内内存 Internal RAM + Serial.printf("Total heap size = %u\t", ESP.getHeapSize()); + Serial.printf("Available heap = %u\r\n", ESP.getFreeHeap()); + Serial.printf("Lowest level of free heap since boot = %u\r\n", ESP.getMinFreeHeap()); + Serial.printf("Largest block of heap that can be allocated at once = %u\r\n", ESP.getMaxAllocHeap()); + + //SPI RAM + Serial.printf("Total Psram size = %u\t", ESP.getPsramSize()); + Serial.printf("Available Psram = %u\r\n", ESP.getFreePsram()); + Serial.printf("Lowest level of free Psram since boot = %u\r\n", ESP.getMinFreePsram()); + Serial.printf("Largest block of Psram that can be allocated at once = %u\r\n", ESP.getMinFreePsram()); + + byte mac[6]; + WiFi.macAddress(mac); + printf("macAddress 0x%02X:0x%02X:0x%02X:0x%02X:0x%02X:0x%02X\r\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + //以下是启动OTA,可以通过WiFi刷新固件 + ArduinoOTA.setHostname("ESP32_MPPT"); + // No authentication by default + // ArduinoOTA.setPassword("admin"); + + // Password can be set with it's md5 value as well + // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3 + ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3"); + ArduinoOTA.onStart([]() { + String type; + if (ArduinoOTA.getCommand() == U_FLASH) { + type = "sketch"; + } else { // U_SPIFFS + type = "filesystem"; + } + + // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end() + Serial.println("Start updating " + type); + }); + ArduinoOTA.onEnd([]() { + Serial.println("\nEnd"); + }); + ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { + Serial.printf("Progress: %u%%\r", (progress / (total / 100))); + }); + ArduinoOTA.onError([](ota_error_t error) { + Serial.printf("Error[%u]: ", error); + if (error == OTA_AUTH_ERROR) { + Serial.println("Auth Failed"); + } else if (error == OTA_BEGIN_ERROR) { + Serial.println("Begin Failed"); + } else if (error == OTA_CONNECT_ERROR) { + Serial.println("Connect Failed"); + } else if (error == OTA_RECEIVE_ERROR) { + Serial.println("Receive Failed"); + } else if (error == OTA_END_ERROR) { + Serial.println("End Failed"); + } + }); + ArduinoOTA.begin(); + Serial.println("OTA Ready"); + + + //设置时间格式以及时间服务器的网址 + configTime(timezone * 3600, 0, "pool.ntp.org", "time.nist.gov"); + Serial.println("\nWaiting for time"); + while (!time(nullptr)) { + Serial.print("."); + delay(1000); + } + + //SETUP FINISHED + Serial.println("> MPPT HAS INITIALIZED"); //Startup message + +} +unsigned long TenthSecondsSinceStart = 0; +unsigned long LastMillis = 0; +char DateTimeStr[20]; + +void OnSecond() +{ + time_t now = time(nullptr); //获取当前时间 + + //转换成年月日的数字,可以更加自由的显示。 + struct tm* timenow; + timenow = localtime(&now); + unsigned char tempHour = timenow->tm_hour; + unsigned char tempMinute = timenow->tm_min; + unsigned char tempSecond = timenow->tm_sec; + unsigned char tempDay = timenow->tm_mday; + unsigned char tempMonth = timenow->tm_mon + 1; + unsigned int tempYear = timenow->tm_year + 1900; + unsigned char tempWeek = timenow->tm_wday; + + //生成 年月日时分秒 字符串。 + sprintf(DateTimeStr, "%d-%02d-%02d %02d:%02d:%02d" + , tempYear + , tempMonth + , tempDay + , tempHour + , tempMinute + , tempSecond + ); + +} + +void OnTenthSecond() // 100ms 十分之一秒 +{ + + if (TenthSecondsSinceStart % 3 == 0) //0.3S刷新数据, + { + //读取采样数据1 + + //voltageInput = ina1.readBusVoltage()*(R1_VOLTAGE1+R2_VOLTAGE1)/R1_VOLTAGE1; + //voltageOutput = ina2.readBusVoltage()*(R1_VOLTAGE2+R2_VOLTAGE2)/R1_VOLTAGE2; + + //读取采样数据2 + + //CSI_converted = ina1.readShuntCurrent(); + //CSO_converted = ina2.readShuntCurrent(); + } + + if (TenthSecondsSinceStart % 10 == 0) //10次为1秒 + { + OnSecond(); + } +} + +void TenthSecondsSinceStartTask() //100ms +{ + unsigned long CurrentMillis = millis(); + if (abs(int(CurrentMillis - LastMillis)) > 100) + { + LastMillis = CurrentMillis; + TenthSecondsSinceStart++; + OnTenthSecond(); + } +} + +//================== CORE1: LOOP (DUAL CORE MODE) ======================// +void loop() { + ArduinoOTA.handle(); + + TenthSecondsSinceStartTask(); + + Read_Sensors(); //TAB#2 - Sensor data measurement and computation + Device_Protection(); //TAB#3 - Fault detection algorithm + System_Processes(); //TAB#4 - Routine system processes + Charging_Algorithm(); //TAB#5 - Battery Charging Algorithm + Onboard_Telemetry(); //TAB#6 - Onboard telemetry (USB & Serial Telemetry) + LCD_Menu(); //TAB#8 - Low Power Algorithm +} diff --git a/ARDUINO_MPPT_FIRMWARE_V2.1/blinker_UI.txt b/ARDUINO_MPPT_FIRMWARE_V2.1/blinker_UI.txt new file mode 100644 index 0000000..6fd8f2b --- /dev/null +++ b/ARDUINO_MPPT_FIRMWARE_V2.1/blinker_UI.txt @@ -0,0 +1 @@ +{¨version¨¨2.0.0¨¨config¨{¨headerColor¨¨transparent¨¨headerStyle¨¨dark¨¨background¨{¨img¨¨assets/img/bg/2.jpg¨}}¨dashboard¨|{¨type¨¨num¨¨t0¨¨太阳能功率¨¨ico¨¨fal fa-question¨¨clr¨¨#00A90C¨¨min¨É¨max¨¢1c¨uni¨´W´¨bg¨É¨cols¨Í¨rows¨Ë¨key¨¨num-9y2¨´x´É´y´Ë¨lstyle¨Ë¨rt¨»}{ßBßCßD¨累计功率¨ßF¨fad fa-tint¨ßH¨#FBA613¨ßJÉßK¢Q0ußL¨KWh¨ßMÉßNËßOËßP¨num-rgu¨´x´É´y´ÑßRÉßS»}{ßBßCßD¨光伏电压¨ßF¨fad fa-solar-panel¨ßH¨#076EEF¨ßJÉßKº0ßL´V´ßMÉßNÍßOËßP¨num-m2k¨´x´É´y´ÍßRÊßS»}{ßBßCßD¨电池电量¨ßFßGßHßaßJÉßKº0ßL´%´ßMÉßNÍßOËßP¨num-ahb¨´x´Í´y´ËßRËßS»}{ßBßCßD¨温度¨ßF¨fad fa-thermometer-three-quarters¨ßH¨#EA0909¨ßJÉßKº0ßL´℃´ßMÉßNËßOËßP¨num-ycz¨´x´Í´y´ÑßS»ßRÉ}{ßBßCßD¨累计电费¨ßF¨fad fa-handshake-alt¨ßH¨#6010E4¨ßJÉßK¢Q0tßL¨CNY¨ßMÉßNËßOËßP¨num-ao5¨´x´Ë´y´ÑßRÉßS»}{ßBßCßD¨充电电流¨ßF¨fad fa-tachometer-alt-fast¨ßHßgßJÉßKº0ßL´A´ßMÉßNÍßOËßP¨num-3bm¨´x´Í´y´ÏßRÊßS»}{ßBßCßD¨电池电压¨ßF¨fad fa-database¨ßHßaßJÉßKº0ßL´V´ßMÉßNÍßOËßP¨num-l24¨´x´Í´y´ÍßRÊßS»}{ßBßCßD¨光伏电流¨ßFßoßHßgßJÉßKº0ßL´A´ßMÉßNÍßOËßP¨num-5up¨´x´É´y´ÏßRÊßS»}{ßB¨cha¨ßMɨsty¨¨line¨ßH¨#389BEE¨¨sty1¨ßx¨clr1¨ßy¨sty2¨ßx¨clr2¨ßyßNÑßOÌßP¨cha-9ay¨´x´É´y´¤A¨key0¨¨data-1¨¨key1¨¨data-2¨¨key2¨¨data-3¨ßD¨光伏功率¨´t1´´电压´´t2´´电流´}{ßB¨deb¨¨mode¨ÉßMÉßNÑßOÌßP¨debug¨´x´É´y´¤H}{ßB¨btn¨ßF¨fad fa-charging-station¨ß1CÉßD¨充电中¨´t1´¨文本2¨ßMÉßNÊßOÊßP¨btn-e6n¨´x´Ï´y´ÑßRÍ}{ßBß1EßF¨fad fa-sun¨ß1CÉßD¨文本1¨´t1´ß1HßMÉßNÊßOÊßP¨btn-e3t¨´x´Ð´y´ÑßRÍ}{ßBß1EßF¨fad fa-signal¨ß1CÉßDß1K´t1´ß1HßMÉßNÊßOÊßP¨btn-q4l¨´x´Ð´y´ÒßRÍ}{ßBß1EßF¨fad fa-signal-1¨ß1CÉßDß1K´t1´ß1HßMÉßNÊßOÊßP¨btn-ogw¨´x´Ï´y´ÒßRÍ}{ßBßvßMÉßwßxßHßyßzßxß10ßyß11ßxß12ßyßNÑßOÌßP¨cha-nud¨´x´É´y´¤Dß14¨data-4¨ßD¨充电功率¨ß16¨data-5¨´t1´´电压´ß18¨data-6¨´t2´´电流´}÷¨actions¨|÷¨triggers¨|÷ßS|ßQßXßbßdßhßmßpßsßu÷} \ No newline at end of file