**Most natural observations are exponentational/logarithmic in nature.**

I often do simple hardware using Microchip PIC processors (usually 12F or 16F families). Hardware doing some business in the home.

One such example is my Christmas-tree-lightning-controller. Basically it only turns my electric Christmas-tree-lights on when I want to see them on…

In order to do this, it needs to measure the out-door light. It uses an accumulation cell (of 8 samples) and a moving average register with 8 cells: Light or darkness is determined from 8 accumulated samples of “10-bits light” averaged through the latest 8×8 samples…

8×8 samples of 10-bits equals 6 bits of 10bits equals 16 bits…

So the output of the moving average register is at most 16 bits wide and should pose no problems on a modern microcontroller.

Unfortunately, the small PIC micros are not very good at “multi-byte” calculations why the 16-bit result is a bit awkward to deal with. And my simple experiments indicates that light-level comparisons should be measured on a “percentage change” basis and not as an absolute comparison.

If I could just do a simple 8-bit logarithm function of the 16-bit absolute result, I would be able to do simple percentage comparisons of different light level measurements by simple subtraction of 8-bit values. Even the simples PIC’s can do subtraction of 8-bit values without special engineered software subroutines ðŸ™‚

Being inspired by the ÂµLaw compression schemes used in Telephony, I wrote this little routine, that basically calculates 16Ã—log_{2}(x), where x is some 16-bit value and the result is an 8-bit value. Simulating the calculations in software gives a maximum error of 1-bit on the result.

; NOTE: Variables wi, r0 and r1 are ; defined elsewhere in on-chip RAM ; ; log2: calcuate r0 = approx 16*log2(r1:r0). ; wi, r1 destroyed ; log2: movlw 16 movwf wi ; loop log2_loop: bcf STATUS,C rlf r0,f rlf r1,f ; C affected decfsz wi,f ; Z affected btfsc STATUS,C goto log2_done goto log2_loop ; done log2_done: movlw 0xf0 andwf r1,w iorwf wi,w movwf r0 swapf r0,f return |

The simpe logarithm shown above I’ve used lots of different places. If You want to know how or why it works, don’t hesistate to put a comment below.

Unfortunately, my Christmas-tree-lights-controller is not (yet) perfect, as sudden, heavy light seems to overflow the moving averager. In other words, when the terrorist children living next-door are having fun with fireworks, the lights on my outdoor Christmas tree blinks in its own secret manner ðŸ™‚

Hi, you actually can save one goto opcode:

; NOTE: Variables wi, r0 and r1 are

; defined elsewhere in on-chip RAM

;

; log2: calcuate r0 = approx 16*log2(r1:r0).

; wi, r1 destroyed

;

log2:

movlw 16

movwf wi

; loop

log2_loop:

bcf STATUS,C

rlf r0,f

rlf r1,f ; C affected

decfsz wi,f ; Z affected

btfss STATUS,C

goto log2_loop

; done

log2_done:

movlw 0xf0

andwf r1,w

iorwf wi,w

movwf r0

swapf r0,f

return

Nope, wait a sec.

The

`decfsz wi,f`

skips the bit test and exits the loop via`goto log2_done`

. If you inverse the bit test and removes the goto that exits the loop, the decfsz continues the loop instead of exiting.