網絡編程(Modbus進階)

思維導圖

Modbus RTU(先學一點理論)

概念

Modbus RTU 是工業自動化領域 最廣泛應用的串行通信協議,由 Modicon 公司(現施耐德電氣)于 1979 年推出。它以 高效率、強健性、易實現的特點成為工業控制系統的通信標準。 包括RS232/485等工業總線協議。

與Modbus TCP區別

與modbus TCP不同的是RTU沒有報文頭MBAP字段,但是在尾部增加了兩個CRC檢驗字節(CRC16),因為網絡協議中自帶校驗,所以在TCP協議中不需要使用CRC校驗碼。

RTU和TCP的總體使用方法基本一致,只是在創建modbus對象時有所不同,TCP需要傳入網絡socket信息;而RTU需要傳入串口相關信息。

特點

1.遵循主從問答的通信方式

2.采用串口的方式進行通信

設置串口參數時要求:(了解,后續還會用)

波特率為9600(波特率是指每秒鐘傳輸的比特數)

8位數據位 (數據位是指每個字符中包含的比特數)

1位停止位 (停止位是指在每個字符傳輸結束后添加的比特數)

無流控 (流控是指在數據傳輸過程中控制數據流量的一種機制,無流控表示在該設置下沒有額外的控制機制來控制數據流量)

modbus rtu協議格式

地址碼 功能碼 數據 校驗碼

地址碼(1字節):從機ID

功能碼(1字節):和modbus tcp一樣(01 02 03 04 05 06 0f 10H)

數據:起始地址、地址、數量、數據、字節計數;和modbus tcp一樣。

校驗碼(2字節):對地址碼、功能碼、數據進行校驗,由函數生成,循環冗余校驗 (低字節在前)

