Contributed by ckdsx.cn, organized by Ai-Thinker
[Peripheral Porting] Ai-WB2+Modbus 485 RTU Remote Control
Video demo:<https://www.bilibili.com/video/BV1Hapxe4EsV/>
- What are Modbus and RS485? Modbus is simply a simple protocol used in industry!
Click to expand full code
**顾名思义**,它是一个Bus,即总线协议。比如串口协议、IIC协议、SPI都是通信协议。
**RS485****是一种通用的通信标准,广泛用于数据采集和控制应用中。它的主要优点之一是它允许将多个 RS485设备放在同一条总线上,这使得多个节点可以相互连接。**
**RS-485(目前称为EIA/TIA-485)是通信物理层的标准接口,一种信号传输方式,OSI(开放系统互连)模型的第一级。创建 RS-485是为了扩展RS-232接口的物理功能。**A serial EIA-485 connection is made with a cable of two or three wires: one data line, one wire with inverted data, and usually one zero wire (ground, 0V). In this way, transmitters and receivers exchange data over twisted-pair cables made of 22 or 24 AWG solid wire.
1.1 Comparing RS485 and RS232?
The RS485 and RS232 serial communication protocols have been in use for more than 50 years and are still widely used throughout commerce and industry. Extending the capabilities of the RS232 standard was the driving force behind the development of the RS485 protocol. The table below summarizes these two standards.
| Protocol | RS232 | RS485 |
|---|---|---|
| Protocol type | Full duplex | Half duplex |
| Signal type | Unbalanced | Balanced |
| Number of devices | 1 transmitter and 1 receiver | Up to 32 transmitters and 43 receivers |
| Maximum data transfer | 19.2Kbps at 15 meters | 10Mbps at 15 meters |
| Maximum cable length | About 15.25 meters at 19.2Kbps | About 1220 meters at 100Kbps |
| Output current | 500mA | 250mA |
| Minimum input voltage | +/- 3V | 0.2V differential |
1.2 Now, let's look at the main differences between these two protocols.
1.2.1 Number of transmitters and receivers
The RS232 serial interface is designed to connect two devices. The protocol supports communication between a single transmitter and a single receiver.
The RS485 interface can connect up to 32 serial devices to one transmitter.
1.2.2 Operating distance
Devices using the RS232 protocol are limited to a distance of 15 meters between transmitter and receiver while still achieving maximum data transfer rates. This length can be extended if slower data rates can be tolerated.
The RS485 protocol greatly extends the operating distance. It supports maximum data rates over a length of 1200 meters, making the RS485 protocol an excellent choice for communication between physically distant devices.
1.2.3 Data transfer speed
The RS232 interface transfers data at 1Mb/s over distances up to 15 meters. RS485 provides higher speeds of up to 10Mb/s within 15 meters. When the maximum length of 1200 meters is reached, the RS485 protocol transfers data at 100Kb/s.
1.2.4 Electrical noise issues and ground potential
The RS232 interface is a voltage-level-based system that performs best with minimal differences in ground potential. Environments with high electrical noise and variable ground potential can affect RS232's ability to transmit data reliably and may cause data loss or corruption.
The RS485 protocol uses a differential voltage system, allowing it to operate effectively in environments with higher electrical noise. A byproduct of the differential voltage system is the extended data transmission distance, higher transfer speed, and the lower voltages used by RS485.
1.3 What does Modbus contain?
Modbus-RTU, Modbus-ASCII, and Modbus-TCP are the three protocols above. A device will have only one of them. If your device uses Modbus-RTU, just look at the corresponding section below. Generally speaking, most devices use the Modbus-RTU protocol.
1.4 Frame structure Frame structure = address + function code + data + checksum
Click to expand full code
**地址**:占用一个字节,范围0-255,其中有效范围是1-247,其他有特殊用途,比如255是广播地址(广播地址就是应答所有地址,正常的需要两个设备的地址一样才能进行查询和回复)。
**功能码**:占用一个字节,功能码的意义就是,知道这个指令是干啥的,比如你可以查询从机的数据,也可以修改数据,所以不同功能码对应不同功能。
**数据**:根据功能码不同,有不同结构,在下面的实例中有说明。
**校验**:为了保证数据不错误,增加这个,然后再把前面的数据进行计算看数据是否一致,如果一致,就说明这帧数据是正确的,我再回复;如果不一样,说明你这个数据在传输的时候出了问题,数据不对的,所以就抛弃了。This is an Ai-WB2 Modbus library based on the Modbus RTU protocol. It supports the following Modbus protocol commands:
*0x01: Read one or more coil registers;
*0x02: Read one or more discrete input registers;
*0x03: Read one or more holding registers;
*0x04: Read one or more input registers;
*0x05: Write a single coil register;
*0x06: Write a single holding register;
*0x0F: Write multiple coil registers;
*0x10: Write multiple holding registers;
1.5 Modbus command examples
1.5.1 Querying data from the slave with address 01.
Master sends: 01 03 00 00 00 01 84 0A
Slave replies: 01 03 02 19 98 B2 7E
Sending data analysis

