MPPT_Code_ESP8266.ino 25 KB

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