#include <SimpleModbusSlave.h>
#define ledPin 13 // onboard led
#define buttonPin 7 // push button
/* This example code has 9 holding registers. 6 analogue inputs, 1 button, 1 digital output
and 1 register to indicate errors encountered since started.
Function 5 (write single coil) is not implemented so I'm using a whole register
and function 16 to set the onboard Led on the Atmega328P.
The modbus_update() method updates the holdingRegs register array and checks communication.
Note:
The Arduino serial ring buffer is 128 bytes or 64 registers.
Most of the time you will connect the arduino to a master via serial
using a MAX485 or similar.
In a function 3 request the master will attempt to read from your
slave and since 5 bytes is already used for ID, FUNCTION, NO OF BYTES
and two BYTES CRC the master can only request 122 bytes or 61 registers.
In a function 16 request the master will attempt to write to your
slave and since a 9 bytes is already used for ID, FUNCTION, ADDRESS,
NO OF REGISTERS, NO OF BYTES and two BYTES CRC the master can only write
118 bytes or 59 registers.
Using the FTDI USB to Serial converter the maximum bytes you can send is limited
to its internal buffer which is 60 bytes or 30 unsigned int registers.
Thus:
In a function 3 request the master will attempt to read from your
slave and since 5 bytes is already used for ID, FUNCTION, NO OF BYTES
and two BYTES CRC the master can only request 54 bytes or 27 registers.
In a function 16 request the master will attempt to write to your
slave and since a 9 bytes is already used for ID, FUNCTION, ADDRESS,
NO OF REGISTERS, NO OF BYTES and two BYTES CRC the master can only write
50 bytes or 25 registers.
Since it is assumed that you will mostly use the Arduino to connect to a
master without using a USB to Serial converter the internal buffer is set
the same as the Arduino Serial ring buffer which is 128 bytes.
*/
// Using the enum instruction allows for an easy method for adding and
// removing registers. Doing it this way saves you #defining the size
// of your slaves register array each time you want to add more registers
// and at a glimpse informs you of your slaves register layout.
//////////////// registers of your slave ///////////////////
enum
{
// just add or remove registers and your good to go...
// The first register starts at address 0
ADC0,
ADC1,
ADC2,
ADC3,
ADC4,
ADC5,
LED_STATE,
BUTTON_STATE,
TOTAL_ERRORS,
// leave this one
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()
{
/* parameters(long baudrate,
unsigned char ID,
unsigned char transmit enable pin,
unsigned int holding registers size,
unsigned char low latency)
The transmit enable pin is used in half duplex communication to activate a MAX485 or similar
to deactivate this mode use any value < 2 because 0 & 1 is reserved for Rx & Tx.
Low latency delays makes the implementation non-standard
but practically it works with all major modbus master implementations.
*/
modbus_configure(9600, 1, 2, TOTAL_REGS_SIZE, 0);
pinMode(ledPin, OUTPUT);
pinMode(buttonPin, INPUT);
}
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);
for (byte i = 0; i < 6; i++)
{
holdingRegs[i] = analogRead(i); //Analog Input channel 0 ~6까지 7개 데이터를 읽어서 HoldingRegs변수로 넣는다.
delayMicroseconds(50); //지연시간을 50마이크로 sec를 준다.
}
byte buttonState = digitalRead(buttonPin); // buttonPin값을 읽어서 buttonState변수로 바이트로 넣는다.
// assign the buttonState value to the holding register
holdingRegs[BUTTON_STATE] = buttonState; //buttonState변수의 바이트값을 홀딩레지서터 어레이의 BUTTON_STATE 어레이값으로 넣는다.
// read the LED_STATE register value and set the onboard LED high or low with function 16
byte ledState = holdingRegs[LED_STATE];
if (ledState) // set led
digitalWrite(ledPin, HIGH);
if (ledState == 0 || buttonState) // reset led
{
digitalWrite(ledPin, LOW);
holdingRegs[LED_STATE] = 0;
}
}