RS485 Relay Raspberry pi

RS485 Relay Raspberry pi


Download Build manual Build Manual.pdf

After building up the Iso RS485/422 adapter, I figured I needed to do a project that used RS485 loopback tests can only keep you amused for so long… So here is an RS485 relay controller using the PIC16F628A that can be controlled using serial commands from cron to switch devices on and off at predetermined time

Hardware

The hardware design is shown in the schematic below:-

 

Click to enlarge
Click to enlarge

 

Power is supplied via the the connector J1 and into a 7805 linear regulator to supply 5V to the circuit and the PIC micro controller. The PIC16F628A is run off an 1.8432 Mhz crystal in order to give direct integer divider for baud rates.

The RS485 node address is set via a 5 way DIP switch DSW1 that is pulled up internally by port B this gives 32 possible addresses . A standard RS485 converter is connected to the UART pins and direction is controlled by the DE/RE signal.

At the last node on the network then J3 should be fitted to terminate the RS485 network. The Relay is driven by the RLY1 signal via Q1.

RS485%20LayoutThe layout is on a two layer PCB that fits into an open

enclosure that can be fitted on a DIN rail module

from pheonix contact shown here

http://www.farnell.com/datasheets/99364.pdf

This allows multiple PCB’s to be put in one enclosure.

The bill of materials for this project is

 

 

QTY PART-REFS VALUE

Resistors

———

2 R1,R2 1k (May need to reduce to 560 for the Relay drive)

1 R3 10k

1 R4 120

Capacitors

———-

2 C1,C2 220p

2 C3,C4 47uF

Integrated Circuits

——————-

1 U1 PIC16F628A

1 U2 78L05

1 U3 MAX487

Transistors

———–

1 Q1 BC549BP

Diodes

——

2 D1,D3 1N4001

1 D2 LED

Miscellaneous

————-

1 DSW1 DIPSW_5

1 J1 TBLOCK-I5

1 J2 TBLOCK-I3

1 J3 CONN-H2

1 RL1 G5CLE-1-DC5

The Protocol

For this initial network we’ll use a simple ASCII proprietary protocol as follows each command is 5 characters structured as below:

$AACMx

$ is the start of packet character

AA is the address in ASCII for example $01 would access node 1

CM is the command initially 2 commands are supported

ON= Turns relay on

OF= Turns relay off

x is the number of the relay on the board

So to turn on the relay at address 22 the command would be $22ON1 and to turn it off would be $22OF1 note no return character is sent after the command.

The code is set up to run at 19K2 baud 8N1 as default.

The PIC code

The code is written in Hitech C and uses the onboard USART with an RX interrupt routine. The code now includes timeout and corrects a previous error where I had config set up to run from the internal oscillator rather than external oscillator.

The Address is read from the external DIP switch

/**********************************************************

*RS485 Node Software

*Copyright (c) Nigel Brooke 2013

*Processor=16F628A

*Crystal Frequency = 1.8432 MHz

***********************************************************/

#include

#include

#include “string.h”

#include

#define DE RB0

#define RELAY RA0

#define _XTAL_FREQ 1843200

#define SER_BUFFER_SIZE 8

#define RX_PIN TRISB1

#define TX_PIN TRISB2

#if NINE == 1

#define NINE_BITS 0x40

#else

#define NINE_BITS 0

#endif

#define SPEED 0x4

#define SER_FIFO_MASK (SER_BUFFER_SIZE-1)

__CONFIG (0x3D21); //Note make sure to check this is set up for XT Oscillator

const char* Relayon[]=

{

“$00ON1″,”$01ON1″,”$02ON1″,”$03ON1″,”$04ON1″,”$05ON1″,”$06ON1″,”$07ON1″,”$08ON1″,”$09ON1″,”$10ON1″,”$11ON1″,”$12ON1″,”$13ON1″,”$14ON1″,”$15ON1″,”$16ON1″,”$17ON1″,”$18ON1″,”$19ON1″,”$20ON1″,”$21ON1″,”$22ON1″,”$23ON1″,”$24ON1″,”$25ON1″,”$26ON1″,”$27ON1″,”$28ON1″,”$29ON1″,”$30ON1″,”$31ON1″,”$32ON1”,

};

const char* Relayoff[]=

{

“$00OF1″,”$01OF1″,”$02OF1″,”$03OF1″,”$04OF1″,”$05OF1″,”$06OF1″,”$07OF1″,”$08OF1″,”$09OF1″,”$10OF1″,”$11OF1″,”$12OF1″,”$13OF1″,”$14OF1″,”$15OF1″,”$16OF1″,”$17OF1″,”$18OF1″,”$19OF1″,”$20OF1″,”$21OF1″,”$22OF1″,”$23OF1″,”$24OF1″,”$25OF1″,”$26OF1″,”$27OF1″,”$28OF1″,”$29OF1″,”$30OF1″,”$31OF1″,”$32OF1”,

};

unsigned char rxfifo[SER_BUFFER_SIZE];

volatile unsigned char rxiptr, rxoptr, Addptr,Timeout;

unsigned char input;

void interrupt ISR()

{

if (T0IF)

{

Timeout–;

if(Timeout == 0)

{

Timeout = 8;

rxiptr = 0;

}

T0IF = 0;

TMR0=0;

}

while(RCIF)

{

TMR0 = 0;

Timeout = 8; //Set for around 1 second timeout

input = getch(); // read a response from the user*/

if (input == ‘$’) //Look for the beginning of packet

{

rxiptr = 0; //If the beginning then reset the pointer

}

rxfifo[rxiptr] = input;

rxiptr++;

}

if(OERR)

{

CREN = 0;

CREN = 1;

}

}

init_comms()

{

RX_PIN = 1;

TX_PIN = 1;

SPBRG = 5;

RCSTA = (NINE_BITS|0x90);

TXSTA = (SPEED|NINE_BITS|0x20);

}

void main(void){

/*Set up Ports*/

OPTION_REG = 0b01010111;

CMCON=0B00000111;

TRISA=0B11111110;

TRISB=0B11111110;

RCIE = 1;

T0IE = 1; /* Enable peripheral interrupts */

PSA = 0;

PEIE = 1;

GIE = 1; /* Enable global interrupts */

TRISA=0B11110000; //Setup Port A Registers

TRISB=0B11111110; //Setup Port B Registers

RELAY = 0; //Set Relay to Off

init_comms(); // set up the USART – settings defined in usart.h

DE = 0;

rxiptr = 0;

Timeout = 8;

while(1){

Addptr = PORTB >>3 &0b00011111;

if (rxiptr == 6) //wait until 6 characters have been received into buffer

{

if(strncmp(rxfifo,Relayon[Addptr],6) == 0)

{

RELAY = 1;

}

else if (strncmp(rxfifo,Relayoff[Addptr],6) == 0)

{

RELAY = 0;

}

rxiptr = 0;

}

}

}

Running from the Raspberry pi

With a simple piece of python code below the relay can be switched on at the adress set by the DIP switch. To switch the relay off just change the command to OF.

If these are written as separate functions then these can be called from CRON to make a simple scheduler.

#!/user/bin/env python

import serial

import datetime

from time import sleep

ser = serial.Serial(“/dev/ttyAMA0”,baudrate=19200,parity=serial.PARITY_NONE,stopbits=serial.STOPBITS_ONE,bytesize=serial.EIGHTBITS )

ser.open

ser.write(‘$’)

sleep(0.1)

ser.write(‘2’)

sleep(0.1)

ser.write(‘4’)

sleep(0.1)

ser.write(‘O’)

sleep(0.1)

ser.write(‘N’)

sleep(0.1)

ser.write(‘1’)

sleep(0.1)

print “Relay On”

ser.close()

Running from Crontab

Now we have a program to switch the relay on and off we can set up a crontab schedule to automate the relays to switch on and off at various times during the day.

To edit the crontab first make sure it is installed apt-get install crontab

Then to edit the crontab type crontab -e

at the terminal window.

For example the command

01 22 * * * python /home/pi/Relayon1.py

will switch on relay 1 at 22:01 every day and the command

40 23 * * * python /home/pi/Relayoff1.py

will turn the same relay off at 23:40 each day.

Below is an example of my current crontab

# m h dom mon dow command

15 15 * * * python /home/pi/Relayon1.py

20 15 * * * python /home/pi/Relayoff1.py

40 23 * * * python /home/pi/Relayoff1.py

01 22 * * * python /home/pi/Relayon1.py

30 6 * * * python /home/pi/Relayon1.py

30 7 * * * python /home/pi/Relayoff1.py

36 15 * * * python /home/pi/Relayon2.py

56 15 * * * python /home/pi/Relayoff2.py