-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpilminder 14m2 batt operation 14-10-2011.bas
478 lines (374 loc) · 17.7 KB
/
pilminder 14m2 batt operation 14-10-2011.bas
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
'TIMING TEST RESULTS
'26/9/2011
'8 hr test resulted in 8hrs 2 seconds duration using modified interupt routine on mains operation
'1 hr test perfect again using mains interupt ! Allowed led to flash for 3 mins before taking med, hence a 1 hr 3 min time as expected.
'27/9/2011
'12 hr test in progress using pilminder 08m2 plugpack operation 27-9-2011 solved bug 3.bas on mains operation
'- tripped at 12hrs exactly. Allowed it to flash for a while before allowing test to continue to 24 hr point
'- where it tripped on shedule again!
'28/0/2011
'using code pilminder 08m2 plugpack operation 28-9-2011 working on item D.bas
'started 8 hr test (3 pips) running off internal timer - light flashed 8 hrs 34 secs later
'/29/9/2011
'started 1 hr test using code pilminder 08m2 plugpack operation 28-9-2011 working on item D.bas
'- internal timer 59 min 58 secs allowed led to wink 2 mins, thenacknoledged it
'- sencond time around 59 mins 30 secs
'- 3rd time 59 mins 50 secs
'4th time on mians - 59 mins and about 30 secs
'5th time on mains timing = 59 mins! I suspect it is not returning to mains timing at all!
'6/10
'series of 3 or 4 1 hr tests, on both mains and batt timing , also checked switching between timing sources. No fault found
'7/10
;12 hr test on batt timing - within30 secs. swapped to and from to mains, no problems. 12 hr test on mains continues....
;declaring bug 7 not found - cant fix what aint broke! might be related to debug...
;declaring development D done.
'13/10
;declaring development E done.
;started a 8 hr test on mains
;8hr bit was fine, but it didnt do the beepy thing 30 mins later. it wasnt doing anything....
;likely to be sun onto the IR sensor..
'made new sensor hood suitable for daytime use, started 3 hr test. started flashing exactly on time. 30 mins & 30 sec timers worked ok as well.
'BUGLIST
'*1* done - Reminder LED flashes inconsistently
'*2* done Reminder beep for bottle not back in holder is inconsistent as well
'*3* done Late med interval timer to add a beep if user not taken pill doesnt work
'*4* fault not found I THINK the bottle may be being tested as being present all the time - this will reduce battery endurance if thats the case
'*5* fault not found Exec loop is being stopped in a 1:30 duty cycle by Check_Med_Time - at least when debug in execloop it is...
'*6* Shouldnt the return in the interupt be right @ the end of the function????
'*7* fault not found later - related to bug 10? changeover from mains to internal timer, sometimes dumps sec and min timers - single pip might be a clue
'*8" reminder beep to put bottle back not working on repeating 1 hr timer (was on internal timer on this test) . it buzes when time expired
' it does work when on the mains timer! needs a retest
'*9* the user has to put the bottle back for the 30 sec timer at begining to work. It all stalls if you leave it out
'*10* changeoevr from mains<>battery very flaky. often reboots i think its hardware not software - psu rail glitch i suspect
'*11* done beeping to get user to put bottle back only lasts 3 min 50 sec, and side_led is left on when it stops. byte counter overflowing...
'IDEAS FOR DEVELOPMENT
'**A** done - User should be prompted to take 1st dose of meds as soon as programming complete
'**B** Can have test/demo mode where everything happens quicky - test if bottle present on start or not *****
'**C** Can make beep increase in pitch as more meds per day added ****
'**D** done Add a test to see if mains pluses present or not, use internal timer interupt if its not ****
' **** Ideally needs hardware to change between mains/bat as well - germnaium diodes?
'**E** done Allow user to specfify a day to NOT take meds if med count =1 (sat night for Tony S)
'**F** Allow user to pre-empt the reminder somehow
'**G** done The reminder to put the bottle back needs to be more urgent pip-pip-pip pip-pip-pip
'**H** Remove pip at 24 hr rollover (2 of them)
'**I** Remove InteruptCounterMax variables and logic
'**J** Test for bottle missing at medtime and generate alarm, rather than assume pill taken.
'**K** Tidy code indents ect
'**L** done Swap outputs 1 and 2 then add tune during the skiped med istead of a boring beep
'**M** Experiment with checking IR level and looking for an abrubt change in level, rather than a crossing of a threshold.
'compare level now against a rolling average of last few reads
'this might be a better way of detecting bottle up or foil up if sunlight is involved in the mix.
'be a problem if the sensor is swamped - but you could probably detect that as well.
'Bottle missing @ start = demo mode **B**
'Bottle present and static during med timer programming = 1 med per day, skip this day and every 7th subsequent day **E**
'bottle present and removed/replaced = current behaviour = 'x' meds per 24 hr period
'#freq m4
' developed using compiler 5.4.2
'14M2 hardware
'Program Variables
symbol LineFreq = 50 ; 50 Hz
symbol HighMask = %00000100 ; Interrupt mask for high-going input3 interrupt
symbol LowMask = %00000000 ; Interrupt mask for low-going input3 interrupt
symbol PinMask = %00000100 ; input3 is the interrupt line
'symbol IR_Threshold = 150 ; slice level for deciding if bottle present or not
symbol Late_Med_Interval = 29 ; Number mins+1 flashing till beeper goes off as well
symbol MainsFailedThreshold = 2 ; Slice level for deciding when mains is gone & switch to internal timing
'08M2 I/O definitions
'symbol Side_LED = 0 ' output 0 on pin 7 (via open collector driver)
'symbol Beeper = 2 ' output 2 on pin 5 (drives IR led via 470ohm resistor) ** why ?? would leave tx led on all the time !! **
'symbol IR_TX_LED = 1 ' output 1 on pin 6 (drives piezo directly)
'symbol MainsFreq = 3 ' input 3 on pin 4 (driven from 5VAC plugpack, 10k series R 5v1 zenner to gnd)
'symbol IR_RX_LED = 4 ' input 4 on pin 3 (analogue input, 10K to gnd, LED to Vcc)
'symbols for 14m2 pilminder hardware (in wooden case)
symbol IR_TX_LED = B.1 'output 1 (via open collector drver)
symbol Beeper = B.2 'output 2
symbol Side_LED = B.3 'output 3 (via open collector drver)
symbol IR_RX_LED = C.0 'input 0 (analogue input)
symbol MainsFreq = C.2 'input 3 on pin 5 (driven from 5VAC plugpack, 10k series R 5v1 zenner to gnd)
'the wooden pillminder not setup for mains input as yet...
symbol IR_Threshold = 20'
symbol Bat_Voltage_Sensor = 4 ; not used yet...
'the wooden pillminder is setup for low battery detection, but there is no code for it in this version
'Register B0 Bit definitions
symbol Second_Flag = bit0
symbol Bottle_Missing_Flag = bit1
symbol Day_Roll_Over_Flag = bit2
symbol Remind_Req_Flag = bit3
symbol Min_Flag = bit4
symbol Demo_Mode_Flag = bit5 'do you need this?
symbol Sched_Bottle_Check_Flag = bit6
symbol Int_Sense_Flag = bit7 ; Semaphore to indicate whether the int sense is high or low
'Register B1 Bit definitions
symbol Mains_Failed_Flag = bit8
symbol Skip_Tune_Played_Already_Flag = bit9
'Register B2 - B27 definitions
'b2 & b3 used as w1 / MinCount
symbol MinCount = w1 'elasped minutes since rollover
symbol SecCount = b4
symbol Mainscount = b5
symbol MedsPerDay = b6
symbol IR_Level = b7
'b8 & b9 used as w4
symbol Med_Interval = w4
'symbol available = b10
symbol ConfirmCounter = b11
'b12 & b13 used as w6
symbol TimeToNextMed = w6 'b12/b13
symbol InteruptCounter = b14
symbol InteruptCounterMax = b15 'can delete this on production
symbol SkipDayCounter = b16 ''a non zero value indicates MedSkipDay is active, the skip day is 1
'b17 available
'B18 & b19 used as w9
symbol Bottle_Check_Counter = w9 ' b18/19 needs a word avoid overflow of a byte at ~ 3 min 50 - counts seconds
'=================================================================
Begin:
'**B** Can have test/demo mode where everything happens quicky - test if bottle present on start or not *****
' gosub Check_Bottle
' if Bottle_Missing_Flag = 1 then
' Demo_Mode_Flag = 1
' let MedsPerDay = 255
' Med_Interval = 1
' TimeToNextMed = Med_Interval
' debug
' goto main: 'jump around all the med time setting stuff
' endif
' debug
'remove and replace bottle X times in next 30 secs to allow user to nominate # times per day to take meds
for SecCount = 0 to 30 ' 30 secs in which to program medication schedule
gosub Check_Bottle
if Bottle_Missing_Flag =1 then
MedsPerDay = MedsPerDay +1
'**C** Can make beep increase in pitch as more meds per day added ****
sound Beeper, (125,1)
endif
LoopBotBack:
gosub Check_Bottle
if Bottle_Missing_Flag =1 then goto LoopBotBack: 'loop around till bottle bac33k
pause 600
next SecCount
if MedsPerDay = 0 then
' assume user wants to skip this day and every 7th subsequent
SkipDayCounter = 1 'a non zero value indicates MedSkipDay is active, 1 is the SkipDay
let MedsPerDay = 1
endif
if MedsPerDay > 24 then
let MedsPerDay = 24 ; 1 dose per hour maximum
endif
'Reflect meds per day back to user...
for ConfirmCounter = 1 to MedsPerDay
sound Beeper, (125,1)
pause 600
next ConfirmCounter
ConfirmCounter = 0 ;allows counter to be used again in Bottle_Check routine
SecCount = 0 ;start from scratch
'at this point, MedsPerDay (A BYTE) contains a number > 1 representing # doses per 24 hrs required
Med_Interval = 1440 / MedsPerDay ' # mins in 24 hrs divided by # doses required
'at this point, Med_Interval (a WORD) contains the # minutes between doses
'Preload timers so user prompted to take meds now programing is complete item **A**
If MedsPerDay >=3 then
TimeToNextMed = Med_Interval
Else 'medsPerDay <3
Remind_Req_Flag = 1
Endif 'MedsPerDay >3
main:
'setint %00000100, %00000100 ' jump to interrupt on C.2 going high
setint HighMask,PinMask
execloop:
' All subroutines must yield promptly, and NOT hold the processor.
'Interupt routine looks after counting mains pulses, and maintaining timing
wait_Second_Flag:
If Second_Flag = 0 then
inc InteruptCounter ;determine the normal number of interupts in an Execloop cycle in InteruptCounterMax
if interuptCounter > InteruptCounterMax then
InteruptCounterMax = InteruptCounter
endif
If InteruptCounter > MainsFailedThreshold then ; no interupt will be happening...
Mains_Failed_Flag = 1
gosub SysTimer ;update system time using the local timer
endif
GoTo wait_Second_Flag 'ensures a stable flash of the led, somewhat random otherwise - bug **1**
Else
gosub Check_Med_Time 'checks if time to flash side led or make noise - calls remind
gosub Is_Bottle_Back_Check 'checks if time to squeal at user for not putting bottle back
'If Min_Flag = 1 then
' debug
'Endif
Second_Flag = 0; Flags only stays up 1 pass
Day_Roll_Over_Flag = 0;
Min_Flag = 0
Endif
GoTo execloop
Check_Med_Time:
if MedsPerDay >=3 then
'if meds taken 3X day or more, the time of day isnt used to trip reminder, instead a time relative to the
'last time a dose was taken is used
;the reminders will get later in the day as time goes on, but will always the same time apart.
if Second_Flag = 1 and TimeToNextMed => Med_Interval then
gosub Remind
endif
Else 'medsPerDay <3
'if meds taken 1 or 2 times per day, the time of day is used to trip reminder at regular intervals
'irrspective of when the last dose was taken
;reminders will occur at regular intervals
'here if medsperday = 1 or 2
if Day_Roll_Over_Flag = 1 or MedsPerDay = 2 and Mincount = 720 and SecCount =0 then
Remind_Req_Flag = 1
endif
if Second_Flag = 1 and Remind_Req_Flag = 1 then
If SkipDayCounter <> 1 then '1 is SkipDay
gosub remind
Else ' here if skipday and its the normal time to take meds
tune 2, 13,B.3,($49,$40,$44,$49,$4B,$44,$40,$4B,$50,$44,$40,$50,$46,$42,$49,$46,$44,$40,$49,$00,$44,$40,$79,$77,$77,$79,$39)
'tune 1, 13,($49,$40,$44,$49,$4B,$44,$40,$4B,$50,$44,$40,$50,$46,$42,$49,$46,$44,$40,$49,$00,$44,$40,$79,$77,$77,$79,$39)
Remind_Req_Flag = 0
Endif
endif
'endif 'If SkipDayCounter = 1
endif 'MedsPerDay >3
Return
Remind:
'flashes the reminder led
'checks to see if the bottle picked up
'when bottle is picked up, sets sched_bottle_check_flag and dumps timers
gosub Toggle_Side_LED
If Min_Flag = 1 then
Bottle_check_counter = Bottle_check_counter +1
Endif
if Bottle_check_counter > Late_Med_Interval then
sound Beeper, (125,1)
Endif
gosub check_bottle 'this assumes user will never pre-empt the reminder....
'debug bottle_missing
if Bottle_Missing_Flag = 1 then 'assume meds just taken
TimeToNextMed = 0 'sets next med time relative to when bottle lifted
'Day_Roll_Over_Flag = 0
;Med_taken_Flag = 1' what resets or uses this?
'Med_Missed_Flag = 0 'what resets or uses this?
Low Side_LED ;force led off - 50% chance it will be on otherwise....
Sched_Bottle_Check_Flag = 1
Remind_Req_Flag = 0
Bottle_check_counter = 0
endif 'If Bottle_missing = 1 then
Return
Is_Bottle_Back_Check:
if sched_Bottle_Check_Flag = 1 and Second_Flag = 1 then
Bottle_Check_Counter = Bottle_Check_Counter + 1
gosub Check_Bottle
if bottle_Missing_Flag = 0 then 'user has put bottle back in holder, all good
sched_Bottle_Check_Flag = 0
Bottle_Check_Counter = 0
Low Side_LED ;force led off - 50% chance it will be on otherwise....
elseif Bottle_Check_Counter > 30 then ' after 30 secs
gosub Toggle_Side_LED
For ConfirmCounter = 0 to 5
sound Beeper, (125,1)
pause 10
Next ConfirmCounter
endif
endif
Return
Toggle_Side_LED:
' Drive side led - toggle every second'
if Second_Flag = 1 then
toggle Side_LED
endif
Return
'=================================================================
Check_Bottle:
'powers up ir led and reads adc connected to IR sensor
'checks it against threshold. Sets Bottle_Missing flag if bottle not in holder
high IR_TX_LED
let Bottle_Missing_Flag = 0
readadc IR_RX_led, IR_level
low IR_TX_LED
if IR_Level > IR_Threshold then
let Bottle_Missing_Flag = 1
endif
'470 ohm tx current limit resistor, 5k rx resistor to gnd with IR led to VCC.
'ambient dark
'60 units bottle missing 2-5 when in place when ambient is dark. may be scope to reduce tx current further
'ambient full sun
'bright sunshine a problem.mt bottle in full sun reads 130, full bottle in full sun about 20 bottle missing in full sun reads 250
Return
'=================================================================
SysTimer:
'Only runs if the mains driven interupt isnt happening (this is detected in execloop)
'Otherwise, it does what the mains timer does, with much less precision.
'maintains a second counter in SecCount
'toggles Second_Flag every second
'maintains a minute counter in MinCount
'resets MinCount to 0 at 24hr rollover and sets flag Day_Roll_Over_Flag
'increments TimeToNextMed Counter every minute (used for reminders > 3 per day)
'here when internal timer gets to 1 second and only if interupts arent happening
If time >= 1 Then ; Internal timer has reached 1 second
let time = 0 ; set it back to start
MainsCount = 1 ; may as well clear it
inc SecCount ; Increment the second register
Second_Flag = 1 ; Second flag cleared again at end of execloop.
if SecCount >= 60 then
SecCount = 0
Inc MinCount
Min_Flag = 1
Inc TimeToNextMed
endif
if MinCount >= 1440 then 'day over, start again
MinCount = 0 'reset elasped min counter
Day_Roll_Over_Flag = 1 '1 = sat...
if SkipDayCounter >= 1 then 'SkipDayCounter = 0 means SkipDay inactive
inc SkipDayCounter
if SkipDayCounter = 8 then 'week over
SkipDayCounter =1
endif
endif
sound Beeper, (200,1) '1 pip for rollover time
endif
endif
Return
interrupt:
;maintains a mains frequency counter in MainsCount
'maintains a second counter in SecCount
'toggles Second_Flag every second
'toggles Tenth_Flag every 10th second
'maintains a minute counter in MinCount
'resets MinCount to 0 at 24hr rollover and sets flag Day_Roll_Over_Flag
'increments TimeToNextMed Counter every minute (used for reminders > 3 per day)
if Int_Sense_Flag = 0 then
; if the interrupt was called on a low-going transition,
; just re-set the interrupt for a high-going transition on pin3
Int_Sense_Flag = 1
setint HighMask,PinMask
return
else ' Int_Sense_Flag must be = 1
inc MainsCount
Mains_Failed_Flag = 0 ;its obviously not, a mains pulse bought us here!
InteruptCounter = 0 ;determine the normal number of interupts in an execloop cycle (in InteruptCounterMax)
'if MainsCount >= 2 then
if MainsCount >= LineFreq then
MainsCount = 0
inc SecCount ; Increment the second register
Second_Flag = 1 ; Second flag cleared again at end of execloop.
endif
Int_Sense_Flag = 0
if SecCount >= 60 then
'if SecCount >= 2 then
SecCount = 0
Inc MinCount
Min_Flag = 1
Inc TimeToNextMed
endif
if MinCount >= 1440 then 'day over, start again
MinCount = 0 'reset elasped min counter
'MinCount = 1439 'reset elasped min counter to day-1
Day_Roll_Over_Flag = 1
if SkipDayCounter >= 1 then
inc SkipDayCounter
if SkipDayCounter = 8 then 'week over
SkipDayCounter =1
endif
endif
sound Beeper, (200,1) '1 pip for rollover time
endif
setint LowMask,PinMask ; Re-enable interrupts for pin3 = low
return
endif ' Where is the if for this?
' Return **? ** Shouldnt the return be here????