-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathharvest.c
505 lines (406 loc) · 16.3 KB
/
harvest.c
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
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
/****************************************************************************
* XLP 16-bit Dev board + Energy Harvesting kit demo code
*****************************************************************************
* FileName: harvest.c
* Dependencies: system.h
* Processor: PIC24F16KA102
* Hardware: XLP 16-bit Development Board
* Complier: Microchip C30 v3.10 or higher
* Company: Microchip Technology, Inc.
*
* Copyright and Disclaimer Notice
*
* Copyright ©2007-2008 Microchip Technology Inc. All rights reserved.
*
* Microchip licenses to you the right to use, modify, copy and distribute
* Software only when embedded on a Microchip microcontroller or digital
* signal controller and used with a Microchip radio frequency transceiver,
* which are integrated into your product or third party product (pursuant
* to the terms in the accompanying license agreement).
*
* You should refer to the license agreement accompanying this Software for
* additional information regarding your rights and obligations.
*
* SOFTWARE AND DOCUMENTATION ARE PROVIDED “AS IS?WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY
* WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A
* PARTICULAR PURPOSE. IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE
* LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY,
* CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY
* DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO
* ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES,
* LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS,
* TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT
* NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
*
* Author Date Comment
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Brant Ivey 4/1/10 Initial Release
*****************************************************************************/
/****************************************************************************
Section: Includes
***************************************************************************/
#include "system.h"
#ifdef USE_HARVESTER
/****************************************************************************
Section: Global Variables
***************************************************************************/
HARVEST_STATUS harvesterStatus;
/****************************************************************************
Section: Energy Harvester Functions
***************************************************************************/
/****************************************************************************
Function:
void InitHarvester()
Summary:
Initialize harvester charge state tracking information.
Description:
Initializes the harvester charge state tracking variable. The code reads
VDD from the harvester. If VDD is close to max value, assume 50% charge.
Otherwise, assume battery is low for saftey in order to prevent over
discharging.
Precondition:
None.
Parameters:
None.
Returns:
None.
***************************************************************************/
void InitHarvester()
{
GetVddVal(); //Sample VDD
//If VDD is close to max, set counter to 50% charge.
//Otherwise, assume low battery.
if(vddVal >= 3400)
{
harvesterStatus.bits.battRunCount = MAX_BATT_LOOPS/2;
}
else
{
harvesterStatus.bits.battRunCount = MAX_BATT_LOOPS;
}
} //end InitHarvester()
/****************************************************************************
Function:
void GetHarvesterState()
Summary:
Update harvester state variables based on battery charge and harvester inputs.
Description:
Reads the /CHARGE pin and battery charge counter to determine the current
state of the harvester. There are 5 harvester states as defined by
the BATTERY_STATES enumeration in harvest.h.
Battery is fully charged when the /CHARGE pin has been asserted
for long enough to decrement the battery state variable to 0.
Battery is low when either a low VDD is detected or the battery state
variable reaches the maximum loop count.
Precondition:
InitHarvester()
Parameters:
None.
Returns:
None.
***************************************************************************/
void GetHarvesterState()
{
#ifdef CYMBET_EVAL08
//read the /Charge pin
CHARGE_TRIS = 1;
IdleMs(1);
harvesterStatus.bits.charging = !CHARGE_PORT;
CHARGE_TRIS = 0;
//1 hr full charge = 3600 sec
if(harvesterStatus.bits.battRunCount == 0 && harvesterStatus.bits.charging == 1)
{
harvesterStatus.bits.fullCharge = 1; //full charge
}
else
{
harvesterStatus.bits.fullCharge = 0; //charging
}
#endif
//When VDD < low batt threshold, or we've been running from
//battery power for too long, the battery is low
if(vddVal < MIN_VDD || harvesterStatus.bits.battRunCount == MAX_BATT_LOOPS)
{
harvesterStatus.bits.lowBatt = 1;
harvesterStatus.bits.fullCharge = 0;
}
else
{
harvesterStatus.bits.lowBatt = 0;
}
} //end GetHarvesterState
/****************************************************************************
Function:
void HandleHarvesterState()
Summary:
Modifies application operation based on harvester state and tracks battery
charge status.
Description:
Changes application operation based on the harvester and battery status.
The battery charge state is tracked using a loop counter which is
incremented and decremented as the app runs from battery power (increment)
or charges the battery while running from the harvester (decrement).
Battery discharging is assumed to be linear, with each loop consuming
the same amount of current.
Battery charging has two states: low to 80% charge, which charges quickly
(first half of charge time) and 80% to fill, which charges slowly
(remaining half of charge time).
When the battery is fully charged and power from the harvester is present,
the battery is disconnected from the circuit and the application runs
directly from harvester power.
When the battery is in a low charge state, the application is put into
a low power mode and does not perform any actions until more charge is
available in the battery.
Precondition:
InitHarvester()
Parameters:
None.
Returns:
None.
***************************************************************************/
void HandleHarvesterState()
{
WORD_VAL battState;
int runCount;
battState.Val = harvesterStatus.Val>>13;
runCount = harvesterStatus.bits.battRunCount; //copy to local variable to remove structure access times
switch(battState.Val)
{
case BATT_CHARGED: //CHARGED: batoff = 1, runcount = 0
#ifdef CYMBET_EVAL08
BATOFF_LAT = 1; //When fully charged, disconnect batteries and run from harvester
#endif
runCount = 0;
break;
case MED_CHARGING: //MED_CHARGING: batoff = 0
#ifdef CYMBET_EVAL08
BATOFF_LAT = 0; //Connect battery to harvester so it can charge
#endif
if(tasks.bits.alarm == 1) //only do battery charging on RTCC wakeup
{
//Check the number of loops run from the battery to get an estimate of battery charge level
if(runCount > (MAX_BATT_LOOPS*2/10))
{
//Solar cell charges the first 80% of the batteries in the first 1/2 of the charge time.
//So, if the battery charge level is less than 80%, decrement run counter faster for this quick charge rate.
if(runCount > (MAX_BATT_LOOPS*8/10)*ALARM_PERIOD/(FULL_CHARGE_TIME/2))
{
runCount -= (MAX_BATT_LOOPS*8/10)*ALARM_PERIOD/(FULL_CHARGE_TIME/2);
}
else
{
runCount = 0; //reset to zero if less than the decrement amount to avoid roll-under
}
}
else
{
//The last 20% of the batteries charge in the remaining 1/2 of the charge time.
//So, if the battery charge level is more than 80%, decrement run counter slower for this slow charge rate.
if(runCount > (MAX_BATT_LOOPS*2/10)*ALARM_PERIOD/(FULL_CHARGE_TIME/2))
{
runCount -= (MAX_BATT_LOOPS*2/10)*ALARM_PERIOD/(FULL_CHARGE_TIME/2);
}
else
{
runCount = 0; //reset to zero if less than the decrement amount to avoid roll-under
}
}
}
break;
case LOW_CHARGING: //LOW_CHARGING: batoff = 0, limited actions
#ifdef CYMBET_EVAL08
BATOFF_LAT = 0; //Connect battery to harvester so it can charge
#endif
if(tasks.bits.alarm == 1) //only do battery charging on RTCC wakeup
{
//Check the number of loops run from the battery to get an estimate of battery charge level
if(runCount > (MAX_BATT_LOOPS*2/10))
{
//Solar cell charges the first 80% of the batteries in the first 1/2 of the charge time.
//So, if the battery charge level is less than 80%, decrement run counter faster for this quick charge rate.
if(runCount > (MAX_BATT_LOOPS*8/10)*ALARM_PERIOD/(FULL_CHARGE_TIME/2))
{
runCount -= (MAX_BATT_LOOPS*8/10)*ALARM_PERIOD/(FULL_CHARGE_TIME/2);
}
else
{
runCount = 0; //reset to zero if less than the decrement amount to avoid roll-under
}
}
else
{
//The last 20% of the batteries charge in the remaining 1/2 of the charge time.
//So, if the battery charge level is more than 80%, decrement run counter slower for this slow charge rate.
if(runCount > (MAX_BATT_LOOPS*2/10)*ALARM_PERIOD/(FULL_CHARGE_TIME/2))
{
runCount -= (MAX_BATT_LOOPS*2/10)*ALARM_PERIOD/(FULL_CHARGE_TIME/2);
}
else
{
runCount = 0; //reset to zero if less than the decrement amount to avoid roll-under
}
}
}
//low battery, limit actions until more charge available
tasks.bits.button = 0;
tasks.bits.sample = 0;
tasks.bits.store = 0;
tasks.bits.cap = 0;
break;
case LOW_BATT: //LOW_BATT: batoff = 0, timer = 0, limited actions
#ifdef CYMBET_EVAL08
BATOFF_LAT = 0; //Connect battery to circuit so it can power PIC
#endif
//low battery, limit actions until more charge available
tasks.bits.button = 0;
tasks.bits.sample = 0;
tasks.bits.store = 0;
tasks.bits.cap = 0;
break;
case BATT_POWER: //BATT_POWER: batoff = 0, runcount++, timer = 0
#ifdef CYMBET_EVAL08
BATOFF_LAT = 0; //Connect battery to circuit so it can power PIC
#endif
//Running from battery, increment counter to keep track of battery level
runCount++;
if(tasks.bits.button == 1)
{
//pressing buttons consumes more power, so add an extra loop to account for it
runCount++;
}
//If baud rate of UART is 115200 or less then the baud rate
//is slow enough that UART transmissions add a large amount of time
//to the loop. So, if transmitting, add some extra counts to account
//for this longer loop time.
#if (BAUDRATE <= 115200UL)
if(tasks.bits.transmit == 1)
{
runCount+= 115200UL/BAUDRATE; //115k= 1 extra loop, for slower baud rates, add aditional counts
}
#endif
if(runCount > MAX_BATT_LOOPS)
{
runCount = MAX_BATT_LOOPS;
}
break;
}
harvesterStatus.bits.battRunCount = runCount; //copy local variable back to run counter
}//end HandleHarvesterState()
/****************************************************************************
Function:
void TransmitHarvesterState()
Summary:
Transmits the current state of the harvester and battery charge.
Description:
Transmits the present state of the harvester (charging or discharging) and
the battery state (battery % left, charged, or low).
Precondition:
InitHarvester()
Parameters:
None.
Returns:
None.
***************************************************************************/
void TransmitHarvesterState()
{
WORD_VAL battState;
BYTE temp;
//turn on external circuits if disabled
#ifdef USE_PWRCTL
if(PWRCTL_PORT)
{
mPWR_ON();
IdleMs(UART_WAIT);
}
#endif
_UxMD = 0; //Enable UART
UARTInit();
UARTPrintString("\r\nBATT LEVEL: ");
battState.Val = harvesterStatus.Val>>13;
switch(battState.Val)
{
case BATT_CHARGED: //CHARGED: FULL
UARTPrintString("100%, Solar Powered");
break;
case LOW_CHARGING: //LOW_CHARGING: LOW BAT, Charging
UARTPrintString("LOW BATT ");
tasks.bits.transmit = 0; //turn off transmitting to save power
//NOTE: NO BREAK, USES FALL THROUGH TO SAVE CODE SPACE
case MED_CHARGING: //MED_CHARGING: %%, Charging
UARTPrintString("CHARGING ");
//NOTE: NO BREAK, USES FALL THROUGH TO SAVE CODE SPACE
case BATT_POWER: //BATT_POWER: %%
temp = (BYTE)((DWORD)(MAX_BATT_LOOPS-harvesterStatus.bits.battRunCount)*100/MAX_BATT_LOOPS);
if(temp>99)
{
temp = 99;
}
UARTPutChar((temp/10)%10 + '0');
UARTPutChar(temp%10 + '0');
UARTPutChar('%');
break;
case LOW_BATT: //LOW_BATT: LOW BAT
UARTPrintString("LOW");
tasks.bits.transmit = 0; //turn off transmitting to save power
break;
}
UARTPrintString("\r\n");
#ifdef USE_PWRCTL
mPWR_OFF();
#endif
_UxMD = 1;
}//end TransmitHarvesterState
/****************************************************************************
Function:
void StoreHarvesterState(void)
Summary:
Save current harvester status to EEPROM.
Description:
Saves the current harvester state information to external EEPROM in
case of reset event.
Precondition:
InitI2C()
Parameters:
Global variable - eeAddress.
Returns:
None.
***************************************************************************/
void StoreHarvesterState (void)
{
BYTE datVal[2];
datVal[0] = harvesterStatus.Val;
datVal[1] = harvesterStatus.Val>>8;
writePacket(0x2, datVal, 2);
//wait in Idle for EEPROM write to complete
while(writeWait())
{
IdleUs(EEPROM_ACK_WAIT);
}
}
/****************************************************************************
Function:
void RestoreHarvesterState(void)
Summary:
Read havester status from EEPROM.
Description:
Read the harvester state bits from the external EEPROM and store to
harvesterStatus.
Precondition:
InitI2C()
Parameters:
None.
Returns:
Global variable - harvesterStatus
***************************************************************************/
void RestoreHarvesterState (void)
{
BYTE dataVal[2];
BYTE *pByte;
//Init pointer and read EERPOM
pByte = dataVal;
readPacket(2,pByte,0x02);
//Load address from EEPROM
harvesterStatus.Val = (dataVal[0] + (((WORD)dataVal[1])<<8));
}
#endif