I'm running a network of instruments using a 4 wire RS-485 scheme,
where there is a single master and multiple slaves. All the slave
receivers connect to the master transmitter, and all the slave
transmitters connect to the master receiver. I have logic that
automatically switches all the slaves into receive mode whenever the
master drives it's transmit signal active.
All the slaves contain PICs (18fxxxx) and use the UART to implement the RS-485.
I Now want to make a different version that operates as a party line,
with all transmitters and receivers connected together. To do so, each
node has to know how to turn off its transmitter as soon as it has
finished a transmission.
What's the cleanest way, in a PIC, to do this? I think I can't use the
UART Transmit interrupt, because it does not tell you when the last
byte has gone out on the wire. I know I could use a timer but consider
that my solution of last resort. I'm looking for any other ideas that
would let me turn off the transmitter at the earliest possible moment,
as soon as the last transmitted byte is on the wire.
> I Now want to make a different version that operates as a party line,
> with all transmitters and receivers connected together. To do so, each
> node has to know how to turn off its transmitter as soon as it has
> finished a transmission.
There's a flag which tells you when TXREG is ready to accept more data,
and another flag which tells you when Stop bit has been transmitted.
You could use this latter one.
I also add some little delay past it (say 2 bit time) to be safe.
>What's the cleanest way, in a PIC, to do this? I think I
>can't use the UART Transmit interrupt, because it does not
>tell you when the last byte has gone out on the wire.
Actually you could do this. It does require some logic at the receiving end
to know that the message has ended, but I have seen it done where the
processor was more of a state machine than a processor as we know it.
What you do is put an extra character at the end of message (typically 0xFF)
and the receiver then has to be prepared for a corrupted character after the
end of message character that precedes the 0xFF, as the 0xFF can be
corrupted because you may be turning off the RS485 transmitter part way
through the start bit. If you turn it off after the start bit, then there is
no corruption, bit depending on how fast another device can turn round to
transmit then you may get the first character from the next transmitter
corrupted because the start bit occurs inside the 0xFF character time.
You will also need to look at the timings of the UART to ensure that the
TxBufEmpty flag doesn't occur during the stop bit of the previous character.
I agree that you cannot use the uart interrupt, since it only interrupts
when there is room in the transmit buffer. There is still possibly data
being shifted out. I think the only option is to use a timer interrupt
instead of the uart interrupt. You can then check to see if the transmit
shift register is empty.
Note that the uart in the 24H series lets you generate an interrupt when
there is room in the transmit buffer, when the last character has been
shifted out, or when a character has been moved from the transmit fifo
into the shift register (there's room for another character in the fifo).
> I'm running a network of instruments using a 4 wire RS-485 scheme,
> where there is a single master and multiple slaves. All the slave
> receivers connect to the master transmitter, and all the slave
> transmitters connect to the master receiver. I have logic that
> automatically switches all the slaves into receive mode whenever the
> master drives it's transmit signal active.
>
> All the slaves contain PICs (18fxxxx) and use the UART to implement the
> RS-485.
>
> I Now want to make a different version that operates as a party line,
> with all transmitters and receivers connected together. To do so, each
> node has to know how to turn off its transmitter as soon as it has
> finished a transmission.
>
> What's the cleanest way, in a PIC, to do this? I think I can't use the
> UART Transmit interrupt, because it does not tell you when the last
> byte has gone out on the wire. I know I could use a timer but consider
> that my solution of last resort. I'm looking for any other ideas that
> would let me turn off the transmitter at the earliest possible moment,
> as soon as the last transmitted byte is on the wire.
>>another flag which tells you when Stop bit has been transmitted.
>>You could use this latter one.
>>
> which flag is that? Is it in the TXSTA register ?
Well, should be TRMT... and don't remember where it is now!
The other one is TXIF...
Try searching for them, I'll be back later.
I work with rs422 similar projects almost every day.
The way you need to do is to send let say 10 byte of data
the last one is modulo 256 checksum. When receiver gets the data
based on checksum value can detect if there is an error.
As far as what can you send there is no limit you can send
any info you want. Here is basic frame looks like.
The flag is TRMT in the TXSTA register
Taher Uzri
----- Original Message -----
From: "Neil Baylis" <spam_OUTneil.baylisTakeThisOuTgmail.com>
To: "Microcontroller discussion list - Public." <.....piclistKILLspam@spam@mit.edu>
Sent: Thursday, June 14, 2007 11:32 AM
Subject: [PIC] 2 Wire RS-485 question
> > another flag which tells you when Stop bit has been transmitted.
> > You could use this latter one.
> >
>
> Dario..
>
> which flag is that? Is it in the TXSTA register ?
>
> Neil
> --
> I work with rs422 similar projects almost every day.
RS422 is point to point only. I'm using multidrop bus topolog, so must be 485..
> I am not sure if this is what you are asking.
>
With multiple drivers able to drive the bus, each driver has to know
when it can disable itself, once it has finished transmitting. In
order to operate the bus at the maximum speed, the driver needs to be
disabled as soon as possible after the last bit has been sent.
Since it's a party line, I would be receiving my own transmissions.
Maybe I could disable the driver when I successfully receive the last
byte I sent. The timing would be right, but is risky if something goes
wrong with the transmission.. then the driver would never disable. And
such a scheme means two interrupts per byte, which is ugly.
I like the idea of tacking an extra byte onto the message. I'll have
to think more about that, might work out fine.
Oh yes, I see now. Unfortunately, it doesn't generate an interrupt.
It's going to set about 100 usec after the last interrupt. (I'm doing
115200 Baud). That's too long to just spin and wait. (My nodes are
pretty busy).
But the receiver (who's going to send the next message) does get an
interrupt, and will be putting something on the wire very quickly,
within a few microseconds.
It's looking like a timer of about 100 usec is the best option. I
would start the timer when I get the interrupt for the last
transmitted byte, and disable the transmitter when the timer expires.
> I'm running a network of instruments using a 4 wire RS-485 scheme,
> where there is a single master and multiple slaves. All the slave
> receivers connect to the master transmitter, and all the slave
> transmitters connect to the master receiver. I have logic that
> automatically switches all the slaves into receive mode whenever the
> master drives it's transmit signal active.
>
> All the slaves contain PICs (18fxxxx) and use the UART to implement the
> RS-485.
>
> I Now want to make a different version that operates as a party line,
> with all transmitters and receivers connected together. To do so, each
> node has to know how to turn off its transmitter as soon as it has
> finished a transmission.
>
> What's the cleanest way, in a PIC, to do this? I think I can't use the
> UART Transmit interrupt, because it does not tell you when the last
> byte has gone out on the wire. I know I could use a timer but consider
> that my solution of last resort. I'm looking for any other ideas that
> would let me turn off the transmitter at the earliest possible moment,
> as soon as the last transmitted byte is on the wire.
You might be able to get away with this:
Send an extra byte at the end of your message. As soon as you get the UART
transmit interrupt for this byte immediately turn off your transmitter.
Depending on your maximum interrupt latency you will end up with a short
'glitch' on the outgoing wire. This may or may not be interpreted as a start
bit by other devices. You could possibly get rid of the glitch by adding an
RC network between the PIC and the RS485 chip. Yes, I know, this is sick!
piclist-bounces@mit.edu wrote:
> With multiple drivers able to drive the bus, each driver has
> to know when it can disable itself, once it has finished
> transmitting. In order to operate the bus at the maximum
> speed, the driver needs to be disabled as soon as possible
> after the last bit has been sent.
hmmm. I recall vaguely an article I read about this:
not sure if this is what you are looking for, and its been
a while since i read it, but ISTR there is a circuit
illustrated that uses the humble 555 to automatically
disable the driver after the last bit is sent.
Neil
I've also seen a hardware solution where the TX line from the
processor is used to trigger a fast-attack switch to turn the TX on
when it detects the start bit. It includes slow decay that delays the
TX disable for about one byte length. The top speed is limited by the
attack time but it was working fine at 38400b/s although the start bit
gets truncated by a uS or so.
> Oh yes, I see now. Unfortunately, it doesn't generate an interrupt.
> It's going to set about 100 usec after the last interrupt. (I'm doing
> 115200 Baud). That's too long to just spin and wait. (My nodes are
> pretty busy).
>
> But the receiver (who's going to send the next message) does get an
> interrupt, and will be putting something on the wire very quickly,
> within a few microseconds.
>
> It's looking like a timer of about 100 usec is the best option. I
> would start the timer when I get the interrupt for the last
> transmitted byte, and disable the transmitter when the timer expires.
> Oh yes, I see now. Unfortunately, it doesn't generate an interrupt.
> It's going to set about 100 usec after the last interrupt. (I'm doing
> 115200 Baud). That's too long to just spin and wait. (My nodes are
> pretty busy).
>
> But the receiver (who's going to send the next message) does get an
> interrupt, and will be putting something on the wire very quickly,
> within a few microseconds.
>
> It's looking like a timer of about 100 usec is the best option. I
> would start the timer when I get the interrupt for the last
> transmitted byte, and disable the transmitter when the timer expires.
Well, here is another idea based on my previous one:
In the transmitter:
(1) Send an additional byte at the end of each 'packet' (in response to
TXIF)
(2) One BIT (not byte!) time later disable the transmitter
You would still need to delay between steps one and two, but that would only
be for about 10 uSec instead of 100. Also, the exact delay is not
particularly important, just so that it long enough to ensure the entire
start bit is transmitted before the transmitter is turned off. This might
let you do some other work while waiting to disable the transmitter.
In the receiver:
(1) Expect an additional byte at the end of the packet. You will see a
proper 'start' bit because of the delay between steps one and two above. The
receiver may or may not detect a framing error, depending on the idle state
of the link when no transmitter is active. This can be prevented by adding
appropriate biasing resistors: a pulldown on one RS485 data line and a
pullup on the other.
(2) Immediately after receiving the RXIF status for the additional byte the
receiver can enable its own transmitter and start blasting away.
In other nodes ('watchers'):
Other systems on the wire will see a continuous stream of bytes.
> In the transmitter:
>
> (1) Send an additional byte at the end of each 'packet' (in response to
> TXIF)
> (2) One BIT (not byte!) time later disable the transmitter
(and related to other answers - just my opinion).
I'd avoid sending another "byte", i.e. another start bit etc. I
preferred just keeping the Bus "high" for some bit-time.
I also find sooo "oldish" :) a method, to use an external 555 or other
switch to recover from TX mode into RX mode...
Having a MCU should allow for easier handling.
All the RS485 half duplex stuff I've done has always used the TXIF to
determine when to put another byte into the transmit buffer. I use the
TXSTA.TRM bit to determine when the shift register is empty so that I
can disable the RX485 driver. I don't bother looking at this flag until
I know I've put the last byte into the TXREG. Then when TXIF is true
(TXREG is now empty) I test TXSTA.TRM.
part 1 754 bytes content-type:text/plain; charset="us-ascii"; format=flowedHere is how I solved this problem in a product that's working for
more than 3 years now and I used this solution since then (see the
attachement).
When idle, the usart TX line is 5V, so Q1 is in conduction and the
transceiver is in receive state. So you listen to the comms on the
bus. When you send a byte on the usart at each 0V on TX line the
transceiver goes in transmit state, it's data input is tied to ground
and puts a 0 logic on the bus line. As soon as the bit ends it
releases the line and goes in receive state.
The bus has to be held in 1 logic by adding 2 more resistors at
master's end (or you can distribute this resistors all over the
network) from 485A line to +5V and from 485B line to GND.
Hope it helps,
Mircea Chiriciuc
part 2 18304 bytes content-type:image/jpeg; name="485_small.jpg"; (decode) part 3 35 bytes content-type:text/plain; charset="us-ascii" (decoded 7bit)
Mircea, I like this solution. Just curious, what Baud rate are you
using? The resistors won't pull the line to the '1' state as quickly
as the driver would.
BTW, I already have the resistors at each end of the bus, so I
wouldn't have to add them. Just need an inverter (i.e. your Q1) to
drive the enable from the TX data.
>
> When idle, the usart TX line is 5V, so Q1 is in conduction and the
> transceiver is in receive state. So you listen to the comms on the
> bus. When you send a byte on the usart at each 0V on TX line the
> transceiver goes in transmit state, it's data input is tied to ground
> and puts a 0 logic on the bus line. As soon as the bit ends it
> releases the line and goes in receive state.
> The bus has to be held in 1 logic by adding 2 more resistors at
> master's end (or you can distribute this resistors all over the
> network) from 485A line to +5V and from 485B line to GND.
>
> Hope it helps,
I'm running the network at 38400 baud but whet I came up with this
solution I have run tests with two RS232-RS485 convertors built on a
testboard between two computers, on 500m of UTP cable and it worked
at 115200 baud without loosing a single byte. With a turn on/off time
of 4ns, Q1 toggles the RE/DE pin fast enough to keep the bit within
accepted tolerance even for 115200. If cable capacitance is your
concern, choose the two line biasing resistors close to minimum
accepted value. At 38400 I even didn't had to terminate the line. Do
the math on your cable parameters at 1200m which if I recall right is
the maximum length of a 485 line.
The resistors on A and B line are for holding the line steady in 1
logic to increase the noise immunity of the network (if I recall
right, the 485 specs are not to fresh in my memory).
After all it's a simple schematics to run a test on breadboard and
see for your self. Take care on the power line decoupling and GND
routing though.
And remember, always have fun :)
My best,
Mircea Chiriciuc
At 09:35 PM 6/16/2007, you wrote:
>The resistors won't pull the line to the '1' state as quickly
>as the driver would