AN #30 - RS-485 Master Slave Communication


485modul.bas - description of implemented subroutines

Download source code in an30.zip

Introduction 485modul.bas is not a program; it is only a program backbone, which has all subroutines necessary for communication between micro controllers. And because time management is also very handy, there is also a timer interrupt subroutine, which uses TIMER0. TIMER1 is used for timing off the communication staff and should not be used by programmer. TIMER0 interrupt subroutine and time management First, lets make clear: For communication we do not need time management and any timer interrupt routine at all. But, may be, somebody will find it useful and educational when solving a similar problem The Interrupt subroutine should be as short and quick as possible. Therefore some of the time management code we placed in the main program loop. There is also some initial work, which has to be done in the initial phase of the main program:

' //////////////////TIMER0 ////////////////

Config Timer0 = Timer , Gate = Internal , Mode = 1

On Timer0 Timer0isr

Enable Timer0

Load Timer0 , 195

' load 195 at mode = 1 and crystal = 12 MHz means 50 msec


At Mode = 1 and crystal frequency 12 MHz stands, timer interrupt will occur after n times 256 µsec (microseconds). If n is 195, then 195 times 256 µsec makes 49920 µsec which is approximately 50 msec (milliseconds). Another fact, which makes time management inaccurate is, we need time to disable interrupts. So as you see, we are not very exact at time management, but for most purposes it serves. If we need accurate time management, better use the devices specially designed for it.
Dim Seconds As Byte

Dim Minutes As Byte

Dim Hours As Byte

Dim Days As Byte

Seconds = 0

Minutes = 0

Hours = 0

Days = 0

Start Timer0

' ////////////////////////////////////////

Enable Interrupts

' Main program loop

Do

If Seconds >= 60 Then

Seconds = Seconds - 60

Incr Minutes

If Minutes >= 60 Then

Minutes = Minutes - 60

Incr Hours

If Hours >= 24 Then

Hours = Hours - 24

Incr Days

End If

End If

End If

........... Here the main program proceeds his work in loop ......


In the main program we assume somebody else (well, we know it will be the TIMER0 interrupt subroutine) will take care to increment byte Seconds each second. In the main program we only take care to do all the necessary adjustment when seconds counter reaches 60. How to set initial contents to hours, minutes and days, is now not our concern. Let us now have a look at the timer0isr timer0 interrupt subroutine!
'---------timer0 interrupt subroutine takes control every 50 msec

Timer0isr:

Dim Ticounter As Byte

'every 50 msec:

Load Timer0 , 195

Incr Ticounter

If Ticounter >= 20 Then

' every second

Ticoutner = 0

Incr Seconds

End If

Return

'---------timer0 interrupt subroutine - end ----


If we get timer an interrupt and if timer interrupt subroutine takes control every 50 msec, we need to count until 20 to reach a second. That is why we have in the timer interrupt subroutine a special counter of timer interrupts, which is incremented every time the timer interrupt routine takes control. When this counter reaches 20, then timer interrupt routine increment counter Seconds. Then the Timer interrupt routine returns control to main program, which proceeds its work exactly there, where he was interrupted for a very short time.

RS232/RS485 sending data

This is supposed to be the most simple communication between micro controllers where we have one master and some slaves who only respond on a master request. May be, somebody shall contribute the code for SNAP protocol, well for the very beginning I found it to complicated.

We send messages with a standard length for the whole system. First byte in the message is always 02 STX, last byte is always 03 ETX, second byte is slave address for which the message is meant to, or if slave is sending the message, which slave is sending the message. When slave is sending the message it is always meant for the master. The last byte but one is CRC8 check byte.

In the main program we have the following code:

$baud = 1200

$crystal = 12000000

' Message format if n = 8:

' Stx Adr Cmd P01 P02 P03 Crc Etx

' INDX 1 2 3 . . . . N

Const N = 8 'message length

Const Nminusone = N - 1

Const Nminustwo = N - 2

Dim Xx1(n) As Byte 'input area

Dim Xx2(n) As Byte 'buffer area

Dim Xx3(n) As Byte 'output and process area

Dim X1 As Byte

Dim X3 As Byte

Dim Msg As Bit

Declare Sub Sendsr

Print ;


In the statement Const N=8 we set the length of all messages in the system to 8. So there are defined areas XX1, XX2, and XX3 for messages with the same length.

For sending only XX3 is relevant. The other two areas are needed for reading the messages. Communication rate is defined in the statements $baud and $crystal. But to mislead the Basom8051 to use these information to set accurately timer1, which is responsible for baud rate, we must issue statement Print ; If not, we should calculate the correct values and set timer1 appropriately. It is easier to use BASCOM for doing this.

Before we are in the main program call subroutine SENDIT, we must put the message itself into the XX3 area. Subroutine SENDIT when called does the following:

  1. Puts value 2 (STX) into XX3(1)
  2. Calculates CRC8 check byte and puts it into XX3(Nminusone). As work byte while calculating CRC8 check byte it uses also XX3(n)
  3. Puts value 3 (ETX) into XX3(n)
  4. Then it disables interrupts.
