MPPT_Code_ESP8266.ino 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661
  1. //----------------------------------------------------------------------------------------------------
  2. // ARDUINO MPPT SOLAR CHARGE CONTROLLER (Version-3)
  3. // Author: Debasish Dutta/deba168
  4. // www.opengreenenergy.in
  5. //
  6. // This code is for an arduino Nano based Solar MPPT charge controller.
  7. // This code is a modified version of sample code from www.timnolan.com
  8. // updated 21/06/2015
  9. //
  10. // Mods by Aplavins 06/19/2015
  11. //// Specifications : //////////////////////////////////////////////////////////////////////////////////////////////////////
  12. //
  13. // 1.Solar panel power = 50W
  14. //
  15. // 2.Rated Battery Voltage= 12V ( lead acid type )
  16. // 3.Maximum current = 5A //
  17. // 4.Maximum load current =10A //
  18. // 5. In put Voltage = Solar panel with Open circuit voltage from 17 to 25V //
  19. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  20. #include "TimerOne.h" // using Timer1 library from http://www.arduino.cc/playground/Code/Timer1
  21. #include <LiquidCrystal_I2C.h> // using the LCD I2C Library from https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads
  22. #include <Wire.h>
  23. #include <SoftwareSerial.h> // using the Software Serial library Ref : http://www.arduino.cc/en/Reference/SoftwareSerialConstructor
  24. //----------------------------------------------------------------------------------------------------------
  25. //////// Arduino pins Connections//////////////////////////////////////////////////////////////////////////////////
  26. // A0 - Voltage divider (solar)
  27. // A1 - ACS 712 Out
  28. // A2 - Voltage divider (battery)
  29. // A4 - LCD SDA
  30. // A5 - LCD SCL
  31. // D2 - ESP8266 Tx
  32. // D3 - ESP8266 Rx through the voltage divider
  33. // D5 - LCD back control button
  34. // D6 - Load Control
  35. // D8 - 2104 MOSFET driver SD
  36. // D9 - 2104 MOSFET driver IN
  37. // D11- Green LED
  38. // D12- Yellow LED
  39. // D13- Red LED
  40. // Full scheatic is given at http://www.instructables.com/files/orig/F9A/LLR8/IAPASVA1/F9ALLR8IAPASVA1.pdf
  41. ///////// Definitions /////////////////////////////////////////////////////////////////////////////////////////////////
  42. #define ENABLE_DATALOGGER 0
  43. #define SOL_AMPS_CHAN 1 // Defining the adc channel to read solar amps
  44. #define SOL_VOLTS_CHAN 0 // defining the adc channel to read solar volts
  45. #define SOL_AMPS_CHAN 1 // Defining the adc channel to read solar amps
  46. #define BAT_VOLTS_CHAN 2 // defining the adc channel to read battery volts
  47. #define AVG_NUM 8 // number of iterations of the adc routine to average the adc readings
  48. // ACS 712 Current Sensor is used. Current Measured = (5/(1024 *0.185))*ADC - (2.5/0.185)
  49. #define SOL_AMPS_SCALE 0.026393581 // the scaling value for raw adc reading to get solar amps // 5/(1024*0.185)
  50. #define SOL_VOLTS_SCALE 0.029296875 // the scaling value for raw adc reading to get solar volts // (5/1024)*(R1+R2)/R2 // R1=100k and R2=20k
  51. #define BAT_VOLTS_SCALE 0.029296875 // the scaling value for raw adc reading to get battery volts
  52. #define PWM_PIN 9 // the output pin for the pwm (only pin 9 avaliable for timer 1 at 50kHz)
  53. #define PWM_ENABLE_PIN 8 // pin used to control shutoff function of the IR2104 MOSFET driver (hight the mosfet driver is on)
  54. #define PWM_FULL 1023 // the actual value used by the Timer1 routines for 100% pwm duty cycle
  55. #define PWM_MAX 100 // the value for pwm duty cyle 0-100%
  56. #define PWM_MIN 60 // the value for pwm duty cyle 0-100% (below this value the current running in the system is = 0)
  57. #define PWM_START 90 // the value for pwm duty cyle 0-100%
  58. #define PWM_INC 1 //the value the increment to the pwm value for the ppt algorithm
  59. #define TRUE 1
  60. #define FALSE 0
  61. #define ON TRUE
  62. #define OFF FALSE
  63. #define TURN_ON_MOSFETS digitalWrite(PWM_ENABLE_PIN, HIGH) // enable MOSFET driver
  64. #define TURN_OFF_MOSFETS digitalWrite(PWM_ENABLE_PIN, LOW) // disable MOSFET driver
  65. #define ONE_SECOND 50000 //count for number of interrupt in 1 second on interrupt period of 20us
  66. #define LOW_SOL_WATTS 5.00 //value of solar watts // this is 5.00 watts
  67. #define MIN_SOL_WATTS 1.00 //value of solar watts // this is 1.00 watts
  68. #define MIN_BAT_VOLTS 11.00 //value of battery voltage // this is 11.00 volts
  69. #define MAX_BAT_VOLTS 14.10 //value of battery voltage// this is 14.10 volts
  70. #define BATT_FLOAT 13.60 // battery voltage we want to stop charging at
  71. #define HIGH_BAT_VOLTS 13.00 //value of battery voltage // this is 13.00 volts
  72. #define LVD 11.5 //Low voltage disconnect setting for a 12V system
  73. #define OFF_NUM 9 // number of iterations of off charger state
  74. //------------------------------------------------------------------------------------------------------
  75. //Defining led pins for indication
  76. #define LED_RED 11
  77. #define LED_GREEN 12
  78. #define LED_YELLOW 13
  79. //-----------------------------------------------------------------------------------------------------
  80. // Defining load control pin
  81. #define LOAD_PIN 6 // pin-2 is used to control the load
  82. //-----------------------------------------------------------------------------------------------------
  83. // Defining lcd back light pin
  84. #define BACK_LIGHT_PIN 5 // pin-5 is used to control the lcd back light
  85. // ---------------------------For ESP8266--------------------------------------------------------------
  86. // replace with your channel's thingspeak API key
  87. String apiKey = "DPK8RMTFY2B1XCAF";
  88. // connect 2 to TX of Serial USB
  89. // connect 3 to RX of serial USB
  90. SoftwareSerial ser(2,3); // RX, TX
  91. //---------------------------------------------------------------------------------------------------------
  92. //------------------------------------------------------------------------------------------------------
  93. /////////////////////////////////////////BIT MAP ARRAY//////////////////////////////////////////////////
  94. //-------------------------------------------------------------------------------------------------------
  95. byte solar[8] = //icon for termometer
  96. {
  97. 0b11111,
  98. 0b10101,
  99. 0b11111,
  100. 0b10101,
  101. 0b11111,
  102. 0b10101,
  103. 0b11111,
  104. 0b00000
  105. };
  106. byte battery[8]=
  107. {
  108. 0b01110,
  109. 0b11011,
  110. 0b10001,
  111. 0b10001,
  112. 0b11111,
  113. 0b11111,
  114. 0b11111,
  115. 0b11111,
  116. };
  117. byte _PWM [8]=
  118. {
  119. 0b11101,
  120. 0b10101,
  121. 0b10101,
  122. 0b10101,
  123. 0b10101,
  124. 0b10101,
  125. 0b10101,
  126. 0b10111,
  127. };
  128. //-------------------------------------------------------------------------------------------------------
  129. // global variables
  130. float sol_amps; // solar amps
  131. float sol_volts; // solar volts
  132. float bat_volts; // battery volts
  133. float sol_watts; // solar watts
  134. float old_sol_watts = 0; // solar watts from previous time through ppt routine
  135. unsigned int seconds = 0; // seconds from timer routine
  136. unsigned int prev_seconds = 0; // seconds value from previous pass
  137. unsigned int interrupt_counter = 0; // counter for 20us interrrupt
  138. unsigned long time = 0; // variable to store time the back light control button was pressed in millis
  139. int delta = PWM_INC; // variable used to modify pwm duty cycle for the ppt algorithm
  140. int pwm = 0; // pwm duty cycle 0-100%
  141. int back_light_pin_State = 0; // variable for storing the state of the backlight button
  142. int load_status = 0; // variable for storing the load output state (for writing to LCD)
  143. enum charger_mode {off, on, bulk, bat_float} charger_state; // enumerated variable that holds state for charger state machine
  144. // set the LCD address to 0x27 for a 20 chars 4 line display
  145. // Set the pins on the I2C chip used for LCD connections:
  146. // addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
  147. LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // Set the LCD I2C address
  148. //------------------------------------------------------------------------------------------------------
  149. // This routine is automatically called at powerup/reset
  150. //------------------------------------------------------------------------------------------------------
  151. void setup() // run once, when the sketch starts
  152. {
  153. lcd.begin(20,4); // initialize the lcd for 16 chars 2 lines, turn on backlight
  154. lcd.backlight();
  155. lcd.createChar(1,solar);
  156. lcd.createChar(2,battery);
  157. lcd.createChar(3,_PWM);
  158. pinMode(LED_RED, OUTPUT);
  159. pinMode(LED_GREEN, OUTPUT);
  160. pinMode(LED_YELLOW, OUTPUT);
  161. pinMode(PWM_ENABLE_PIN, OUTPUT); // sets the digital pin as output
  162. Timer1.initialize(20); // initialize timer1, and set a 20uS period
  163. Timer1.pwm(PWM_PIN, 0); // setup pwm on pin 9, 0% duty cycle
  164. TURN_ON_MOSFETS; // turn off MOSFET driver chip
  165. Timer1.attachInterrupt(callback); // attaches callback() as a timer overflow interrupt
  166. Serial.begin(9600); // open the serial port at 9600 bps:
  167. ser.begin(9600); // enable software serial
  168. ser.println("AT+RST"); // reset ESP8266
  169. pwm = PWM_START; //starting value for pwm
  170. charger_state = off; // start with charger state as off
  171. pinMode(BACK_LIGHT_PIN, INPUT);
  172. pinMode(LOAD_PIN,OUTPUT);
  173. digitalWrite(LOAD_PIN,LOW); // default load state is OFF
  174. digitalWrite(BACK_LIGHT_PIN,LOW); // default LCd back light is OFF
  175. // display the constant stuff on the LCD
  176. lcd.setCursor(0, 0);
  177. lcd.print("SOL");
  178. lcd.setCursor(4, 0);
  179. lcd.write(1);
  180. lcd.setCursor(8, 0);
  181. lcd.print("BAT");
  182. lcd.setCursor(12, 0);
  183. lcd.write(2);
  184. }
  185. //------------------------------------------------------------------------------------------------------
  186. // Main loop
  187. //------------------------------------------------------------------------------------------------------
  188. void loop()
  189. {
  190. read_data(); // read data from inputs
  191. run_charger(); // run the charger state machine
  192. print_data(); // print data
  193. load_control(); // control the connected load
  194. led_output(); // led indication
  195. lcd_display(); // lcd display
  196. wifi_datalog(); // sends data to thingspeak
  197. }
  198. //------------------------------------------------------------------------------------------------------
  199. // This routine reads and averages the analog inputs for this system, solar volts, solar amps and
  200. // battery volts.
  201. //------------------------------------------------------------------------------------------------------
  202. int read_adc(int channel){
  203. int sum = 0;
  204. int temp;
  205. int i;
  206. for (i=0; i<AVG_NUM; i++) { // loop through reading raw adc values AVG_NUM number of times
  207. temp = analogRead(channel); // read the input pin
  208. sum += temp; // store sum for averaging
  209. delayMicroseconds(50); // pauses for 50 microseconds
  210. }
  211. return(sum / AVG_NUM); // divide sum by AVG_NUM to get average and return it
  212. }
  213. //------------------------------------------------------------------------------------------------------
  214. // This routine reads all the analog input values for the system. Then it multiplies them by the scale
  215. // factor to get actual value in volts or amps.
  216. //------------------------------------------------------------------------------------------------------
  217. void read_data(void) {
  218. sol_amps = (read_adc(SOL_AMPS_CHAN) * SOL_AMPS_SCALE -12.01); //input of solar amps
  219. sol_volts = read_adc(SOL_VOLTS_CHAN) * SOL_VOLTS_SCALE; //input of solar volts
  220. bat_volts = read_adc(BAT_VOLTS_CHAN) * BAT_VOLTS_SCALE; //input of battery volts
  221. sol_watts = sol_amps * sol_volts ; //calculations of solar watts
  222. }
  223. //------------------------------------------------------------------------------------------------------
  224. // This is interrupt service routine for Timer1 that occurs every 20uS.
  225. //
  226. //------------------------------------------------------------------------------------------------------
  227. void callback()
  228. {
  229. if (interrupt_counter++ > ONE_SECOND) { // increment interrupt_counter until one second has passed
  230. interrupt_counter = 0; // reset the counter
  231. seconds++; // then increment seconds counter
  232. }
  233. }
  234. //------------------------------------------------------------------------------------------------------
  235. // This routine uses the Timer1.pwm function to set the pwm duty cycle.
  236. //------------------------------------------------------------------------------------------------------
  237. void set_pwm_duty(void) {
  238. if (pwm > PWM_MAX) { // check limits of PWM duty cyle and set to PWM_MAX
  239. pwm = PWM_MAX;
  240. }
  241. else if (pwm < PWM_MIN) { // if pwm is less than PWM_MIN then set it to PWM_MIN
  242. pwm = PWM_MIN;
  243. }
  244. if (pwm < PWM_MAX) {
  245. Timer1.pwm(PWM_PIN,(PWM_FULL * (long)pwm / 100), 20); // use Timer1 routine to set pwm duty cycle at 20uS period
  246. //Timer1.pwm(PWM_PIN,(PWM_FULL * (long)pwm / 100));
  247. }
  248. else if (pwm == PWM_MAX) { // if pwm set to 100% it will be on full but we have
  249. Timer1.pwm(PWM_PIN,(PWM_FULL - 1), 20); // keep switching so set duty cycle at 99.9%
  250. //Timer1.pwm(PWM_PIN,(PWM_FULL - 1));
  251. }
  252. }
  253. //------------------------------------------------------------------------------------------------------
  254. // This routine is the charger state machine. It has four states on, off, bulk and float.
  255. // It's called once each time through the main loop to see what state the charger should be in.
  256. // The battery charger can be in one of the following four states:
  257. //
  258. // On State - this is charger state for MIN_SOL_WATTS < solar watts < LOW_SOL_WATTS. In this state isthe solar
  259. // watts input is too low for the bulk charging state but not low enough to go into the off state.
  260. // In this state we just set the pwm = 99.9% to get the most of low amount of power available.
  261. // Bulk State - this is charger state for solar watts > MIN_SOL_WATTS. This is where we do the bulk of the battery
  262. // charging and where we run the Peak Power Tracking alogorithm. In this state we try and run the maximum amount
  263. // of current that the solar panels are generating into the battery.
  264. // Float State - As the battery charges it's voltage rises. When it gets to the MAX_BAT_VOLTS we are done with the
  265. // bulk battery charging and enter the battery float state. In this state we try and keep the battery voltage
  266. // at MAX_BAT_VOLTS by adjusting the pwm value. If we get to pwm = 100% it means we can't keep the battery
  267. // voltage at MAX_BAT_VOLTS which probably means the battery is being drawn down by some load so we need to back
  268. // into the bulk charging mode.
  269. // Off State - This is state that the charger enters when solar watts < MIN_SOL_WATTS. The charger goes into this
  270. // state when there is no more power being generated by the solar panels. The MOSFETs are turned
  271. // off in this state so that power from the battery doesn't leak back into the solar panel.
  272. //------------------------------------------------------------------------------------------------------
  273. void run_charger(void) {
  274. static int off_count = OFF_NUM;
  275. switch (charger_state) {
  276. case on:
  277. if (sol_watts < MIN_SOL_WATTS) { // if watts input from the solar panel is less than
  278. charger_state = off; // the minimum solar watts then
  279. off_count = OFF_NUM; // go to the charger off state
  280. TURN_OFF_MOSFETS;
  281. }
  282. else if (bat_volts > (BATT_FLOAT - 0.1)) { // else if the battery voltage has gotten above the float
  283. charger_state = bat_float; // battery float voltage go to the charger battery float state
  284. }
  285. else if (sol_watts < LOW_SOL_WATTS) { // else if the solar input watts is less than low solar watts
  286. pwm = PWM_MAX; // it means there is not much power being generated by the solar panel
  287. set_pwm_duty(); // so we just set the pwm = 100% so we can get as much of this power as possible
  288. } // and stay in the charger on state
  289. else {
  290. pwm = ((bat_volts * 10) / (sol_volts / 10)) + 5; // else if we are making more power than low solar watts figure out what the pwm
  291. charger_state = bulk; // value should be and change the charger to bulk state
  292. }
  293. break;
  294. case bulk:
  295. if (sol_watts < MIN_SOL_WATTS) { // if watts input from the solar panel is less than
  296. charger_state = off; // the minimum solar watts then it is getting dark so
  297. off_count = OFF_NUM; // go to the charger off state
  298. TURN_OFF_MOSFETS;
  299. }
  300. else if (bat_volts > BATT_FLOAT) { // else if the battery voltage has gotten above the float
  301. charger_state = bat_float; // battery float voltage go to the charger battery float state
  302. }
  303. else if (sol_watts < LOW_SOL_WATTS) { // else if the solar input watts is less than low solar watts
  304. charger_state = on; // it means there is not much power being generated by the solar panel
  305. TURN_ON_MOSFETS; // so go to charger on state
  306. }
  307. else { // this is where we do the Peak Power Tracking ro Maximum Power Point algorithm
  308. if (old_sol_watts >= sol_watts) { // if previous watts are greater change the value of
  309. delta = -delta; // delta to make pwm increase or decrease to maximize watts
  310. }
  311. pwm += delta; // add delta to change PWM duty cycle for PPT algorythm (compound addition)
  312. old_sol_watts = sol_watts; // load old_watts with current watts value for next time
  313. set_pwm_duty(); // set pwm duty cycle to pwm value
  314. }
  315. break;
  316. case bat_float:
  317. if (sol_watts < MIN_SOL_WATTS) { // if watts input from the solar panel is less than
  318. charger_state = off; // the minimum solar watts then it is getting dark so
  319. off_count = OFF_NUM; // go to the charger off state
  320. TURN_OFF_MOSFETS;
  321. set_pwm_duty();
  322. }
  323. else if (bat_volts > BATT_FLOAT) { // If we've charged the battery abovethe float voltage
  324. TURN_OFF_MOSFETS; // turn off MOSFETs instead of modiflying duty cycle
  325. pwm = PWM_MAX; // the charger is less efficient at 99% duty cycle
  326. set_pwm_duty(); // write the PWM
  327. }
  328. else if (bat_volts < BATT_FLOAT) { // else if the battery voltage is less than the float voltage - 0.1
  329. pwm = PWM_MAX;
  330. set_pwm_duty(); // start charging again
  331. TURN_ON_MOSFETS;
  332. if (bat_volts < (BATT_FLOAT - 0.1)) { // if the voltage drops because of added load,
  333. charger_state = bulk; // switch back into bulk state to keep the voltage up
  334. }
  335. }
  336. break;
  337. case off: // when we jump into the charger off state, off_count is set with OFF_NUM
  338. TURN_OFF_MOSFETS;
  339. if (off_count > 0) { // this means that we run through the off state OFF_NUM of times with out doing
  340. off_count--; // anything, this is to allow the battery voltage to settle down to see if the
  341. } // battery has been disconnected
  342. else if ((bat_volts > BATT_FLOAT) && (sol_volts > bat_volts)) {
  343. charger_state = bat_float; // if battery voltage is still high and solar volts are high
  344. }
  345. else if ((bat_volts > MIN_BAT_VOLTS) && (bat_volts < BATT_FLOAT) && (sol_volts > bat_volts)) {
  346. charger_state = bulk;
  347. }
  348. break;
  349. default:
  350. TURN_OFF_MOSFETS;
  351. break;
  352. }
  353. }
  354. //------------------------------------------------------------------------------------------------------
  355. // Main loop.
  356. //
  357. //------------------------------------------------------------------------------------------------------
  358. void loop()
  359. {
  360. read_data(); //read data from inputs
  361. run_charger(); //run the charger state machine
  362. //print_data(); //print data
  363. load_control(); // control the connected load
  364. led_output(); // led indication
  365. lcd_display(); // lcd display
  366. wifi_datalog();
  367. delay(500);
  368. }
  369. //----------------------------------------------------------------------------------------------------------------------
  370. /////////////////////////////////////////////LOAD CONTROL/////////////////////////////////////////////////////
  371. //----------------------------------------------------------------------------------------------------------------------
  372. void load_control(){
  373. if ((sol_watts < MIN_SOL_WATTS) && (bat_volts > LVD)){ // If the panel isn't producing, it's probably night
  374. digitalWrite(LOAD_PIN, LOW); // turn the load on
  375. load_status = 1; // record that the load is on
  376. }
  377. else{ // If the panel is producing, it's day time
  378. digitalWrite(LOAD_PIN, HIGH); // turn the load off
  379. load_status = 0; // record that the load is off
  380. }
  381. }
  382. //------------------------------------------------------------------------------------------------------
  383. // This routine prints all the data out to the serial port.
  384. //------------------------------------------------------------------------------------------------------
  385. void print_data(void) {
  386. Serial.print(seconds,DEC);
  387. Serial.print(" ");
  388. Serial.print("Charging = ");
  389. if (charger_state == on) Serial.print("on ");
  390. else if (charger_state == off) Serial.print("off ");
  391. else if (charger_state == bulk) Serial.print("bulk ");
  392. else if (charger_state == bat_float) Serial.print("float");
  393. Serial.print(" ");
  394. Serial.print("pwm = ");
  395. Serial.print(pwm,DEC);
  396. Serial.print(" ");
  397. Serial.print("Current (panel) = ");
  398. Serial.print(sol_amps);
  399. Serial.print(" ");
  400. Serial.print("Voltage (panel) = ");
  401. Serial.print(sol_volts);
  402. Serial.print(" ");
  403. Serial.print("Power (panel) = ");
  404. Serial.print(sol_volts);
  405. Serial.print(" ");
  406. Serial.print("Battery Voltage = ");
  407. Serial.print(bat_volts);
  408. Serial.print(" ");
  409. Serial.print("\n\r");
  410. //delay(1000);
  411. }
  412. //-------------------------------------------------------------------------------------------------
  413. //---------------------------------Led Indication--------------------------------------------------
  414. //-------------------------------------------------------------------------------------------------
  415. // light an individual LED
  416. // we remember which one was on before in last_lit and turn it off if different
  417. void light_led(char pin)
  418. {
  419. static char last_lit;
  420. if (last_lit == pin)
  421. return;
  422. if (last_lit != 0)
  423. digitalWrite(last_lit, LOW);
  424. digitalWrite(pin, HIGH);
  425. last_lit = pin;
  426. }
  427. // display the current state via LED as follows:
  428. // YELLOW means overvoltage (over 14.1 volts)
  429. // RED means undervoltage (under 11.9 volts)
  430. // GREEN is between 11.9 and 14.1 volts
  431. void led_output(void)
  432. {
  433. static char last_lit;
  434. if(bat_volts > 14.1 )
  435. light_led(LED_YELLOW);
  436. else if(bat_volts > 11.9)
  437. light_led(LED_GREEN);
  438. else
  439. light_led(LED_RED);
  440. }
  441. //------------------------------------------------------------------------------------------------------
  442. //-------------------------- LCD DISPLAY --------------------------------------------------------------
  443. //-------------------------------------------------------------------------------------------------------
  444. void lcd_display()
  445. {
  446. static bool current_backlight_state = -1;
  447. back_light_pin_State = digitalRead(BACK_LIGHT_PIN);
  448. if (current_backlight_state != back_light_pin_State) {
  449. current_backlight_state = back_light_pin_State;
  450. if (back_light_pin_State == HIGH)
  451. lcd.backlight();// finish with backlight on
  452. else
  453. lcd.noBacklight();
  454. }
  455. if (back_light_pin_State == HIGH)
  456. {
  457. time = millis(); // If any of the buttons are pressed, save the time in millis to "time"
  458. }
  459. lcd.setCursor(0, 1);
  460. lcd.print(sol_volts);
  461. lcd.print("V ");
  462. lcd.setCursor(0, 2);
  463. lcd.print(sol_amps);
  464. lcd.print("A");
  465. lcd.setCursor(0, 3);
  466. lcd.print(sol_watts);
  467. lcd.print("W ");
  468. lcd.setCursor(8, 1);
  469. lcd.print(bat_volts);
  470. lcd.setCursor(8,2);
  471. if (charger_state == on)
  472. lcd.print("on ");
  473. else if (charger_state == off)
  474. lcd.print("off ");
  475. else if (charger_state == bulk)
  476. lcd.print("bulk ");
  477. else if (charger_state == bat_float)
  478. {
  479. lcd.print(" ");
  480. lcd.setCursor(8,2);
  481. lcd.print("float");
  482. }
  483. //-----------------------------------------------------------
  484. //--------------------Battery State Of Charge ---------------
  485. //-----------------------------------------------------------
  486. lcd.setCursor(8,3);
  487. int pct = 100.0*(bat_volts - 11.3)/(12.7 - 11.3);
  488. if (pct < 0)
  489. pct = 0;
  490. else if (pct > 100)
  491. pct = 100;
  492. pct = pct - (pct%10);
  493. lcd.print(pct);
  494. lcd.print("% ");
  495. //---------------------------------------------------------------------
  496. //------------------Duty Cycle-----------------------------------------
  497. //---------------------------------------------------------------------
  498. lcd.setCursor(15,0);
  499. lcd.print("PWM");
  500. lcd.setCursor(19,0);
  501. lcd.write(3);
  502. lcd.setCursor(15,1);
  503. lcd.print(" ");
  504. lcd.setCursor(15,1);
  505. lcd.print(pwm);
  506. lcd.print("%");
  507. //----------------------------------------------------------------------
  508. //------------------------Load Status-----------------------------------
  509. //----------------------------------------------------------------------
  510. lcd.setCursor(15,2);
  511. lcd.print("Load");
  512. lcd.setCursor(15,3);
  513. if (load_status == 1)
  514. {
  515. lcd.print("On ");
  516. }
  517. else
  518. {
  519. lcd.print("Off ");
  520. }
  521. spinner();
  522. backLight_timer(); // call the backlight timer function in every loop
  523. }
  524. void backLight_timer(){
  525. if((millis() - time) <= 15000) // if it's been less than the 15 secs, turn the backlight on
  526. lcd.backlight(); // finish with backlight on
  527. else
  528. lcd.noBacklight(); // if it's been more than 15 secs, turn the backlight off
  529. >>>>>>> bad0d746d2a86af933d66a9ca0fdc61c6db8619a
  530. }
  531. void spinner(void) {
  532. static int cspinner;
  533. static char spinner_chars[] = { '/','-','\\','|' };
  534. cspinner++;
  535. lcd.print(spinner_chars[cspinner%4]);
  536. }
  537. //-------------------------------------------------------------------------
  538. //----------------------------- ESP8266 WiFi ------------------------------
  539. //--------------------------Plot System data on thingspeak.com-------------
  540. //-------------------------------------------------------------------------
  541. void wifi_datalog()
  542. {
  543. // thingspeak needs 15 sec delay between updates
  544. static int lastlogged;
  545. if ( seconds - lastlogged < 16 )
  546. return;
  547. lastlogged = seconds;
  548. // convert to string
  549. char buf[16];
  550. String strTemp = dtostrf( sol_volts, 4, 1, buf);
  551. Serial.println(strTemp);
  552. // TCP connection
  553. String cmd = "AT+CIPSTART=\"TCP\",\"";
  554. cmd += "184.106.153.149"; // api.thingspeak.com
  555. cmd += "\",80";
  556. ser.println(cmd);
  557. if(ser.find("Error")){
  558. Serial.println("AT+CIPSTART error");
  559. return;
  560. }
  561. // prepare GET string
  562. String getStr = "GET /update?api_key=";
  563. getStr += apiKey;
  564. getStr +="&field1=";
  565. getStr += String(strTemp);
  566. getStr += "\r\n\r\n";
  567. // send data length
  568. cmd = "AT+CIPSEND=";
  569. cmd += String(getStr.length());
  570. ser.println(cmd);
  571. if(ser.find(">")){
  572. ser.print(getStr);
  573. }
  574. else{
  575. ser.println("AT+CIPCLOSE");
  576. // alert user
  577. Serial.println("AT+CIPCLOSE");
  578. }
  579. }