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)

(+) 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


; Version 1.0, 2017-08-17 12:50
;
; I2C Transmit and Recieve, using base-line instruction set (PIC-33), Steve's Macro instruction set
; This version uses 2 pins only , so uses TRIS to isolate the drive from I2C bus and thus not very fast
;
; [I use a faster approach, no TRIS but needs 4 pins (2 out, 2 in) ...
;  ... plus 2x Shockley diodes to isolate the 'Hi' drive (from the output only pins) from the I2C bus ]
;
; Quick overview of I2C operation:
; 1) To start a transfer, Master ensures CLK is HI, then pulls Data Lo, then CLK Lo
; 2) To send data, Master sets up Data, then sends CLK Hi pulse (Master has to check CLK goes Hi as slave can hold it Lo to force wait)
; 3) To fetch data, Master sets CLK Hi (checks CLK Hi), samples data, sets CLK LO
; 4) After 8 bits, Master checks the Slave Ack bit with a Clk Hi (+wait for hI). Ack = data Lo = OK, Nack = Hi = fail.
; 5) After Ack, both Master and Slave can hold CLK Lo until it's ready for next byte
; 6) To release the bus, Master removes all drive (allows both CLK and Data to go Hi)
; 7) To indicate busy, Slave waits until Master has recieved Ack (Clk Lo) then holds CLK Lo until it's ready
;
; See I2C manual:- http://www.nxp.com/docs/en/user-guide/UM10204.pdf
;
;
; NB. This code assumes this PIC is the (only) Master (i.e. I2C in single Master configuration)
; 
; 
; I2CPORT = the i/o PORT (address) containing the 3 bits used for I2C
; bSCL = Clk (i/o pin) bit number
; bSDA = Data (i/o pin) bit number
; rI2Ctris contains a copy of the tri-state settings for I2CPORT
;  (this I2C subrouine will only modify the bSCL and bSDA bits) 
; rData is the data byte to be sent (or recieved)
; rTemp is used as the bit counter
;
; CALL I2Cstart to grab the I2C bus and transmit a data byte from rData (this selects the Slave for TxD or RxD)
; CALL I2CTxD to transmit a date byte (start must be called first)
; CALL I2CRxD to recieve a byte (start must be called first)
; CALL I2Cstop to release the bus (must be called after TxD or RxD)
;
; On Return, Acc can be used for 'Skip if no Error' (ADD Acc,PCL) as follows :-
; If Error (no Ack recieved), Acc == 0 and ADD Acc,PCL will execute the next instruction (typically a JMP to error handler)
; If no Error, Ack recieved, Acc = 1 and ADD Acc,PCL will skip the next instruction
;  NOTE. To work, the CALL has to be from LOW half of 512 address bank (ADD PCL clears bit9), and can't be on FE or FF (page boundary)
;
; WARNING - all subroutines will 'lock up' if the sCLK line is being held Lo (i.e. whilst Slave forces bit/bus wait)
;
;
I2Cstart  ;CALL to start the I2C and send a (slave select) byte.
; NOTE. we always start with a 'select slave', so at least one byte TxD always comes before RxD
;
; Don't assume this routine has been used befor, so start by making sure the clk and data drive bits are disabled (tri-state)
 bSET rI2Ctris,bSCL     ;Set bits in tri-state 'copy' reg. (Hi = set tristate = disable output, set as input)
 bSET rI2Ctris,bSDA
 COPY rI2Ctris,Acc      ;get the tri-state copy settings ..
 TRIS I2CPORT           ; and make sure I2C lines are tri-state (will be pulled hi by the I2C 200R bus pull-ups))
 ; Now make sure the clk and data bits will be driven Lo when TRIS ebables them
; WARNING bSET/bCLR one bit at a time will READ ALL THE PINS, then set ONLY that one, then write them to the o/p latch
;  any pin that is an input will get it's current state written to the o/p latch ..
; Since bith SCL and SDA are tri-state, a bCLR on one will always set the other Hi !
;  so setting 2nd pin Lo can't be done using bCLR direct
 bCLR I2CPORT,bSCL,Acc       ;get the pin state to Acc (with clk set lo)
 bCLR Acc,bSDA               ;force Data 0
 COPY Acc,I2CPORT            ;copy settings to the port o/p latch (both clk and data 0)
;
; OK, now grab the bus .. first make sure CLK is Hi
 SKIPset I2CPORT,bSCL
   JMP $-1
; Yep - set data Lo
 COPY rI2Ctris,Acc
 bCLR Acc,bSDA  ;rtris with data Lo to Acc
 TRIS I2CPORT           ; .. and to the I2C bus
; OK, now to select the Bus, with data Lo, set CLK lO .. then wait a bit
 bCLR Acc,bSCL          ;set for o/p clk Lo
 TRIS I2CPORT           ;clk Lo (and data Lo) to the I2C bus
