~Page http://www.piclist.org/techref/microchip/gotchas.htm Modified by:JMN-EFP-786 jamesnewton@efplus.com preview-to: http://www.microchip.com/10/lit/suppdoc/errata/index.htm http://www.microchip.com/10/lit/suppdoc/errata/index.htm is the current Microchip errata page. ~Page http://www.piclist.org/techref/microchip/gotchas.htm Modified by:JMN-EFP-786 replace-to: http://www.microchip.com/10/lit/suppdoc/errata/index.htm is the current Microchip errata page. http://www.sxlist.com/techref/microchip/i2c-eeprom.htm Modified by:JMN-EFP-786 replace-to:
For many years I've been irritated by the relatively large amount of code needed to talk to I2C EEPROMS, especially on c5x parts where stack depth is limited. I swore one day I'd try to do some highly optimised code. I finally got around to it, and 30-odd sheets of paper later, below is the result
It's primarily targetted at c5x applications, and was designed with the following criteria & limitations in mind (based on several real applicati ons) :
The following limitation of the current code is considered acceptable for the applications targeted : The number of bytes to read/write, and the RAM address to read/write are likely to be fixed at assemble time, so it doesn't matter if strange offsets etc. are required to these values, as this costs no code space, and can be handled easily with macros.
The code will read or write up to 14 bytes per call, although the write cache size of small eeproms will usually limit writes to 8 bytes or fewer. READ THE DATASHEET CAREFULLY to find the cache size for the device you are using, and be aware that this can vary between different manufacturers of the same part, and part revisions (e.g. Microchip 24LC01 vs. 24LC01B).
The current code body uses 68 words (including return). The code used to set-up addresses etc. is not counted as this will be different in different applications. Three words can be saved if 'fast mode' eeproms are used (e.g. 24LC01B at 5V). 4 registers are used,(plus FSR), one of which is for the eeprom address, which is preserved and can be eliminated if only one address will be used. No internal CALLs are used.
Explanatory notes - the following notes describe the more subtle aspects of the code - you don't need to understand them if you just want to use the code 'as is', but you will if you want to modify or optimise it further!
The code runs in two 'phases' - a write phase and a read phase, the latter only being used for read operations. Each phase begins with a start condition, followed by the control byte.
The variable 'cnt' holds two counts, one per nibble, stored as negative numbers, i.e. counting up to zero.
The flags byte is used as follows :
Using the same byte for flags and the bit count doesn't actually take any more code - the extra cycles to increment the count it by adding 20h are saved by not having to initialise the count - it's done when the flags are set up.
When SCL is set high, if SDA is tri-state (input or '1' output), the SDA output register bit may get set high (which would prevent SDA going low) by read-modify-write bit operations on SCL. This problem is avoided by clearing both SDA and SCL bits together with ANDWF. This will not cause SDA glitches, as the only time this clearing will change the SDA output register state is when SDA is tri-stated.
FSR is incremented on every byte - there's no point doing it conditionally as all that's needed to compensate is an assembly-time offset.
Note that in a few cases you will need to add a clrwdt somewhere inside the retry loop, depending on choice of eeprom, WDT prescale setting, and the delay between a write and any subsequent read or write attempt. The worst-case write time of a 24LC01B is 10mS, and the PIC's worst-case undivided watchdog period is 9mS.
Everyone's application is different, and so there is scope for further optimisation depending on particular requirements - here are a few suggestions :
If power consumption is an issue, you may want to add a delay to the retry loop to reduce the number of retries that will be attempted when the eeprom is busy writing.
A 10K pullup resistor is required from SDA to Vdd. No pullup is required on SCL as open-drain SCL drive is not required for eeprom applications.
Note that this code will not work as-is with the 12CE51x devices, and although it could be modified, it may not be especially optimal - the CE devices don't (all?) have a write cache, so the multi-byte write capability will not be useful in its current form.
;***********************************************************************
; compact I2C eeprom access code V1.0
; (C) Mike Harrison 1998
; example code for PIC12C508
;------------------------------------------------------- workspace
cnt equ 08 ; byte count register
flags equ 09 ; flags and bit count :
read equ 0 ; 1 to read bytes, 0 to write
addr equ 1 ; 0 to send eeprom address byte
rden equ 2 ; 1 to enable read next cycle
; b5-7 used as bit counter
temp equ 0a ; read/write data byte
eeadr equ 0b ; eeprom address
iiport equ gpio ; port address
sclbit equ 4 ; SCL port pin (no pullup required)
sdabit equ 5 ; SDA port pin (10K pullup to Vdd required)
lotris equ b'00101' ; TRIS setting with SCL and SDA outputs, other bits as required by application
hitris equ lotris+(1<,
movlw address-3 ; FSR offset due to unconditional increment
movwf fsr
movlw 0ef - bytes ; 2 writes (control, address) + n+1 reads (control,data)
call do_iic
endm
writeee macro bytes,address
; usage : writeee ,
movlw address-1
movwf fsr
movlw 0e0 - (bytes <<4) ; n+2 writes (control,address,data), no reads
call do_iic
endm
;-----------------------------------------------------------do_iic
do_iic ; read/write byte(s) to I2C EEPROM
; W & FSR to be setup as follows :
; read : EF - nbytes FSR = RAM address-1
; write : E0 - (nbytes<<4) FSR = RAM address-3
; eeadr holds eeprom address (preserved on exit)
; on exit, FSR points to the byte after the last one read/written
; nbytes can be up to 14, but eeprom write cache may limit this
movwf cnt
retry_iic
clrf flags ; initialise flags and bit count
phaseloop
movlw hitris
tris iiport ; ensure SDA high
bsf iiport,sclbit ; SCL high
bcf iiport,sdabit ; ensure SDA o/p reg low
movlw lotris
goto $+1 ; ensure Tsu:sta - can be omitted in fast mode
tris iiport ; sda low - start condition
movlw iiadr ; IIC control byte (write)
btfsc flags,rden
movlw iiadr+1 ; .. or read control byte if read pending
movwf temp ; IIC control byte
bcf iiport,sclbit ; scl low - code above ensures Thd:sta
byteloop ;
; start of byte read/write section
movlw lotris
btfss flags,read ; set SDA high (tri-state) if reading
btfsc temp,7 ; set SDA low only if writing and data bit = 0
movlw hitris ; (sda o/p register bit will be low)
tris iiport
goto $+1 ; wait set-up time
bsf iiport,sclbit ; clock high (may set SDA o/p reg bit high)
clc ; used later - done here for timing
movlw 0ff^(1<
// demo of Mike's optimised IIC code for eeprom access under hitech C
// (C) Mike Harrison 2001 email mike -at- whitewing.co.uk
// Note that this doesn't seem to work when local optimisation is enabled, as it
// appears to 'optimise' the asm code by simply ignoring it! Global optimisation seems to be OK.
// this is intended for inclusion within C source, not as a seperate 'extern' module
// It could be converted to the latter form easily, and this would avoid the above optimisation
// problem. (If anyone does this please let me have a copy!)
// see notes on original assembler version for more details.
// this version works under hitech C V7.86, and was tested on a PIC16C74
// if anyone who knows C better can suggest any improvements to the C side of this please let me know!
//asm macros
#define c 0
#define z 2
#define skpnc btfsc _STATUS,c
#define skpc btfss _STATUS,c
#define sec bsf _STATUS,c
#define clc bcf _STATUS,c
#define skpz btfss _STATUS,z
#define skpnz btfsc _STATUS,z
#define tris dw 0x60+
#define rp0 5
// define indf - missing from hitech
static volatile unsigned char INDF @ 0x00;
// eeprom port bits (PORT A)
#define sclbit 2
#define sdabit 3
#define ee_scl _PORTA,sclbit
#define ee_sda _PORTA,sdabit
#define hitris 0x1a // PORT A TRIS for SDA high
#define lotris hitris-(1<
http://204.210.50.240/techref/microchip/crack.htm
Modified by:JMN-EFP-786
replace-to:
Cracking / Guarding PICs
Its amost always harder to break copy protection on a PIC (and/or more expensive) than just hireing a programmer to duplicate the function of the original...
...and then its legal.
http://www.piclist.com/techref/microchip/ios.htm
Modified by:JMN-EFP-786 jamesnewton@efplus.com
preview-to: http://www.piclist.com/techref/microchip/rs485.htm
RS-485 (RS485)
http://www.piclist.com/techref/microchip/rs485.htm
Modified by:JMN-EFP-786 jamesnewton@efplus.com
preview-to: http://www.piclist.com/techref/microchip/rs485-fav.htm
RS485 Networking for intelligent house by Frank A. Vorstenbosch
http://www.piclist.com/techref/microchip/rs485-fav.htm
Modified by:JMN-EFP-786
replace-to:
PIC Microcontoller
Input / Output Methods
RS485 Networking for intelligent house by Frank A. Vorstenbosch
...my
colleague Brian wants all of his house rewired. Also, we have been
toying around with placing temperature sensors around our office (which
we need to prove that our airconditioning doesn't work).
After some thought about power-line RF drivers and such, we decided
on RS485-type network at a low data rate (16kbps approx). When used
with appropriate slew-rate limited drivers (MAX487) you can have relatively
long stubs on your network. The network is terminated on both ends
with 100R, with two 1k resistors biasing the network into a '0' state.
The temperature sensors I've built use just four active components:
a DS1621 I2C temperature sensor, a MAX487 line driver, a PIC 12C509
and a 78L05. We're planning to use four-wire cable at home (+12V, GND
and the two differential data lines) and cat-5 network cabling in
the office.
Below is the code for the RS485 protocol that we use. This code is
heavily macro'd, but should be readable. If enough people show
interest then I'll put the include files needed and the rest of the
(not quite working) temperature sensor application up on my or Brian's
home page.
Frank
Note: This source requires PC graphics to show the diagrams.
Note 2: JBS - BTFSC+GOTO
JBC - BTFSS+GOTO
LOOP - DECFSZ+GOTO
LOOPI - INCFSZ+GOTO
STR - MOVWF
LD - MOVF,W
JZ - SKPNZ+GOTO
FRAME..FEND sets up a set of local registers
etc.
; IMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM;
; : :
; : 485.I :
; : :
; : RS-485 home automation bus interface. :
; : :
; : Copyright 1997, Frank A. Vorstenbosch. :
; : :
; HMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM<
;
; Uses: FLAG_IDSTRING - a flag, somewhere in a register
; FLAG_BROADCAST - a flag, somewhere in a register (can be same as
FLAG_IDSTRING)
; RxTxD - a port pin for received and transmitted data
; TxEN - another port pin set high to enable transmitter
frame 485
byte Shifter485
byte Counter485
byte TempA485
byte CRCLow485
byte CRCHigh485
byte Timer485
static OurTC
fend 485
#define Timer485 TempC485
; ZDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD?
; 3 3
; 3 Description. 3
; 3 3
; @DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDY
; Two twisted pairs in cable, one for data and one for power/ground. Power is
; supplied as 9..12V as measured on the peripheral -- a transmitter may take
; approx. 120mA when using 100j terminators, or 104mA using 120j terminators
; in addition to any local power needs.
;
; The network protocol is designed to run on 4MHz 12-bit PICs at ~16kb/s in
; software. The longest packet takes less than 23ms to send, the shortest
; packet less than 2.5ms. CSMA is used to prevent two devices transmitting
; at the same time.
; Synchronous message format:
;
; - Start bit (100-250us duration)
; Peripherals try sending a start bit of 100-200us, then float the
; line, see if the line goes back to 0, and if it does, then drive
; it low for the remainder of the 20us, then start sending data.
; If the line is still driven to 1, then the peripheral will back
; off until the bus is idle for >100us, then try sending another
; start bit. The peripheral will try progressively longer start
; bits up to the limit of 200us. The host uses a 250us start bit
; to give it priority over all peripherals (this also means that
; most peripherals can ignore start bits <250us long).
; - Flags byte
; 7..6 - transfer direction:
; 00 - peripheral to host
; 01 - peer to peer (UNIM)
; 10 - host to peripheral
; 11 - reserved
; 5 - reserved
; 4..0 - data length
; - Peripheral or destination address byte or 255 for broadcast
(Flags<7..6>=10)
; - Optional source address byte (Flags<7..6>=01) (UNIM)
; - Command byte (Flags<7..6>=10) or status byte (Flags<7..6>=00)
; Command
; 0 - Are you there? (Returns up to 31 byte ID string)
; 1 - Data poll
; 2..255 - User defined commands
; Status
; 0 - OK
; 1 - CRC error
; 2 - Command error
; 3 - Parameter error
; 4 - No (more) data
; 5..254 - User defined errors
; 255 - Data broadcast
; - 0..31 data bytes
; - CRC-16 over Flags, Address and Data bytes
; ZDDDDDDDDDDDD//DDDDDDDDDDD? Z
; Start line idle 3 100-250us 325us3
; DDDDDDDDDDDDDDDDDY @DDDDY
; ZDDDD? Z
; 0-bit 325us325us3
; Y @DDDDY
; ZDDDDDDDDDD? Z
; 1-bit 3 50us 325us3
; Y @DDDDY
;
; The low period at the end of each byte is 50us rather than 25us, giving
; devices time to process the byte. Thus, the byte 0x54 would be transmitted
as:
;
; ZDDDD? ZDDDDDDDDDD? ZDDDD? ZDDDDDDDDDD? ZDDDD? ZDDDDDDDDDD?
ZDDDD? ZDDDD? Z
; 325us325us3 50us 325us325us325us3 50us 325us325us325us3 50us
325us325us325us325us3 50us 3
; Y @DDDDY @DDDDY @DDDDY @DDDDY @DDDDY
@DDDDY @DDDDY @DDDDDDDDDDY
; ZDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD?
; 3 3
; 3 Local definitions. 3
; 3 3
; @DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDY
ifndef FLAG_IDSTRING
ifndef FLAG_BROADCAST
error "FLAG_IDSTRING and/or FLAG_BROADCAST must be defined"
endif
#define FLAG_IDSTRING FLAG_BROADCAST
endif
ifndef FLAG_BROADCAST
#define FLAG_BROADCAST FLAG_IDSTRING
endif
; ZDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD?
; 3 3
; 3 Receive a message from the RS485 bus. 3
; 3 3
; @DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDY
;
; In: W - Size of receive buffer
; fsr - pointer to first byte of receive buffer
; Act: Receive a message from the RS485 bus.
; Out: Receive buffer filled in with command and data bytes
; Counter485 - Number of data bytes
; W - error code
; 0 - no error
; 1 - message was not addressed to us
; 2 - message was too long for our buffer
; 3 - CRC error
; Regs: Shifter485, Counter485, fsr, tmp, TempA485, TempB485, TempC485
; Note: Assumes that the start bit has already been detected.
; Uses one stack level internally, can only be called from top level
ReceiveMessage str Counter485
TRACE 1,"ReceiveMessage"
clr CRCHigh485
clr CRCLow485
jbs RxTxD,$ ; wait for start bit to end
call RM_Byte ; receive flags & length
byte
retbc Shifter485,7,1 ; if peripheral-to-host then
ignore it
ld Shifter485
str TempA485
subwf Counter485,w
retc 2
movlw 31
andwf Shifter485,w
str Counter485
inc Counter485 ; count command as a data
byte
bcf FLAG_BROADCAST ; assume is's not a
broadcast
call RM_Byte ; receive device ID
call DeviceID
xorwf Shifter485,w ; is the message addressed
to us personally?
jz RM_Loop
incf Shifter485,w ; or is it a broadcast?
retnz 1
bsf FLAG_BROADCAST
RM_Loop call RM_Byte ; receive command/data byte
ld Shifter485
inc fsr
str ind
loop Counter485,RM_Loop
call RM_Byte ; receive first CRC byte
call RM_Byte ; receive second CRC byte
ld TempA485
str Counter485
ld CRCHigh485
xorwf CRCLow485,w
retnz 3 ; CRC error
movlw 31
andwf Counter485 ; clear unwanted bits in the
length byte
retlw 0
; zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
RM_Byte ldk Timer485,8<<<4
RMB_Loop jbc RxTxD,$ ; wait for bit to start
clc
RMB_Inner incfsz Timer485 ; time the length of the bit
jbs RxTxD,RMB_Inner
; here the low nibble of Timer485 should be 6 or 13
btfsc Timer485,3 ; detect 1 bit if 9 counts
or more
stc
ld status ; carry is LSB of status reg
ister
rl Shifter485 ; shift bit into register
xorwf CRCLow485,w
clrc
rr CRCHigh485
rr CRCLow485
andlw 1
xorwf CRCLow485
movlw 0xa0
skipz
xorwf CRCHigh485
movlw 0x0f
iorwf Timer485
loopi Timer485,RMB_Loop
retlw 0
; ZDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD?
; 3 3
; 3 Entry point to subroutines for SendMessage. 3
; 3 3
; @DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDY
SM_Byte_tmp ld tmp ; [1]
SM_Byte str Shifter485 ; [1]
SM_Byte_Sh ldk Timer485,8<<4 ; [2]
jp SMB_Loop ; [2]
; ZDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD?
; 3 3
; 3 Send a message on the RS485 bus. 3
; 3 3
; @DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDY
;
; In: W - Number of data bytes in message
; tmp - Status byte
; fsr - pointer to first byte to transmit
; Act: Send a message on the RS485 bus.
; Out: W - error code
; 0 - no error
; 1 - failed to send message after 8 attempts
; Regs: Shifter485, Counter485, CRCHigh485, CRCLow485, Timer485, fsr, tmp,
(OurTC)
; Note: Uses one stack level internally, can only be called from top level
SendMessage str Shifter485
TRACE 1,"SendMessage"
ldk Counter485,8
clr CRCHigh485
clr CRCLow485
clr gpio ; set TxEN low
movlw NORMAL_TRIS ; float RxTxD (with pull-up)
tris gpio
SM_WaitIdle movlw 30
subwf OurTC,w ; shorter delay if longer
start bit used
str Timer485
SMWI_Loop jbs RxTxD,SM_WaitIdle ; [2] wait for bus to be
idle for 100..150us
loopi Timer485,SMWI_Loop ; [3]
movlw TxEN_MASK|RxTxD_MASK
btfss RxTxD ; last chance: if activity
on bus then don't set TxEN high
str gpio ; drive TxEN high
jbc TxEN,SM_WaitIdle ; wait some more if the STR
wasn't executed
movlw NORMAL_TRIS&~RxTxD_MASK ; quickly drive RxTxD to
high level
tris gpio
movlw NORMAL_TRIS ; and then float it again
tris gpio
ifdef HOST
movlw 36 ; host uses 250us timeout
else
movlw 13
addwf OurTC,w
addwf OurTC,w
endif
str Timer485 ; wait for 100..200us
SM_SendStartH call Delay4Ticks ; [4]
loop Timer485,SM_SendStartH ; [3]
clr gpio ; disable transmitter
brake ; it takes ~2.5us for the
MAX487 to go into read mode
movlw TxEN_MASK ; moved here to prevent
back-to-back I/O accesses
jbs RxTxD,SM_BackOff ; if RxTxD still high, then
back off
str gpio ; enable transmitter again
movlw NORMAL_TRIS&~RxTxD_MASK ; start driving RxTxD pin
(to low state)
tris gpio
call Delay9Ticks
ld Shifter485
andlw 31
str Counter485
call SM_Byte_Sh ; send flags & length byte
call Delay13Ticks
call DeviceID
call SM_Byte ; send our ID
call Delay16Ticks
call SM_Byte_tmp ; send status byte
jbs FLAG_IDSTRING,SM_LoopCode
test Counter485
jz SM_CRCNoData ; [2]
call Delay8Ticks ; [8]
jp SMLD_Enter ; [2]
SM_LoopData call Delay12Ticks ; [12]
SMLD_Enter ld ind
inc fsr
call SM_Byte ; send data byte
loop Counter485,SM_LoopData
jp SM_SendCRC
SM_LoopCode brake
movlw 31
andwf fsr,w
str tmp
movlw IDString
addwf tmp,w
call PCW
inc fsr
call SM_Byte ; send ID string byte
loop Counter485,SM_LoopCode
brake
SM_SendCRC brake
nop
SM_CRCNoData call Delay8Ticks
ld CRCHigh485
str tmp
ld CRCLow485
call SM_Byte ; send first CRC byte
call Delay16Ticks
call SM_Byte_tmp ; send second CRC byte
movlw NORMAL_TRIS
clr gpio ; disable transmitter
tris gpio ; float RxTxD
retlw 0 ; return OK
; zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
SM_BackOff incf OurTC,w ; increment our timer
andlw 7 ; only 3 LSBs used
str OurTC
decfsz Counter485,f ; after 8 attempts, return
error to caller
retlw 1
jp SM_WaitIdle
; DDDDD Subroutine for SendMessage DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
SMB_Loop bsf RxTxD
ld CRCLow485
xorwf Shifter485,w
clc
rr CRCHigh485
rr CRCLow485
andlw 1
xorwf CRCLow485 ; if W=0, then do nothing,
skipz ; otherwise CRC^=0xa001
movlw 0xa0
xorwf CRCHigh485
SMB_Wait1 inc Timer485 ; [1] 25us high bit for a
'0'
movlw 0xf0 ; [1]
jbc Timer485,1,SMB_Wait1 ; [3/2]
rl Shifter485
jnc SMB_ShortBit
SMB_Wait2 inc Timer485 ; [1] 50us high bit for a
'1'
jbc Timer485,3,SMB_Wait2 ; [3/2]
brake
nop
SMB_ShortBit andwf Timer485 ; W=0xf0 here
bcf RxTxD
SMB_Wait3 inc Timer485 ; [1] 25us low bit
nop ; [1]
jbc Timer485,2,SMB_Wait3 ; [3/2]
movlw 0x0f
iorwf Timer485
loopi Timer485,SMB_Loop
retlw 0
; DDDDD EOF 485.I DDDDD
http://www.piclist.com/techref/microchip/rs485.htm
Modified by:JMN-EFP-786
replace-to:
The practical differences of 232 vs 485 are:
- single-dended versus differential
- sender-receiver only versus multidrop possible
Doesn't RS485 typically use a 9 bit address byte protocol for multidrop communications?
see also:
-
http://www.chipcenter.com/circuitcellar/july99/c79bppdf.pdf 'The Art and Science of RS-485'
- http://www.embedded.com/1999/9908/ "Controlling the Transmit Enable Line on RS-485 Transceivers" Aug'99 Embedded Systems Programming
http://204.210.50.240/techref/microchip/rs485.htm
Modified by:JMN-EFP-786
replace-to:
Olin Lathrop says:
The architectural difference between RS-232 and RS-485 is that 232 is a
bi-directional point to point link, whereas 485 is a single channel bus.
RS-232 can also carry additional signals used for flow control and modem
control.
Electrically, each 232 signal uses a single wire with symmetric voltages
about a common ground wire. 485 uses two wires to carry the single signal
differentially. Both wires use 0 to 5 volts, with the two wires being
driven opposite. The purpose of this is to provide noise immunity, because
much of the common mode signal can be rejected by the receiver.
{ed: Although it is not a part of the specifications, in most cases...} Both 232 and 485 use the same asynchronous encoding of individual bytes.
This is the familiar start bit, followed by data bits (usually 8), followed
by stop bits (usually 1 nowadays). Both the transmitter and receiver have
to agree on the bit rate in advance. All timing within a byte is relative
to the leading edge of the start bit. The PIC USART module was deliberately
designed to support this encoding in its asynchronous (UART) mode. The low
level PIC code is the same for both 232 and 485 because it is transmitting
and receiving bytes via the UART (or a software UART).
The big difference to the software is that only one device on a 485 bus can
transmit at a time, whereas there are separate dedicated transmit and
receive channels for the single device at the other end of a 232 link.
There must also be external hardware that enables driving the bus when
transmitting. This hardware is usually controlled from a separate PIC pin,
but there are also some "automatic" schemes.
The RS-485 standard (well sortof, "RS" actually stands for "recommended
standard") defines how to transmit and receive bytes to/from the bus
electrically. Issues like flow control, collision avoidance, and data
reliability are left completely as an exercise to the implementer. In a
pure RS-485 system, these have to be dealt with in the protocol. As you can
imagine, there are lots of ways of dealing with this, and the right choice
depends on the particular system. The solution often envolves wrapping data
into packets, each with a checksum, and some kind of ACK/retry scheme. So
far I've dealt with collision avoidance by having a single master with all
other bus devices being slaves that only talk when asked to by the master.
Note that this can still give the appearance to upper levels of slaves
initiating data transfer if the master polls each slave often enough (this
is also how USB works, by the way).
Each RS-485 system is different, and therefore probably requires a different
protocol. You inquiry to the PIC list has prompted me to put some RS-485
information on my PIC development resources web page. This includes an
excerpt of the protocol specification for one real-world system, provided as
an example.
http://www.piclist.com/techref/microchip/rs485.htm
Modified by:JMN-EFP-786 jamesnewton@efplus.com
preview-to: http://www.piclist.org/techref/postbot.asp?by=time&id=piclist\2001\02\25\113704a
PICList post "RS485 code?"
http://www.piclist.com/techref/microchip/time.htm
Modified by:JMN-EFP-786 jamesnewton@efplus.com
preview-to: http://www.piclist.org/techref/postbot.asp?by=time&id=piclist\2001\02\26\023715a
PICList post "simple one-second timer"http://www.piclist.com/techref/microchip/time.htm
Modified by: jamesnewton@geocities.com
ON 20010226@2:31:54 PM
http://www.piclist.com/techref/microchip/time.htm
Modified by:JMN-EFP-786 jamesnewton@efplus.com
archive:-to: http://www.piclist.org/techref/postbot.asp?by=time&id=piclist\2001\02\26\023715a
PICList post "simple one-second timer"
ON 20010226@2:33:10 PM
http://www.piclist.com/techref/microchip/time.htm
Modified by:JMN-EFP-786 jamesnewton@efplus.com
archive:-to: http://www.piclist.org/techref/postbot.asp?by=time&id=piclist\2001\02\22\191446a
PICList post "Timer Tribulations"
ON 20010226@2:51:07 PM
http://www.piclist.com/techref/microchip/time.htm
Modified by:JMN-EFP-786 jamesnewton@efplus.com
to archive:http://www.piclist.org/techref/postbot.asp?by=time&id=piclist\2001\02\23\052917a
PICList post "Re: [PIC] Timer Tribulations" Using house mains w/o pugging in
ON 20010226@4:46:32 PM
http://www.piclist.com/techref/microchip/time.htm
Modified by:JMN-EFP-786 jamesnewton@efplus.com
to says
test
ON 20010227@10:51:38 AM
http://www.sxlist.com/techref/microchip/index.htm
Modified by:JMN-EFP-786 jamesnewton@efplus.com
to Interested:/techref/member/JMN-EFP-786/index.htm
JMN-EFP-786
ON 20010227@2:11:26 PM at page:
http://www.sxlist.com/techref/microchip/devprogs.htm
JMN-EFP-786 James Newton added 'Archive
http://www.piclist.org/techref/postbot.asp?by=time&id=piclist\2001\02\26\224059a
PICList post "Picstart upgrade (voltage trim)"'
ON 20010228@12:25:31 PM at page:
http://www.piclist.com/techref/microchip/16f84-rs232-an.htm
AK--373 Andy Kelley added 'claim
ON 20010228@12:28:10 PM at page:
http://www.piclist.com/techref/microchip/16f84-rs232-an.htm
AK--373 Andy Kelley edited the page