Electronic_Load_software_V35B.ino 52 KB

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