; OK thats the start, now send data ..
;
I2CTxD  ; Entry point for transmit (another) byte (I2Cstart must have been called first to select the slave ..)
 LOAD 0x08             ;Set the bit count (DECFSZ will dec and skip if zero to end the loop)
 COPY Acc, rTemp
; (re)load the Acc with tris settings
 COPY rI2Ctris,Acc
 bCLR Acc,bSCL  ;default = both clk and data Hi, need clk Lo
;
; Bit transmit will loop back here with clk Lo ready to set next data bit
I2CdataTx
; OK, now we can set a (next) data bit .. set data, Clk Hi loop for next
 ROTR rData        ;first (next) bit = b0 to Cy
 bCLR Acc,bSDA     ;assume it's zero, set tris to o/p 0
 SKIP nCY    ;skip if bit is 0
   bSET Acc,bSDA          ;need hi, tris to input (i.e. set SDA bit Hi)
 TRIS I2CPORT           ;data to the I2C bus
 ; release the CLK
 bSET Acc,bSCL          ;prepare to release the clk (hi)
 TRIS I2CPORT           ;release the Clk (data unchanged)
 SKIPset I2CPORT,bSCL   ;check CLK Hi ..
   JMP $-1              ; .. Slave can hold clk Lo to force a wait
; Slace has data, pull clk Lo before changing to next bit
 bCLR Acc,bSCL          ;enable output (Clk Lo)
 TRIS I2CPORT           ;clk lo to the I2C bus
; any more to do ?
 DECFSZ rTemp ;dec count, skip if zero
 JMP I2CdataTx
;
; all done, release the data line, get the Ack 
 bSET Acc,bSDA            ;tri-state data bit Hi
 TRIS I2CPORT           ;release data line
; now clk in the slave Ack bit (Hi = failed, Lo = ok)
 bSET Acc,bSCL          ;clk hi
; this is where RxD arrives to get the slave Ack
I2CslaveAck
 TRIS I2CPORT           ; .. to the I2C bus
 bCLR Acc,bSCL          ;prepare exit with clk Lo
; get slave Ack
 SKIPset I2CPORT,bSCL  ; remember = slave can hold CLK Lo to force a wait
   JMP $-1
; OK ack status is valid, sample data pin
 SKIPset I2CPORT,bSDA  ;input data Lo is OK, hi is error
  JMP $+3
 TRIS I2CPORT           ; Clk lo to I2C bus
 RETURN 0x01       ;slave sent 0, all OK (return 1 for ADD Acc,PCL skip error jump if OK)
 TRIS I2CPORT           ; Clk Lo to I2C bus
 RETURN 0          ;return with Acc= 0 = error (return 0 for ADD Acc,PCL, execute next inst = jump to error)
;
;
;
;
I2CRxD  ;reviece a byte (I2Cstart must have been called first to select the slave ..)
; on entry, I2C bus clk is Lo (rI2Ctris has both bits Hi)
 COPY rI2Ctris,Acc      ;get the tri-state copy settings
 LOAD rDate 0x08        ;set the bit count
; the sequence is much the same as data transmit, expect we wait for clk Hi then sample bSDA
I2CRxDwait
 TRIS I2CPORT           ;release the clk
 SKIPclr I2CPORT,bSCL   ;wait for CLk hi
  JMP $-1
 bCLR Cy               ;assume data bit is 0
 SKIPclr I2CPORT,bSDA  ;skip if is 0
   bSET Cy
 ROTL rData            ;get the bit
 bCLR Acc,bSCL         ;say we got it (clk lo)
 TRIS I2CPORT 
 bSET Acc,bSCL        ;prepare to release the clk
 DECFSZ rTemp ;dec count, skip if zero
 JMP I2CRxDwait
; all done, exit via get slave Ack
 JMP I2CslaveAck
;
;
;
I2Cstop  ;release the I2C bus
; on entry, I2C bus clk is Lo (rI2Ctris has both bits Hi)
; to release, data Lo, then Clk Hi, then Data Hi
 COPY rI2Ctris,Acc      ;get tris copy for this port
 bCLR Acc,bSDA          ;set for tris data lo
 bCLR Acc,bSCL          ;now clk Lo
 TRIS I2CPORT           ;set both clk data lo
 bSET Acc,bSCL          ; clk to Hi
 TRIS I2CPORT           ;release the clk
 SKIPset I2CPORT,bSCL   ;wait for slave to relese clk
   JMP $-1
 COPY rI2Ctris,Acc      ;both data and clk hi
 TRIS I2CPORT           ;release the bus
 RETURN 0x01            ;return with all OK
;
; ends

This note last modified: 17th Aug 2017 16:21.

[top]

(+) 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]