logo
background
 Home and Links
 Your PC and Security
 Server NAS
 Wargames
 Astronomy
 PhotoStory
 DVD making
 Raspberry Pi
 PIC projects
 Other projects
 Next >>

Using the PIC for everything

Links to all my PIC tips, tricks and 'mini-project' notes

Whilst the mid-range PIC's can tackle many complex and otherwise almost impossible applications with ease, the challenge is to minimise cost by using the cheapest baseline PIC 'whenever possible'. Baseline PIC's can be had for less than 50p each = I purchased many 16F5x chips for between 40 and 50p each (mainly from CPC as 'remaindered' stock in their 'Bargain bin' section).

The even cheaper to use 12F675 (it has an internal OSC) can be found for as little as 20p (in Qty 10pcs, eBay), as can many other PIC's for less than £1 each. These PIC's are so cheap that you will soon start using them 'for everything' (especially as the PIC can often be used in place of a higher cost 'single function' digital chip - such as divider, ADC, PWM generator etc.) !

Buying the PIC in a 'TSOP' package is (sometimes) cheaper than the DIL/DIP package version = and whilst this costs you 10-20p extra for a mini-PCB TSOP-DIP 'converter', if you use a 'bigger' PCB than the PIC TSOP really needs you can mount other devices (resistors, caps, even osc. crystals) on the same board - and make use of the extra 'pin holes' to wire this up to the rest of your circuit

Below is a mix of programming tips and tricks, common circuit tricks and all the 'mini-projects' I've used the PIC for

I hope these details proves as useful to you as it does to me !

Below, click on the '+' to expand 'in place' (includes diagrams/images) or click the title URL (to view/download the text only version).

(+) 0004 Multi byte ADD - (24bit)

(+) 0005 new PIC 33 instruction set - (macros)

(+) 0006 Binary multiply methods

(+) 0007 8x8 - (multiply)



(-) 0008 8x16 - (multiply)


16x8 Multiply (shift and ADD) Subroutine

You can find many 8x16 multiply methods (for example, see piclist math methods), however implementation is typically 'left up to the user' :-). Generating 'optimum' code depends on your goal, either max. speed or minimum code space.

My 'new PIC 33 instruction set (macros)' contains a MUL8x16 macro that implements a 'maximum speed' approach, so this subroutine is aimed at 'minimum code space' approach (i.e. it takes longer because it loops).

Method

The basic binary 'shift and add' method uses one value to control the adding of the second value into the 'top' of the result, after which the result is shifted down 1 bit and the next control bit is checked. After n shifts (and n possible adds) the result is complete.

When it comes to 8x16, the result will be 24 bits. The temptation is to shift the 8 bit value as the 'control' and ADD the 16 bit value into the result (since this limits the process to a maximium of 8 ADD operations), HOWEVER the PIC instruction set (and ALU) only supports the ADD of the Accumerlator to a Register.

This would mean keeping the ADD value in a temp register pair and copying byte at a time to the ACC in order to perform a 16 bit ADD - whereas an 8bit value can be kept in the Acc all the time. Further, the 'skip on shift no Cy' can skip the single 8bit ADD instruction, but a 16bit ADD sequence would have to be 'jumped' on no Cy.

All this means it's actually faster to 'shift' the m16 register pair and ADD the m8 value, up to 16 times, than it is to shift the m8 byte and add the m16 (a 2 byte register pair ADD with Cy propergation 'costs' at least 6 instructions), up to 8 times.

Further, if the m8 value is copied to the Acc for the ADD, then it's register can be re-used as part of the result, plus the m16 value register pair can be 'double used' as the Mid/Lo result as m16 will be totally 'shifted out' of the bottom (as the result is shifted in from the top) during processing.

Hence we actually perform '16(shit)x8(ADD)' (rather than 8(shift)x16(ADD)).

Note that 'shifting down' means that any Cy from the top byte ADD is automatically preserved (i.e. it's shifted into the (new) top bit). When we 'know' that m16 is 'small' (many top bits 0), it would be 'nice' to accumerlate the ADD starting from the bottom up (instead of from top down), since that means we can skip the '0 bits'.

The problem with this is the Cy - when ADD to LSB generates a Cy we can't just 'shift it up' - instead we have to propergate it up (by INCrementing the Mid/Hi byte) .. and that can result in the top 2 bytes changing (so we can't 'double use' them as both m16 and part of the result). In short, the ADD has to be at the top end (with shift down), not the bottom end (with shift up).

The subroutine below will multiply a 16 bit (shift) value (Mid,Lo) by an 8 bit (ADD) value (Hi), passed in 3 registers (Hi,Mid,Lo). To save on register space, the same 3 registers will be used to hold the (24 bit) result.

