Electronic_Load_software_V35.ino 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390
  1. //SCULLCOM HOBBY ELECTRONICS
  2. //ELECTRONIC DC LOAD PROJECT
  3. //Software Version 35 (4x5 Matrix Keypad Version - modified key layout)
  4. //14th April 2018
  5. #include <SPI.h> //include SPI library (Serial Peripheral Interface)
  6. #include <Wire.h> //include I2C library
  7. #include <LiquidCrystal_I2C.h> // F Malpartida's NewLiquidCrystal library
  8. // https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads/NewliquidCrystal_1.3.4.zip
  9. #include <math.h> //
  10. #include <Adafruit_MCP4725.h> //Adafruit DAC library https://github.com/adafruit/Adafruit_MCP4725
  11. #include <MCP342x.h> //Steve Marple library avaiable from https://github.com/stevemarple/MCP342x
  12. #include <MCP79410_Timer.h> //Scullcom Hobby Electronics library http://www.scullcom.com/MCP79410Timer-master.zip
  13. #include <EEPROM.h> //include EEPROM library used for storing setup data
  14. #include <Keypad.h> //http://playground.arduino.cc/Code/Keypad
  15. const byte ROWS = 5; //five rows
  16. const byte COLS = 4; //four columns
  17. //define the symbols on the buttons of the keypads
  18. char hexaKeys[ROWS][COLS] = {
  19. {'<','0','>','F'},
  20. {'7','8','9','E'},
  21. {'4','5','6','D'},
  22. {'1','2','3','C'},
  23. {'A','B','#','*'}
  24. };
  25. byte rowPins[ROWS] = {9, 10, 11, 12, 14}; //connect to the row pin outs of the keypad
  26. byte colPins[COLS] = {5, 6, 7, 8}; //connect to the column pin outs of the keypad
  27. //initialize an instance of class NewKeypad
  28. Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);
  29. char customKey;
  30. char decimalPoint; //used to test for more than one press of * key (decimal point)
  31. Adafruit_MCP4725 dac; //constructor
  32. uint8_t address = 0x68; //0x68 is the default address for the MCP3426 device
  33. MCP342x adc = MCP342x(address);
  34. const byte MCP79410_ADDRESS = 0x6f; //0x6f is the default address for the MCP79410 Real Time Clock IC
  35. MCP79410_Timer timer = MCP79410_Timer(MCP79410_ADDRESS);
  36. //Set the pins on the I2C chip used for LCD connections
  37. //ADDR,EN,R/W,RS,D4,D5,D6,D7
  38. LiquidCrystal_I2C lcd(0x27,2,1,0,4,5,6,7); //0x27 is the default address of the LCD with I2C bus module
  39. const byte pinA = 2; //digital pin (also interrupt pin) for the A pin of the Rotary Encoder (changed to digital pin 2)
  40. const byte pinB = 4; //digital pin for the B pin of the Rotary Encoder
  41. const byte CursorPos = 17; //analog pin A3 used as a digital pin to set cursor position (rotary encoder push button)
  42. const byte LoadOnOff = 15; //analog pin A1 used as a digital pin to set Load ON/OFF
  43. const byte TriggerPulse = 16; //analog pin A2 used as a digital pin for trigger pulse input in transient mode
  44. const byte fan = 3; //digital pin 3 for fan control output (changed to Digital pin 3)
  45. const byte temperature = A6; //analog pin used for temperature output from LM35 (was A0 previously but changed)
  46. int temp; //
  47. float BatteryLife = 0; //
  48. float BatteryLifePrevious = 0; //
  49. float Seconds = 0; //time variable used in Battery Capacity Mode (BC)
  50. float SecondsLog = 0; //variable used for data logging of the time in seconds
  51. float BatteryCutoffVolts; //used to set battery discharge cut-off voltage
  52. float MaxBatteryCurrent = 1.0; //maximum battery current allowed for Battery Capacity Testing
  53. int stopSeconds; //store for seconds when timer stopped
  54. int CP = 8; //cursor start position
  55. boolean toggle = false; //used for toggle of Load On/Off button
  56. unsigned long controlVoltage = 0; //used for DAC to control MOSFET
  57. long current = 0; //variable used by ADC for measuring the current
  58. long voltage = 0; //variable used by ADC for measuring the voltage
  59. float reading = 0; //variable for Rotary Encoder value divided by 1000
  60. float setCurrent = 0; //variable used for the set current of the load
  61. float setPower = 0; //variable used for the set power of the load
  62. float setResistance = 0; //variable used for the set resistance of the load
  63. float setCurrentCalibrationFactor = 0.980; //calibration adjustment - set as required if needed (was 1.000)
  64. float displayCurrentCal = 0.000; //calibration correction for LCD current display (was 0.040)
  65. int Load = 0; //Load On/Off flag
  66. float setControlCurrent = 0; //variable used to set the temporary store for control current required
  67. int VoltsDecimalPlaces = 3; //number of decimal places used for Voltage display on LCD
  68. float ActualVoltage = 0; //variable used for Actual Voltage reading of Load
  69. float ActualCurrent = 0; //variable used for Actual Current reading of Load
  70. float ActualPower = 0; //variable used for Actual Power reading of Load
  71. float ResistorCutOff = 999; //maximum Resistor we want to deal with in software
  72. float BatteryCurrent; //
  73. float LoadCurrent; //
  74. int CurrentCutOff = EEPROM.read(0x00);
  75. int PowerCutOff = EEPROM.read(0x20);
  76. int tempCutOff = EEPROM.read(0x40);
  77. int setReading = 0; //
  78. int ControlVolts = 0; //used to set output current
  79. float OutputVoltage = 0; //
  80. String Mode =" "; //used to identify which mode
  81. int modeSelected = 0; //Mode status flag
  82. int lastCount = 50; //
  83. volatile float encoderPosition = 0; //
  84. volatile unsigned long factor= 0; //number of steps to jump
  85. volatile unsigned long encoderMax = 999000; //sets maximum Rotary Encoder value allowed CAN BE CHANGED AS REQUIRED (was 50000)
  86. float LiPoCutOffVoltage = 3.0; //set cutoff voltage for LiPo battery
  87. float LiFeCutOffVoltage = 2.8; //set cutoff voltage for LiFe battery
  88. float NiCdCutOffVoltage = 1.0; //set cutoff voltage for NiCd battery
  89. float ZiZnCutOffVoltage = 1.0; //set cutoff voltage for ZiZn battery
  90. float PbAcCutOffVoltage = 1.75; //set cutoff voltage for PbAc battery
  91. String BatteryType =" ";
  92. byte exitMode = 0; //used to exit battery selection menu and return to CC Mode
  93. char numbers[10]; //keypad number entry - Plenty to store a representation of a float
  94. byte index = 0;
  95. int z = 1; //was previously 0
  96. float x = 0;
  97. int y = 0;
  98. int r = 0;
  99. float LowCurrent = 0; //the low current setting for transcient mode
  100. float HighCurrent = 0; //the high current setting for transcient mode
  101. unsigned long transientPeriod; //used to store pulse time period in transcient pulse mode
  102. unsigned long current_time; //used to store the current time in microseconds
  103. unsigned long last_time; //used to store the time of the last transient switch in micro seconds
  104. boolean transient_mode_status; //used to maintain the state of the trascient mode (false = low current, true = high current)
  105. float transientList [10][2]; //array to store Transient List data
  106. int total_instructions; //used in Transient List Mode
  107. int current_instruction; //used in Transient List Mode
  108. //--------------------------------Interrupt Routine for Rotary Encoder------------------------
  109. void isr()
  110. {
  111. static unsigned long lastInterruptTime = 0;
  112. unsigned long interruptTime = millis();
  113. if (interruptTime - lastInterruptTime > 5) { //
  114. if (digitalRead(pinB) == LOW)
  115. {
  116. encoderPosition = encoderPosition - factor;
  117. }else{
  118. encoderPosition = encoderPosition + factor;
  119. }
  120. encoderPosition = min(encoderMax, max(0, encoderPosition)); // sets maximum range of rotary encoder
  121. lastInterruptTime = interruptTime;
  122. }
  123. }
  124. //---------------------------------Initial Set up---------------------------------------
  125. void setup() {
  126. Serial.begin(9600); //used for testing only
  127. Wire.begin(); //join i2c bus (address optional for master)
  128. Wire.setClock(400000L); //sets bit rate to 400KHz
  129. MCP342x::generalCallReset(); //Reset devices
  130. delay(1); //MC342x needs 300us to settle, wait 1ms - (may not be required)
  131. pinMode (pinA, INPUT);
  132. pinMode (pinB, INPUT);
  133. pinMode (CursorPos, INPUT_PULLUP);
  134. pinMode (LoadOnOff, INPUT_PULLUP);
  135. pinMode (TriggerPulse, INPUT_PULLUP);
  136. pinMode (fan, OUTPUT);
  137. TCCR2B = (TCCR2B & 0b11111000) | 1; //change PWM to above hearing (Kenneth Larvsen recommendation)
  138. pinMode (temperature, INPUT);
  139. analogReference(INTERNAL); //use Arduino internal reference for tempurature monitoring
  140. attachInterrupt(digitalPinToInterrupt(pinA), isr, LOW);
  141. dac.begin(0x61); //the DAC I2C address with MCP4725 pin A0 set high
  142. dac.setVoltage(0,false); //reset DAC to zero for no output current set at Switch On
  143. lcd.begin(20, 4); //set up the LCD's number of columns and rows
  144. lcd.setBacklightPin(3,POSITIVE); // BL, BL_POL
  145. lcd.setBacklight(HIGH); //set LCD backlight on
  146. lcd.clear(); //clear LCD display
  147. lcd.setCursor(6,0); //set LCD cursor to column 0, row 4
  148. lcd.print("SCULLCOM"); //print SCULLCOM to display with 5 leading spaces (you can change to your own)
  149. lcd.setCursor(1,1); //set LCD cursor to column 0, row 1 (start of second line)
  150. lcd.print("Hobby Electronics"); //print Hobby Electronics to display (you can change to your own)
  151. lcd.setCursor(1,2);
  152. lcd.print("DC Electronic Load"); //
  153. lcd.setCursor(0,3);
  154. lcd.print("Ver. 35 (5x4 Keypad)"); //
  155. delay(2000); //3000 mSec delay for intro display
  156. lcd.clear(); //clear dislay
  157. setupLimits();
  158. delay(3000);
  159. lcd.clear();
  160. last_time = 0; //set the last_time to 0 at the start (Transicent Mode)
  161. transient_mode_status = false; //set the initial transient mode status (false = low, true = high);
  162. setCurrent = LowCurrent; //first set the current to the low current value (Transicent Mode)
  163. lcd.setCursor(8,0);
  164. lcd.print("OFF"); //indicate that LOAD is off at start up
  165. Current(); //sets initial mode to be CC (Constant Current) at Power Up
  166. customKey = customKeypad.getKey();
  167. }
  168. //------------------------------------------Main Program Loop---------------------------------
  169. void loop() {
  170. if(CurrentCutOff > 5){ //Test and go to user set limits if required
  171. userSetUp();
  172. }else{
  173. readKeypadInput(); //read Keypad entry
  174. if (digitalRead(LoadOnOff) == LOW) {
  175. LoadSwitch(); //Load on/off
  176. }
  177. transient(); //test for Transient Mode
  178. lcd.setCursor(18,3); //sets display of Mode indicator at bottom right of LCD
  179. lcd.print(Mode); //display mode selected on LCD (CC, CP, CR or BC)
  180. if(Mode != "TC" && Mode != "TP" && Mode != "TT" && Mode != "TL"){ //if NOT transient mode then Normal Operation
  181. reading = encoderPosition/1000; //read input from rotary encoder
  182. maxConstantCurrentSetting(); //set maxiumum Current allowed in Constant Current Mode (CC)
  183. powerLevelCutOff(); //Check if Power Limit has been exceeded
  184. temperatureCutOff(); //check if Maximum Temperature is exceeded
  185. batteryCurrentLimitValue(); //Battery Discharge Constant Current Limit Value in BC Mode
  186. displayEncoderReading(); //display rotary encoder input reading on LCD
  187. lastCount = encoderPosition; //store rotary encoder current position
  188. CursorPosition(); //check and change the cursor position if cursor button pressed
  189. }else{
  190. transientLoadToggle(); //Start Transient Mode
  191. }
  192. readVoltageCurrent(); //routine for ADC's to read actual Voltage and Current
  193. ActualReading(); //Display actual Voltage, Current readings and Actual Wattage
  194. dacControl();
  195. dacControlVoltage(); //sets the drive voltage to control the MOSFET
  196. batteryCapacity(); //test if Battery Capacity (BC) mode is selected - if so action
  197. fanControl(); //call heatsink fan control
  198. }
  199. }
  200. //------------------------------------------------Read Keypad Input-----------------------------------------------------
  201. void readKeypadInput (void) {
  202. customKey = customKeypad.getKey();
  203. // if (customKey != NO_KEY){ //only used for testing keypad (uncomment if required for testing keypad)
  204. // Serial.print("customKey = "); //only used for testing keypad (uncomment if required for testing keypad)
  205. // Serial.println(customKey); //only used for testing keypad (uncomment if required for testing keypad)
  206. // } //only used for testing keypad (uncomment if required for testing keypad)
  207. if(customKey == 'E'){ //check for Load on/off
  208. LoadSwitch();
  209. }
  210. if(customKey == 'D'){ //check if Set-Up Mode Selected
  211. delay(200);
  212. toggle = false; //switch Load OFF
  213. userSetUp();
  214. encoderPosition = 0; //reset encoder reading to zero
  215. index = 0;
  216. z = 1; //sets column position for LCD displayed character
  217. decimalPoint = (' '); //clear decimal point text character reset
  218. }
  219. if(customKey == 'C'){ //check if Transient Mode Selected
  220. toggle = false; //switch Load OFF
  221. transientType();
  222. encoderPosition = 0; //reset encoder reading to zero
  223. index = 0;
  224. z = 1; //sets column position for LCD displayed character
  225. decimalPoint = (' '); //clear decimal point text character reset
  226. }
  227. if(customKey == 'A'){ //check if Constant Current button pressed
  228. toggle = false; //switch Load OFF
  229. lcd.setCursor(8,0);
  230. lcd.print("OFF");
  231. Current(); //if selected go to Constant Current Selected routine
  232. encoderPosition = 0; //reset encoder reading to zero
  233. index = 0;
  234. z = 1; //sets column position for LCD displayed character
  235. decimalPoint = (' '); //clear decimal point test character reset
  236. }
  237. if(customKey == 'B'){ //check if Constant Power button pressed
  238. toggle = false; //switch Load OFF
  239. lcd.setCursor(8,0);
  240. lcd.print("OFF");
  241. Power(); //if selected go to Constant Power Selected routine
  242. encoderPosition = 0; //reset encoder reading to zero
  243. index = 0;
  244. z = 1; //sets column position for LCD displayed character
  245. decimalPoint = (' '); //clear decimal point test character reset
  246. }
  247. if(customKey == '#'){ //check if Constant Resistance button pressed
  248. toggle = false; //switch Load OFF
  249. lcd.setCursor(8,0);
  250. lcd.print("OFF");
  251. Resistance(); //if selected go to Constant Resistance Selected routine
  252. encoderPosition = 0; //reset encoder reading to zero
  253. index = 0;
  254. z = 1; //sets column position for LCD displayed character
  255. decimalPoint = (' '); //clear decimal point test character reset
  256. }
  257. if(customKey == '*'){ //check if Battery Capacity button pressed
  258. dac.setVoltage(0,false); //Ensures Load is OFF - sets DAC output voltage to 0
  259. toggle = false; //switch Load OFF
  260. batteryType(); //select battery type
  261. index = 0;
  262. z = 1; //sets column position for LCD displayed character
  263. decimalPoint = (' '); //clear decimal point test character reset
  264. if (exitMode == 1){ //if NO battery type selected revert to CC Mode
  265. lcd.setCursor(8,0);
  266. lcd.print("OFF");
  267. Current(); //if selected go to Constant Current Selected routine
  268. encoderPosition = 0; //reset encoder reading to zero
  269. customKey = 'A';
  270. }
  271. else
  272. {
  273. lcd.setCursor(16,2);
  274. lcd.print(BatteryType); //print battery type on LCD
  275. lcd.setCursor(8,0);
  276. lcd.print("OFF");
  277. timer.reset(); //reset timer
  278. BatteryLifePrevious = 0;
  279. CP = 9; //set cursor position
  280. BatteryCapacity(); //go to Battery Capacity Routine
  281. }
  282. }
  283. if (Mode != "BC"){
  284. if(customKey >= '0' && customKey <= '9'){ //check for keypad number input
  285. numbers[index++] = customKey;
  286. numbers[index] = '\0';
  287. lcd.setCursor(z,3); //
  288. lcd.print(customKey); //show number input on LCD
  289. z = z+1;
  290. }
  291. if(customKey == '>'){ //check if decimal button key pressed
  292. if (decimalPoint != ('>')){ //test if decimal point entered twice - if so skip
  293. numbers[index++] = '.';
  294. numbers[index] = '\0';
  295. lcd.setCursor(z,3);
  296. lcd.print(".");
  297. z = z+1;
  298. decimalPoint = ('>'); //used to indicate decimal point has been input
  299. }
  300. }
  301. if(customKey == '<'){ //clear input entry
  302. index = 0;
  303. z = 1; //sets column position for LCD displayed character
  304. lcd.setCursor(z,3);
  305. lcd.print(" ");
  306. numbers[index] = '\0'; //
  307. decimalPoint = (' '); //clear decimal point test character reset
  308. }
  309. if(customKey == 'F') { //use entered number
  310. x = atof(numbers);
  311. reading = x;
  312. encoderPosition = reading*1000;
  313. index = 0;
  314. numbers[index] = '\0';
  315. z = 1; //sets column position for LCD displayed character
  316. lcd.setCursor(0,3);
  317. lcd.print(" ");
  318. decimalPoint = (' '); //clear decimal point test character reset
  319. }
  320. }
  321. }
  322. //----------------------Limit Maximum Current Setting-----------------------------------------
  323. void maxConstantCurrentSetting (void) {
  324. if (Mode == "CC" && reading > CurrentCutOff){ //Limit maximum Current Setting
  325. reading = CurrentCutOff;
  326. encoderPosition = (CurrentCutOff * 1000); //keep encoder position value at maximum Current Limit
  327. lcd.setCursor(0,3);
  328. lcd.print(" "); //20 spaces to clear last line of LCD
  329. }
  330. if (Mode == "CP" && reading > PowerCutOff) { //Limit maximum Current Setting
  331. reading = PowerCutOff;
  332. encoderPosition = (PowerCutOff * 1000); //keep encoder position value at maximum Current Limit
  333. lcd.setCursor(0,3);
  334. lcd.print(" "); //20 spaces to clear last line of LCD
  335. }
  336. if (Mode == "CR" && reading > ResistorCutOff ) { //Limit maximum Current Setting
  337. reading = ResistorCutOff;
  338. encoderPosition = (ResistorCutOff * 1000); //keep encoder position value at maximum Current Limit
  339. lcd.setCursor(0,3);
  340. lcd.print(" "); //20 spaces to clear last line of LCD
  341. }
  342. }
  343. //----------------------Power Level Cutoff Routine-------------------------------------------
  344. void powerLevelCutOff (void) {
  345. if (ActualPower > PowerCutOff){ //Check if Power Limit has been exceed
  346. reading = 0;
  347. encoderPosition = 0;
  348. lcd.setCursor(0,3);
  349. lcd.print(" ");
  350. lcd.setCursor(0,3);
  351. lcd.print("Exceeded Power");
  352. lcd.setCursor(8,0);
  353. lcd.print("OFF");
  354. toggle = false; //switch Load Off
  355. }
  356. }
  357. //----------------------Battery Constant Current Limit Value------------------------------------------
  358. void batteryCurrentLimitValue (void) {
  359. if (Mode == "BC" && reading > MaxBatteryCurrent){
  360. reading = MaxBatteryCurrent;
  361. encoderPosition = (MaxBatteryCurrent*1000); //keep encoder position value at 1000mA
  362. }
  363. }
  364. //----------------------Display Rotary Encoder Input Reading on LCD---------------------------
  365. void displayEncoderReading (void) {
  366. lcd.setCursor(8,2); //start position of setting entry
  367. if ( ( Mode == "CP" || Mode == "CR" ) && reading < 100 ) {
  368. lcd.print("0");
  369. }
  370. if (reading < 10) { //add a leading zero to display if reading less than 10
  371. lcd.print("0");
  372. }
  373. if ( Mode == "CP" || Mode == "CR" ) {
  374. lcd.print (reading, 2); //show input reading from Rotary Encoder on LCD
  375. } else {
  376. lcd.print (reading, 3);
  377. }
  378. lcd.setCursor (CP, 2); //sets cursor position
  379. lcd.cursor(); //show cursor on LCD
  380. }
  381. //--------------------------Cursor Position-------------------------------------------------------
  382. //Change cursor the position routine
  383. void CursorPosition(void) {
  384. // Defaults for two digits before decimal and 3 after decimal point
  385. int unitPosition = 9;
  386. //Power and Resistance modes can be 3 digit before decimal but only 2 decimals
  387. if ( Mode == "CP" || Mode == "CR" ) {
  388. unitPosition = 10;
  389. }
  390. if (digitalRead(CursorPos) == LOW) {
  391. delay(200); //simple key bounce delay
  392. CP = CP + 1;
  393. if (CP == unitPosition + 1 ) {
  394. CP = CP + 1;
  395. }
  396. }
  397. if (CP > 13) { CP = unitPosition; } //No point in turning tens and hundreds
  398. if (CP == unitPosition +4 ) { factor = 1; }
  399. if (CP == unitPosition +3 ) { factor = 10; }
  400. if (CP == unitPosition +2 ) { factor = 100; }
  401. if (CP == unitPosition ) { factor = 1000; }
  402. }
  403. //---------------------------------------------Read Voltage and Current--------------------------------------------------------------
  404. void readVoltageCurrent (void) {
  405. MCP342x::Config status;
  406. // Initiate a conversion; convertAndRead() will wait until it can be read
  407. adc.convertAndRead(MCP342x::channel1, MCP342x::oneShot,
  408. MCP342x::resolution16, MCP342x::gain1, //"gain1" means we have select the input amp of the ADC to x1
  409. 1000000, voltage, status);
  410. // Initiate a conversion; convertAndRead() will wait until it can be read
  411. adc.convertAndRead(MCP342x::channel2, MCP342x::oneShot,
  412. MCP342x::resolution16, MCP342x::gain4, //"gain4" means we have select the input amp of the ADC to x4
  413. 1000000, current, status);
  414. }
  415. //-----------------------------------Calculate Actual Voltage and Current and display on LCD-----------------------------------------
  416. void ActualReading(void) {
  417. ActualCurrent = (((current*2.048)/32767) * 2.5); //calculate load current
  418. currentDisplayCal(); //LCD display current calibration correction
  419. ActualVoltage = (((voltage*2.048)/32767) * 50.4); //calculate load voltage upto 100v (was 50)
  420. ActualPower = ActualVoltage*ActualCurrent;
  421. if (ActualPower <=0){
  422. ActualPower = 0;
  423. }
  424. if (ActualVoltage <=0.0){ //added to prevent negative readings on LCD due to error
  425. ActualVoltage = 0.0;
  426. }
  427. if (ActualCurrent <= 0.0){ //added to prevent negative readings on LCD due to error
  428. ActualCurrent = 0.0;
  429. }
  430. lcd.setCursor(0,1);
  431. if ( ActualCurrent < 10.0 ) {
  432. lcd.print(ActualCurrent,3);
  433. } else {
  434. lcd.print(ActualCurrent,2);
  435. }
  436. lcd.print("A");
  437. lcd.print(" ");
  438. if (ActualVoltage < 10.0) {
  439. lcd.print(ActualVoltage, 3);
  440. } else {
  441. lcd.print(ActualVoltage, 2);
  442. }
  443. lcd.print("V");
  444. lcd.print(" ");
  445. if (ActualPower < 100 ) {
  446. lcd.print(ActualPower,2);
  447. } else {
  448. lcd.print(ActualPower,1);
  449. }
  450. lcd.print("W");
  451. lcd.print(" ");
  452. }
  453. //-----------------------DAC Control Voltage for Mosfet---------------------------------------
  454. void dacControlVoltage (void) {
  455. if (Mode == "CC"){
  456. setCurrent = reading*1000; //set current is equal to input value in Amps
  457. setReading = setCurrent; //show the set current reading being used
  458. setControlCurrent = setCurrent * setCurrentCalibrationFactor;
  459. controlVoltage = setControlCurrent;
  460. }
  461. if (Mode == "CP"){
  462. setPower = reading*1000; //in Watts
  463. setReading = setPower;
  464. setCurrent = setPower/ActualVoltage;
  465. setControlCurrent = setCurrent * setCurrentCalibrationFactor;
  466. controlVoltage = setControlCurrent; //
  467. }
  468. if (Mode == "CR"){
  469. setResistance = reading; //in ohms
  470. setReading = setResistance;
  471. setCurrent = (ActualVoltage)/setResistance*1000;
  472. setControlCurrent = setCurrent * setCurrentCalibrationFactor;
  473. controlVoltage = setControlCurrent;
  474. }
  475. if (Mode == "TC" || Mode == "TP" || Mode == "TT" || Mode == "TL"){ //Transient Modes
  476. setControlCurrent = (setCurrent * 1000) * setCurrentCalibrationFactor;
  477. controlVoltage = setControlCurrent;
  478. }
  479. }
  480. //-------------------------------------Battery Capacity Discharge Routine----------------------------------------------------
  481. void batteryCapacity (void) {
  482. if (Mode == "BC"){
  483. setCurrent = reading*1000; //set current is equal to input value in Amps
  484. setReading = setCurrent; //show the set current reading being used
  485. setControlCurrent = setCurrent * setCurrentCalibrationFactor;
  486. controlVoltage = setControlCurrent;
  487. lcd.setCursor(0,3);
  488. lcd.print (timer.getTime()); //start clock and print clock time
  489. Seconds = timer.getTotalSeconds(); //get totals seconds
  490. LoadCurrent = ActualCurrent; //if timer still running use present Actual Current reading
  491. if (timer.status() == 2){ //if timer is halted then use last Actual Current reading before timer stopped
  492. LoadCurrent = BatteryCurrent;
  493. }
  494. BatteryLife = (LoadCurrent*1000)*(Seconds/3600); //calculate battery capacity in mAh
  495. lcd.setCursor(9,3);
  496. BatteryLife = round(BatteryLife);
  497. if(BatteryLife >= BatteryLifePrevious){ //only update LCD (mAh) if BatteryLife has increased
  498. if (BatteryLife < 10) { //add a 3 leading zero to display if reading less than 10
  499. lcd.print("000");
  500. }
  501. if (BatteryLife >= 10 && BatteryLife <100){ //add a 2 leading zero to display
  502. lcd.print("00");
  503. }
  504. if (BatteryLife >= 100 && BatteryLife <1000){ //add a 1 leading zero to display
  505. lcd.print("0");
  506. }
  507. lcd.print(BatteryLife,0);
  508. lcd.setCursor(13,3);
  509. lcd.print("mAh");
  510. BatteryLifePrevious = BatteryLife; //update displayed battery capacity on LCD
  511. }
  512. }
  513. if (Mode == "BC" && ActualVoltage <= BatteryCutoffVolts){ //stops clock if battery reached cutoff level and switch load off
  514. BatteryCurrent = ActualCurrent;
  515. dac.setVoltage(0,false); //reset DAC to zero for no output current set at switch on
  516. toggle = false; //Load is toggled OFF
  517. lcd.setCursor(8,0);
  518. lcd.print("OFF"); //indicate that LOAD is off at start up
  519. timer.stop();
  520. }
  521. if (Mode == "BC" && Load == 1){ //Routine used for data logging in Battery Capacity Mode
  522. if (Seconds != SecondsLog){ //only send serial data if time has changed
  523. SecondsLog = Seconds;
  524. Serial.print (SecondsLog); //sends serial data of time in seconds
  525. Serial.print (","); //sends a comma as delimiter for logged data
  526. Serial.println (ActualVoltage); //sends serial data of Voltage reading
  527. }
  528. }
  529. }
  530. //--------------------------------------------------Fan Control----------------------------------------------------------
  531. void fanControl (void) {
  532. temp = analogRead(temperature);
  533. temp = temp * 0.107421875; // convert to Celsius
  534. if (temp >= 40){ //if temperature 40 degree C or above turn fan on.
  535. digitalWrite(fan, HIGH);
  536. } else {
  537. digitalWrite(fan, LOW); //otherwise turn fan turned off
  538. }
  539. lcd.setCursor(16,0);
  540. lcd.print(temp); //display temperature of heatsink on LCD
  541. lcd.print((char)0xDF);
  542. lcd.print("C");
  543. }
  544. //-----------------------Toggle Current Load ON or OFF------------------------------
  545. void LoadSwitch(void) {
  546. delay(200); //simple key bounce delay
  547. if(toggle)
  548. {
  549. lcd.setCursor(8,0);
  550. lcd.print("OFF");
  551. current_instruction = 0; //reset current instruction for Transient List Mode to zero
  552. last_time = 0; //reset last time to zero
  553. transientPeriod = 0; //reset transient period time to zero
  554. setCurrent = 0; //reset setCurrent to zero
  555. toggle = !toggle;
  556. Load = 0;
  557. }
  558. else
  559. {
  560. lcd.setCursor(8,0);
  561. lcd.print("ON ");
  562. lcd.setCursor(0,3);
  563. lcd.print(" "); //clear bottom line of LCD
  564. toggle = !toggle;
  565. Load = 1;
  566. }
  567. }
  568. //-----------------------Select Constant Current LCD set up--------------------------------
  569. void Current(void) {
  570. Mode = ("CC");
  571. lcd.setCursor(0,0);
  572. lcd.print("DC LOAD");
  573. lcd.setCursor(0,2);
  574. lcd.print(" ");
  575. lcd.setCursor(0,2);
  576. lcd.print("Set I = ");
  577. lcd.setCursor(16,2);
  578. lcd.print(" ");
  579. lcd.setCursor(14,2);
  580. lcd.print("A");
  581. lcd.setCursor(0,3); //clear last line of time info
  582. lcd.print(" "); //20 spaces so as to allow for Load ON/OFF to still show
  583. CP = 9; //sets cursor starting position to units.
  584. }
  585. //----------------------Select Constant Power LCD set up------------------------------------
  586. void Power(void) {
  587. Mode = ("CP");
  588. lcd.setCursor(0,0);
  589. lcd.print("DC LOAD");
  590. lcd.setCursor(0,2);
  591. lcd.print(" ");
  592. lcd.setCursor(0,2);
  593. lcd.print("Set W = ");
  594. lcd.setCursor(16,2);
  595. lcd.print(" ");
  596. lcd.setCursor(14,2);
  597. lcd.print("W");
  598. lcd.setCursor(0,3); //clear last line of time info
  599. lcd.print(" "); //20 spaces so as to allow for Load ON/OFF to still show
  600. CP = 10; //sets cursor starting position to units.
  601. }
  602. //----------------------- Select Constant Resistance LCD set up---------------------------------------
  603. void Resistance(void) {
  604. Mode = ("CR");
  605. lcd.setCursor(0,0);
  606. lcd.print("DC LOAD");
  607. lcd.setCursor(0,2);
  608. lcd.print(" ");
  609. lcd.setCursor(0,2);
  610. lcd.print("Set R = ");
  611. lcd.setCursor(16,2);
  612. lcd.print(" ");
  613. lcd.setCursor(14,2);
  614. lcd.print((char)0xF4);
  615. lcd.setCursor(0,3); //clear last line of time info
  616. lcd.print(" "); //20 spaces so as to allow for Load ON/OFF to still show
  617. CP = 10; //sets cursor starting position to units.
  618. }
  619. //----------------------- Select Battery Capacity Testing LCD set up---------------------------------------
  620. void BatteryCapacity(void) {
  621. Mode = ("BC");
  622. lcd.setCursor(0,0);
  623. lcd.print("BATTERY");
  624. lcd.setCursor(0,2);
  625. lcd.print(" ");
  626. lcd.setCursor(0,2);
  627. lcd.print("Set I = ");
  628. lcd.setCursor(14,2);
  629. lcd.print("A");
  630. lcd.setCursor(0,3); //clear last line of time info
  631. lcd.print(" "); //20 spaces so as to allow for Load ON/OFF to still show
  632. }
  633. //----------------------Battery Type Selection Routine------------------------------------------------
  634. void batteryType (void) {
  635. exitMode = 0; //reset EXIT mode
  636. lcd.noCursor(); //switch Cursor OFF for this menu
  637. lcd.clear();
  638. lcd.setCursor(0,0);
  639. lcd.print("Select Battery Type");
  640. lcd.setCursor(0,1);
  641. lcd.print("1=LiPo/Li-Ion 2=LiFe");
  642. lcd.setCursor(0,2);
  643. lcd.print("3=NiCd/NiMH 4=ZiZn");
  644. lcd.setCursor(0,3); //clear last line of time info
  645. lcd.print("5=Set Voltage 6=Exit"); //20 spaces so as to allow for Load ON/OFF to still show
  646. customKey = customKeypad.waitForKey(); //stop everything till the user press a key.
  647. if (customKey == '1'){
  648. BatteryCutoffVolts = LiPoCutOffVoltage;
  649. BatteryType = ("LiPo");
  650. }
  651. if (customKey == '2'){
  652. BatteryCutoffVolts = LiFeCutOffVoltage;
  653. BatteryType = ("LiFe");
  654. }
  655. if (customKey == '3'){
  656. BatteryCutoffVolts = NiCdCutOffVoltage;
  657. BatteryType = ("NiCd");
  658. }
  659. if (customKey == '4'){
  660. BatteryCutoffVolts = ZiZnCutOffVoltage;
  661. BatteryType = ("ZiZn");
  662. }
  663. if (customKey == '5'){
  664. BatteryType = ("SetV");
  665. }
  666. if (customKey == '6'){ //Exit selection screen
  667. exitMode = 1;
  668. }
  669. if (customKey == '7' || customKey == '8' || customKey == '9' || customKey == '0' || customKey == 'A' || customKey == 'B' || customKey == 'C' || customKey == 'D' || customKey == '*' || customKey == '#' || customKey == 'E' || customKey == 'F' || customKey == '<' || customKey == '>' ){
  670. batteryType(); //ignore other keys
  671. }
  672. if(BatteryType == "SetV" && exitMode != 1){
  673. setBatteryCutOff();
  674. }
  675. batteryTypeSelected(); //briefly display battery type selected and discharge cut off voltage
  676. lcd.clear();
  677. }
  678. //--------------------------Set DAC Voltage--------------------------------------------
  679. void dacControl (void) {
  680. if (!toggle){
  681. dac.setVoltage(0,false); //set DAC output voltage to 0 if Load Off selected
  682. if(Mode == "BC" && ActualVoltage >= BatteryCutoffVolts && timer.status() == 1){
  683. timer.stop();
  684. }
  685. }else{
  686. //Serial.println("Control Voltage"); //used for testing only
  687. //Serial.println(controlVoltage); //used for testing only
  688. dac.setVoltage(controlVoltage,false); //set DAC output voltage for Range selected
  689. if(Mode == "BC" && ActualVoltage >= BatteryCutoffVolts && timer.status() != 1){
  690. timer.start();
  691. }
  692. }
  693. }
  694. //--------------------------Battery Selected Information--------------------------------------------
  695. void batteryTypeSelected (void) {
  696. if (exitMode !=1){ //if battery selection was EXIT then skip this routine
  697. lcd.clear();
  698. lcd.setCursor(2,0);
  699. lcd.print("Battery Selected");
  700. lcd.setCursor(8,1);
  701. lcd.print(BatteryType); //display battery type selected
  702. lcd.setCursor(2,2);
  703. lcd.print("Discharge Cutoff");
  704. lcd.setCursor(6,3);
  705. lcd.print(BatteryCutoffVolts); //display battery discharge cut off voltage
  706. lcd.print(" volts");
  707. delay(3000);
  708. }
  709. }
  710. //--------------------------Set Battery Cut-Off Voltage--------------------------------------------
  711. void setBatteryCutOff (void) {
  712. lcd.clear();
  713. lcd.setCursor(4,0);
  714. lcd.print("Enter Battery");
  715. lcd.setCursor(3,1);
  716. lcd.print("Cut-Off Voltage");
  717. y = 8;
  718. z = 8;
  719. r = 2;
  720. inputValue();
  721. BatteryCutoffVolts = x;
  722. lcd.clear();
  723. }
  724. //------------------------Key input used for Battery Cut-Off and Transient Mode------------------------
  725. void inputValue (void){
  726. while(customKey != 'F'){ //check if enter pressed (was previously #)
  727. customKey = customKeypad.getKey();
  728. if(customKey >= '0' && customKey <= '9'){ //check for keypad number input
  729. numbers[index++] = customKey;
  730. numbers[index] = '\0';
  731. lcd.setCursor(z,r);
  732. lcd.print(customKey); //show number input on LCD
  733. z = z+1;
  734. }
  735. if(customKey == '>'){ //Decimal point
  736. if (decimalPoint != ('>')){ //test if decimal point entered twice - if so ski
  737. numbers[index++] = '.';
  738. numbers[index] = '\0';
  739. lcd.setCursor(z,r);
  740. lcd.print(".");
  741. z = z+1;
  742. decimalPoint = ('>'); //used to indicate decimal point has been input
  743. }
  744. }
  745. if(customKey == '<'){ //clear entry
  746. index = 0;
  747. z = y;
  748. lcd.setCursor(y,r);
  749. lcd.print(" ");
  750. numbers[index] = '\0'; //
  751. decimalPoint = (' '); //clear decimal point test character reset
  752. }
  753. }
  754. if(customKey == 'F') { //enter value
  755. x = atof(numbers);
  756. index = 0;
  757. numbers[index] = '\0';
  758. decimalPoint = (' '); //clear decimal point test character reset
  759. }
  760. }
  761. //----------------------------------------Transient Mode--------------------------------------------
  762. void transientMode (void) {
  763. if(Mode != "TL"){
  764. y = 11;
  765. z = 11;
  766. lcd.noCursor(); //switch Cursor OFF for this menu
  767. lcd.clear();
  768. lcd.setCursor(3,0);
  769. lcd.print("Transient Mode");
  770. lcd.setCursor(0,1);
  771. lcd.print("Set Low I=");
  772. lcd.setCursor(19,1);
  773. lcd.print("A");
  774. r = 1;
  775. inputValue();
  776. if(x >= CurrentCutOff){
  777. LowCurrent = CurrentCutOff;
  778. }else{
  779. LowCurrent = x;
  780. }
  781. lcd.setCursor(11,r);
  782. lcd.print(LowCurrent,3);
  783. customKey = '0';
  784. z = 11;
  785. lcd.setCursor(0,2);
  786. lcd.print("Set High I=");
  787. lcd.setCursor(19,2);
  788. lcd.print("A");
  789. r = 2;
  790. inputValue();
  791. if(x >= CurrentCutOff){
  792. HighCurrent = CurrentCutOff;
  793. }else{
  794. HighCurrent = x;
  795. }
  796. lcd.setCursor(11,r);
  797. lcd.print(HighCurrent,3);
  798. customKey = '0';
  799. if(Mode == "TC" || Mode == "TP"){
  800. z = 11;
  801. lcd.setCursor(0,3);
  802. lcd.print("Set Time = ");
  803. lcd.setCursor(16,3);
  804. lcd.print("mSec");
  805. r = 3;
  806. inputValue();
  807. transientPeriod = x;
  808. lcd.setCursor(11,r);
  809. lcd.print(transientPeriod);
  810. }else{
  811. lcd.setCursor(0,3);
  812. lcd.print(" ");
  813. }
  814. lcd.clear();
  815. toggle = false; //switch Load OFF
  816. lcd.setCursor(8,0);
  817. lcd.print("OFF"); //print on display OFF
  818. }else{
  819. transientListSetup();
  820. lcd.clear();
  821. toggle = false; //switch Load OFF
  822. lcd.setCursor(8,0);
  823. lcd.print("OFF"); //print on display OFF
  824. }
  825. }
  826. //----------------------------------------Transient Type Selection--------------------------------------------
  827. void transientType (void) {
  828. toggle = false; //switch Load OFF
  829. exitMode = 0; //reset EXIT mode
  830. lcd.noCursor(); //switch Cursor OFF for this menu
  831. lcd.clear();
  832. lcd.setCursor(3,0);
  833. lcd.print("Transient Mode");
  834. lcd.setCursor(0,1);
  835. lcd.print("1 = Continuous");
  836. lcd.setCursor(0,2);
  837. lcd.print("2 = Toggle");
  838. lcd.setCursor(11,2); //
  839. lcd.print("3 = Pulse"); //
  840. lcd.setCursor(0,3); //
  841. lcd.print("4 = List"); //
  842. lcd.setCursor(11,3); //
  843. lcd.print("5 = Exit"); //
  844. customKey = customKeypad.waitForKey(); //stop everything till the user press a key.
  845. if (customKey == '1'){
  846. Mode = ("TC");
  847. }
  848. if (customKey == '2'){
  849. Mode = ("TT");
  850. }
  851. if (customKey == '3'){
  852. Mode = ("TP");
  853. }
  854. if (customKey == '4'){
  855. Mode = ("TL");
  856. }
  857. if (customKey == '5'){ //Exit selection screen
  858. exitMode = 1;
  859. }
  860. if (customKey == '6' || customKey == '7' || customKey == '8' || customKey == '9' || customKey == '0' || customKey == 'A' || customKey == 'B' || customKey == 'C' || customKey == 'D' || customKey == '*' || customKey == '#' || customKey == 'E' || customKey == 'F' || customKey == '<' || customKey == '>' ){
  861. transientType(); //ignore other keys
  862. }
  863. lcd.clear();
  864. if (exitMode == 1){ //if NO Transient Mode type selected revert to CC Mode
  865. lcd.setCursor(8,0);
  866. lcd.print("OFF");
  867. Current(); //if selected go to Constant Current Selected routine
  868. encoderPosition = 0; //reset encoder reading to zero
  869. customKey = 'A';
  870. }else{
  871. transientMode();
  872. }
  873. }
  874. //----------------------------------------Transient--------------------------------------------
  875. void transient (void) {
  876. if(Mode == "TC" || Mode == "TP" || Mode == "TT" || Mode == "TL"){
  877. lcd.noCursor(); //switch Cursor OFF for this menu
  878. lcd.setCursor(0,0);
  879. lcd.print("DC LOAD");
  880. if(Mode != "TL"){
  881. lcd.setCursor(0,2);
  882. lcd.print("Lo=");
  883. lcd.setCursor(3,2);
  884. lcd.print(LowCurrent,3);
  885. lcd.setCursor(8,2);
  886. lcd.print("A");
  887. lcd.setCursor(11,2);
  888. lcd.print("Hi=");
  889. lcd.setCursor(14,2); //
  890. lcd.print(HighCurrent,3);
  891. lcd.setCursor(19,2);
  892. lcd.print("A");
  893. }else{
  894. delay(1);
  895. }
  896. if(Mode == "TC" || Mode == "TP" || Mode == "TL"){
  897. lcd.setCursor(0,3); //
  898. lcd.print("Time = ");
  899. lcd.setCursor(7,3);
  900. lcd.print(transientPeriod);
  901. lcd.setCursor(12,3); //
  902. lcd.print("mSecs");
  903. }else{
  904. lcd.setCursor(0,3);
  905. lcd.print(" ");
  906. }
  907. }
  908. delay(1);
  909. }
  910. //-------------------------------------Transcient List Setup-------------------------------------------
  911. void transientListSetup(){
  912. lcd.noCursor();
  913. lcd.clear();
  914. lcd.setCursor(0,0);
  915. lcd.print("Setup Transient List");
  916. lcd.setCursor(0,1);
  917. lcd.print("Enter Number in List");
  918. lcd.setCursor(0,2);
  919. lcd.print("(between 2 to 10 max");
  920. y = 0;
  921. z = 0;
  922. r = 3;
  923. inputValue();
  924. total_instructions = int(x-1);
  925. customKey = '0';
  926. lcd.clear();
  927. for(int i=0; i<=(total_instructions); i++){
  928. lcd.setCursor(0,0);
  929. lcd.print("Set Current ");
  930. lcd.print(i+1);
  931. lcd.setCursor(16,1);
  932. lcd.print("A");
  933. y = 0;
  934. z = 0;
  935. r = 1;
  936. inputValue(); //get the users input value
  937. transientList[i][0] = x; //store the users entered value in the transient list
  938. customKey = '0';
  939. lcd.setCursor(0,2);
  940. lcd.print("Set Time ");
  941. lcd.print(i+1);
  942. lcd.setCursor(16,3);
  943. lcd.print("mSec");
  944. y = 0;
  945. z = 0;
  946. r = 3;
  947. inputValue(); //get the users input value
  948. transientList[i][1] = x; //store the users entered value in the transient list
  949. customKey = '0';
  950. lcd.clear();
  951. }
  952. current_instruction = 0; //start at first instrution
  953. }
  954. //-------------------------------------Transcient Load Toggel-------------------------------------------
  955. void transientLoadToggle(){
  956. if(Mode == "TC"){
  957. current_time = micros(); //get the current time in micro seconds()
  958. if (last_time == 0){
  959. last_time = current_time;
  960. } else {
  961. switch (transient_mode_status){
  962. case (false):
  963. // we are in the low current setting
  964. if ((current_time - last_time) >= (transientPeriod * 1000.0)){
  965. transientSwitch(LowCurrent, true);
  966. }
  967. break;
  968. case (true):
  969. // we are in the high current setting
  970. if ((current_time - last_time) >= (transientPeriod * 1000.0)){
  971. transientSwitch(HighCurrent, true);
  972. }
  973. break;
  974. }
  975. }
  976. }
  977. if(Mode == "TP"){
  978. current_time = micros(); //get the current time in micro seconds()
  979. if (last_time == 0){
  980. last_time = current_time;
  981. transientSwitch(LowCurrent, true);
  982. }
  983. if (digitalRead(TriggerPulse) == LOW){
  984. // a trigger pluse is received
  985. // set to the high current
  986. transientSwitch(HighCurrent, true);
  987. } else {
  988. if ((current_time - last_time) >= (transientPeriod * 1000.0)){
  989. transientSwitch(LowCurrent, true);
  990. }
  991. }
  992. }
  993. if(Mode == "TT"){ // this function will toggle between high and low current when the trigger pin is taken low
  994. if (digitalRead(TriggerPulse) == LOW){
  995. switch (transient_mode_status){
  996. case (false):
  997. transientSwitch(LowCurrent, true);
  998. delay(200); //added to prevent key bounce when transient button used (date of addition 31-03-2018)
  999. break;
  1000. case (true):
  1001. transientSwitch(HighCurrent, true);
  1002. delay(200); //added to prevent key bounce when transient button used (date of addition 31-03-2018)
  1003. break;
  1004. }
  1005. }
  1006. }
  1007. if(Mode == "TL"){
  1008. if (Load == 1){ //Only perform Transient List if Load is ON
  1009. current_time = micros(); //get the current time in micro seconds()
  1010. if (last_time == 0){
  1011. last_time = current_time;
  1012. transientPeriod = transientList[current_instruction][1]; //Time data for LCD display
  1013. transientSwitch(transientList[current_instruction][0], false);
  1014. }
  1015. if((current_time - last_time) >= transientList[current_instruction][1] * 1000){ //move to next list instruction
  1016. current_instruction++;
  1017. if(current_instruction > total_instructions){
  1018. current_instruction = 0;
  1019. }
  1020. transientPeriod = transientList[current_instruction][1]; //Time data for LCD display
  1021. transientSwitch(transientList[current_instruction][0], false);
  1022. }
  1023. }
  1024. }
  1025. }
  1026. //-------------------------------------Transcient Switch-------------------------------------------
  1027. void transientSwitch(float current_setting, boolean toggle_status){
  1028. if (toggle_status){
  1029. transient_mode_status = !transient_mode_status;
  1030. }
  1031. setCurrent = current_setting;
  1032. //Serial.print("set current = "); //used for testing only
  1033. //Serial.println(setCurrent); //used for testing only
  1034. last_time = current_time;
  1035. }
  1036. //-------------------------------------User set up for limits-------------------------------------------------
  1037. void userSetUp (void) {
  1038. y = 14;
  1039. z = 14;
  1040. lcd.noCursor(); //switch Cursor OFF for this menu
  1041. lcd.clear();
  1042. lcd.setCursor(4,0);
  1043. lcd.print("User Set-Up");
  1044. lcd.setCursor(0,1);
  1045. lcd.print("Current Limit=");
  1046. lcd.setCursor(19,1);
  1047. lcd.print("A");
  1048. r = 1;
  1049. inputValue();
  1050. CurrentCutOff = x;
  1051. EEPROM.write(0x00, CurrentCutOff);
  1052. lcd.setCursor(14,r);
  1053. lcd.print(CurrentCutOff);
  1054. customKey = '0';
  1055. z = 14;
  1056. lcd.setCursor(0,2);
  1057. lcd.print("Power Limit =");
  1058. lcd.setCursor(19,2);
  1059. lcd.print("W");
  1060. r = 2;
  1061. inputValue();
  1062. PowerCutOff = x;
  1063. EEPROM.write(0x20, PowerCutOff); //
  1064. lcd.setCursor(14,r);
  1065. lcd.print(PowerCutOff);
  1066. customKey = '0';
  1067. z = 14;
  1068. lcd.setCursor(0,3);
  1069. lcd.print("Temp. Limit =");
  1070. lcd.setCursor(18,3);
  1071. lcd.print((char)0xDF);
  1072. lcd.print("C");
  1073. r = 3;
  1074. inputValue();
  1075. tempCutOff = x;
  1076. EEPROM.write(0x40, tempCutOff);
  1077. lcd.setCursor(14,r);
  1078. lcd.print(tempCutOff);
  1079. lcd.clear();
  1080. lcd.setCursor(8,0);
  1081. lcd.print("OFF");
  1082. Current(); //if selected go to Constant Current Selected routine
  1083. encoderPosition = 0; //reset encoder reading to zero
  1084. customKey = 'A';
  1085. }
  1086. //------------------------------------------High Temperature Cut-Off--------------------------------------------------------------
  1087. void temperatureCutOff (void){
  1088. if (temp >= tempCutOff){ //if Maximum temperature is exceeded
  1089. reading = 0;
  1090. encoderPosition = 0;
  1091. lcd.setCursor(0,3);
  1092. lcd.print(" ");
  1093. lcd.setCursor(0,3);
  1094. lcd.print("Over Temperature");
  1095. lcd.setCursor(8,0);
  1096. lcd.print("OFF");
  1097. toggle = false; //switch Load Off
  1098. }
  1099. }
  1100. //-----------------------------------------Current Read Calibration for LCD Display --------------------------------------------
  1101. void currentDisplayCal (void){
  1102. if(ActualCurrent <= 0){
  1103. ActualCurrent = 0;
  1104. }else if(Load == 0){
  1105. ActualCurrent = 0;
  1106. }else{
  1107. ActualCurrent = ActualCurrent + displayCurrentCal;
  1108. }
  1109. /* if (ActualCurrent <= 0.5)
  1110. {
  1111. ActualCurrent = (ActualCurrent +(displayCurrentCal * 3));
  1112. }
  1113. else if (ActualCurrent >= 0.5 && ActualCurrent <1.0)
  1114. {
  1115. ActualCurrent = (ActualCurrent + (displayCurrentCal * 2));
  1116. }
  1117. else if (ActualCurrent >= 1.0 && ActualCurrent <= 1.4)
  1118. {
  1119. ActualCurrent = (ActualCurrent + (displayCurrentCal));
  1120. }
  1121. else
  1122. {
  1123. ActualCurrent = ActualCurrent;
  1124. }
  1125. */
  1126. }
  1127. //-----------------------------Show limits Stored Data for Current, Power and Temp-----------------------------
  1128. void setupLimits (void){
  1129. lcd.clear();
  1130. lcd.setCursor(1,0);
  1131. lcd.print("Maximum Limits Set");
  1132. lcd.setCursor(0,1);
  1133. lcd.print("Current Limit=");
  1134. lcd.setCursor(17,1);
  1135. lcd.print("A");
  1136. lcd.setCursor(15,1);
  1137. CurrentCutOff = EEPROM.read(0x00);
  1138. lcd.print(CurrentCutOff);
  1139. lcd.setCursor(0,2);
  1140. lcd.print("Power Limit =");
  1141. lcd.setCursor(17,2);
  1142. lcd.print("W");
  1143. lcd.setCursor(15,2);
  1144. PowerCutOff = EEPROM.read(0x20);
  1145. lcd.print(PowerCutOff);
  1146. lcd.setCursor(0,3);
  1147. lcd.print("Temp. Limit =");
  1148. lcd.setCursor(17,3);
  1149. lcd.print((char)0xDF);
  1150. lcd.print("C");
  1151. tempCutOff = EEPROM.read(0x40);
  1152. lcd.setCursor(15,3);
  1153. lcd.print(tempCutOff);
  1154. }
  1155. //---------------------------------------------------------------------------------------------------------