I am not a student and THIS IS NOT HOMEWORK. I am a mid 30's mechanical engineer that has been playing with coding and microprocessors since the late 90's. I have never taken, nor will I ever take, any sort of formal training to learn this stuff. Everything I know is the result of books, forums, and experimenting on my own. I DO have a passion for elegance and cleanliness in the things I create whether they be physical or coded which is why I ask questions like this but ultimately I'm interested in function over beauty.
Regarding this particular usage, I ask the question because the original code I posted was ugly and I was sure a better solution existed. The wording of the question was deliberately broad because I use this sort of function in a variety of ways. The current use requires powers of 10 because of the application but the first time I needed this sort of numeric reduction was to take a value of time from millis() and break it down into hours, minutes, and seconds. I had hoped to take a single answer from a broad question, and utilize it in multiple programs.
For the sake of detail I will reiterate that the current application is a speedometer/odometer display. The final build is months if not years away from completion because I am working on this in my spare time between work, wife, kids, etc. Again, referencing my desire for clean and elegant solutions, I will be using the existing speedometer pickup on the bike (inductive sensor). I've decided against using interrupts to count the pulses from the sensor because I'm not convinced that the other functions will continue to work properly as road speed increases. Instead I will be running the pulses through a frequency to voltage converter and monitor an analog input to determine current speed. The issue then became how to use an ever changing speed input to track how far I've gone. My solution there is not as elegant as I would like but should result in a reasonably accurate measurement. Each time the input is sampled, the current time is stored. The new sample and time are then compared to the previous sample and time, and the distance traveled is calculated based on those deltas. Unfortunately the divisor to convert to MPH from a millisecond time base is 3,600,000 and the time between samples is so short that even floating point math didn't work so I had to keep everything in integer form. However this caused my distance variable to overflow almost instantly at any speed. To correct for that I used an "if" routine to increments the odoTenths variable by 1 every time the distance variable reaches (or exceeds) 3,600,000 and then subtracts that 3600000 from the value of the distance variable. This keeps that variable down to a reasonable size without losing resolution from my measurement. The odo variable is then miles traveled x 10 which gives me a display resolution of .1 miles (typical of any display). That variable is then broken down into the individual 10^n components for the actual display. The original suggestion was a great one IMO but it had the failing that it modified the odo variable in order to perform the math which is something my current setup will not tolerate. What I ended up with is based on that suggestion and much cleaner than my original code, though still not "pretty". I spent some time working on a loop function to clean it up further but gave up before I found a good way to generate incrementing powers of 10. My searching came up with the pow() function but as that involves floating point math I decided against using it.
static byte odo[6] = {0,0,0,0,0,0};
static unsigned long odoTenths = 0;
if (distance >= 3600000){
odoTenths += 1;
distance -= 3600000;
}
odo[0] = odoTenths/1 % 10;
odo[1] = (odoTenths/10) % 10;
odo[2] = (odoTenths/100) % 10;
odo[3] = (odoTenths/1000) % 10;
odo[4] = (odoTenths/10000) % 10;
odo[5] = (odoTenths/100000) % 10;
@ holmes, I like your method in post 6 but it won't work (at least not directly as written) because it requires the tracking variable to be modified by the math routine. I was able to build my math into a loop that seems to be working but some additional testing is still needed. :
byte odoIndex = 0;
unsigned long odoDivide = 1;
while (odoIndex < 6) {
odo[odoIndex] = (odoTenths/odoDivide) % 10;
odoDivide *= 10;
odoIndex += 1;
}