Then in the loop sends all bytes to Sbuf. Scon.1 bit will be set by the micro controller when the byte is sent, and then we may put next byte into Sbuf.

On my testing board bit P1.1 is used to control MAX485 to switch Send/Receive.

Sub Sendsr

Xx3(1) = 2

Xx3(n) = 0

Xx3(nminusone) = 0

'calculation of the CRC8 checkbyte

For X3 = 1 To Nminustwo

Xx3(n) = Xx3(nminusone) Xor Xx3(x3)

Xx3(nminusone) = Lookup(xx3(n) , Crc8)

Next ' Check byte is calculated and put into right place

Xx3(n) = 3 'ETX



Disable Interrupts

Reset Scon.1

Set P1.1 'switch MAX485 to send

For X3 = 1 To N

Sbuf = Xx3(x3)

Bitwait Scon.1 , Set

Reset Scon.1

Next

Reset P1.1 'switch MAX485 to receive

Enable Interrupts

End Sub


For actual calculation of CRC8 check byte a CRC8 lookup table is needed at the end of program. It is big and it is not copied to this document.

RS232/RS485 receiving data Receiving data is programmed in a serial interrupt subroutine. While the main program is working whatever is designed to do, with one eye - serial interrupt subroutine - is watching what is happening on the communication line. When some byte appears on input, serial interrupt subroutine is activated to place the received byte to appropriate place, without to interrupt the logic of main program. When the last byte of message is received and message is checked and message is meant to us, then serial interrupt subroutine moves the message from input area XX1 to buffer area XX2 and set the bit named Msg to signal the main program, there is message to be proceed, have a look!

Main program does not process the message immediately. Not earlier then main program comes in the processing loop to the place, where the processing of input messages is provided. This can take some time. Meantime on the line some other bytes are received. That is why the buffer message area is necessary.

To activate serial interrupt receiving routine there is little code in main program:

Enable Serial

On Serial Serrut

Reset Msg

X1 = N + 1

' Index X1 to put received bytes to the right place we set

' in the way, that interrupt receiving routine will synchronize

' on the beginning of message on STX byte

' set max485 on Receive (for RS232 not necessary)

Reset P1.1


New Message begins with byte 02 = STX. But not every byte 02 is the beginning of message. It might also be data in the middle of message. Only if index byte X1 is outside message, it means, the passed message is fully read, then byte 02 is with high probability the beginning of new message. So we interpret byte 02 as beginning of new message only when index byte X1 points outside message that is greater then message length. This is why we set X1 to N+1 at the very beginning.

When message of fixed length N is fully received, the byte received last when X1 = N must bi STX = 03. If so, then we check, if the message is meant for us, that is if the address bytes match our slave address, (if we are master, all messages from slaves are meant to master) in if so, then the input routine checks if CRC8 check byte fits. If everything is OK, then we move the message from input area XX1 to buffer area XX2 in set the bit Msg to inform the main program.

Serial interrupt subroutine is like this:

Serrut:

Dim Swrk1 As Byte

Swrk1 = Inkey()

Scon.1 = 0

' Msg Format:

' Stx Adr Cmd P01 P02 P03 Crc Etx

' INDX 1 2 3 . . . . N

If Swrk1 = 2 And X1 > N Then

' If received byte is 02 and index greater then N, we synchronize

For X1 = 2 To N

Xx1(x1) = 0

Next

X1 = 1

End If



If X1 <= N Then

Xx1(x1) = Swrk1

End If



If X1 = N And Swrk1 = 3 Then

' If it is end of message

' If Xx1(2) = Slaveadr Then

' if program is master and not slave we comment this test



' Crc8 check:

Swrk1 = 0 'tmp

Xx1(n) = 0 'crc

For X1 = 1 To Nminusone

Swrk1 = Xx1(n) Xor Xx1(x1)

Xx1(n) = Lookup(swrk1 , Crc8)

Next

' move message to buffer area if CRC8 OK

If Swrk1 = 0 Then

For X1 = 1 To N

Xx2(x1) = Xx1(x1)

Next

Xx2(n) = 3

Set Msg

End If

' End If

End If

Incr X1

Return


There is no CRC8 Lookup table to be seen here, it is in attached modul485.bas

Attached sample programs are:

  • Modul485.bas which is not a program, but only skeleton which can be used, when starting writing a new program, with the serial communication.
  • 485oddaj.bas is a sample program, which sends each second a message. Something like this: 'Hi, slave no "O", my clock shows this time' and puts the same info on LCD
  • 485sprej.bas is a sample slave program, which only reads message from line, and puts info about master's clock on LCD
  • 485rxtx.bas is a sample slave program, who after receiving masters clock info, sends back slave's clock info.
  • 485master.bas is a master sample program, who sends the message the same way the 485oddaj.bas does, but waits for an answer from slave. Both messages go on LCD.