Reply data analysis

The basic flow for querying data is:
Send: slave address + the function code indicating what to do + the register address to query + the number of register addresses to query + checksum
Reply: slave address + the function code sent by the master + the number of bytes of data to send to the master + data + checksum
1.5.2 Modifying data of the slave with address 01.
Master sends: 01 06 00 00 00 01 48 0A
Slave replies: 01 06 00 00 00 01 48 0A
Sending data analysis

Reply data
parsing
1.6 For the Modbus-RTU protocol, it is enough to understand the three basic function codes 0x03, 0x06, and 0x10. Let's recall their data field sections respectively:
0x03 — the master needs to send the starting address + the number of registers, and the slave replies with the total byte count + data;
0x06 — the master sends the starting address + data content (since you only modify one, the starting address is the address to be modified), and the slave returns the starting address + data content (they turn out to be identical!)
0x10 — the master sends the starting address + the number of registers + total byte count + data, and the slave returns the starting address + the number of registers
- Peripheral introduction:
RS485 to TTL module,

RS485 remote I/O networking module, IODO controller, Modbus 
3.3V and 5.0V power/signal compatible RS485 auto-direction module. No "transmit-receive" control is needed; using this module is as simple as operating a serial port. The transparent-transmission module converts TTL signals to RS485 signals and vice versa. However, you must always remember that 485 is half-duplex communication. This communication method enables bidirectional communication, but not simultaneously in both directions — the two directions must alternate. In other words, each end of the communication channel can be either a transmitter or a receiver, but at any given moment, information can only flow in one direction. Baud rate: supports 110 to 128000bps.
Module highlights:
(1) Wide supply voltage range: 3.3V ~ 5.5V.
(2) Compatible with 3.3V and 5.0V signals.
(3) Uses original imported chips with industrial-grade design and strong anti-interference capability. It also adopts a more effective 485 lightning-protection design, so it can be used in harsh industrial sites and outdoor environments. Operating temperature is -40°C to +85°C, and the transmission distance can reach a kilometer (tested with 850 meters of 2*1.5 cable; it is recommended to use within 800 meters — add a repeater if exceeding 800 meters).
(4) Adopts a half-hole (castellated) process design with a board thickness of 0.8mm, so it can easily be used as a daughter board or soldered with terminals.
(5) Equipped with RXD and TXD signal indicator LEDs, so the transmission/reception status is always in view.
Module features:
(1) This module fully considers the 485 bus lightning-protection and anti-interference design. When transmitting over long distances outdoors,
connecting the module's "earth ground" terminal to ground provides excellent anti-interference and lightning protection, making the 485 bus safer; for short-distance indoor transmission, grounding is not required.
(2) Uses the standard 2.54mm pitch design for easy secondary development.
(3) Has a 120-ohm matching resistor; shorting RO enables the matching resistor, which is recommended for long-distance transmission.
(4) Supports multi-device communication and can be connected to a bus with up to 128 devices.
(5) The module supports hot-swapping without the signal latch-up phenomenon seen with other 485 chips.
(6) Large-area copper pour to prevent signal interference.
2.1 Common chip selection
SN75176, SN75276, SN75179, SN75180, MAX485, MAX488, MAX490
2.2 Initialization process
2.2.1 Include header files
Click to expand full code
#include<stdio.h>
#include<string.h>
#include<FreeRTOS.h>
#include<task.h>
#include<blog.h>
#include"bl_sys.h"
#include<hosal_uart.h>
#include"softcrc.h"
#include"stdint.h"
#include"string.h"2.2.2 Set initialization parameters
Baud rate: the default serial port is configured at 9600 baud, 8 data bits, no parity, and 1 stop bit.
hosal_uart_dev_tuart_dev_log = {
.config= {
.uart_id= 1,
.tx_pin= 16, // TXD GPIO
.rx_pin= 7, // RXD GPIO
.cts_pin= 255,
.rts_pin= 255,
.baud_rate= 115200,
.data_width= HOSAL_DATA_WIDTH_8BIT,
.parity= HOSAL_NO_PARITY,
.stop_bits= HOSAL_STOP_BITS_1,
.mode= HOSAL_UART_MODE_POLL,
},
};
hosal_uart_init(&uart_dev_log);
2.2.3 Configure the pins used
Default serial pins: hardware UART
Four on-board pins are used: TX, RX, 3.3V, GND (wiring method — see the module manual or the figure below)
RS485 pins: connect A+ to A+, B- to B-; ground GND if the data is noisy.
- Porting process (material introduction, porting to the project, pin selection);
3.1 Material introduction
Addresses and commands can be written directly into arrays in hexadecimal; the CRC16 checksum needs to be calculated or looked up from a table.
Refer to online CRC tutorials; use the local CRC library file for a second-layer wrapper to implement CRC checksum calculation and the functions for appending and printing the checksum value. For more on CRC calculation, please refer to online tutorials.
Since the only convenient module on hand was the Modbus RS485 remote I/O module, I used this module to build an example that sends commands to control its output relay on and off.
3.1.1 Circuit wiring diagram
Ai-WB2 => TTL serial => MAX485 => twisted pair A, B => RS485 device
Note: When connecting the AI-WB2 to the module, connect RX to RX and TX to TX. Adjust the wiring according to your module's manual!


