Category Archives: 18F14K22

PIC talks UART on RS-485

PIC talks UART on RS-485

Overview

RS-485 is a differential serial communications link. The link is not open-ended and doesn’t use the local hardware’s ground. The specification is defined by hardware; not the actual communications protocol. I’ve personally ran into dozens of different protocols using RS-485 that including MODbus, BACnet MS/TP, Johnson Controls N2Open, etc. Officially “RS-485” is now TIA-485-A but you’ll find it called RS-485 or EIA-485 more times than not, I’ll switch to referencing this standard as “TIA-485” or just 485 for the remainder of the article. TIA-485 was designed to be a multi-drop bus for multiple devices and multiple “masters” on one communications trunk. Most commonly you’ll find TIA-485 on a 2, 3 or 4 wire circuit with 24-18 gauge wire. The specification boasts of long distance communication relative to its old cousin RS-232, up to 4000ft. TIA-485 is still heavily in use with power control, automation, and monitoring systems. Nearly all commercial and industrial controls systems use TIA-485 to date. You can read more in TSB-89-A.pdf including some of the definitions I’ve used.


 

The communication

It is important to remember TIA-485 is an electrical specification, not a software protocol nor are their recommended physical interfaces. There are other specifications which sit on top of the TIA-485 specifications, BACnet MS/TP and MODbus being two popular choice in industry but likely not your best choice as a hobbyist. The specification was embraced by industry when it was released by the EIA in 1983 so it makes a great option for wired communications for microcontrollers. I’ve personally seen many 6502-variant systems with robust proprietary protocols on top of the bus so you should be able to develop your own protocol with out too much overhead on many of the PIC mid-range devices.

Typical speeds are 9,600 to 115k baud. In my experiences I’ve seen 9,600, 38,400 and 76,800 baud used most commonly. Typically longer segments use slower speeds for reliability, however if you have short runs you can run your bus into the multiple Mbps range.
Multiple devices? Yes, In practice the specification defines up to 32 “loads” on one bus. There have been some clever devices developed to operate as a “1/2 load” allowing for 64 devices on one segment.

Some of the actual specifications:

  • Balanced interface
  • 120 Ohm typical impedance
  • -7 to +12V common mode range
  • 200mV differential voltage between twisted pair
  • 100Kbps @ 4000ft (much faster the shorter you limit the bus)
  • full duplex (4-wire) or half duplex (2-3 wires)
  • 32 nodes

In my example I use a USB to RS-232 adapter to my PC followed by a RS-232 to TIA-485 adapter from B&B Electronics model number: 485SD9TB ($75).


 

The circuit

For this circuit I pulled some small 20-pin PIC development boards I had created for some experimentation with TIA-485. I hadn’t gotten to use these yet and as these were the second PCB I had ever developed in Eagle CAD I found I had made a few mistakes so I will not publish the circuit as it would be a disservice to you. You’ll note a little dead-bug wiring with the /RESET pull-up resistor. I also placed some of my jumpers in a manor I had wished I configured differently. Perhaps I’ll re-manufacture these for the more expanded board in a future article. Below I have provided a “sample” circuit which is the RS485 click board if you’re using a MikroElektronika development board. I used the Analog Devices ADM485 for my circuit although I’ve been testing some polarity agnostic devices from other manufactures. The ADM485 is a low power transceiver; You can review its specification sheet in this PDF. I used a simple test configuration as shown in this diagram:

EIA485_circuit

 

In your circuit you will want to connect your UART TX pin to the transceiver DI pin. A digital output pin to DE to enable/disable the driver. Your UART RX pin will be wired to the ADM485 RO pin and another digital output connected to the RE pin to enable/disable the receiver. The other connections on the transceiver include the power and the A and B bus pins that you connect to other transceiver chips as shown below. I used a common two wire bus configuration.

IMG_4781

 

This is photo was pulled from the TI RS-485 Reference Design Guide

Typical daisy-chain bus structure

Typical daisy-chain bus structure.

 

EIA-485 home-brew development board

EIA-485 home-brew development board

Francesco scolded me for trying to pass off this mostly-hardware article without at least a hint of a schematic; what was I thinking? 🙂 Below is the schematic of the RS485 click from MikroElecktronika. This is a good starting point. You’ll notice some options to drop in termination resistors (jumpers 32, 33, and 34 depending on how you want to reference your signal, talking about ground loops and ground potential difference is beyond the scope of this article but that is the purpose for the jumper configurations). This board was set up for half-duplex as was mine. This is the most common configuration of the 485 bus.