rTemp is used as the 16 step loop counter (or we can 'unwind' the code into 16 steps) :-
m8 in Hi is copied to Acc, m16 in Mid,Lo (mult16) is shifted down (so b0 to Cy).
If Cy is set, then m8 (in Acc) is added to Hi and the loop continues with the next shift.

After 16 shifts, m16 will be completly shifted out of Mid,Lo and Hi,Mid,Lo will contain the full result.

; MULTIPLY8x16 ;Unsigned 8x16 multiply subroutine ; Called with the 8bit multiplier in mRegHi, 16bit multiplicand in mRegMid+mRegLo ; Returns with 24bit result mRegHi,mRegMid,mRegLo. ; Acc and rTemp (count) are used ; Note, 'no shortcut' header (i.e. no 0 or 1 tests, code still works, but takes same time in all cases) LOAD 0x1F        ;count 16 COPY Acc,rTemp   ;set loop COPY mRegHi,Acc   ;copy m8 to Acc CLR mRegHi        ;clr m8 reg for use with result RRF mRegMid     ;shift m16 down (we don't care if Cy is shifted into b15, because it will be discarded by last shift at end) RRF mRegLo      ;m16,b0 to Cy Loop              ;loop is 16*8 CLK's, irrespective of ADD/no ADD ; (back) here with Cy set if ADD needed Skip nCy        ;skip ADD if no cy ADD Acc,mRegHi  ;add m8 to msb, may set Cy (which will need to be shifted into Hi) RRF mRegHi      ;add was skipped no Cy, or add may have set Cy, either way shift Cy into Hi RRF mRegMid     ;shift m16 down RRF mRegLo      ;next bit m16,bX to Cy DECFSZ rTemp    ;done last add ? dec loop, skip if zero (no effect on flags) Jump Loop     ;nZ, not done, keep looping (no effect on flags) RETURN        ;all ADDs done, exit (with Acc 0) note, last shift b0 is ignored
Total of 14 instructions, cost 6+ 16*8+ 2(return) = 136 Clk's.

The multiply can be 'short cut' by checking for *0 (and/or *1) by adding extra instructions to the 6 'header' set, however that adds extra overhead to all MULtiplies, so is only 'worth it' if your applicatio is giong to result in lots of 0* or 1*

; Header for 0 test shortcut COPY mRegLo,Acc  ;++extra code for 0 test, check Lo, sets Z (cost is +1) = to test for *1, use DECFSZ (Dec reg to Acc, skip if Z) Skip Z           ;++extra for Z test +2 Jmp LoNotZero    ;++cont. if Lo nonZ, cost is +2 clk for jump CLR mRegHi       ;Lo is Z, clr Hi and exit RETURN LoNotZero        ;Z cost is +4 total if nonZ LOAD 0x1F        ;count 16 COPY Acc,rTemp   ;set loop COPY mRegHi,Acc   ;copy m8 to Acc (sets Z) Skip Z          ;++extra code for Z test (+1) Jmp HiNotZero   ;++continue if Hi non-Z (+2) CLR mRegLo      ; Hi is Z, clr Lo and exit RETURN HiNotZero       ;Z test cost is +3 clks if Hi nonZ CLR mRegHi      ;clr m8 reg for use with result RRF mRegMid     ;shift m16 down (we don't care if Cy is shifted into b15, because it will be discarded by last shift at end) RRF mRegLo      ;m16,b0 to Cy ; CONTINUE WITH 16*8 INSTRUCTION LOOP ABOVE
This note last modified: 11th Aug 2017 10:54.

[top]

(+) 0011 Bi color LED driving

(+) 0012 One pin dual LED and button detect

(+) 0013 Input only multi button detect

(+) 001a One pin controls motor Fwd off Reverse

(+) 001c One pin controls 3 relays

(+) 0020 I2C bit banging

(+) 0021 I2C code

(+) 0021 Serial link - (9600 baud)

(+) 0028 RS422 RS485 drive with one PIC pin

(+) 0030 D to A conversion - (R2R DAC)

(+) 0031 Ternary DAC - (R3R)

(+) 0032 Hybrid ternary bit conversion - (code)

(+) 0035 Pulse Width Modulation - (PWM)

(+) 0040 Gearing axis sensor

(+) 005a TYC50 AC motor details

(+) 0061 16F54 2char month map - (VTI)

(+) 0062 DDmmmYYYY character map - (VTI)

(+) 1000 PIC16F684 tips and tricks

(+) 2000 18Fx tips and tricks

(+) 6500 18Fxx data Table output - (max rate)

(+) 6501 18Fxx Return with value LUT - (max rate)

(+) 6502 18Fxx extended instruction data output - (max rate)

(+) 6530 simple data transmission

(+) 6540 Using RS485

Next subject :- index

[top]