MQTT协议的智能家居之指纹锁

2024-04-19 07:48

本文主要是介绍MQTT协议的智能家居之指纹锁,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

基于之前的智能家居项目,这次添加了指纹锁设备的设计,硬件端主要使用0.96oled显示屏,ESP8266-NODEMCU,BYJ48步进电机以及配套驱动板,AS608指纹模块。
整个项目除了硬件端,还接入了我自己的服务器,可通过APP进行云端远程操控,对指纹锁进行模式设置和指纹设置。
装置器件图放在下面,以供参考:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
附上演示视频:

智能家居-基于mqtt协议的APP控制指纹锁装置

代码通过arduino编写,也一并贴在下面

/*** 本项目用于AS608指纹模块使用,使用到GPIO5(D1)引脚作为模拟输出TX引脚*/
#include <SoftwareSerial.h>
#include <FS.h>
#include <U8g2lib.h>                       //U8g2lib库
#include <Wire.h>                          //Wire库
#include <Ticker.h>                        //Ticker库
#include <ESP8266WebServer.h>
#include <WiFiManager.h> 
#include <ArduinoJson.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#define PRODUCT_ID    "TOP" //服务器用户名
#define API_KEY    "tx6WM==zmW21Z2pt4susBRlHMuY="//用户密码
#define DEVICE_ID "door_device"//设备名
#define TOPIC     "door_control"//订阅主题
//
bool door_clock=false;
//
WiFiClient wifiClient;
int count = 0; //ticker1控制 数据上传下发的间隔时间(s)
PubSubClient mqttClient(wifiClient);
const char* mqttServer = "***********;//服务器地址
const uint16_t mqttPort =****;//mqtt接口端口
char msgJson[75];//存json下发信息数据
char msg_buf[200];//存json上传数据及标识位
SoftwareSerial  mySerial(D3,D4);
const unsigned char welcome[] = {0X30,0X01,0X00,0X30,0X00,0X40,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X7C,0X00,0X00,0XC0,0X9F,0X1F,
0XFF,0X01,0X00,0XFC,0XC0,0X30,0X82,0X00,0X00,0X80,0X60,0X20,0XC2,0X00,0X00,0XC0,
0X20,0X20,0X62,0X00,0X00,0XC0,0X20,0X30,0X3A,0X00,0X00,0X40,0X30,0X10,0X0F,0X00,
0X00,0X40,0X10,0X18,0X03,0X00,0X00,0X40,0X20,0X0C,0X03,0X00,0X00,0X40,0XE0,0X07,
0X03,0X00,0X00,0X00,0XC0,0X01,0X02,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XE0,0X00,0X00,0X00,
0X00,0X00,0XF8,0X7F,0X00,0X00,0X00,0X00,0XFC,0X7F,0X00,0X00,0X00,0X00,0XFE,0XFF,
0X00,0X00,0X00,0X00,0XFF,0XFF,0X01,0X00,0X00,0X00,0XFF,0XFF,0X01,0X00,0X00,0X80,
0XFF,0XFC,0X03,0X00,0X00,0X80,0X1F,0XF0,0X03,0X00,0X00,0XC0,0X1F,0XE0,0X07,0X00,
0X00,0XC0,0X0F,0XC0,0X07,0X00,0X00,0XC0,0X0F,0XC0,0X07,0X00,0X00,0XC0,0X03,0X00,
0X07,0X00,0X00,0XC0,0X01,0X20,0X07,0X00,0X00,0XC0,0X7D,0XFC,0X02,0X00,0X00,0X80,
0X00,0X00,0X02,0X00,0X00,0X00,0X00,0X7A,0X03,0X00,0X00,0X00,0X18,0X10,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X80,0X02,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XE0,0X0F,0X00,0X00,
0X00,0X00,0X82,0X44,0X00,0X00,0X00,0XE0,0X07,0X60,0X00,0X00,0X00,0XF8,0X0F,0XF0,
0X00,0X00,0X00,0XFC,0X37,0XF0,0X03,0X00,0X00,0XFE,0XC7,0XFF,0X07,0X00,0X80,0XFF,
0X07,0XFF,0X1F,0X00,0XC0,0XFD,0X07,0X70,0X3F,0X00,0XF8,0XFF,0X03,0X70,0XFF,0X01,
0XFE,0XFF,0X07,0X70,0XFE,0X0F,0XFF,0XFF,0X09,0X78,0XFE,0X1F,0XFF,0XFF,0X03,0X7C,
0XFC,0X3F,0XFF,0XFF,0X23,0X7E,0XFC,0X3F,0XFF,0XFF,0XC3,0X3F,0XF8,0X7F,0XFF,0XFF,
0X87,0X3F,0XF8,0XFF,0XFF,0XFF,0X07,0X18,0XF8,0XFF,0XFF,0XFF,0X07,0X00,0XF8,0XFF,
0XFF,0XFF,0X07,0X00,0XF8,0XFF,0XFF,0XFF,0X0F,0X00,0XF8,0XFF,0XFF,0XFF,0X3F,0X00,
0XF8,0XFF,0XFF,0XFF,0XDF,0X00,0XF8,0XFF,0XFF,0XFF,0X1F,0X00,0XF8,0XFF,0XFF,0XFF,
0X1F,0X00,0XF0,0XFF,0XFF,0XFF,0X1F,0X00,0XF0,0XFF,0XFF,0XFF,0X1F,0X00,0XF0,0XFF,};
U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, SCL, SDA, U8X8_PIN_NONE);//D7 GPIO13 D8 GPIO15// D1 D2
byte buf_getfinger[20]={0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x03,0x01,0x00,0x05};//录一个指纹
byte buf_clear[20]={0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x03,0x0d,0x00,0x11};//清空指纹信息
byte buf_delete[20]={0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x07,0x0c,0x00,0x01,0x11};//删除指纹信息 本条只是模板需要更改
byte buf_finger_char[20]={0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0X04,0x02,0x01,0x00,0x08};//生成指纹特征
byte buf_identity[20]={0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0X03,0x11,0x00,0x15};//工作模式,读取指纹数据进行比对  返回ID
byte buf_getlist[20]={0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x03,0x1f,0x00,0x23};//获取指纹目录,数据是001010101格式 不是很好用,所以采用了新方法使用(在录入指纹时编写记事本文件存储)
byte buf_add[20]={0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0X03,0x10,0x00,0x14};//注册添加指纹 返回ID
byte buf_logo[6]={0xEF,0x01,0xFF,0xFF,0xFF,0xFF};
byte buf[32];
String file_name = "/AS608/users.txt"; //被读取的文件位置和名称
String file_list="";
int work_index=0;
void setup() {Serial.begin(57600);mySerial.begin(57600);//不采用外部按钮控制,不够灵活且占用引脚,改为软件控制,空出的引脚可作为门锁开关电机控制/*pinMode(D5,INPUT_PULLUP);//正常工作模式pinMode(D6,INPUT_PULLUP);//添加模式pinMode(D7,INPUT_PULLUP);//删除模式pinMode(D8,INPUT_PULLUP);//查询指纹列表digitalWrite(D6,HIGH);digitalWrite(D7,HIGH);digitalWrite(D5,HIGH);digitalWrite(D8,HIGH);*///控制电机pinMode(D5,OUTPUT);pinMode(D6,OUTPUT);pinMode(D7,OUTPUT);pinMode(D8,OUTPUT);pinMode(D0,OUTPUT);////pinMode(10,OUTPUT);//pinMode(9,OUTPUT);// WiFi.mode(WIFI_STA);WiFiManager wifiManager;// 自动连接WiFi。以下语句的参数是连接ESP8266时的WiFi名称wifiManager.autoConnect("门锁WiFi设置");mqttClient.setServer(mqttServer, mqttPort);// 设置MQTT订阅回调函数mqttClient.setCallback(receiveCallback);connectMQTTServer();if(SPIFFS.begin()){ // 启动SPIFFSSerial.println("SPIFFS Started.");} else {Serial.println("SPIFFS Failed to Start.");}u8g2.begin();//允许显示UTF8字符u8g2.enableUTF8Print();//文本的参考点为左上角u8g2.setFontPosTop();u8g2.clearBuffer();u8g2.drawXBMP(40, 0, 48, 64, welcome);u8g2.sendBuffer();delay(1000);
}
void connectMQTTServer() {String clientId = DEVICE_ID;String productId = PRODUCT_ID;String apiKey = API_KEY;// 连接MQTT服务器if (mqttClient.connect(clientId.c_str(), productId.c_str(), apiKey.c_str())) {Serial.println("MQTT Server Connected.");Serial.println("Server Address: ");Serial.println(mqttServer);Serial.println("ClientId:");Serial.println(clientId);subscribeTopic(); // 订阅指定主题} else {Serial.print("MQTT Server Connect Failed. Client State:");Serial.println(mqttClient.state());delay(1000);}
}
// 订阅指定主题
void subscribeTopic() {// 这么做是为确保不同设备使用同一个MQTT服务器测试消息订阅时,所订阅的主题名称不同String topicString = TOPIC;char subTopic[topicString.length() + 1];strcpy(subTopic, topicString.c_str());// 通过串口监视器输出是否成功订阅主题以及订阅的主题名称if (mqttClient.subscribe(subTopic)) {Serial.println("Subscrib Topic:");Serial.println(subTopic);} else {Serial.print("Subscribe Fail...");}
}
//获取下发指令topic 指定主题 payload 下发信息,以字节存储 length 下发信息长度
void receiveCallback(char* topic, byte* payload, unsigned int length) {Serial.print("Message Received [");Serial.print(topic);Serial.print("] ");String receiveMessage;for (int i = 0; i < length; i++) {Serial.print((char)payload[i]);receiveMessage += (char)payload[i];}Serial.println("----" + receiveMessage + "----");Serial.print("Message Length(Bytes) ");Serial.println(length);///StaticJsonDocument<128> doc;deserializeJson(doc, receiveMessage);String door_control = doc["door_cmd"]; // String door_message = doc["message"];//Serial.print(control);if(door_control=="add"){Serial.println("添加指纹模式");work_index=1;String msg;StaticJsonDocument<48> doc;doc["door_msg"] = "add ok";serializeJson(doc, msg);char publishMsg[msg.length() + 1];strcpy(publishMsg, msg.c_str());int lens = strlen(publishMsg);mqttClient.publish("getMessage", publishMsg, lens);   }else if(door_control=="delete"){Serial.println("删除指纹模式");work_index=2;String msg;StaticJsonDocument<48> doc;doc["door_msg"] = "delete ok";serializeJson(doc, msg);char publishMsg[msg.length() + 1];strcpy(publishMsg, msg.c_str());int lens = strlen(publishMsg);mqttClient.publish("getMessage", publishMsg, lens);   }else if(door_control=="list"){Serial.println("查看指纹模式");work_index=3;File dataFile = SPIFFS.open(file_name, "r"); String user_list;String msg;for(int i=0;i<dataFile.size();i++){user_list+=(char)dataFile.read();}dataFile.close(); StaticJsonDocument<80> doc;doc["door_msg"] = user_list;serializeJson(doc, msg);char publishMsg[msg.length() + 1];strcpy(publishMsg, msg.c_str());int lens = strlen(publishMsg);mqttClient.publish("getMessage", publishMsg, lens);    }else if(door_control=="work"){Serial.println("工作模式");work_index=0;String msg;StaticJsonDocument<48> doc;doc["door_msg"] = "work ok";serializeJson(doc, msg);char publishMsg[msg.length() + 1];strcpy(publishMsg, msg.c_str());int lens = strlen(publishMsg);mqttClient.publish("getMessage", publishMsg, lens);}
}
void finger_add(){u8g2.setFontPosTop();u8g2.setFont(u8g2_font_crox2hb_tr);u8g2.clearBuffer();u8g2.drawStr(30, 0, "add finger");u8g2.drawLine(0, 14, 128, 14);u8g2.sendBuffer();mySerial.write(buf_add, 12);u8g2.setFont(u8g2_font_crox2hb_tr);u8g2.drawStr(0, 20, "pressing");delay(2000);int i = 0;/* while (Serial.available()<6) {delay(1000);u8g2.drawStr(i+64, 20, ".");Serial.println("正在连接");i = i + 5;u8g2.sendBuffer();}*/if(Serial.available()>6){size_t len = Serial.available();  //返回可读数据的长度uint8_t sbuf[len];Serial.readBytes(sbuf, len);if(sbuf[6]==0x07){//Serial.println("验证指纹");if(sbuf[9]==0x00){u8g2.drawStr(0, 34, "ok!");u8g2.drawStr(0, 48, "new ID:");u8g2.setCursor(80, 48);u8g2.print(sbuf[10]);u8g2.print(sbuf[11]);u8g2.sendBuffer();Serial.println("注册成功,存在");Serial.print("ID:");Serial.print(sbuf[10]);Serial.print(sbuf[11]);Serial.println();File dataFile = SPIFFS.open(file_name, "a");dataFile.print("用户");dataFile.print(sbuf[10]);dataFile.println(sbuf[11]); dataFile.println(",");        dataFile.close();                         }else if(sbuf[9]==0x01){Serial.println("识别错误,请重新按下指纹");u8g2.drawStr(0, 20, "error!");u8g2.drawStr(0, 22, "press again!");u8g2.sendBuffer();}else if(sbuf[9]==0x1e){Serial.println("注册失败!");u8g2.drawStr(0, 20, "fail!");u8g2.sendBuffer();}delay(1000);}}}
void getlist(){//读取文件内容并且通过串口监视器输出文件信息u8g2.setFontPosTop();u8g2.setFont(u8g2_font_crox2hb_tr);u8g2.clearBuffer();u8g2.drawStr(30, 0, "finger list");u8g2.drawLine(0, 14, 128, 14);u8g2.sendBuffer();u8g2.setCursor(0, 26);File dataFile = SPIFFS.open(file_name, "r"); String user_list;for(int i=0;i<dataFile.size();i++){user_list+=(char)dataFile.read();}u8g2.print(user_list);Serial.print(user_list);  u8g2.sendBuffer();dataFile.close(); delay(1000);
}
void finger_clear(){mySerial.write(buf_clear, 12);u8g2.setFontPosTop();u8g2.setFont(u8g2_font_crox2hb_tr);u8g2.clearBuffer();u8g2.drawStr(30, 0, "finger clear");u8g2.drawLine(0, 14, 128, 14);u8g2.sendBuffer();u8g2.setCursor(0, 26);delay(1000);if(Serial.available()>6){size_t len = Serial.available();  //返回可读数据的长度uint8_t sbuf[len];Serial.readBytes(sbuf, len);/*for(int i=0; i<len; i++){      // 然后通过串口监视器输出readBytesSerial.print(sbuf[i],HEX);          // 函数所读取的信息}*/if(sbuf[6]==0x07){//Serial.println("验证指纹");if(sbuf[9]==0x00){u8g2.println("success!");u8g2.sendBuffer();Serial.println("删除成功!");File dataFile = SPIFFS.open(file_name, "w");dataFile.print("");dataFile.close();    Serial.println();}else if(sbuf[9]==0x01){Serial.println("包错误!");u8g2.println("error!");u8g2.sendBuffer();}else if(sbuf[9]==0x11){u8g2.println("fail!");u8g2.sendBuffer();Serial.println("删除失败!");}delay(2000);}}
}
void work(){mySerial.write(buf_identity, 12);u8g2.setFontPosTop();u8g2.setFont(u8g2_font_crox2hb_tr);u8g2.clearBuffer();u8g2.drawStr(10, 0, "finger working");u8g2.drawLine(0, 14, 128, 14);u8g2.drawStr(0, 18, "press checking!");u8g2.sendBuffer();u8g2.setCursor(0, 32);delay(1000);if(Serial.available()>6){size_t len = Serial.available();  //返回可读数据的长度uint8_t sbuf[len];Serial.readBytes(sbuf, len);/*for(int i=0; i<len; i++){      // 然后通过串口监视器输出readBytesSerial.print(sbuf[i],HEX);          // 函数所读取的信息}*/if(sbuf[6]==0x07){//Serial.println("验证指纹");if(sbuf[9]==0x00){u8g2.print("wecome!");u8g2.setCursor(0, 46);u8g2.print("ID:");u8g2.print(sbuf[10]);u8g2.print(sbuf[11]);u8g2.sendBuffer();Serial.println("识别成功,存在");Serial.print("ID:");Serial.print(sbuf[10]);Serial.print(sbuf[11]);Serial.println();/*** 添加开门模块* 可改为步进电机更为精确和稳定* 暂时手里只有个N20减速电机,加个驱动板拿来用用*/for(int i=0;i<200;i++){delay(2);digitalWrite(D5, HIGH);digitalWrite(D6, HIGH);digitalWrite(D7, LOW);digitalWrite(D8, LOW);delay(2);digitalWrite(D5, LOW);digitalWrite(D6, HIGH);digitalWrite(D7, HIGH);digitalWrite(D8, LOW);delay(2);digitalWrite(D5, LOW);digitalWrite(D6, LOW);digitalWrite(D7, HIGH);digitalWrite(D8, HIGH);delay(2);digitalWrite(D5, HIGH);digitalWrite(D6, LOW);digitalWrite(D7, LOW);digitalWrite(D8, HIGH);}for(int i=0;i<200;i++){delay(2);digitalWrite(D5, HIGH);digitalWrite(D6, HIGH);digitalWrite(D7, LOW);digitalWrite(D8, LOW);delay(2);digitalWrite(D5, HIGH);digitalWrite(D6, LOW);digitalWrite(D7, LOW);digitalWrite(D8, HIGH);delay(2);digitalWrite(D5, LOW);digitalWrite(D6, LOW);digitalWrite(D7, HIGH);digitalWrite(D8, HIGH);delay(2);digitalWrite(D5, LOW);digitalWrite(D6, HIGH);digitalWrite(D7, HIGH);digitalWrite(D8, LOW);}}else if(sbuf[9]==0x01){u8g2.print("error!");u8g2.setCursor(0, 46);u8g2.print("press again!");u8g2.sendBuffer();Serial.println("识别错误,请重新按下指纹");}else if(sbuf[9]==0x09){u8g2.print("no user!");u8g2.setCursor(0, 46);u8g2.print("press again!");u8g2.sendBuffer();Serial.println("没有检索到该用户,请重新按下指纹");}delay(1000);}}
}
void loop() {//mySerial.listen(); //软件控制方式if (mqttClient.connected()) { // 如果开发板成功连接服务器// 每隔2秒钟发布一次信息// 保持心跳 若电机正在运转,暂时不发信息(由于mcu没有多线程,不能同时运转电机和上传下发数据)mqttClient.loop();} else {                  // 如果开发板未能成功连接服务器connectMQTTServer();    // 则尝试连接服务器}//硬件控制方式/*if(digitalRead(D5)==LOW){Serial.println("工作模式0");work_index=0;//工作模式}else if(digitalRead(D6)==LOW){Serial.println("工作模式1");work_index=1;//添加模式}else if(digitalRead(D7)==LOW){Serial.println("工作模式2");work_index=2;//删除模式}else if(digitalRead(D8)==LOW){Serial.println("工作模式3");work_index=3;//查询模式}*/if(work_index==0){work();}else if(work_index==1){finger_add();}else if(work_index==2){finger_clear();}else if(work_index==3){getlist();}}

app上面由于加入了我整个项目中,不是很好展示,不过可以进行硬件端控制,代码中注释掉了,有需要可以自己改动一下IO口即可使用。

下个项目准备做一个基于esp32-cam的云端视频监控,然后加入到我的智能家居里面,提高拓展性。

这篇关于MQTT协议的智能家居之指纹锁的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/916954

相关文章

Nginx中配置HTTP/2协议的详细指南

《Nginx中配置HTTP/2协议的详细指南》HTTP/2是HTTP协议的下一代版本,旨在提高性能、减少延迟并优化现代网络环境中的通信效率,本文将为大家介绍Nginx配置HTTP/2协议想详细步骤,需... 目录一、HTTP/2 协议概述1.HTTP/22. HTTP/2 的核心特性3. HTTP/2 的优

关于WebSocket协议状态码解析

《关于WebSocket协议状态码解析》:本文主要介绍关于WebSocket协议状态码的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录WebSocket协议状态码解析1. 引言2. WebSocket协议状态码概述3. WebSocket协议状态码详解3

Qt 中集成mqtt协议的使用方法

《Qt中集成mqtt协议的使用方法》文章介绍了如何在工程中引入qmqtt库,并通过声明一个单例类来暴露订阅到的主题数据,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧... 目录一,引入qmqtt 库二,使用一,引入qmqtt 库我是将整个头文件/源文件都添加到了工程中进行编译,这样 跨平台

Java如何接收并解析HL7协议数据

《Java如何接收并解析HL7协议数据》文章主要介绍了HL7协议及其在医疗行业中的应用,详细描述了如何配置环境、接收和解析数据,以及与前端进行交互的实现方法,文章还分享了使用7Edit工具进行调试的经... 目录一、前言二、正文1、环境配置2、数据接收:HL7Monitor3、数据解析:HL7Busines

【Linux】应用层http协议

一、HTTP协议 1.1 简要介绍一下HTTP        我们在网络的应用层中可以自己定义协议,但是,已经有大佬定义了一些现成的,非常好用的应用层协议,供我们直接使用,HTTP(超文本传输协议)就是其中之一。        在互联网世界中,HTTP(超文本传输协议)是一个至关重要的协议,他定义了客户端(如浏览器)与服务器之间如何进行通信,以交换或者传输超文本(比如HTML文档)。

【Go】go连接clickhouse使用TCP协议

离开你是傻是对是错 是看破是软弱 这结果是爱是恨或者是什么 如果是种解脱 怎么会还有眷恋在我心窝 那么爱你为什么                      🎵 黄品源/莫文蔚《那么爱你为什么》 package mainimport ("context""fmt""log""time""github.com/ClickHouse/clickhouse-go/v2")func main(

2024.9.8 TCP/IP协议学习笔记

1.所谓的层就是数据交换的深度,电脑点对点就是单层,物理层,加上集线器还是物理层,加上交换机就变成链路层了,有地址表,路由器就到了第三层网络层,每个端口都有一个mac地址 2.A 给 C 发数据包,怎么知道是否要通过路由器转发呢?答案:子网 3.将源 IP 与目的 IP 分别同这个子网掩码进行与运算****,相等则是在一个子网,不相等就是在不同子网 4.A 如何知道,哪个设备是路由器?答案:在 A

基于人工智能的智能家居语音控制系统

目录 引言项目背景环境准备 硬件要求软件安装与配置系统设计 系统架构关键技术代码示例 数据预处理模型训练模型预测应用场景结论 1. 引言 随着物联网(IoT)和人工智能技术的发展,智能家居语音控制系统已经成为现代家庭的一部分。通过语音控制设备,用户可以轻松实现对灯光、空调、门锁等家电的控制,提升生活的便捷性和舒适性。本文将介绍如何构建一个基于人工智能的智能家居语音控制系统,包括环境准备

Modbus-RTU协议

一、协议概述 Modbus-RTU(Remote Terminal Unit)是一种基于主从架构的通信协议,采用二进制数据表示,消息中的每个8位字节含有两个4位十六进制字符。它主要通过RS-485、RS-232、RS-422等物理接口实现数据的传输,传输距离远、抗干扰能力强、通信效率高。 二、报文结构 一个标准的Modbus-RTU报文通常包含以下部分: 地址域:单个字节,表示从站设备

网络原理之TCP协议(万字详解!!!)

目录 前言 TCP协议段格式 TCP协议相关特性 1.确认应答 2.超时重传 3.连接管理(三次握手、四次挥手) 三次握手(建立TCP连接) 四次挥手(断开连接)  4.滑动窗口 5.流量控制 6.拥塞控制 7.延迟应答 8.捎带应答  9.基于字节流 10.异常情况的处理 小结  前言 在前面,我们已经讲解了有关UDP协议的相关知识,但是在传输层,还有