A sample schematic for a UART to 485 interface. Note the ADM485 is pin compatible with the SN75176. The schematic shown is the actual schematic of the RS485 click board from MikroElektronika.

A sample schematic for a UART to 485 interface. Note the ADM485 is pin compatible with the SN75176. The schematic shown is the actual schematic of the RS485 click board from MikroElektronika.

The Code

The code is no different from using the standard UART on the PIC. You can read more about that on our UART article or use any UART code you desire. To use multiple devices you will may have to develop your own protocol for addressing and sending/receiving/replying to data. I’ve place this on my “PROJECTS TO-DO” list and will link that project in once I get to it.

For my testing I re-used my code on the PIC talks UART article, but in this case I had previously made a TIA-485+20 pin PIC development board so I decided to port my code to the PIC18F14K22. Instead of ‘Hello world’ I opted for the program to simply repeat a character for easy testing.

You may recognize this simple XC8 UART transmit function:


void uart_xmit(unsigned int mydata_byte) {   //this function sends 1 character to the UART transmit buffer
while(!TXSTAbits.TRMT);   // make sure buffer full bit is high before transmitting
TXREG = mydata_byte;   // transmit data by loading variable into the TXREG register
}

void write_uart(const char *txt){
    while(*txt != 0) uart_xmit(*txt++);     //this send a string to the TX buffer through my 'uart_xmit' function
                                            //one character at a time
}

And then the actual code to send the repeating characters:


while (1) {
 write_uart("Hello, world!");   //send Hello, world! to UART
 uart_xmit(0x0A);   //send an ASCII character for line feed
 __delay_ms(149);   //delay 149 milliseconds
 write_uart("From 0xEE.net");   //send From 0xEE.net
 uart_xmit(0x0A);   //send an ASCII character for line feed
 __delay_ms(149);   //delay 149 milliseconds
 } //... wash, rinse, repeat

I have plans to develop a light-weight protocol for use in some projects. My goal is a single master with multiple “slaves”. The slaves will be “polled” so they will listen and only respond when commanded to respond. I will likely include some form of change-in-state poll on a quick poll and follow-up with actual polling of data as needed. I will also include some form of addressing and ability to “time-out” on devices no longer on the bus or powered down.


 

The Results

 

Oscilloscope

For ease of visibility I picked on one letter to show you what the signal between the 485 A and B bus terminals looks like on the oscilloscope. You can clearly see the Z character (binary ‘1011010’). As before the data is transmitted LSB first with a start and stop bit 0101101, note that this signal is inverted from the signal recorded below on the logic analyzer. I made this measurement at the A/B output of the transceiver chip.

The EIA-485 signal reading ASCII character "Z" on an oscilloscope.

The TIA-485 signal reading ASCII character “Z” on an oscilloscope.

Logic analyzer

The output of the logic analyzer…  this shows the capture of the UART output as it goes to the transceiver chip on a single character (for comparison with the above TIA-485 output):

Using the logic analyzer to look at the ASCII character "Z" being send by the UART to the ADM485 transceiver.

Using the logic analyzer to look at the ASCII character “Z” being sent by the UART to the ADM485 transceiver.

As before here is the whole string in the test program being captured:

Hello.. on Logic Analyzer

Terminal program

For my test I decided a quick connection to my PC through its RS-232 port and converted over to TIA-485 by the B&B converter showed my circuit was working correctly and the UART on the PIC was sending proper information to my PC.

Sending Hello World! from PIC UART through TIA-485 bus and converted to RS-232 to be captured by a terminal program.

Sending Hello World! from PIC UART through TIA-485 bus and converted to RS-232 to be captured by a terminal program.

 

Connecting to the UART on the PC via TIA-485

Connecting to the UART on the PC via TIA-485

Physical Measurements

Enabling and Disabling the transceiver shouldn’t be left to the wayside if you’re only using the circuits for point-to-point communications. I noted that my circuit consumed 5mA with the transceiver disabled, 61mA enabled with no termination resistors and 83mA with a 100 Ohm termination resistor at the output of the transmitter. A considerable amount of power if you’re operating on batteries.


Final thoughts

 

As usual you can find more information on Wikipedia and a number of other sites including Analog Devices, TI and Maxium who make interface chips for the communications link. I look forward to developing a light-weight 485 protocol for the PIC and perhaps it’s something we can build on with our readers input.

Why? What use is TIA-485 to you and me? Well if you haven’t figured it out by now I have always favored TIA-485 in two applications:
1. hardwired communications lines that run more than a couple feet, and
2. When I want multiple addressed micro devices to communicate on the same trunk to a master and perhaps with each other.