3.2 Sample reference code
The RS485 transmission example code is as follows:
Click to expand full code
#include<Ai_WB2_RS485.h>
intcounter = 0;
voidsetup() {
RS485.begin(9600);
}
voidloop() {
RS485.beginTransmission();
RS485.print("hello");
RS485.println(counter);
RS485.endTransmission();
counter++;
delay(1000);
}The RS485 reception and serial print example code is as follows:
Click to expand full code
#include<Ai_WB2_RS485.h>
voidsetup() {
Serial.begin(9600);
while(!Serial);
RS485.begin(9600);
//enable reception, can be //disabled with: RS485.noReceive();
RS485.receive();
}
voidloop() {
if(RS485.available()) {
Serial.write(RS485.read());
}
}Note: When sending commands directly through a serial assistant, failure may occur because the command is not in hexadecimal, or because a carriage return/line feed (0D0A) is appended to the end of the command!
Note: When sending commands directly through a serial assistant, failure may occur because the command is not in hexadecimal, or because a carriage return/line feed (0D0A) is appended to the end of the command!
Program flow: the WB2 sends commands via the serial port to the RS485-to-TTL module; the remote I/O module receives the data through the Modbus A and B ports, parses it, and then executes the command actions.
Observed behavior: the TX indicator LED on the RS485-to-TTL module blinks every two seconds, and the remote I/O module's output ports 1, 2, 3, 4 turn on in sequence, then turn off in sequence.
If you don't have the hardware, you can use a serial assistant to observe the commands being sent. Remember to check the HEX display option. See the figure below.

The program code is in the attachment:
The program is too simple to be packaged as a library; you can modify and use it directly.
The make-related content is the same as in the helloworld project.
PS: Thanks to the garden director, Yin, Dog Brother, Brother Jie, Brother Yao and all the other seniors for their enthusiastic help! For compilation and flashing, please refer to the forum tutorials! If you have any questions I didn't anticipate, feel free to ask; I'll do my best to help answer and solve them!
As for the build environment + Ubuntu system + WSL, I really had to set it up no fewer than ten times... (please optimize the environment, thank you) Most of the time in this study session was spent setting up the build environment, and it also cost a WB2-32S (the firmware was flashed wrong and it got bricked — any advice on how to recover it?) plus a bunch of steamed buns and coffee, and maybe even a couple of strands of hair!

