Hubo Library

- Main Page
- Related Pages
- Modules
- Namespaces
- Data Structures
- Files

- File List
- Globals

All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
BatteryTest.cpp
Go to the documentation of this file.
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <string>
4
5 #include "../hubolib.h"
6 #include "../hubocfg.h" // Required for changing default I2C device.
7
8 using namespace HuboLib;
9 using namespace std;
10
11 /*
12 Compile and link:
13 g++ BatteryTest.cpp -L../ -lhubo -lpthread -lrt -o BatteryTest
14 Run:
15 sudo ./BatteryTest
16 Purpose:
17 This little app allows for charging/discharging a battery up/down to a given value while capturing the voltage at a given rate.
18 The Hubo relays will be used for switching the power supply as well as the load.
19 Charging/dischargiong can be interrupted for a given time in order to measure the relaxation voltage (hence estimating capacity).
20
21 # Discharging down to 2152 digits relaxation voltage (relaxation time is 900s)
22 # AD channel: 0
23 # Sampling rate [ms]: 1000ms
24 # Relay: 7 (128)
25 # Duty count: 3600s -> 60min
26 # Relax count: 900s -> 15min
27 # Charge/Discharge: d
28 # Digits after relaxation: 2152
29 ./BatteryTest 0 1000 128 3600 900 d 2152 discharge_test.csv
30
31 # Charging up to 2710 digit relaxation voltage (relaxation time is 900s)
32 # AD channel: 0
33 # Sampling rate [ms]: 1000ms
34 # Relay: 6 (64)
35 # Duty count: 3600s -> 60min
36 # Relax count: 900s -> 15min
37 # Charge/Discharge: c
38 # Digits after relaxation: 2710
39 ./BatteryTest 0 1000 64 3600 900 c 2710 charge_test.csv
40
41 Note - in this example a voltage devider 1:8 was used in front of the Hubo AD-channel in order to measure voltages up to 20V.
42 */
43
44 string GetDateTime (char seperator, char timeSeperator);
45 bool AppendFile (string sFile, string sText);
46 unsigned long GetADValueAndLog (unsigned char adPin, string sFile);
47 string Convert2String (long value);
48 char g_buffer [1024];
49
50 int main(int argc, char* argv[])
51 {
52 if (argc != 9)
53 {
54 printf ("Usage: \n BatteryTest <AD pins> <sample rate [ms]> <DO pins> <duty count> <relax count> <charge/discharge {c, d}> <stop at AD> <filename>\n");
55 printf (" example: BatteryTest 0 1000 128 3600 900 d 2152 discharge_test.csv\n");
56 return 0;
57 }
58
59 unsigned char adPin = 0; // 0..7
60 long logSpeed = 1000; // [ms]
61 unsigned char doPins = 0; // 0..255
62 long dutyCount = 1; // 1..n
63 long relaxCount = 1; // 1..n
64 char chargeDischarge = 'c'; // c, d
65 unsigned long stopAtADValue = 0; // 0..n
66 string sFile = ""; // log file name
67
68 // 1 adPin
69 if (sscanf (argv[1], "%hhu", &adPin) != 1 || adPin>7 )
70 {
71 printf ("AD Pin could not be determined!\n");
72 return 0;
73 }
74
75 // 2 logSpeed
76 if (sscanf (argv[2], "%ld", &logSpeed) != 1)
77 {
78 printf ("Logspeed could not be determined!\n");
79 return 0;
80 }
81
82 // 3 doPins
83 if (sscanf (argv[3], "%hhu", &doPins) != 1)
84 {
85 printf ("DO Pin(s) could not be determined!\n");
86 return 0;
87 }
88
89 // 4 dutyCount
90 if (sscanf (argv[4], "%ld", &dutyCount) != 1 || dutyCount<1)
91 {
92 printf ("Duty count could not be determined!\n");
93 return 0;
94 }
95
96 // 5 relaxCount
97 if (sscanf (argv[5], "%ld", &relaxCount) != 1 || relaxCount<1)
98 {
99 printf ("Relax count could not be determined!\n");
100 return 0;
101 }
102
103 // 6 chargeDischarge
104 if (sscanf (argv[6], "%c", &chargeDischarge) != 1 || ! (chargeDischarge=='c' || chargeDischarge=='d'))
105 {
106 printf ("Charge discahrge at could not be determined!\n");
107 return 0;
108 }
109
110 // 7 stopAtADValue
111 if (sscanf (argv[7], "%lu", &stopAtADValue) != 1)
112 {
113 printf ("Stop at AD value could not be determined!\n");
114 return 0;
115 }
116
117 // 8 file name
118 if (sscanf (argv[8], "%s", g_buffer) != 1)
119 {
120 printf ("File name could not be determined!\n");
121 return 0;
122 }
123 sFile = g_buffer;
124
125 // If required - set the I2C device to work with. The Raspberry Pi uses "/dev/i2c-1" which is default, the Banana Pi uses "/dev/i2c-0"
126 #ifdef BPI
127 g_I2CConfig.m_sI2CDevice = "/dev/i2c-0";
128 #endif
129
130 // Initialize the library once in your program.
131 if (!Initialize())
132 {
133 printf ("Error: Initialize\n");
134 return 1;
135 }
136
137 // Log settings.
138 sprintf (g_buffer, "%s %d %ld 0x%02X %ld %ld %c %ld %s\n", argv[0], (int) adPin, logSpeed, (int) doPins, dutyCount, relaxCount, chargeDischarge, stopAtADValue, sFile.c_str());
139 string sLine = string(g_buffer) + "\n";
140 AppendFile(sFile, sLine);
141 printf ("%s", g_buffer);
142
143 // For simplicity define all channel to be read from the ADC.
144 unsigned short overSampling[MAX_MCP3x08_CHANNELS] = { 1, 1, 1, 1, 1, 1, 1, 1 };
145 Set_MCP3x08_Oversampling (overSampling);
146
147 // Wait as long until we have valid values in the buffers.
148 Wait_For_MCP3x08_Buffered_Values();
149 Wait_For_MCP23017_Buffered_Values();
150
151
152 unsigned long adcCount = 0;
153 bool bStop = false;
154 unsigned long long relaxTime = 0; // [ms]
155 unsigned long long dutyTime = 0; // [ms]
156 unsigned long long adcDutySum = 0; // [digit]
157 unsigned long long adcDutyCount = 0; // [count]
158
159 while (1)
160 {
161 // Log short note on relaxing phase.
162 sLine = "Relaxing";
163 printf ("%s\n", sLine.c_str());
164 AppendFile(sFile, sLine);
165 Set_DO_Channels(0x00);
166
167 for (int count=0; count<relaxCount; count++)
168 {
169 adcCount = GetADValueAndLog(adPin, sFile);
170 usleep(1000L * logSpeed);
171 relaxTime += logSpeed;
172 }
173 // At the end of a relaxing phase....
174 if (chargeDischarge=='c')
175 {
176 // ... if charging check the voltage to be less than overcharge voltage level.
177 if (adcCount>stopAtADValue)
178 {
179 sLine = "End of relaxing phase and voltage above limit.";
180 printf ("%s\n", sLine.c_str());
181 AppendFile(sFile, sLine);
182 bStop = true;
183 break;
184 }
185 else
186 printf ("adcCount=%ld stopAtADValue=%ld\n", adcCount, stopAtADValue);
187 }
188
189 // Log short note on duty phase.
190 sLine = chargeDischarge=='c' ? "Charging" : "Discharging";
191 printf ("%s\n", sLine.c_str());
192 AppendFile(sFile, sLine);
193 Set_DO_Channels(doPins);
194
195 for (int count=0; count<dutyCount; count++)
196 {
197 adcCount = GetADValueAndLog(adPin, sFile);
198
199 // Check analog value and stop if trigger level is reached.
200 if (chargeDischarge=='d')
201 {
202 // Currently actively discharging.
203 if (adcCount<stopAtADValue)
204 {
205 sLine = "Passing lower limit while discharging.";
206 printf ("%s\n", sLine.c_str());
207 AppendFile(sFile, sLine);
208 bStop = true;
209 break;
210 }
211 }
212
213 usleep(1000L * logSpeed);
214 dutyTime += logSpeed;
215
216 // Track average values of ADC count (hence average voltage).
217 adcDutySum += adcCount;
218 adcDutyCount++;
219 }
220 // Trigger level reached?
221 if (bStop)
222 break;
223 }
224
225 // Clear any outputs.
226 Set_DO_Channels(0x00);
227
228 // Log for another "relax time" period.
229 for (int count=0; count<relaxCount; count++)
230 {
231 adcCount = GetADValueAndLog(adPin, sFile);
232 usleep(1000L * logSpeed);
233 relaxTime += logSpeed;
234 }
235
236 // Print total relaxing time.
237 sprintf (g_buffer, "Total relax time: %llds = %lfh\n", relaxTime/1000L, ((double)(relaxTime/1000L))/3600.0);
238 printf ("%s", g_buffer);
239 AppendFile(sFile, g_buffer);
240
241 // Print total duty time.
242 sprintf (g_buffer, "Total duty time: %llds = %lfh\n", dutyTime/1000L, ((double)(dutyTime/1000L))/3600.0);
243 printf ("%s", g_buffer);
244 AppendFile(sFile, g_buffer);
245
246 // Print average adc duty value.
247 if (adcDutyCount)
248 {
249 sprintf (g_buffer, "Average ADC duty value: %ld digit\n", (long)(adcDutySum / adcDutyCount));
250 printf ("%s", g_buffer);
251 AppendFile(sFile, g_buffer);
252 }
253
254 // More for beautiness than that it would still have any effect.
255 Wait_For_MCP23017_Buffered_Values();
256
257 // Free library resources.
258 Uninitialize();
259
260 return 0;
261 }
262
263 unsigned long GetADValueAndLog(unsigned char adPin, string sFile)
264 {
265 string sLine = GetDateTime(' ', ':');
266 sLine += " ";
267
268 // Read channel and output its value.
269 unsigned long adcCount = 0;
270 double volt = 0.0;
271 if (Get_AI_Channel (adPin, adcCount, volt))
272 sprintf (g_buffer, "%04ld", adcCount);
273 else
274 sprintf (g_buffer, "????");
275 sLine += g_buffer;
276
277 sLine +="\n";
278 printf ("%s", sLine.c_str());
279 AppendFile(sFile, sLine);
280
281 return adcCount;
282 }
283
284 string GetDateTime(char seperator, char timeSeperator)
285 {
286 time_t t = time(0); // get time now
287 struct tm *pNow = localtime (&t);
288 sprintf (g_buffer, "%02d.%02d.%d%c%02d%c%02d%c%02d", pNow->tm_mday, (pNow->tm_mon + 1), (pNow->tm_year + 1900), seperator, pNow->tm_hour, timeSeperator, pNow->tm_min, timeSeperator, pNow->tm_sec);
289 // printf ("Time = %s\n", g_buffer);
290 return string(g_buffer);
291 }
292
293 bool AppendFile(string sFile, string sText)
294 {
295 FILE* pFile = fopen (sFile.c_str(), "a+");
296 if (!pFile)
297 return false;
298 bool bResult = fputs (sText.c_str(), pFile) > 0;
299 fflush (pFile);
300 fclose(pFile);
301 return bResult;
302 }
303
304 string Convert2String(long value)
305 {
306 if (sprintf(g_buffer, "%ld", value) != 1)
307 return string("");
308
309 string s (g_buffer);
310 return s;
311 }
HuboLib::I2C_Config::m_sI2CDevice
const char * m_sI2CDevice
Definition: hubocfg.h:48
GetADValueAndLog
unsigned long GetADValueAndLog(unsigned char adPin, string sFile)
Definition: BatteryTest.cpp:263
HuboLib::Wait_For_MCP3x08_Buffered_Values
bool Wait_For_MCP3x08_Buffered_Values()
Waits until the input buffer of the MCP3x08 are initialized from the hardware.
g_buffer
char g_buffer[1024]
Definition: BatteryTest.cpp:48
MAX_MCP3x08_CHANNELS
#define MAX_MCP3x08_CHANNELS
Definition: hubolib.h:39
main
int main(int argc, char *argv[])
Definition: BatteryTest.cpp:50
HuboLib::Initialize
bool Initialize()
Initializes the library.
HuboLib::Set_DO_Channels
bool Set_DO_Channels(unsigned char value)
Requests the background thread to update all 8 bits of the digital output to the value specified...
std
AppendFile
bool AppendFile(string sFile, string sText)
Definition: BatteryTest.cpp:293
HuboLib::g_I2CConfig
I2C_Config g_I2CConfig
HuboLib::Get_AI_Channel
bool Get_AI_Channel(int channel, unsigned long &count, double &volt)
Get the buffered and oversampled data from the MCP3x08.
Convert2String
string Convert2String(long value)
Definition: BatteryTest.cpp:304
HuboLib::Set_MCP3x08_Oversampling
bool Set_MCP3x08_Oversampling(unsigned short overSampling[MAX_MCP3x08_CHANNELS])
Specifies the ADC channels to be sampled as well as the number they get oversampled.
HuboLib::Uninitialize
void Uninitialize()
Releases any resources bound to the library.
HuboLib::Wait_For_MCP23017_Buffered_Values
bool Wait_For_MCP23017_Buffered_Values()
Waits until input and output buffers of the MCP23017 master are initialized from the hardware...
GetDateTime
string GetDateTime(char seperator, char timeSeperator)
Definition: BatteryTest.cpp:284
HuboLib
Definition: hubocfg.h:10