Skip to content

Commit 55681b5

Browse files
authored
Rework examples (#51)
* Fix typo * Fix typo * Comment rework for consistency and readability * Update the schematic * rework examples with more comments and scaling.
1 parent e418472 commit 55681b5

File tree

5 files changed

+380
-263
lines changed

5 files changed

+380
-263
lines changed

examples/full/full.ino

+166-134
Original file line numberDiff line numberDiff line change
@@ -4,186 +4,218 @@
44
Control and Read Arduino I/Os using Modbus serial connection.
55
66
This sketch show how to use the callback vector for reading and
7-
controleing Arduino I/Os.
7+
controlling Arduino I/Os.
88
9-
* Control digital pins mode using holding registers 0 .. 13.
10-
* Controls digital output pins as modbus coils.
11-
* Reads digital inputs state as discreet inputs.
12-
* Reads analog inputs as input registers.
9+
* Control digital pins mode using holding registers 0 .. 50.
10+
* Control digital output pins as modbus coils.
11+
* Read digital inputs as discreet inputs.
12+
* Read analog inputs as input registers.
1313
* Write and Read EEPROM as holding registers.
1414
15-
The circuit: ( see: ./extras/ModbusSetch.pdf )
16-
* An Arduino.
17-
* 2 x LEDs, with 220 ohm resistors in series.
18-
* A switch connected to a digital input pin.
19-
* A potentiometer connected to an analog input pin.
20-
* A RS485 module (Optional) connected to RX/TX and a digital control pin.
21-
22-
Created 8 12 2015
15+
Created 08-12-2015
2316
By Yaacov Zamir
2417
18+
Updated 31-03-2020
19+
By Yorick Smilda
20+
2521
https://github.com/yaacov/ArduinoModbusSlave
2622
2723
*/
2824

2925
#include <EEPROM.h>
3026
#include <ModbusSlave.h>
3127

32-
/* slave id = 1, control-pin = 8, baud = 9600
33-
*/
34-
#define SLAVE_ID 1
35-
#define CTRL_PIN 8
36-
#define BAUDRATE 9600
28+
#define SLAVE_ID 1 // The Modbus slave ID, change to the ID you want to use.
29+
#define RS485_CTRL_PIN 8 // Change to the pin the RE/DE pin of the RS485 controller is connected to.
30+
#define SERIAL_BAUDRATE 9600 // Change to the baudrate you want to use for Modbus communication.
31+
#define SERIAL_PORT Serial // Serial port to use for RS485 communication, change to the port you're using.
3732

38-
#define PIN_MODE_INPUT 0
39-
#define PIN_MODE_OUTPUT 1
33+
// The position in the array determines the address. Position 0 will correspond to Coil, Discrete input or Input register 0.
34+
uint8_t digital_pins[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}; // Add the pins you want to read as a Discrete input.
35+
uint8_t analog_pins[] = {A0, A1, A2, A3, A4, A5}; // Add the pins you want to read as a Input register.
4036

41-
/**
42-
* Modbus object declaration.
43-
*/
44-
Modbus slave(SLAVE_ID, CTRL_PIN);
37+
// The EEPROM layout is as follows
38+
// The first 50 bytes are reserved for storing digital pin pinMode_setting
39+
// Byte 51 and up are free to write any uint16_t to.
4540

46-
void setup() {
47-
uint16_t pinIndex;
48-
uint16_t eepromValue;
49-
50-
/* set pins for mode.
51-
*/
52-
for (pinIndex = 3; pinIndex < 14; pinIndex++) {
53-
// get one 16bit register from eeprom
54-
EEPROM.get(pinIndex * 2, eepromValue);
55-
56-
// use the register value to set pin mode.
57-
switch (eepromValue) {
58-
case PIN_MODE_INPUT:
59-
pinMode(pinIndex, INPUT);
60-
break;
61-
case PIN_MODE_OUTPUT:
62-
pinMode(pinIndex, OUTPUT);
63-
break;
64-
}
41+
// You shouldn't have to change anything below this to get this example to work
42+
43+
uint8_t digital_pins_size = sizeof(digital_pins) / sizeof(digital_pins[0]); // Get the size of the digital_pins array
44+
uint8_t analog_pins_size = sizeof(analog_pins) / sizeof(analog_pins[0]); // Get the size of the analog_pins array
45+
46+
// Modbus object declaration
47+
Modbus slave(SERIAL_PORT, SLAVE_ID, RS485_CTRL_PIN);
48+
49+
void setup()
50+
{
51+
// Set the defined digital pins to the value stored in EEPROM.
52+
for (uint16_t i = 0; i < digital_pins_size; i++)
53+
{
54+
uint8_t pinMode_setting;
55+
// Get the pinMode_setting of this digital pin from the EEPROM.
56+
EEPROM.get(i, pinMode_setting);
57+
58+
pinMode(digital_pins[i], pinMode_setting);
6559
}
66-
67-
// RS485 control pin must be output
68-
pinMode(CTRL_PIN, OUTPUT);
69-
70-
/* register handler functions.
71-
* into the modbus slave callback vector.
72-
*/
60+
61+
// Set the defined analog pins to input mode.
62+
for (int i = 0; i < analog_pins_size; i++)
63+
{
64+
pinMode(analog_pins[i], INPUT);
65+
}
66+
67+
// Register functions to call when a certain function code is received.
7368
slave.cbVector[CB_READ_COILS] = readDigital;
7469
slave.cbVector[CB_READ_DISCRETE_INPUTS] = readDigital;
7570
slave.cbVector[CB_WRITE_COILS] = writeDigitalOut;
7671
slave.cbVector[CB_READ_INPUT_REGISTERS] = readAnalogIn;
7772
slave.cbVector[CB_READ_HOLDING_REGISTERS] = readMemory;
7873
slave.cbVector[CB_WRITE_HOLDING_REGISTERS] = writeMemory;
79-
80-
// set Serial and slave at baud 9600.
81-
Serial.begin( BAUDRATE );
82-
slave.begin( BAUDRATE );
74+
75+
// Set the serial port and slave to the given baudrate.
76+
SERIAL_PORT.begin(SERIAL_BAUDRATE);
77+
slave.begin(SERIAL_BAUDRATE);
8378
}
8479

85-
void loop() {
86-
/* listen for modbus commands con serial port.
87-
*
88-
* on a request, handle the request.
89-
* if the request has a user handler function registered in cbVector.
90-
* call the user handler function.
91-
*/
80+
void loop()
81+
{
82+
// Listen for modbus requests on the serial port.
83+
// When a request is received it's going to get validated.
84+
// And if there is a function registered to the received function code, this function will be executed.
9285
slave.poll();
9386
}
9487

95-
/**
96-
* Handel Read Input Status (FC=01/02)
97-
* write back the values from digital pins (input status).
98-
*
99-
* handler functions must return void and take:
100-
* uint8_t fc - function code.
101-
* uint16_t address - first register/coil address.
102-
* uint16_t length/status - length of data / coil status.
103-
*/
104-
uint8_t readDigital(uint8_t fc, uint16_t address, uint16_t length) {
105-
// read digital input
106-
for (int i = 0; i < length; i++) {
107-
// write one boolean (1 bit) to the response buffer.
108-
slave.writeCoilToBuffer(i, digitalRead(address + i));
88+
// Modbus handler functions
89+
// The handler functions must return void and take the following parameters:
90+
// uint8_t fc - function code
91+
// uint16_t address - first register/coil address
92+
// uint16_t length/status - length of data / coil status
93+
94+
// Handle the function codes Read Input Status (FC=01/02) and write back the values from the digital pins (input status).
95+
uint8_t readDigital(uint8_t fc, uint16_t address, uint16_t length)
96+
{
97+
// Check if the requested addresses exist in the array
98+
if (address > digital_pins_size || (address + length) > digital_pins_size)
99+
{
100+
return STATUS_ILLEGAL_DATA_ADDRESS;
101+
}
102+
103+
// Read the digital inputs.
104+
for (int i = 0; i < length; i++)
105+
{
106+
// Write the state of the digital pin to the response buffer.
107+
slave.writeCoilToBuffer(i, digitalRead(digital_pins[address + i]));
109108
}
110109

111110
return STATUS_OK;
112111
}
113112

114-
/**
115-
* Handel Read Holding Registers (FC=03)
116-
* write back the values from eeprom (holding registers).
117-
*/
118-
uint8_t readMemory(uint8_t fc, uint16_t address, uint16_t length) {
119-
uint16_t value;
120-
121-
// read program memory.
122-
for (int i = 0; i < length; i++) {
123-
EEPROM.get((address + i) * 2, value);
124-
125-
// write uint16_t value to the response buffer.
126-
slave.writeRegisterToBuffer(i, value);
113+
// Handle the function code Read Holding Registers (FC=03) and write back the values from the EEPROM (holding registers).
114+
uint8_t readMemory(uint8_t fc, uint16_t address, uint16_t length)
115+
{
116+
// Read the requested EEPROM registers.
117+
for (int i = 0; i < length; i++)
118+
{
119+
// Below 50 is reserved for pinModes, above 50 is free to use.
120+
if (address + i <= 50)
121+
{
122+
uint8_t value;
123+
124+
// Read a value from the EEPROM.
125+
EEPROM.get((address + i), value);
126+
127+
// Write the pinMode from EEPROM to the response buffer.
128+
slave.writeRegisterToBuffer(i, value);
129+
}
130+
else
131+
{
132+
uint16_t value;
133+
134+
// Read a value from the EEPROM.
135+
EEPROM.get((address + i) * 2, value);
136+
137+
// Write the value from EEPROM to the response buffer.
138+
slave.writeRegisterToBuffer(i, value);
139+
}
127140
}
128141

129142
return STATUS_OK;
130143
}
131144

132-
/**
133-
* Handel Read Input Registers (FC=04)
134-
* write back the values from analog in pins (input registers).
135-
*/
136-
uint8_t readAnalogIn(uint8_t fc, uint16_t address, uint16_t length) {
137-
// read analog input
138-
for (int i = 0; i < length; i++) {
139-
// write uint16_t value to the response buffer.
140-
slave.writeRegisterToBuffer(i, analogRead(address + i));
145+
// Handle the function code Read Input Registers (FC=04) and write back the values from the analog input pins (input registers).
146+
uint8_t readAnalogIn(uint8_t fc, uint16_t address, uint16_t length)
147+
{
148+
// Check if the requested addresses exist in the array
149+
if (address > analog_pins_size || (address + length) > analog_pins_size)
150+
{
151+
return STATUS_ILLEGAL_DATA_ADDRESS;
152+
}
153+
154+
// Read the analog inputs
155+
for (int i = 0; i < length; i++)
156+
{
157+
// Write the state of the analog pin to the response buffer.
158+
slave.writeRegisterToBuffer(i, analogRead(analog_pins[address + i]));
141159
}
160+
161+
return STATUS_OK;
142162
}
143163

144-
/**
145-
* Handle Force Single Coil (FC=05) and Force Multiple Coils (FC=15)
146-
* set digital output pins (coils).
147-
*/
148-
uint8_t writeDigitalOut(uint8_t fc, uint16_t address, uint16_t length) {
149-
// set digital pin state(s).
150-
for (int i = 0; i < length; i++) {
151-
digitalWrite(address + i, slave.readCoilFromBuffer(i));
164+
// Handle the function codes Force Single Coil (FC=05) and Force Multiple Coils (FC=15) and set the digital output pins (coils).
165+
uint8_t writeDigitalOut(uint8_t fc, uint16_t address, uint16_t length)
166+
{
167+
// Check if the requested addresses exist in the array
168+
if (address > digital_pins_size || (address + length) > digital_pins_size)
169+
{
170+
return STATUS_ILLEGAL_DATA_ADDRESS;
171+
}
172+
173+
// Set the output pins to the given state.
174+
for (int i = 0; i < length; i++)
175+
{
176+
// Write the value in the input buffer to the digital pin.
177+
digitalWrite(digital_pins[address + i], slave.readCoilFromBuffer(i));
152178
}
153179

154180
return STATUS_OK;
155181
}
156182

157-
/**
158-
* Handle Write Holding Register(s) (FC=06, FC=16)
159-
* write data into eeprom.
160-
*/
161-
uint8_t writeMemory(uint8_t fc, uint16_t address, uint16_t length) {
162-
uint16_t value;
163-
uint16_t registerIndex;
164-
165-
// write to eeprom.
166-
for (int i = 0; i < length; i++) {
167-
registerIndex = address + i;
168-
169-
// get uint16_t value from the request buffer.
170-
value = slave.readRegisterFromBuffer(i);
171-
172-
EEPROM.put(registerIndex * 2, value);
173-
174-
/* if this register sets digital pins mode,
175-
* set the digital pins mode.
176-
*/
177-
if (registerIndex > 2 && registerIndex < 14 && registerIndex != CTRL_PIN) {
178-
// use the register value to set pin mode.
179-
switch (value) {
180-
case PIN_MODE_INPUT:
181-
pinMode(registerIndex, INPUT);
182-
break;
183-
case PIN_MODE_OUTPUT:
184-
pinMode(registerIndex, OUTPUT);
185-
break;
183+
// Handle the function codes Write Holding Register(s) (FC=06, FC=16) and write data to the eeprom.
184+
uint8_t writeMemory(uint8_t fc, uint16_t address, uint16_t length)
185+
{
186+
// Write the received data to EEPROM.
187+
for (int i = 0; i < length; i++)
188+
{
189+
if (address + i <= 50)
190+
{
191+
// Check if the requested addresses exist in the array.
192+
if (address + i > digital_pins_size)
193+
{
194+
return STATUS_ILLEGAL_DATA_ADDRESS;
195+
}
196+
197+
// Read the value from the input buffer.
198+
uint8_t value = slave.readRegisterFromBuffer(i);
199+
200+
// Check if the value is 0 (INPUT) or 1 (OUTPUT).
201+
if (value != INPUT || value != OUTPUT)
202+
{
203+
return STATUS_ILLEGAL_DATA_VALUE;
186204
}
205+
206+
// Store the received value in the EEPROM.
207+
EEPROM.put(address + i, value);
208+
209+
// Set the pinmode to the received value.
210+
pinMode(digital_pins[address + i], value);
211+
}
212+
else
213+
{
214+
// Read the value from the input buffer.
215+
uint16_t value = slave.readRegisterFromBuffer(i);
216+
217+
// Store the received value in the EEPROM.
218+
EEPROM.put(address + i * 2, value);
187219
}
188220
}
189221

0 commit comments

Comments
 (0)