In this post I’d like to describe you a project I’m working on that consists of connecting an Android multi touch panel to one (or more) Arduino slave(s) using modbus protocol and RS485.
Even though the idea of this project could be applied in many fields, I chose to contextualize it in a typical smart home context: a touch display that dims lights, shows temperatures and bulbs statuses.
The nice feature of the Android multi touch panel I used is that it has many interfaces such as Ethernet, RS485, RS32 and I²C as well.
I expressly selected RS485 because Arduino-based microcontrollers are not ready for Ethernet yet (even though some examples still exist but without great success). Indeed, RS485 is a well known standard that has been widely used in the industrial context and in building automation applications. It is a half-duplex, 2-wires, low noise bus that allows high speeds and remote devices connection (up to 1200 meters).
Furthermore, modbus is a serial communication protocol, developed for industrial applications, open and easy to deploy and maintain. I used modbus RTU, but other variations of the protocol still exist though.
I divided the project into core parts, namely:
Electrical parts
The key ingredients for this project are the following:
- An Android based multi touch panel
- One (or more) Arduino board (not necessarily Mega)
- A Maxim’s Max485 chip (or eventually a cheaper one like TI’s sn75176a)
- Led
- A temperature sensor (like TMP36)
- Switches
- A potentiometer
- One 120 Ohm resistor (not used in this project because of the short distance between master and slave)
- Wires and some soldering experience 🙂
Circuit diagram
The picture on the right shows an overview of the circuit diagram of the project (some parts of the picture made with Fritzing). More than one Arduino board could be connected to the bus though.
Arduino sketch
Arduino sketch essentially uses SimpleSlaveModbus library (Tutorial on how to install a new Arduino library). I personally suggest you to take a look at documentation in order to have a better idea on how this library works.
After including the modbus library header at the beginning of the source code, I declared an integer array (named holdingRegs) that stores the modbus registers. Function code 16 writes into them whereas function code 3 read them. The first two registers are reserved for analog values such as those gathered from A0 and A1 Arduino’s pins. INDIG0 to INDIG4 are served for digital inputs, OUTD0 to OUTD4 to digital outputs and AOUT0 for PWM.
In the setup section of the sketch, I call the modbus_configure function in order to configure the modbus with the following parameters: the baud rate, the ID of the slave (address), the transmit enable pin and the number of registers. Subsequently, I basically configure the digital Arduino pins with pinMode.
#include #define pinDig 3 #define pinDigOut 6 //////////////// registers of the slave /////////////////// enum { // The first register starts at address 0 ADC0, ADC1, INDIG0, INDIG1, INDIG2, INDIG3, OUTD0, OUTD1, OUTD2, OUTD3, AOUT0, TOTAL_ERRORS, TOTAL_REGS_SIZE // total number of registers for function 3 and 16 share the same register array }; unsigned int holdingRegs[TOTAL_REGS_SIZE]; // function 3 and 16 register array void setup() { modbus_configure(38400, 1, 2, TOTAL_REGS_SIZE); //digital inputs configuration for(int i=10; i pinMode(i, INPUT_PULLUP); } //digital outputs pinMode(3, OUTPUT); pinMode(4, OUTPUT); pinMode(5, OUTPUT); pinMode(6, OUTPUT); //modbus led pinMode(8, OUTPUT); //PWM pinMode(9, OUTPUT); //modbus registers initialization for (int i=0; i holdingRegs[i] = 0; } }
In the loop of the sketch, I inserted a call to modbus_update specifying, as a first parameter, the reference to the array that stores the modbus registers. This function will take care of the received modbus commands and will modify the registers accordingly in case of writing or reading requests.
The remaining part of the sketch reads the analog values from pin A0 and A1, reads the digital values (remember we set those digital pin to INPUT_PULLUP) and finally writes the digital values of the switches.
Finally, in order to have an insight on the status of the communication channel, I used a red led that indicates when a modbus message is received and processed. This is accomplished by modifying the modbus slave library and inserting a couple of digitalWrites (set to HIGH or LOW whenever necessary).
void loop() { // modbus_update() is the only method used in loop(). It returns the total error // count since the slave started. You don't have to use it but it's useful // for fault finding by the modbus master. holdingRegs[TOTAL_ERRORS] = modbus_update(holdingRegs); holdingRegs[0]=analogRead(0); holdingRegs[1]=analogRead(1); //digital inputs for (int i=0; i < 4; i++){ holdingRegs[i+2]=digitalRead(10+i); } for(int i=0; i < 4; i++){ digitalWrite(pinDig+i,holdingRegs[pinDigOut+i]); } //PWM analogWrite(9, holdingRegs[10]); }
In the following post, Android project for smart home automation, I’ll present you how to make an Android app that communicates with Arduino’s slaves using a native modbus library.
That’s it! If you liked this article, please share it!
The sequel of this post is out! Let’s look at how to communicate between Arduino Ethernet and Android through modbus tcp.
Update: For those of you that are using one of the latest SimpleModbusSlave library, the Arduino code presented above needs some simple adjustments. Thanks Luis for letting me know. I used SimpleModbusSlave version V7 library.
With version V7 you need to modify the modbus_configure method call. It accepts more parameters than the previous library versions, namely:
- a pointer to the hardware serial interface
- the baudrate of the modbus connection
- the modbus byte format. Values available are:
- SERIAL_8N2: 1 start bit, 8 data bits, 2 stop bits
- SERIAL_8E1: 1 start bit, 8 data bits, 1 Even parity bit, 1 stop bit
- SERIAL_8O1: 1 start bit, 8 data bits, 1 Odd parity bit, 1 stop bit
- node id
- enable pin
- holding register size
- pointer to the holding register size
Basically, the new modbus_configure call might be the following:
modbus_configure(&Serial, 38400, SERIAL_8N2, 1, 2, HOLDING_REGS_SIZE, holdingRegs);
Since the reference of the registers’ array holdingRegs has been passed to the library by the modbus_configure, the modbus_update method call does not need to process it. In fact, you only need to call the method without any parameter.
you may also like this: