While talking to my father one afternoon, he mentioned that my grandmother was having trouble remembering to use her nebulizer. Due to the fact that the purpose of the nebulizer is to assist in providing the body with the amounts of oxygen it can no longer collect on its own and the fact that lack of oxygen has a direct impact on brain function, a ‘catch-22’ scenario arises. I, as always, tried to solve the problem.
All she really needed was an alarm that would reset itself to a time four hours in the future after she used the nebulizer. Simple enough. It also shouldn’t require her to learn anything new and should only operate during her waking hours. I also wanted it to be battery operated and as such, capable of lasting at least a year without recharging. Before spending the time and effort required to create something from scratch, I tried to find an off-the-shelf product that fit my requirements. Sadly, I could not find anything that met all of these requirements. In all honesty, if it was easier to find an electronic organizer –from days of old — that allowed me to run user-created programs, I’d have done that in a heartbeat. Alas, I set off to research which microcontroller would fit the bill.
Initially, I planned on using the Arduino. I’ve used it for a dozen past projects and I really like the community support and Processing ( the middleware language it uses ). Unfortunately, they still cost nearly $30 a piece and aren’t exactly power-sippers out of the box. A friend suggested taking a look at the TI Launchpad due to its low cost and focus on minimizing power consumption. I did and was sold! Power consumption could drop into the microamp range as opposed to the milliamp range and doing so was both supported and encouraged with the Launchpad. It also has a built-in realtime clock (RTC) function that allows me to keep track of what time it is without the need for any external components. Additionally, USB serial support can remain intact without drawing power for the programming circuitry. This means that updates should be possible over USB if a bug is found or an enhancement needs to be made. This is one of my other obstacles. I’m currently living near D.C. and my grandmother lives in south Florida. I won’t be able to do much troubleshooting remotely, so a maintenance-free (or very low maintenance) device is highly desirable.
The basic flow:
- Beginning of Day alarm goes off
- Set countdown timer alarm
- Countdown timer alarm is hit
- Turn on buzzer sound
- If button is not pressed within 10 minutes, turn off buzzer and set the alarm for an hour from now
- Button is pressed
- Turn off buzzer sound
- Reset countdown timer
- End of Day alarm is hit
- Remove countdown timer
How Premature Optimization Was the Root of Failure
Writing the logic for a dynamically-set alarm that will only be triggered only during a certain hour range and reset to the start hour otherwise was more difficult than I imagined it would be. The Launchpad contains registers for its RTC functionality that store year, month, day, hour (12), minute, second, and AM/PM. The 12HR time makes things tricky. It requires extra logic for crossing the AM/PM divides when adding hours to the current time to set the next alarm. It also means that, in order to keep things simple, I had to write somewhat inflexible code that currently lacks support for scenarios outside of my specific use-case. It should be noted that the RTC library from TI provides a function get24Hour( ), but it requires 23 clock cycles per call ( documented here ). It wouldn’t matter so much if we rarely hit it, but it’s hit it every second to check if the current hour and the hour to turn on the alarm are the same. Instead, I decided to compare the values in the registers holding the hour and PM values since the reading and comparison operations should only take one clock cycle each and, thus, should not require as much power.
Update: The actions and goals described above were a smidgen more aggressive than necessary and greatly made spaghetti out of my code. Despite having tested many scenarios as I coded, I did not do a full regression test prior to sending the device off. My decision to ship so soon was due to my eagerness to put a solution in place, but has cost my grandmother more time without a solution as the initial version was buggy due to improper comparisons with BCD hours. Another very interesting lesson I learned from this initial release was about users: despite one’s best efforts, a user will always do something unintended. As I mentioned above, I wrote the program in a way that accounted for time of day and did not allow the alarm to be set during the hours that my grandmother is normally asleep. Despite my father having explained this to my grandmother, she believed it necessary to disconnect the buzzer from the board. This is not such a big deal except that the device’s exact purpose is to help someone who forgets to do things (in this case that would probably be plugging the buzzer back in). The reason this is of such great interest to me is that I had not even considered the possibility of it happening.
As I noted in the update to Version 1, there was a major bug with the Binary-coded Decimal (BCD) representation of the hours. The number retrieved from TI_hour or get24Hours( ), is in BCD. BCD is simple enough to understand, but conversion of BCD into decimal and vice versa isn’t so trivial. Basically for the purposes of dealing with the hours on the Launchpad, BCD representation is just each digit of a decimal number coded into 4 bits. So, 11pm would be hour 23 and the BCD representation of 23 is 0010 0011. This is also 0x23 in hex. Addition is where things become more complex. Since each digit must be within the range 0 – 9, something must be done if the sum of two numbers is greater than 9. For a solution to this, please refer to the Wikipedia link in the first sentence. Unfortunately, I did not have as good a grasp on these concepts when I shipped Version 1 off. I was also unaware of the _bcd_add_short( … ) method. I did get some help from reading this 43oh.com post and ended up using the convertToBinary( … ) method which converts decimal to BCD more efficiently. By using this method to get variables in like-units and using get24Hour() , I was able to clean up much of my code and, as a result, make it easier to trace through and understand. So how was power consumption affected by using these higher level methods rather than doing register comparisons? Honestly, I have no idea. The fact is, my multimeter is telling me it’s consuming 3.5 microamps and that’s roughly what I was getting before. All of my time spent prematurely optimizing was a complete waste!