This module is part of the original MMBasic library. It is reproduced here with kind permission of Hugh Buckle and Geoff Graham. Be aware it may reference functionality which has changed or is deprecated in the latest versions of MMBasic.¶
Note: Any required file(s) are available in the attachments tab (top right).
BATTERY.BAS
100 ' BATTERY.BAS
105 ' Program to test the capacity of a battery
110 ' See Silicon Chip May 2011 for circuit details
115 ' V1.0
120 '
125 '
130 ' Measured resistance of the four load resistors
135 ' These are constant values determined by measuring the actual resistance
140 ' with a digital multimeter. They must be in descending order of values
145 R1 = 56.00
150 R2 = 22.00
155 R3 = 8.20
160 R4 = 3.33
165 '
170 ' Measured value of the 3.3 volt supply
175 Vdd = 3.29
180 '
185 '
190 ' Default terminating voltage level and test current
195 TerminatingVolts = 1.0
200 TestCurrent = 120
205 '
210 '
215 ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
220 ' Configure the input and output pins
225 PIN(11) = 1 : PIN(12) = 1 : PIN(13) = 1 : PIN(14) = 1
230 SETPIN 11, 9 : SETPIN 12, 9 : SETPIN 13, 9 : SETPIN 14, 9
235 SETPIN 1,1
240 '
245 '
250 ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
255 ' Get the operating parameters from the user
260 ' check each response to make sure that it is within acceptable range
265 '
270 CLS : PRINT "Battery test V1.0" : PRINT
275 DO
280 INPUT "Enter the approx test current in mA (600 to 25): ", TestCurrent
285 LOOP WHILE TestCurrent < 25 OR TestCurrent > 600
290 '
295 DO
300 PRINT "Enter the terminating voltage ";
305 PRINT "(default "; FORMAT$(TerminatingVolts, "%4.2f"); "): ";
310 INPUT "", TerminatingVolts
315 LOOP WHILE TerminatingVolts < 0.5 OR TerminatingVolts > 2
320 '
325 PRINT
330 IF PIN(1) / 3.3 * Vdd < TerminatingVolts THEN
335 PRINT "To start the test place the charged battery in the holder";
340 DO : LOOP WHILE PIN(1) / 3.3 * Vdd < TerminatingVolts
345 PRINT : PRINT
350 ENDIF
355 '
360 '
365 '
370 TIME$ = "0:0:0"
375 LASTTIME$ = TIME$
380 PRINT "TIME ", "VOLTS ", "CURRENT", " ACCUMULATED"
385 PRINT "========================================================"
390 '
395 '
400 ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
405 ' Main test loop
410 DO
415 BattV = PIN(1) / 3.3 * Vdd ' measure the battery voltage
420 '
425 ' Calculate the setting required to draw the test current
430 PrevTC = BattV/R1 * 1000
435 FOR i = 2 TO 15
440 TC = 0
445 IF i AND &b0001 THEN TC = TC + BattV/R1
450 IF i AND &b0010 THEN TC = TC + BattV/R2
455 IF i AND &b0100 THEN TC = TC + BattV/R3
460 IF i AND &b1000 THEN TC = TC + BattV/R4
465 TC = TC * 1000
470 IF PrevTC + (TC - PrevTC) / 2 > TestCurrent THEN EXIT FOR
475 PrevTC = TC
480 NEXT i
485 i = i - 1
490 '
495 ' Set the reed relays to draw the test current
500 PIN(11) = NOT(i AND &b0001)
505 PIN(12) = NOT(i AND &b0010)
510 PIN(13) = NOT(i AND &b0100)
515 PIN(14) = NOT(i AND &b1000)
520 '
525 mAhours = mAhours + PrevTC/3600 ' accumulate the mAH reading
530 '
535 IF RIGHT$(TIME$, 2) = "00" THEN
540 PRINT TIME$,FORMAT$(BattV, "%5.3fV "),FORMAT$(PrevTC, "%5.1fmA "),;
545 PRINT FORMAT$(mAhours, "%5.0fmAH")
550 ENDIF
555 '
560 ' wait for the next second
565 DO WHILE TIME$ = LASTTIME$ : LOOP
570 LASTTIME$ = TIME$
575 '
580 LOOP WHILE BattV > TerminatingVolts
585 '
590 PIN(11) = 1 : PIN(12) = 1 : PIN(13) = 1 : PIN(14) = 1
595 '
600 '
605 ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
610 ' print the summary
615 PRINT : PRINT "Test complete. ";
620 PRINT "Battery capacity is "; FORMAT$(mAhours, "%5.0fmAH")
625 PRINT : PRINT
BATTERY2.BAS
100 ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
110 ' BATTERY.BAS
120 ' Program to test the capacity of a battery
130 ' V2.0 Geoff Graham Jan 2011
140 '
150 ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
160 '
170 ' This is an extended version of the battery test program described in
180 ' the May 2011 issue of Silicon Chip. Additional features include:
190 ' - Will draw a graph of the battery voltage on the video output
200 ' - Choice of a constant current, power or resistance type of load
210 ' - Ability to save the data in an Excel compatible file
220 ' - Optional ability to use 5 relays for a finer level of load control
230 '
240 ' See the Silicon Chip article or the accompanying PDF for circuit details
250 '
260 '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
270 '
280 ' Measured resistance of the five load resistors
290 ' These are constant values determined by measuring the actual resistance
300 ' with a digital multimeter. They must be in descending order of values
310 ' if you only have 4 relays set the value of R5 to a very low value (eg, 0.0001)
320 '
330 R1 = 59.228
340 R2 = 29.789
350 R3 = 14.944
360 R4 = 7.516
370 R5 = 3.789
380 '
390 ' Correction for any error in measuring voltage (ie. actual V / Maximite V)
400 VCorrect = 1.019
410 '
420 ' default settings
430 DefaultType$ = "C" ' constant current
440 DefaultBLoad = 200 ' load of 200 mA or mW
445 DefaultRLoad = 25 ' resistive load 25 ohms
450 DefaultThreshold = 0.9 ' cutout voltage to stop the test
460 '
470 ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
480 MaxHist = 100 * 60 ' maximum history to be saved (in minutes)
490 Dim Hist(MaxHist) ' array for holding the history data
500 ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
510 ' Program Start
520 ' The program returns to here when the test has finished
530 '
540 ' Configure the input and output pins
550 Pin(11) = 1 : Pin(12) = 1 : Pin(13) = 1 : Pin(14) = 1 : Pin(15) = 1
560 SetPin 11, 9 : SetPin 12, 9 : SetPin 13, 9 : SetPin 14, 9 : SetPin 15, 9
570 SetPin 1,1
580 '
590 HScale = 2
595 mAhours = 0
600 '
610 Pin(0) = 1 : Print : Print : Cls
620 '
630 ' Get the test parameters from the user
640 Print "Battery capacity test utility V2.0"
650 ' define constants and arrays
655 Do
660 Print
670 Print "C = Constant current drain"
680 Print "P = Constant power drain"
690 Print "R = Constant resistive load"
700 Print "Select (default is "; DefaultType$; ") ";
710 Input Type$
715 If Asc(Type$) = 0 Then Type$ = DefaultType$
720 Type$ = Left$(UCase$(Type$), 1)
725 Loop Until Type$ = "C" Or Type$ = "P" Or Type$ = "R"
730 Print
740 '
750 If Type$ = "C" Then
760 Do
770 Print "Range is 600mA to 20mA"
780 Print "Enter current drain (default is"; DefaultBLoad; ") ";
790 Input BLoad
795 If BLoad = 0 Then Bload = DefaultBLoad
800 Loop While BLoad > 600 Or BLoad < 20
810 ElseIf Type$ = "P" Then
820 Do
830 Print "Range is 750mW to 25mW"
840 Print "Enter power drain (default is"; DefaultBLoad; ") ";
850 Input BLoad
855 If BLoad = 0 Then BLoad = DefaultBLoad
860 Loop While BLoad > 750 Or BLoad < 25
870 ElseIf Type$ = "R" Then
880 Do
900 Print "Range is 60 ohms to 1.8 ohms"
910 Print "Enter resistive load (default is"; DefaultRLoad; ") ";
920 Input BLoad
925 If BLoad = 0 Then BLoad = DefaultRLoad
930 Loop While BLoad > 60 And BLoad < 1.8
960 EndIf
970 '
975 Do
980 Print
990 Print "Enter the cutoff voltage (default is "; Format$(DefaultThreshold, "%3.1f"); ") ";
995 Print "Minimum cutoff is 0.5V"
1000 Input Threshold
1005 If Threshold = 0 Then Threshold = DefaultThreshold
1010 Loop While Threshold < 0.5 Or Threshold > 1.5
1020 Print
1030 '
1040 Do
1060 Input "Save the results to an Excel file (Y/N, default is N) ", SSave$
1070 SSave$ = Left$(UCase$(SSave$), 1)
1075 If Asc(SSave$) = 0 Then SSave$ = "N"
1080 Loop While Not(SSave$ = "Y" Or SSave$ = "N")
1089 '
1090 If SSave$ = "Y" Then
1100 Line Input "Filename (without an extension): "; FName$
1110 Open Left$(FName$, 8) + ".xls" For output As #1
1120 Line Input "Description of battery under test: "; R$
1130 Print #1, R$
1140 If Type$ = "C" Then Print #1, "Constant current of"; BLoad; "mA. Cutoff at"; Threshold; "V"
1150 If Type$ = "P" Then Print #1, "Constant power of"; BLoad; "mW. Cutoff at"; Threshold; "V"
1160 If Type$ = "R" Then Print #1, "Constant resistance of"; BLoad; " ohms. Cutoff at"; Threshold; "V"
1170 Print #1 : Print #1, "Time", "Voltage", "Current", "mAH"
1180 EndIf
1190 '
1200 Print
1210 Line Input "Press ENTER to start the test "; T$
1220 Pin(15) = 0 : Pause 200 ' discharge any floating voltage
1230 Do While Pin(1) * VCorrect <= Threshold
1240 Print "Battery not inserted or not charged (voltage ="; Pin(1) * VCorrect; ")"
1250 Print "Insert battery to continue ";
1260 While Pin(1) * VCorrect <= Threshold : Wend
1270 Pause 750
1280 Loop
1290 '
1300 VScale = (Int(Pin(1) * VCorrect * 10) + 2) ' set the vertical scale
1310 iHist = 0 ' zero the history
1320 GoSub 2790 ' draw the graph axies
1330 '
1340 Time$ = "00:00:00" : LASTTIME$ = "00:00:00" ' init the starting time
1350 BattV = Pin(1) * VCorrect ' initialise the battery voltage
1360 VStart = BattV
1370 VAverage = 0 : AveCnt = 0
1380 '
1390 ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
1400 ' Main test loop
1410 Do
1420 '
1430 If Type$ = "C" Then
1440 ' Calculate the setting required to draw the test current
1450 PrevTL = (BattV/R1) * 1000
1460 For i = 2 To 31
1470 TL = 0
1480 If i And &b00001 Then TL = TL + BattV/R1
1490 If i And &b00010 Then TL = TL + BattV/R2
1500 If i And &b00100 Then TL = TL + BattV/R3
1510 If i And &b01000 Then TL = TL + BattV/R4
1520 If i And &b10000 Then TL = TL + BattV/R5
1530 TL = TL * 1000
1540 If PrevTL + (TL - PrevTL) / 2 > BLoad Then Exit For
1550 PrevTL = TL
1560 Next i
1570 ElseIf Type$ = "P" Then
1580 ' Calculate the setting required to draw the test power
1590 PrevTL = ((BattV * BattV)/R1) * 1000
1600 For i = 2 To 31
1610 TL = 0
1620 If i And &b00001 Then TL = TL + (BattV * BattV)/R1
1630 If i And &b00010 Then TL = TL + (BattV * BattV)/R2
1640 If i And &b00100 Then TL = TL + (BattV * BattV)/R3
1650 If i And &b01000 Then TL = TL + (BattV * BattV)/R4
1660 If i And &b10000 Then TL = TL + (BattV * BattV)/R5
1670 TL = TL * 1000
1680 If PrevTL + (TL - PrevTL) / 2 > BLoad Then Exit For
1690 PrevTL = TL
1700 Next i
1710 ElseIf Type$ = "R" Then
1720 ' Calculate the setting required to draw the test resistance
1730 PrevTL = R1
1740 For i = 2 To 31
1750 TL = 100000000
1760 If i And &b00001 Then TL = (TL * R1) / (TL + R1)
1770 If i And &b00010 Then TL = (TL * R2) / (TL + R2)
1780 If i And &b00100 Then TL = (TL * R3) / (TL + R3)
1790 If i And &b01000 Then TL = (TL * R4) / (TL + R4)
1800 If i And &b10000 Then TL = (TL * R5) / (TL + R5)
1810 If PrevTL - (PrevTL - TL) / 2 < BLoad Then Exit For
1820 PrevTL = TL
1830 Next i
1840 ' print "Selected nearest value of"; PrevTL; " ohms"
1850 Else
1860 Error "Invalid Type$"
1870 EndIf
1880 '
1890 i = i - 1
1900 '
1910 ' Set the reed relays to create the test load
1920 Pin(11) = Not(i And &b00001)
1930 Pin(12) = Not(i And &b00010)
1940 Pin(13) = Not(i And &b00100)
1950 Pin(14) = Not(i And &b01000)
1960 Pin(15) = Not(i And &b10000)
1970 '
1980 ' calculate the current drain at this setting
1990 TC = 0
2000 If i And &b00001 Then TC = TC + BattV/R1
2010 If i And &b00010 Then TC = TC + BattV/R2
2020 If i And &b00100 Then TC = TC + BattV/R3
2030 If i And &b01000 Then TC = TC + BattV/R4
2040 If i And &b10000 Then TC = TC + BattV/R5
2050 TC = TC * 1000 ' current drain in mA
2060 mAhours = mAhours + TC/3600 ' accumulate the mAH reading for each second
2070 '
2080 ' every minute update the display
2090 If Right$(Time$, 2) = "00" Then
2100 Hist(iHist) = BattV : iHist = iHist + 1
2110 If iHist > MaxHist Then GoTo 2330
2120 If iHist > HScale * 60 Then
2130 HScale = HScale + 1
2140 GoSub 2790 ' redraw the graph scale
2150 EndIf
2160 GoSub 2660 ' add this reading to the graph
2170 GoSub 3090 ' print the running summary
2180 EndIf
2190 '
2200 ' wait for the next second
2210 LoopCount = 1
2220 Do While Time$ = LASTTIME$
2230 BattV = BattV + Pin(1) * VCorrect ' while we are waiting make many measurements
2240 LoopCount = LoopCount + 1 ' count the number of measurements
2250 Loop
2260 LASTTIME$ = Time$
2270 BattV = BattV/LoopCount ' and average
2280 '
2290 VAverage = VAverage + BattV : AveCnt = AveCnt + 1
2300 Loop While BattV >= Threshold
2310 '
2320 ' the test has finished - remove the load
2330 Pin(11) = 1 : Pin(12) = 1 : Pin(13) = 1 : Pin(14) = 1 : Pin(15) = 1
2340 '
2350 '
2360 ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
2370 ' print the summary
2380 GoSub 3090 ' update the running summary
2390 Print : T$ = "Test complete. "
2400 T$ = T$ + "Battery capacity is " + Format$(mAhours, "%1.0fmAH") + " at a constant "
2410 If Type$ = "C" Then T$ = T$ + "current of" + Str$(BLoad) + "mA."
2420 If Type$ = "P" Then T$ = T$ + "power of" + Str$(BLoad) + "mW."
2430 If Type$ = "R" Then T$ = T$ + "resistance of" + Str$(BLoad) + " ohms."
2440 If SSave$ = "Y" Then Print #1 : Print #1 : Print #1, T$
2450 Print " " + T$
2460 T$ = "Start voltage = " + Format$(VStart, "%3.2f") + ". End voltage = " + Format$(BattV, "%3.2f")
2470 T$ = T$ + ". Average voltage = " + Format$(VAverage/AveCnt, "%3.2f") + "."
2480 If SSave$ = "Y" Then Print #1, T$
2490 Print " " + T$
2500 If SSave$ = "Y" Then Close #1
2510 '
2520 Print " Press ENTER to test again or CTRL-C to quit...";
2530 Do ' flash LED while waiting
2540 Pause 200 : If Inkey$ = Chr$(&H0D) Then GoTo 500
2550 Pin(0) = 0 : Pause 100 : Pin(0) = 1 : If Inkey$ = Chr$(&H0D) Then GoTo 500
2560 Loop
2570 '
2580 '
2590 '
2600 '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
2610 ' SUBROUTINES
2620 '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
2630 '
2640 ' Subroutine to print the trend line on the graph
2650 '
2660 For i = 1 To iHist - 1
2670 x1 = margin + (width / (HScale * 60)) * (i - 1)
2680 x2 = margin + (width / (HScale * 60)) * (i)
2690 y1 = height - ((Hist(i - 1) * 10) / VScale) * height
2700 y2 = height - ((Hist(i) * 10) / VScale) * height
2710 Line (x1, y1) - (x2, y2), 1
2720 Next i
2730 Return
2740 '
2750 '
2760 ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
2770 ' Subroutine to print the graph axies
2780 '
2790 height = MM.VRes - 100 : margin = 45 : width = MM.HRes - margin - 12
2800 '
2810 Cls
2820 Line (margin,height)-(margin, 0), 1 ' Draw the vert line
2830 Line (margin,height)-(margin + width ,height), 1 ' Draw the horiz line
2840 For i = 0 To VScale ' This loop draws the tick marks
2850 h = height - (height / VScale) * i
2860 t = margin - 5
2870 If i Mod 5 = 0 Then ' Special mark for a unit of 0.1V
2880 Locate margin - 42, h - 3
2890 If h - 3 < 0 Then Locate margin - 42, 0 ' fix if we are off the screen
2900 Print Left$(Format$(i/10,"%f"),3);"V"; ' Label the tick mark
2910 t = margin - 15
2920 EndIf
2930 Line (margin, h)-(t, h), 1 ' Draw the tick mark
2940 Next i
2950 For i = 0 To HScale
2960 t = margin + (width/Hscale) * i
2970 Line (t, height)-(t, height + 9), 1
2980 If i < 10 Then Locate t - 8, height + 14 Else Locate t - 11, height + 14
2990 Print i;
3000 Next i
3010 Locate margin + width/2 - 14, height + 25
3020 Print "Hours"
3030 Return
3040 '
3050 '
3060 '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
3070 ' Subroutine to print the summary data below the graph
3080 '
3090 T$ = Left$(Time$, 5) + " " + Format$(BattV, "%5.3fV ") + " " + Format$(TC, "%5.1fmA ")
3100 T$ = T$ + " " + Format$(mAhours, "%5.0fmAH")
3110 Locate margin + (width - (Len(T$) * 6)) / 2, height + 40
3120 Print t$
3130 If SSave$ = "Y" Then Print #1, (iHist - 1)/60, BattV, TC, mAhours
3140 Return
3150 '