This page is a demo/sketch of the ePIP or Perfect Pub round load share in a Microchip PIC. I rechiped a Maplin's Lottery Number picker kit.
The kit is/was available from Maplin who sourced it from MUTR
The requirement is to distribute a stream of calls in proportion to a number of destinations, with the calls spread as evenly as possible, in the proportions specifed, to each destination.
e.g Assume proportions of 4 Parts, 2 Parts, 2 Parts to destinations A,B,C distribute in the Sequence A,B,A,C, would be better than A,A,A,A,B,B,C,C.
This method works for non integer proportions.
ePIP - endpoints Picked in Proportion.
Perfect Pub Round - Each person pays in proportion to their consumption. Those that drink halfs do not subsidise the Pint drinkers.
I was working on a project that needed to distribute calls in proportions to a number of destinations. These proportions were not simple percentages.
The method being used seemed very clumsy. This method came to me one saturday in the shower. It is very simple and requires no multiples, divides, or lookup tables.
Maplin's Lottery Number Picker kit.
It has a circuit like this:
The switch is connected to A2, and when pressed, A2 is high. The right hand display is turned on by A0 and Left hand display by A1
; ;RA0 - Mux Left. High to turn on Transistor and display ;RA1 - Mux right. ;RA2 - Switch pulled low by 10K goes high on press. ; ; LED ; | ; |/ ;RA0 ---[ 1K ]---| ; |\ ; | ; Vss ; ; ;Take port B high. ; ;Prort B ----[ 180 ]----LED ; ; rb3 ;rb1 rb2 ; rb0 ;rb5 rb4 ; rb6 ;
Re chiped:
Have a number of buckets, one per destination. Fill each bucket in the required proportions. For each call, add the required proportions to each destination's bucket.
The destination for the call is the destination with the fullest bucket.
From the picked destination's bucket, remove the sum of proportions. This keeps the average fill constant.
In the diagram below set P[ i ] for the required proportion. The sum of proportions does not need to add up to 1. For the PIC demo N can be 0 to F
JavaScript Code:
function doAnEventLED(){ var totalWants = 0 var totalBuckets = 0 var maxBucket = 0 var maxBucketCnt = 0 // each output stream has it's own bucket. // for each event put a dollop of water equal to the (parts ) portions wanted into each stream's bucket for ( var cnt=0; cnt < wantA.length ; cnt++ ){ bucketsA[cnt] -= -wantA[cnt]*1 // work out the totals totalWants += wantA[cnt]*1 totalBuckets += bucketsA[cnt]*1 //is this bucket the fullest. // look for the max, or last equal one. if ( bucketsA[cnt] >= maxBucket ) { maxBucketCnt = cnt maxBucket = bucketsA[cnt] } return maxBucketCnt // return destination picked }
PIC 16FXX assembler:
;-------------------------------------------------------------------------- ; Sec 4.1 Load Share routines - LD ;-------------------------------------------------------------------------- ; ; Using the Winner takes all method. ; For each destination, have a bucket and a corresponding want ; ; For each event add the want to the bucket ; Find out which bucket if fullest, i.e is the largest value. ; This this the destination to be used, so now subtract the sum of the wants from this bucket. ; ; expand ;Define macro LDloadShareMac macro n MOVF LDwant#v(n),w addwf LDbucket#v(n),f MOVF LDbucket#v(n),w addwf LDtotalBucket,f comf LDmaxVal,w addwf LDbucket#v(n),w bc LDloadShare#v(n) ; New max value MOVF LDbucket#v(n),w movwf LDmaxVal movlw #v(n) movwf LDmaxPtr LDloadShare#v(n) endm LDdoloadShare movlw 0x80 movwf LDmaxVal clrf LDmaxPtr clrf LDtotalBucket LDloadShareMac 0 LDloadShareMac 1 LDloadShareMac 2 LDloadShareMac 3 LDloadShareMac 4 LDloadShareMac 5 LDloadShareMac 6 ; ; now knock back the fullest bucket with the total counts. ; bankisel LDwant0 movlw LDbucket0 addwf LDmaxPtr,w movwf FSR movfw LDtotalBucket subwf INDF,F return LDloadShareInit movlw 0 movwf LDindex clrf LDmaxPtr call LDclearBuckets ; ; Set up the proportions or parts required. ; movlw 8 movwf LDwant0 movlw 8 movwf LDwant1 movlw 8 movwf LDwant2 movlw 8 movwf LDwant3 movlw 8 movwf LDwant4 movlw 8 movwf LDwant5 movlw 8 movwf LDwant6 return LDclearBuckets clrf LDmaxPtr clrf LDbucket0 clrf LDbucket1 clrf LDbucket2 clrf LDbucket3 clrf LDbucket4 clrf LDbucket5 clrf LDbucket6 clrf LDbucket7 clrf LDbucketCarryOsc return
To randomize the sequence if similar proportions are used, add +/- a percentage of Total sum of proportions.
To mop up rounding errors subtract the sum of the bucket fills instead of the required proportions.
It is possible to modify the proportions during use. Proportions of 0 may require checking to prevent spurious picks during startup.
I have used the 7 segment display to show which destination and its proportion N picked on the display.
the kit only had one button so I have used my single button code to allow the proportions to be set.
It is possible to set the proportions using the button
A short press increments through speeds and ePIP / Parallel Osc displays. A long press enters proportion setting mode. In this mode short presses increment the proportion for the segment. Another long press moves onto the next segment. A very long press resets the mode back to the display mode.
Software: PIC code
Software: PIC code hex
A JavaScript demo: demo:
Using the same buckets use them as an oscillator, and display the most significant bit on the 7 segment display. This produces a pleasing changing display.
The Oscillator drive the left hand display, the carries drive the right hand display.
This demo shows that the proportion picker can be very simple. It was not immeadiatly obvious how to do this.
Thats enough for now!