0:12
this is the fourth video in the SDM 32
0:15
modbus series and today we will start
0:18
with the stm32 as a slave device
0:21
we will see how to program the stm32 as
0:25
a modbus slave device where it will
0:27
respond to the queries sent by the
0:29
master to read the holding and input
0:33
basically we will be working with the
0:35
function codes three and four but this
0:37
time from the slave perspective
0:40
we will also see how the slaves send an
0:43
exception in case it cannot handle the
0:45
request made by the master device
0:48
I have already prepared a library and
0:50
written the code and I will explain it
0:52
as we move along with the video
0:55
I have also made some changes in the
0:59
as I mentioned in the first video the
1:02
modbus is a protocol and it can work
1:04
with any communication standard
1:06
today I am simply using the uart to
1:09
communicate with the computer
1:11
I am using the nucleo f446 controller
1:15
and connecting via the uart is easier
1:19
here you can see I am using the uart 2.
1:23
the mode is set to asynchronous mode
1:27
the board rate is 11 5 200 word length
1:30
of 8 Bits with no parity and one stop
1:36
I have also enabled the interrupt so
1:39
that we can receive data in the
1:42
the pins pa2 and pa3 have been set as
1:49
the connection with the nucleo board is
1:51
pretty simple you just need to connect
1:53
the controller using the USB cable
1:56
you can also use some Ur to rs232
2:00
converter or use the rs-485 module as we
2:04
did in the previous videos
2:06
anyway let's see the code now
2:09
here I have defined the RX and TX
2:14
we know the maximum data that can be
2:16
transferred on the modbus is 256 bytes
2:19
therefore the size is set as 256 bytes
2:24
in the main function we will receive the
2:26
data in the RX data buffer using the
2:29
function you out receive to idle
2:32
Whenever there is an idle line detected
2:35
in the incoming data the RX event
2:37
callback will be called
2:39
the incoming data will be stored in the
2:44
inside the Callback function we will
2:46
check if the first byte in the RX data
2:49
buffer is matching with the slave ID
2:51
that we have defined in the modbus slave
2:55
here I have defined the slave ID as 7.
2:59
the next byte in the RX data buffer
3:01
corresponds to the function code
3:03
requested by the master
3:06
if the master has requested the function
3:08
code 3 we will call the function read
3:13
and if the function code is 4 we will
3:16
call the function read input registers
3:20
before we move on to the modbus source
3:22
file I want to clarify that the CRC file
3:25
is the same that we have used in the
3:34
here I have created a modbus slave.c
3:37
file and a modbuslave.h file
3:41
these files will remain the same in the
3:43
upcoming tutorials also and we will keep
3:46
adding the new function codes to them
3:48
here I have defined the RX and TX data
3:52
buffers again but as the external
3:55
they are originally defined in the main
3:59
I have also defined the uart Handler
4:01
here as an external variable
4:11
next we have the send data function
4:14
which will be used to send the data to
4:18
this time I have added the parameter
4:20
size which would indicate how many bytes
4:22
of the TX data buffer has already been
4:24
occupied before this function is called
4:27
this is because now the CRC will be
4:30
calculated in this function itself and
4:32
the size parameter will be needed to
4:37
let's assume the size is set to 9 that
4:40
means the 9 bytes have been occupied in
4:44
we will store the CRC values at the
4:47
ninth and 10th positions
4:49
and finally send the buffer to the uart
4:52
with 12 bytes in total
4:58
reading of holding and input registers
5:00
are exactly the same things
5:03
there are no changes between them so I
5:06
will only explain one of them
5:08
on the top right you can see the query
5:13
to read the registers we will first
5:15
calculate the start register address
5:19
the address sent by the master is in two
5:21
bytes format so we need to shift the
5:23
higher byte to the left by eight
5:25
positions and then add it with the lower
5:28
next we will calculate the number of
5:31
registers the master has requested
5:33
this data is again sent in the 2 byte
5:36
format and we will convert it to 16-bit
5:40
we will perform a check if the number of
5:42
registers is within the limits of 1 to
5:47
if it is not the slave will send an
5:52
we will talk about the exceptions and
5:54
how to send them later in the video
5:57
this limit of 125 registers is as per
6:03
next we will calculate the address of
6:06
the last register requested by the
6:09
this is equal to the start register
6:11
address plus the number of registers
6:15
this minus 1 is because the register
6:18
address starts from zero
6:20
if the end register address is more than
6:23
49 the slave will again send an
6:26
exception to the master
6:28
actually there can be a total of 10 000
6:30
registers with the end register address
6:34
999 but I have only set the values for
6:40
therefore if the master is requesting
6:42
the value of 50th register or 51st
6:45
register the slave should send an
6:57
if there are no exceptions so far the
7:00
slave will send the registered data to
7:03
we will start preparing the TX data to
7:07
the txt data should contain the slave ID
7:10
the function code the number of bytes
7:12
the slave is going to send the actual
7:15
data in bytes and the two bytes for the
7:20
here we will copy the slave ID first
7:23
then the function code which is the
7:25
second byte of the RX data buffer
7:28
then the number of bytes the slave is
7:30
sending which is twice the number of
7:32
registers the master has requested as
7:35
each register is 16-bit in size and
7:40
I am using an index variable to keep
7:42
track of how many bytes have been
7:44
written to the TX data buffer
7:46
now we will start copying the register
7:49
values into the buffer
7:51
we will repeat this for loop as many
7:53
times as the number of registers
7:55
requested by the master
7:57
the first byte will be the higher data
7:59
byte so we will shift the 16-bit
8:01
register data to the right by eight
8:05
once the higher byte data is stored in
8:07
this position the index variable will
8:11
then the lower byte data will be stored
8:13
at the very next position and here we
8:16
simply and the 16-bit data with zero
8:20
all the values in the database are
8:22
supposed to be 16-bit values and this is
8:25
why we need to convert them to two 8-bit
8:28
I have arranged the values in a way that
8:31
the register address between 10 to 19
8:33
will have values starting with 1 and
8:36
addresses from 20 to 29 will have the
8:38
values starting with 2 and so on
8:44
CE we have converted the 16-bit register
8:47
values into two bytes we will increment
8:49
the start address so that the control
8:52
can go to the next register value in the
8:55
the index variable keeps on updating
8:58
keeping track of the number of bytes
9:00
that has been stored in the TX data
9:03
once the data has been extracted we will
9:07
the CRC will be calculated in the send
9:13
we will pass the index variable to the
9:15
send data function indicating the number
9:18
of bytes in the TX data buffer
9:20
after everything is done we will return
9:23
1 to indicate the success
9:26
so we have two parts in the function
9:28
first where we are checking the query
9:30
made by the master and then the second
9:32
where we will respond to the query by
9:35
sending the register values
9:37
now let's talk about the exceptions
9:40
here again I am referring to this
9:43
document from the modbus.org
9:46
the exception responses topic can be
9:48
found on page one zero one
9:51
here we are interested in the last
9:55
so if the slave device cannot handle the
9:58
query for example if the request is to
10:00
read a non-existent register the slave
10:03
will return an exception with the nature
10:09
exception response has two Fields the
10:12
function code field and the data field
10:15
normally the slave should Echo the
10:18
function code sent by the master
10:20
this is what we did here when there was
10:25
but during an exception the slave adds a
10:28
1 to the MSB of the function code and
10:33
in the data field the slave Returns the
10:38
the exception codes can also be found in
10:43
here we have many exceptions but we will
10:46
work with the first three of these
10:49
we have the illegal function when the
10:51
unknown function code is received by the
10:55
there is a legal data address when the
10:58
data address requested by the master is
11:00
not available in the slave
11:02
and the legal data value when a value in
11:06
the query of the data field is not an
11:08
allowable value for the slave
11:10
we will use these exceptions and we will
11:13
also see them in working
11:16
I have defined these three in the modbus
11:20
here I am using an exception when the
11:23
number of requested registers is outside
11:25
the allowable range as per the modbus
11:28
standard the slave will send an illegal
11:31
data value exception
11:33
and when the end register address is
11:35
outside the defined ones the slave will
11:38
send illegal date address exception
11:41
the modbus exception function takes the
11:43
exception code as the parameter
11:46
here the first byte is the slave ID
11:49
the next byte is the modified function
11:51
code when we add a 1 to the MSB of the
11:55
and the third byte is the exception code
11:59
then we will send this buffer where the
12:02
CRC will be calculated in the send
12:09
so this is how the read holding
12:11
registers function was written
12:14
the read input registers function is
12:16
exactly the same so I don't need to
12:20
the only difference is in the database
12:24
the input registers database is defined
12:27
as a constant array so that it cannot be
12:31
whereas the holding registers is a
12:33
simple array which the master will be
12:35
able to modify in the future video
12:38
this is it for the explanation let's see
12:42
let's build and debug the code
12:48
I am using the simply modbus Master
12:50
software which can be downloaded from
12:52
their official website
12:54
here the mode is set to rtu
12:57
the com Port is 5 where the stm32 as a
13:03
the board rate is 11 5 200 eight data
13:07
bits with one stop bit and no parity
13:10
this is the same configuration that we
13:14
the slave ID is seven we have defined it
13:17
in the sdm-32 program
13:20
we will start with reading holding
13:22
registers and let's say I want to read
13:24
the register at forty thousand one
13:27
I want to read only one register and the
13:30
offset should also be forty thousand one
13:32
as per the modbus standard I am
13:35
expecting the unsigned 16-bit value
13:38
make sure this High byte first is
13:40
checked based on the configuration here
13:44
is the query the master is going to send
13:47
it contains the slave ID the function
13:50
code the start register address the
13:52
number of registers and the CRC
13:55
let's run the code now
13:58
press and button to send the query to
14:01
the master has received the response
14:05
here you can see the data received for
14:07
the register at forty thousand one is
14:09
zero let's read three registers now
14:13
starting from the same address
14:21
here you can see the response received
14:25
it contains 11 bytes and this is the
14:28
same as what the master was expecting
14:32
here you can see the data received for
14:35
the respective registers
14:37
if you check the registers database it
14:40
is the same data that we stored here
14:43
now let's read five registers starting
14:46
from the address 4011.
14:59
we have received 15 bytes in total and
15:03
you can see the value for each register
15:05
these are the five registers the master
15:08
had requested and the master has
15:10
received the same values that we have
15:19
let's see the exceptions now
15:22
as I have already mentioned there are a
15:25
total of 50 registers defined in the
15:28
now say for example if the master wants
15:31
to read two registers starting from 4050
15:36
the register 4050 is present in the
15:39
database but the 51 is not
15:42
therefore the slave will return an
15:44
exception saying the address is illegal
15:47
here you can see the master was
15:49
expecting nine bites but it only
15:53
the exception response will always have
15:55
five bytes one for the slave ID one for
15:58
the function code one for the exception
16:01
code and two for the CRC
16:04
so we saw the exception for the data
16:06
address now let's see the exception for
16:11
let's say the master wants to read
16:13
126 registers starting from the Forty
16:18
we know as per the standard the master
16:21
can request a maximum of 125 registers
16:25
since the master has requested 126 of
16:29
them the slave will send an exception
16:31
about the illegal data value
16:34
there is one more thing I want to point
16:38
let's say the master wants to read two
16:40
bytes starting from 4035.
16:44
here you can see the negative values in
16:47
the respective addresses
16:49
this is because the data type is set as
16:51
a 16-bit signed integer
16:54
let's change this to 16-bit unsigned
16:58
now you can see the positive values
17:01
they are the same as what we stored in
17:05
now let's quickly see the function Code
17:07
4 to read the input registers
17:11
let's say the master wants to read the
17:13
10 registers starting from the 3001.
17:21
here you can see the master is expecting
17:26
it has received all the 25 bytes and you
17:30
can see the values for the respective
17:33
these are the 10 values the master has
17:36
received and they are exactly the same
17:38
as what we have stored in the database
17:41
so I hope you understood the video
17:44
we saw how to program
17:46
stm32 as a slave device so that it can
17:49
respond to the queries regarding holding
17:54
we will cover the reading of coils and
17:56
discrete input in the next video
17:59
I am going to use the same code with a
18:06
you can download the code from the link
18:10
leave comments in case of any doubt
18:13
keep watching and have a nice day ahead