-
Notifications
You must be signed in to change notification settings - Fork 1
/
CC_CV.tsp
196 lines (160 loc) · 5.87 KB
/
CC_CV.tsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
-- This script does CC/CV charging or discharging and charge counting in mAh
-- 2022 mjsc. Run on a Keithley 2450 SMU
--Reset the instrument
reset()
local result
local promptID
local target_voltage
local target_voltage_range
local current_limit
local stop_current
local stop_charge
local promptless = 5
-- flush display events
promptID, result = display.waitevent(1)
-- input voltage
if (cccv_target_voltage and cccv_target_voltage != nil) then
target_voltage = cccv_target_voltage
promptless = promptless - 1
else
target_voltage = display.input.number("Set Target Voltage [V]", display.NFORMAT_PREFIX, 0, 0, 100)
if target_voltage == nil then
exit()
end
end
-- input voltage range
if (cccv_target_voltage_range and cccv_target_voltage_range != nil) then
target_voltage_range = cccv_target_voltage_range
promptless = promptless - 1
else
result = display.input.option("Select source voltage range", "200mV", "2V", "20V", "200V")
if result == display.BUTTON_OPTION1 then
target_voltage_range = 0.2
elseif result == display.BUTTON_OPTION2 then
target_voltage_range = 2
elseif result == display.BUTTON_OPTION3 then
target_voltage_range = 20
elseif result == display.BUTTON_OPTION4 then
target_voltage_range = 200
end
end
-- input current
if (cccv_current_limit and cccv_current_limit != nil) then
current_limit = cccv_current_limit
promptless = promptless - 1
else
current_limit = display.input.number("Set Current Limit [A]", display.NFORMAT_PREFIX, 0, 0, 1)
if current_limit == nil then
exit()
end
current_limit = math.abs(current_limit)
end
-- input stop current
if (cccv_stop_current and cccv_stop_current != nil) then
stop_current = cccv_stop_current
promptless = promptless - 1
else
stop_current = display.input.number("Set Stop Current [A]", display.NFORMAT_PREFIX, 0, 0, 1)
if stop_current == nil then
exit()
end
end
-- input stop charge
if (cccv_stop_charge and cccv_stop_charge != nil) then
stop_charge = cccv_stop_charge
promptless = promptless - 1
else
stop_charge = 0
display.prompt(display.BUTTONS_YESNO, "Do you want to set a charge limit (in mAh)?")
promptID, result = display.waitevent()
if result == display.BUTTON_YES then
stop_charge = display.input.number("Set Charge Limit [mAh]", display.NFORMAT_DECIMAL, 0, 0)
end
end
local prompt_string = "Press OK to run this configuration:\n" .. "Target: " .. tostring(target_voltage) .. " V\n" .. "Source Range: " .. tostring(target_voltage_range) .. " V\n"
prompt_string = prompt_string .. "Limit: " .. tostring(current_limit) .. " A\n".."Stop current: " .. tostring(stop_current) .. " A\n"
if stop_charge != 0 then
prompt_string = prompt_string .. "Stop Charge: " .. tostring(stop_charge) .. " mAh\n"
end
-- no prompt if all values are set globally
if promptless > 0 then
display.prompt(display.BUTTONS_OKCANCEL, prompt_string)
promptID, result = display.waitevent()
if result != display.BUTTON_OK then
exit()
end
end
--set up source function
smu.source.autorange = smu.OFF
smu.source.range = target_voltage_range
smu.source.func = smu.FUNC_DC_VOLTAGE
smu.source.ilimit.level = current_limit
smu.source.level = target_voltage
smu.source.readback = smu.ON
--set up measure function
smu.measure.func = smu.FUNC_DC_CURRENT
smu.measure.terminals = smu.TERMINALS_FRONT
smu.measure.autorange = smu.ON
smu.measure.nplc = 2
smu.source.highc = smu.OFF
smu.measure.sense = smu.SENSE_2WIRE
defbuffer1.clear()
--turn on output and initiate readings
smu.source.output = smu.ON
-- make all vars local
local secs_old
local frac_old
local secs
local frac
local current_rdg
local delta_hour
local charge_accumulator_mAh = 0.0
local break_sign = 0
-- first reading for times
current_rdg, secs, frac = smu.measure.readwithtime(defbuffer1)
local timestart = secs + frac
-- should be enough for > 20h of data
defbuffer1.capacity = 2000000
defbuffer1.clear()
display.changescreen(display.SCREEN_USER_SWIPE)
while break_sign == 0 do
secs_old = secs
frac_old = frac
current_rdg, secs, frac = smu.measure.readwithtime(defbuffer1)
-- charge accumulation
delta_hour = ((secs + frac) - (secs_old + frac_old)) / 3600
charge_accumulator_mAh = charge_accumulator_mAh + (current_rdg * delta_hour * 1000)
display.settext(display.TEXT1, "Total: "..string.format("%.3f", charge_accumulator_mAh).."mAh")
display.settext(display.TEXT2, "Time: "..string.format("%d",math.abs(timestart - (secs + frac))).."s " .. "Cell: "..string.format("%.2f",(defbuffer1.sourcevalues[defbuffer1.endindex])).."V\t" )
-- break if current falls below threshold
if (math.abs(current_rdg) <= stop_current)then
break_sign = 1
end
-- break if stop charge is used and reached
if (stop_charge != 0 and math.abs(charge_accumulator_mAh) >= stop_charge)then
break_sign = 1
end
end
-- display the results
display.settext(display.TEXT2, "Time: "..string.format("%d",math.abs(timestart - (secs + frac))).."s ".. "Done! Monitoring Voltage." )
smu.source.output = smu.OFF
--set the output current to exactly zero and keep output on to avoid discharging the battery
smu.source.autorange = smu.OFF
smu.source.func = smu.FUNC_DC_CURRENT
smu.source.range = 0.001
smu.source.vlimit.level = target_voltage_range
smu.source.level = 0.0
smu.source.readback = smu.ON
--measure battery voltage while waiting for user to turn off the script
smu.measure.func = smu.FUNC_DC_VOLTAGE
smu.measure.terminals = smu.TERMINALS_FRONT
smu.measure.autorange = smu.ON
smu.measure.nplc = 10
smu.source.highc = smu.OFF
smu.measure.sense = smu.SENSE_2WIRE
smu.source.output = smu.ON
while smu.source.output == smu.ON do
current_rdg, secs, frac = smu.measure.readwithtime(defbuffer1)
end
-- assert the opc bit in status.standard.event register
opc()