其實modbus rtu協議的格式和modbus tcp是很像,就是把tcp的MBAP報文頭去掉,只保留了一個字節的主機ID,最后結尾加上了兩個字節的校驗碼。(校驗碼沒有實際意義,是函數生成的不用管

?以01發送的數據格式為例,可以看到數據位是一樣的,上圖就是tcp和rtu協議格式的區別。數據接收也是和tcp一樣的,所以就不再講了。

modbus 庫

官方文檔:libmodbus

1庫的安裝

第一步和第二步都要運行,第一步是為了安裝配置,第二步是為了讓你使用這個庫更方便,把它放在你的C語言庫里。?????

1.1庫的安裝配置(共四步)

通過網盤分享的文件:sqlite-autoconf-3460000.tar.gz
鏈接: https://pan.baidu.com/s/1ro8-xbsFitDSEEK6mSYzwQ?pwd=3521 提取碼: 3521

直接復制命令,別手打,按順序

1. (先下載壓縮包,CtrlC+V復制到虛擬機任意路徑下)在linux中解壓壓縮包

tar -xvf libmodbus-3.1.7.tar.gz

2. 進入源碼目錄

cd libmodbus-3.1.7

3.創建文件夾(存放頭文件、庫文件)

mkdir install

4.執行腳本configure,進行安裝配置(指定安裝目錄)

./configure --prefix=$PWD/install

5. 執行make

make????????????????????????//編譯

6.執行make install

make install????????????????//安裝

執行完成后會在install文件夾下生產對應的頭文件、庫文件件夾install,用于存放產生的頭文件、庫文件等

1.2.庫的使用

要想編譯方便,可以將頭文件和庫文件放到系統路徑下(直接復制命令,別手打,按順序

sudo cp include/modbus/*.h /usr/include

sudo cp lib/* -r /lib -d

后期編譯時,可以直接gcc xx.c -lmodbus(和編譯有關線程代碼一樣)

頭文件默認搜索路徑:/usr/include/usr/local/include(之前文章庫里的內容

庫文件默認搜索路徑:/lib/usr/lib

2.函數接口

在上面的官方文檔里包含所有的函數接口,以下是常用的modbus tcp函數接口,上個文章嘗試自己寫函數,這里就是使用這些別人寫好的庫函數(更方便)。

modbus_t* modbus_new_tcp(const char *ip, int port)

功能:以TCP方式創建Modbus實例,并初始化

參數:ip :ip地址

? ? ? ? ? ?port:端口號

返回值:成功:Modbus實例

失敗:NULL

int modbus_set_slave(modbus_t *ctx, int slave)

功能:設置從機ID

參數:ctx :Modbus實例

? ? ? ? ? ?slave:從機ID

返回值:成功:0

? ? ? ? ? ? ? ?失敗:-1

int modbus_connect(modbus_t *ctx)

功能:和從機(slave)建立連接

參數:ctx:Modbus實例

返回值:成功:0

???????????????失敗:-1

void modbus_free(modbus_t *ctx)

功能:釋放Modbus實例

參數:ctx:Modbus實例

void modbus_close(modbus_t *ctx)

功能:關閉套接字

參數:ctx:Modbus實例

int modbus_read_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest)

功能:讀取線圈狀態,可讀取多個連續線圈的狀態(對應功能碼為0x01

參數:ctx :Modbus實例

? ? ? ? ? ?addr :寄存器起始地址

? ? ? ? ? ?nb :寄存器個數

? ? ???????dest :得到的狀態值

返回值:成功:讀到的數量

???????????????失敗:-1

int modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest)

功能:讀取輸入狀態,可讀取多個連續輸入的狀態(對應功能碼為0x02

參數:ctx :Modbus實例

? ? ? ? ? ?addr :寄存器起始地址

???????????nb :寄存器個數

???????????dest :得到的狀態值

返回值:成功:返回nb的值

? ? ? ? ? ? ? ?失敗:-1

int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest)

功能:讀取保持寄存器的值,可讀取多個連續保持寄存器的值(對應功能碼為0x03

參數:ctx :Modbus實例

? ? ? ? ? ?addr :寄存器起始地址

? ? ? ? ? ?nb :寄存器個數

? ? ? ? ? ?dest :得到的寄存器的值

返回值:成功:讀到寄存器的個數

? ? ? ? ? ? ? ?失敗:-1

int modbus_read_input_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest)

功能:讀輸入寄存器的值,可讀取多個連續輸入寄存器的值(對應功能碼為0x04

參數:ctx :Modbus實例

? ? ? ? ? ?addr :寄存器起始地址

? ? ? ? ? ?nb :寄存器個數

? ? ? ? ? ?dest :得到的寄存器的值

返回值:成功:讀到寄存器的個數

? ? ? ? ? ? ? ?失敗:-1

int modbus_write_bit(modbus_t *ctx, int addr, int status);

功能:寫入單個線圈的狀態(對應功能碼為0x05

參數:ctx :Modbus實例

? ? ? ? ? ?addr :線圈地址

? ? ? ? ? ?status:線圈狀態

返回值:成功:1

? ? ? ? ? ? ? ?失敗:-1

int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *src);

功能:寫入多個連續線圈的狀態(對應功能碼為15

參數:ctx :Modbus實例

? ? ? ? ? ?addr :線圈地址

? ? ? ? ? ?nb :線圈個數

? ? ? ? ? ?src :多個線圈狀態

返回值:成功:寫入的數量

? ? ? ? ? ? ? ?失敗:-1

int modbus_write_register(modbus_t *ctx, int addr, int value);

功能: 寫入單個寄存器(對應功能碼為0x06

參數: ctx :Modbus實例

? ? ? ? ? ? addr :寄存器地址

? ? ? ? ? ? value :寄存器的值

返回值:成功:1

? ? ? ? ? ? ? ?失敗:-1

int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *src);

功能:寫入多個連續寄存器(對應功能碼為16

參數:ctx :Modbus實例

? ? ? ? ? ?addr :寄存器地址

? ? ? ? ? ?nb :寄存器的個數

? ? ? ? ? ?src :多個寄存器的值

返回值:成功:寫入的數量

? ? ? ? ? ? ? ?失敗:-1

有關讀取浮點的就不全舉例了,感興趣可以去查看官方文檔

float modbus_get_float_dcba(const uint16_t *src)

功能:讀取浮點類型的數據

參數:src:讀到數據的存放數組

返回值:轉換后的浮點類型

編程

從上往下寫就可以連接到Modbus Slave,ip要寫主機的IP地址,不要寫成虛擬機的IP地址。,你要是在虛擬機運行的Modbus Slave,那就可以寫虛擬機地址。

編程步驟

1.創建實例

2.設置從機ID

3.建立連接

4.寄存器操作(按需選擇)

5.關閉套接字

6.釋放實例

編程實現

1.基礎步驟實現:
#include <modbus.h>
#include <stdio.h>int main(int argc, char const *argv[])
{char ip[128] = {"192.168.50.224"};         //IPint port = 502;                            //端口號int slave = 1;                             //從機地址int addr = 0x0000;                         //寄存器地址int nb = 0x0002;                           //寄存器數uint16_t dest[12] = {0};                   //接收數組// 創建實例// IP與端口號可作為命令行傳參modbus_t *modbus = modbus_new_tcp(ip, port);if (modbus == NULL){perror("err\n");return -1;}//設置從機IDmodbus_set_slave(modbus, slave);   //建立連接int con = modbus_connect(modbus);if (con == -1){perror("con:\n");return -1;}//寄存器操作int read = modbus_read_registers(modbus, addr, nb, dest);if (read == -1){perror("read:\n");return -1;}for (int i = 0; i < read; i++){printf("%d ", dest[i]);}putchar(10);//關閉套接字modbus_close(modbus);//釋放實例modbus_free(modbus);return 0;
}
2.數據采集小項目:

編程實現采集傳感器數據和控制硬件設備(傳感器和硬件通過slave模擬)

傳感器:2個,光線傳感器、加速度傳感器(x\y\z)

硬件設備:2個,led燈、蜂鳴器

要求:

1.多任務編程:建議多線程

2.循環1s采集一次數據,并將數據打印至終端

3.同時從終端輸入指令控制硬件設備

????????0 1:led燈打開

????????0 0:led燈關閉

????????1 1:蜂鳴器開

????????1 0:蜂鳴器關

#include <stdio.h>
#include <modbus.h>
#include <unistd.h>
#include <pthread.h>void *handler1(void *arg){            //內不含阻塞,相當于后臺運行uint8_t dest1[32] = {0};uint16_t dest2[32] = {0};modbus_t *modbusid = (modbus_t *)arg;int size = 0;while(1){								//讀取線圈狀態size = modbus_read_bits(modbusid,0,2,dest1);if(size == -1){					//容錯判斷perror("modbus_read_registers err");break;}printf("LED:%02x 蜂鳴器:%02x\n",dest1[0],dest1[1]);//查詢寄存器數值size = modbus_read_registers(modbusid,0,2,dest2);if(size == -1){					//容錯判斷perror("modbus_read_registers err");break;}printf("溫度傳感器:%02x 加速度傳感器:%02x\n",dest2[0],dest2[1]);sleep(5);                        //5秒打印一次}
}void *handler2(void *arg){                    //用于執行寫操作,需要輸入指令modbus_t *modbusid = (modbus_t *)arg;int addr,nb,status;int a = 0;				        //標志操作05,06while(1){scanf("%d",&a);				//選擇操作if(a == 5){					//操作單個線圈scanf("%d %d",&addr,&status);modbus_write_bit(modbusid,addr,status);}else if(a == 6){			//操作單個寄存器scanf("%d %d",&addr,&nb);modbus_write_register(modbusid,addr,nb);}if(a == -1)break;}
}int main(int argc, const char *argv[])
{//創建實例modbus_t *modbusid = modbus_new_tcp("192.168.43.148",502);if(modbusid == NULL){perror("modbus_new_tcp err");return -1;}//設置從機IDint slave = 1;if(modbus_set_slave(modbusid,slave) == -1){perror("modbus_set_slave err");return -1;}//建立連接if(modbus_connect(modbusid) == -1){perror("modbus_connect err");return -1;}//寄存器操作pthread_t ptid1;pthread_create(&ptid1,NULL,handler1,modbusid);        //創建第一個線程pthread_detach(ptid1);pthread_t ptid2;pthread_create(&ptid2,NULL,handler2,modbusid);        //創建第二個線程pthread_join(ptid2,NULL);//關閉套接字modbus_close(modbusid);//釋放實例modbus_free(modbusid);return 0;
}

五秒打印一次,終端還可以輸入命令取改變寄存器和線圈值

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/84289.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/84289.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/84289.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

R語言速釋制劑QBD解決方案之二

影響含量均一性的顯著因子&#xff08;%RSD&#xff09; 數據分析表明含量均一性的彎曲性不顯著。如半正態圖&#xff08;圖12&#xff09;所示&#xff0c;影響含量均一性的顯著因子為A&#xff08;原料藥粒徑&#xff09;和C&#xff08;MCC/Lactose&#xff09;。 mod2 <…

大模型原理、架構與落地

近年來&#xff0c;大模型&#xff08;Large Language Models&#xff0c;LLMs&#xff09;在人工智能領域迅猛發展&#xff0c;從GPT-3到GPT-4、Claude、Gemini、文心一言、GLM等模型相繼發布&#xff0c;大模型已逐漸走出實驗室&#xff0c;邁向產業落地。本文將從技術原理、…

WWDC 2025 macOS 26有哪些更新點

在2025年6月10日凌晨結束的WWDC 2025發布會中&#xff0c;蘋果正式發布了全新的macOS 26&#xff0c;并給其命名為Tahoe。 以下為macOS相關的主要內容&#xff1a; 命名方式改變 蘋果正式將各大系統的版本號改為對應年份&#xff0c;讓命名方式更直觀好記&#xff0c;macOS 2…

AI+預測3D新模型百十個定位預測+膽碼預測+去和尾2025年6月10日第104彈

從今天開始&#xff0c;咱們還是暫時基于舊的模型進行預測&#xff0c;好了&#xff0c;廢話不多說&#xff0c;按照老辦法&#xff0c;重點8-9碼定位&#xff0c;配合三膽下1或下2&#xff0c;殺1-2個和尾&#xff0c;再殺4-5個和值&#xff0c;可以做到100-300注左右。 (1)定…

.NET 8集成阿里云短信服務完全指南【短信接口】

文章目錄 前言一、準備工作1.1 阿里云賬號準備1.2 .NET 8項目創建 二、集成阿里云短信SDK2.1 安裝NuGet包2.2 配置阿里云短信參數2.3 創建配置類 三、實現短信發送服務3.1 創建短信服務接口3.2 實現短信服務3.3 注冊服務 四、創建控制器五、測試與優化5.1 單元測試5.2 性能優化…

解決HuggingFace不能git clone的問題

今天在從HuggingFace上clone項目的時候&#xff0c;一直出現超時問題&#xff0c;查了很多資料沒有解決&#xff0c;后來向mentor請教了一下&#xff0c;可以通過鏡像的方法解決這個問題&#xff0c;所以把方法放上來&#xff0c;希望對大家有幫助。 HuggingFace的服務器在國外…

Zookeeper 集群部署與故障轉移

Zookeeper 介紹 Zookeeper 是一個開源的分布式協調服務&#xff0c;由Apache基金會維護&#xff0c;專為分布式應用提供高可用、強一致性的核心基礎能力。它通過簡單的樹形命名空間&#xff08;稱為ZNode樹&#xff09;存儲數據節點&#xff08;ZNode&#xff09;&#xff0c;…

簡單聊下阿里云DNS劫持事件

阿里云域名被DNS劫持事件 事件總結 根據ICANN規則&#xff0c;域名注冊商&#xff08;Verisign&#xff09;認定aliyuncs.com域名下的部分網站被用于非法活動&#xff08;如傳播惡意軟件&#xff09;&#xff1b;頂級域名DNS服務器將aliyuncs.com域名的DNS記錄統一解析到shado…

服務器出現故障怎么辦?快速排查與解決方法

服務器故障的常見原因分析 硬件故障&#xff1a;內存、硬盤、網絡設備故障。 軟件故障&#xff1a;操作系統、應用程序、數據庫異常。 網絡攻擊&#xff08;如DDoS攻擊&#xff09;造成資源耗盡。 快速排查故障的步驟 檢查監控系統報警日志。 查看系統資源使用情況&#x…

Claude vs ChatGPT vs Gemini:功能對比、使用體驗、適合人群

隨著AI應用全面進入生產力場景&#xff0c;市面上的主流AI對話工具也進入“三國殺”時代&#xff1a; Claude&#xff08;Anthropic&#xff09;&#xff1a;新銳崛起&#xff0c;語言邏輯驚艷&#xff0c;Opus 模型被稱為 GPT-4 殺手ChatGPT&#xff08;OpenAI&#xff09;&a…

Git 使用大全:從入門到精通

Git 是目前最流行的分布式版本控制系統&#xff0c;被廣泛應用于軟件開發中。本文將全面介紹 Git 的各種功能和使用方法&#xff0c;包含大量代碼示例和實踐建議。 文章目錄 Git 基礎概念版本控制系統Git 的特點Git 的三個區域Git 文件狀態 Git 安裝與配置安裝 GitLinuxmacOSWi…

SpringBoot 框架第 1 次接口調用慢

文章目錄 背景分析思路 1:DeepSeek 分析思路 2:日志分析思路 3:Arthas 分析下載 Arthas啟動 Arthastrace 調用耗時分析Controller 調用耗時Service 調用分析ServiceImpl 耗時分析IService 耗時分析BaseMapper 耗時分析debug 執行鏈路MyBatisMapperProxy 解讀解決思路 1:預熱…

數據分析Agent構建

數據分析agent構建 代碼資料來源于 Streamline-Analyst&#xff0c;旨在通過該倉庫上的代碼了解如何使用大語言模型構建數據分析工具&#xff1b; 個人倉庫&#xff1a;Data-Analysis-Agent-Tutorial 不同的在于 Data-Analysis-Agent-Tutorial 是在 Streamline-Analyst 基礎…

Java后端檢查空條件查詢

通過拋出運行異常&#xff1a;throw new RuntimeException("請輸入查詢條件&#xff01;");BranchWarehouseServiceImpl.java // 查詢試劑交易&#xff08;入庫/出庫&#xff09;記錄Overridepublic List<BranchWarehouseTransactions> queryForReagent(Branch…

6??Go 語言中的哈希、加密與序列化:通往區塊鏈世界的鑰匙

Go 語言中的哈希、加密與序列化:通往區塊鏈世界的鑰匙 一、前言:離區塊鏈還有多遠? 區塊鏈聽起來可能遙不可及,似乎是只有密碼學專家和資深工程師才能涉足的領域。但事實上,構建一個區塊鏈的核心并不復雜,尤其當你已經掌握了一門系統編程語言,比如 Go。 要真正理解區…

python爬蟲——氣象數據爬取

一、導入庫與全局配置 python 運行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用&#xff1a; 引入數據解析、網絡請求、時間處理、數據庫操作等所需庫。requests&#xff1a;發送 …

Python爬蟲(三):BeautifulSoup庫

1. BeautifulSoup是什么&#xff1f; BeautifulSoup 是一個 Python 庫&#xff0c;專門用來解析 HTML 或 XML 文件&#xff0c;方便我們提取數據。它能把網頁源代碼轉換成樹形結構&#xff0c;讓我們可以輕松查找、修改內容&#xff0c;并自動處理編碼問題&#xff08;如 Unic…

AI電銷機器人智能的發展趨勢是什么?

AI電銷機器人智能的發展趨勢是什么&#xff1f;電銷機器人智能的發展前景怎么樣&#xff1f;隨著互聯網技術的不斷發展&#xff0c;AI電銷機器人智能已經成為了許多企業實現銷售數字化轉型的重要工具&#xff0c;我們一起來看看。 AI電銷機器人正突破傳統語音機械應答的邊界&a…

C++ 求圓面積的程序(Program to find area of a circle)

給定半徑r&#xff0c;求圓的面積。圓的面積應精確到小數點后5位。 例子&#xff1a; 輸入&#xff1a;r 5 輸出&#xff1a;78.53982 解釋&#xff1a;由于面積 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因為我們只保留小數點后 5 位數字。 輸…

C++_哈希表

本篇文章是對C學習的哈希表部分的學習分享 相信一定會對你有所幫助~ 那咱們廢話不多說&#xff0c;直接開始吧&#xff01; 一、基礎概念 1. 哈希核心思想&#xff1a; 哈希函數的作用&#xff1a;通過此函數建立一個Key與存儲位置之間的映射關系。理想目標&#xff1a;實現…