- Published: Sunday, 31 January 2010
- Written by Graham Mitchell
- Hits: 9457
OK, so this project might not be a killer robot or auto-guided missile, though for what ever reason it has turned out to be a decently sized program! The scenario that brought this project to life would most likely be quite unique and rarely encountered, though I thought it would still be worth sharing as the program has a few handy little features and nifty tricks.
I fix/maintain a lot of gear at work that revolves around what is known as "Scheduled Servicing". Nothing new here - if an item has a 60 day Bay Service or Calibration, then every 60 days that servicing is carried out. Some are 30 days, others are 120 days and so forth. There's a problem here though - my work environment complies with Aeronautical AMO regulations (Approved Maintenance Organisation), a very thorough set of regulations/practices to keep a safe and accountable work environment.
I've recently discovered a deficiency with day type calculates for scheduled servicing. Consider the date is 25-Jul-2010, and you've just completed a calibration on a bit of gear that is due again in 60 days. When completing the paperwork, one would normally assume "60 days is two months" and write up the paperwork accordingly (next CAL due 25-Sep-2010). Heaven-behold anyone who uses the item from 23rd - 25th of September is actually in violation of a couple of regulations.
Why? Well the answer has most likely already hit home to most people by now - not every month has 30 days in it. Not only does this highlight possibility to unwillingly violate AMO regs, though there is the opportunity to slightly increase productivity (365 days/12 months = 30.42 days, not 30).
First option is a gimme - Just learn how many days in every month and accommodate for leap years etc... Easy enough, though I would forget it in about 32 minutes.
Second option - use an Excel spreadsheet and calculate the date. For example, the above scenario would be easily solved with the following expression "=DATE(2010,7,25)+60". Excel would display "23/09/2010" in the cell. Given we only have one PC at the end of our work area, it seems a mundane task to stop you in your tracks just to calculate a date.
Third option - make a box that does it for me and can be setup in-situ for easy use. Seems a whole lot of work for such a small deal, though I had nothing on during a Sunday arvo - and got to it.
I'm using a DS1307 RTC (Real Time Clock) as the backbone of time/date keeping. There are a handful of benefits with using the device over a dedicated PIC program - the biggest one is probably a lithium battery with 48mAh or greater will back up the DS1307 for more than 10 years in the absence of power. Not that I plan on using the device once every 10 years - though keeping the cost of consumables down is definitely on the agenda. I'm using two AA lithium batteries as a backup power source on the DS1307 - purely to prevent the loss of data in-case of power interruption. They also allow the unit to be unplugged, transported and reconnected without re-configuring settings (even stored in a draw for a week or two).
The first revision of the project used two switches. One for changing the Mode (projected date forecast), and the other to initiate settings configuration (to set the time/date). It soon became apparent that hitting away on a single button to increment variables was quite annoying - I did want to make something usable by the lowest common denominator at the end of the day. What I trialed and settled on was one button and a potentiometer. I ventured into an interesting method of interaction that will probably form the basis of my future designs.
Before I get to in-depth, consider the normal mode of operation - date projection. I want a box that will tell me what date it is in 30, 60, 120 days time (there's a few other ones, though I'll keep it easy). So, in normal operation, Mode One could display the date in 30 days time, Mode Two in 120 days time and so on. What if I put together a program that automatically calculates how many modes there are, and turns a 10-bit ADC result from the potentiometer into segments for different modes.
For example, I have three modes (30, 60, 120 days) - now simply break the 10-bit potentiometer result into 3 segments (1023/3=341). Therefore, a reading from 0-341 would imply Mode One, 342 to 682 is Mode Two and 683 to 1023 would be Mode Three. I know I'm referring to the processes as "Modes", its more so because the same approach can be transposed into different scenarios quite easily.
"Jittering??" I here some people yell out. For those that didn't yell out, perhaps this would trigger a thought - what happens if the potentiometer is biased at a point of change, such as hovering between 341 and 342. This would make the program jump between Mode One and Mode Two rapidly.... There are a number of methods that can be used to completely remove jitter, and in all honesty I did not experience any "jumpiness" even without the methods employed. First of all, build a stable voltage regulator with all the normal trimmings. Decent input/output caps, a decoupling cap as-close-as-possible to the PIC's Vdd/Vss. The additional method I took was taking many ADC readings and calculating the Median.
Finding the Median from a pool of samples is different to averaging. Consider some ADC samples; 512, 512, 511, 512, 1023. There are 5 readings, they appear to be sitting at about 512, though there is a noise spike which returned 1023. Calculating the average would include the undesirable noise (512+512+511+512+1023) / 5 = 614.
The Median can be found by arranging the results from smallest to largest, and then picking the sample in the middle. In this case, 511, 512, 512, 512, 1023. Our result, 512. This is a much more accurate method of sampling analogue signals, though it takes a little more time. I did have my own function to do this very job, though Swordfish already has such a function as part of the ADC.bas library; ADC.ReadMedian(ChannelNumber). It will take 64 samples and return the Median.
With the above considerations in place, your left with a blissfully easy-to-use and creative method for end users to interact. Here's a video of the unit in use;
How about I break things up a little bit and share the whole program (more tips below the code)
Leap Year Detection
OK, so thats a pretty big program to do something that appears to be simple enough. Another little trick I've picked up along the way with this project is calculating if its a leap year or not.
I always thought it was as easy as "if a year is divisable by 4 then its a leap year". Clearly I've been misslead at somestage! Here's the method;
1. If the year is evenly divisible by 4, go to step 2. Otherwise, go to step 5. 2. If the year is evenly divisible by 100, go to step 3. Otherwise, go to step 4. 3. If the year is evenly divisible by 400, go to step 4. Otherwise, go to step 5. 4. The year is a leap year (it has 366 days). 5. The year is not a leap year (it has 365 days).
In terms of program the above method into Swordfish;
I scale the year up by 2000 as the DS1307 works with a scale of -2000. For example, the year 2010 would be read as 10.
Thoughts and comments are more then welcome!