1. Introduction
In the field of industrial automation, data collection is a very important part. Through data collection, storage and display of industrial equipment, the production process can be monitored and optimized to improve production efficiency and quality. As a communication protocol, Modbus is widely used for data transmission in industrial control systems. Therefore, industrial data acquisition systems based on Modbus have become a common solution.
2. Modbus related knowledge
2, 1 Classification
-
Modbus TCP: Modbus TCP is a Modbus transmission method based on TCP/IP protocol. It transmits data through Ethernet, uses the standard Modbus protocol format, and encapsulates Modbus data in TCP/IP messages for transmission. Modbus TCP supports higher communication speeds and larger data volumes, and can realize distributed control and monitoring through network connections.
-
Modbus ASCII: Modbus ASCII is a character-based Modbus transmission method. It uses ASCII code to represent data and transmits it through the serial port. In Modbus ASCII, each byte is represented by two ASCII characters, so the transfer rate is slower. Modbus ASCII has better readability, but is less efficient for transmitting large amounts of data.
-
Modbus RTU: Modbus RTU is a binary-based Modbus transmission method. It uses binary encoding to represent data and transmit it through the serial port. Modbus RTU has a higher transmission rate and higher transmission efficiency than Modbus ASCII because it directly transmits binary data without the need for ASCII code conversion. Modbus RTU is usually used for short-distance data transmission in a serial communication environment.
2, 2 Features
- Modbus TCP is suitable for high-speed, long-distance communication Ethernet environments and supports multi-master and multi-slave communication.
- Modbus ASCII is suitable for low-speed, short-distance serial communication environments and is easy to debug and diagnose.
- Modbus RTU is suitable for serial communication environments with medium speed and distance, and has high efficiency, real-time performance and reliability.
3. System Design
3.1 Architecture Block Diagram
3, 2 process explanation
1. Manually enter the settings, data, etc. to configure the Modbus slave.
2. The Modbus host adopts multi-threading technology to achieve separation of reading and writing. The Modbus host collects data once per second, and then uses IPC such as shared memory to collect the data and share the data with the web server.
3. The webpage can click or send a GET or POST request to request the Web server to respond to the corresponding operation. If the webpage wants to turn off a light, that is to say, it wants to operate the coil of the slave machine, then it needs to send the request through the http protocol first, and the Webserver receives it. After receiving the data, perform corresponding judgment and processing, and send the data request to the Modbus host through the message queue. After the host receives the data, it operates the slave coil through the ModbusTCP communication protocol format to control the lights off through the web page.
4. Code analysis
Create shared memory code
struct shm *create_shared_memory() { key_t key = ftok(".", 'a'); // 1. Create key if (key < 0) { perror("key err"); exit(1); } int shmid = shmget(key, 128, IPC_CREAT | 0666); // 2. Create or open shared memory if (shmid < 0) { perror("shmget err"); exit(1); } struct shm *p = shmat(shmid, NULL, 0); // 3. Mapping if (p == (struct shm *)-1) { perror("shmat err"); exit(1); } return p; }
4. 1 host collects data
void *handler(void *arg) { struct shm *p = create_shared_memory(); while (1) { modbus_read_registers(ctx, 0, 4, dest); // 4. Call the function corresponding to the function code sprintf(p->buf, "Light sense:%d x:%d y:%d z:%d", dest[0], dest[1], dest[2], dest[3]); // Print content sleep(1); } shmdt(p); pthread_exit(NULL); }
4, 2 Host Write Coil
ctx = modbus_new_tcp("192.168.0.83", 502); // 1. Create an instance modbus_set_slave(ctx, 1); // 2. Set slave ID modbus_connect(ctx); // 3. Connect pthread_t tid; // Create thread if (pthread_create( & amp;tid, NULL, handler, NULL)) { perror("create err"); return -1; } pthread_detach(tid); // No blocking, automatic recycling when the thread ends struct shm *p = create_shared_memory(); p->flag = 1; // read and write while (1) { int i = p->con[0] - 48; int j = p->con[1] - 48; if (p->flag == 1 & amp; & amp; i >= 0 & amp; & amp; j >= 0) { switch(i) { case 0: modbus_write_bit(ctx, 0, j); // 4. Call the function corresponding to the function code break; case 1: modbus_write_bit(ctx, 1, j); // 4. Call the function corresponding to the function code break; default: printf("Input error\\ "); break; } p->flag = 0; } } shmdt(p); // 4. Unmap modbus_close(ctx); // 5. Close the socket modbus_free(ctx); // 6. Release the instance
4. 3 Webserver responds to the web page to collect data
static int modbus_get(int sock, const char *input) { struct shm *p = create_shared_memory(); // read send(sock, p->buf, strlen(p->buf), 0); printf("%s\\ ", p->buf); // 4. Unmap shmdt(p); }
4. 4 Webserver responds to web page operations
static int modbus_set(int sock, const char *input) { struct shm *p = create_shared_memory(); // read and write p->flag = 0; if (p->flag == 0) { sprintf(p->con, "%c%c", input[11], input[13]); send(sock, p->con, strlen(p->con), 0); p->flag = 1; } // 4. Unmap shmdt(p); }
4, 5 HTML
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>System</title> <h1 align="center">WebServer industrial data collection system</h1> <script> function get_info() { //Get the label named username var data = document.getElementsByName("data"); //Get the value attribute value of the first tag // v[0].value = "hello"; var xhr = new XMLHttpRequest();//Create an XMLHttpRequest object var url = ""; xhr.open("post", url, true);//Open the connection xhr.onreadystatechange = function () { if (xhr.readyState === 4 & amp; & amp; xhr.status === 200) { data[0].value = xhr.responseText; } } xhr.send("modbus_get"); } function set_equip(name, id) { var xhr = new XMLHttpRequest();//Create an XMLHttpRequest object var url = ""; xhr.open("post", url, true);//Open the connection if (name == 'equip_1' & amp; & id == 'OFF') xhr.send("modbus_set 0 0"); else if (name == 'equip_1' & amp; & id == 'ON') xhr.send("modbus_set 0 1"); if (name == 'equip_2' & amp; & id == 'OFF') xhr.send("modbus_set 1 0"); else if (name == 'equip_2' & amp; & id == 'ON') xhr.send("modbus_set 1 1"); } </script> </head> <body name="back" style="background-color: orange;"> <div style="text-align: center;margin-top: 100px;"> <!-- Data display --> Data: <input type="text" name="data" value=" "> <!-- Refresh button --> <input type="button" name="flash" value="Refresh" onclick="get_info()"><br> <!-- Device 1: Switch --> LED light: <input type="radio" name="equip_1" id="OFF" checked="default" onclick="set_equip(name,id)">OFF <input type="radio" name="equip_1" id="ON" onclick="set_equip(name,id)">ON<br> <!-- Device 2: Switch --> buzzer: <input type="radio" name="equip_2" id="OFF" checked="default" onclick="set_equip(name,id)">OFF <input type="radio" name="equip_2" id="ON" onclick="set_equip(name,id)">ON </div> </body> </html>