串口通信(5)-C#串口通信数据接收不完整解决方案

本文讲解C#串口通信数据接收不完整解决方案。

目录

一、概述

二、Modbus RTU介绍

三、解决思路

四、实例


一、概述

串口处理接收数据是串口程序编写的关键,在实际应用中基本是哪个采用异步通信的方式,所以接收数据就需要考虑接收数据的完整性,同时需要考虑数据分包,粘包,数据包的错误的情况。

有些场合尤其是全自动化设备指令收发时,数据完整性十分必要。

首先想到在串口接收事件里面添加延时,这种方案能解决分包发送的情况,对其他情况帮助不大,同时对时效要求高的情况下,显得鸡肋,不建议使用。

常规的正确的做法使用缓存的编写方式,当然这种依赖协议的完整性,本文以接收modbus协议数据为例。

二、Modbus RTU介绍

数据帧格式

首先我们要知道一帧正常的MODBUS数据帧包含的内容有:地址域 + 功能码 + 数据 + 差错校验,再者无论是上述哪种协议版本,Modbus帧格式都是一样的:

 

其中地址域:一个字节,理论上代表256个设备,实际可用的只有247个,地址0是广播地址(0~247)

功能码:一个字节,具体含义有规范要求。

数据:N个字节,具体格式和大小跟功能码有关。Modbus信息帧所允许的最大长度为256个字节,所以数据最多252个字节。

差错校验:2个字节,低字节在前,高字节在后。RTU采用16位CRC校验,是从开头一直校验到此之前。在每个RTU数据帧之前和之后有不少于3.5个字符位作为帧的分隔。

Modbus RTU通讯协议在数据通讯上采用主从应答的方式进行。只能由主机(PC,HMI等)通过唯一从机地址发起请求,从机(终端设备)根据主机请求进行响应,即半双工通讯。该协议只允许主机发起请求,从机进行被动响应,因此从机不会主动占用通讯线路造成数据冲突。

类似Modbus RTU协议的主从应答协议还有西门子的PPI、电表常用的DL/T645-2007等协议。

如果想进一步学习可以使用仿真软件进行调试学习

Modbus Poll则可以仿真出ModbusRTU中的主站。

Modbus Slave 可以仿真出ModbusRTU中的从站。

下载地址;https://www.modbustools.com/download/ModbusSlaveSetup64Bit-822.exe

当然可以下载破解版

1、协议格式

信息传输为异步方式,使用16进制进行通讯,信息帧格式:

地址码

功能码

数据区

CRC校验码

1字节

1字节

N字节

2字节

 

地址码

地址码是每个通讯信息帧的第一个字节,一般支持1到247,部分设备也支持0地址,用于接收主机的广播数据,每个从机在总线上地址必须唯一,只有与主机发送的地址码相符的从机才能响应返回数据。

功能码

功能码是每个通讯信息帧的第二个字节。主机发送,通过功能码告知从机设备应当执行何种操作。

常见的八种功能码:

功能码

定义

操作

01H

读取线圈

读取一个或多个连续线圈状态

05H

写单个线圈

操作指定位置的线圈状态

0FH

写多个线圈

操作多个连续线圈状态

02H

读取离散量输入

读取一个或多个连续离散输入状态

04H

读取输入寄存器

读取一个或多个连续输入寄存器数据

03H

读保持寄存器

读取一个或多个保持寄存器数据

06H

写单个保持寄存器

把两个十六进制数据写入对应位置

10H

写多个保持寄存器

把4*N个十六进制数据写入N个连续保持寄存器

 

数据区

数据区随功能码以及数据方向的不同而不同,这些数据可以是“寄存器首地址+读取寄存器数量”、“寄存器地址+操作数据”、“寄存器首地址+操作寄存数量+数据长度+数据”等不同的组合,在“功能码分析”详解不同功能码的数据区。

Modbus CRC校验

Modbus RTU协议常用与工业现场对数据传输的稳定性和正确性有较高的要求,因此通过CRC校验保证数据传输的正确性和完整性。

2、错误反馈

地址与CRC校验错误并不会收到从机的数据反馈,其他错误将向主机返回错误码。数据帧的第二位加上0X80表示请求发生错误(非法功能码、非法数据值等),错误数据帧如下:

地址码

功能码

错误码

CRC校验码

1字节

1字节

1字节

2字节

常见错误码如下:

名称

说明

01H

非法的功能码

不支持该功能码操作寄存器

02H

非法的寄存器地址

访问设备禁止访问的寄存器

03H

非法的数据值

写入不支持的参数值

04H

从机故障

设备工作异常

3、通讯信息传输过程

通讯命令由主机发送从机时,与主机发送的地址码相符的从机接收通讯命令,如果CRC校验无误,则执行相应的操作,然后把执行结果(数据)返回给主机。返回信息中包含地址码、功能码、执行后的数据以及CRC校验码。如果地址不匹配或者CRC校验出错就不返回任何信息。

功能码分析功能码01H:读线圈

例如:主机要读取从机地址为01H,起始线圈地址为00H的1个线圈状态,主机发送:

主机发送

发送数据(HEX)

地址码

01

功能码

01

起始线圈地址

高字节

00

低字节

00

线圈数量

高字节

00

低字节

01

CRC校验

低字节

FD

高字节

CA

如果从机寄存器00H线圈闭合,从机返回:

从机返回

发送数据(HEX)

地址码

01

功能码

01

字节数

01

线圈状态

01

CRC校验码

低字节

90

高字节

48

功能码05H:写单个线圈

例如:主机要控制从机地址为01H,线圈地址为0000H的线圈状态,主机发送:

主机发送

发送数据(HEX)

地址码

01

功能码

01

线圈地址

高字节

00

低字节

00

控制方式

高字节

00(断开)、FF(闭合)

低字节

01

CRC校验

低字节

XX

高字节

XX

从机返回与主机请求相同;

功能码0FH:写多个线圈

例如:主机要控制从机地址为01H,起始线圈地址为00H的4个线圈状态,主机发送:

主机发送

发送数据(HEX)

地址码

01

功能码

0F

起始线圈地址

高字节

00

低字节

00

线圈数量

高字节

00

低字节

04

写入字节数

01

控制方式

00(全部断开)、0F(全部闭合)

CRC校验

低字节

XX

高字节

XX

功能码0FH操作,从机返回:

从机返回

发送数据(HEX)

地址码

01

功能码

0F

起始线圈地址

高字节

00

低字节

00

线圈数量

高字节

00

低字节

04

CRC校验

低字节

54

高字节

08

功能码02H:读离散输入

例如:主机要读取从机地址为01H,起始离散量地址为00H的4个输入状态,主机发送:

主机发送

发送数据(HEX)

地址码

01

功能码

02

起始离散量地址

高字节

00

低字节

00

读取数量

高字节

00

低字节

04

CRC校验

低字节

79

高字节

C9

如果从机首地址00H开始的4离散输入全部检测到输入,从机返回:

从机返回

发送数据(HEX)

地址码

01

功能码

02

字节数

01

离散输入状态

0F

CRC校验码

低字节

E1

高字节

8C

功能码04H:读取输入寄存器

例如:主机要读取从机地址为01H,起始寄存器地址为02H的1个输入寄存器数据,主机发送:

主机发送

发送数据(HEX)

地址码

01

功能码

04

起始寄存器地址

高字节

00

低字节

02

寄存器数量

高字节

00

低字节

01

CRC校验

低字节

90

高字节

0A

如果从机输入寄存器02H的数据为3344H,从机返回:

从机返回

发送数据(HEX)

地址码

01

功能码

04

字节数

02

寄存器05H数据

高字节

33

低字节

44

CRC校验码

低字节

AD

高字节

F3

功能码03H:读保持寄存器

例如:主机要读取从机地址为01H,起始寄存器地址为05H的2个保持寄存器数据,主机发送:

主机发送

发送数据(HEX)

地址码

01

功能码

03

起始寄存器地址

高字节

00

低字节

05

寄存器数量

高字节

00

低字节

02

CRC校验

低字节

D4

高字节

0A

如果从机保持寄存器05H、06H的数据为1122H、3344H,从机返回:

从机返回

发送数据(HEX)

地址码

01

功能码

03

字节数

04

寄存器05H数据

高字节

11

低字节

22

寄存器06H数据

高字节

33

低字节

44

CRC校验码

低字节

4B

高字节

C6

功能码06H:写单个保持寄存器

例如:主机写入9988H的数据给从机地址为01H,寄存器地址为0050H的寄存器,主机发送:

主机发送

发送数据(HEX)

地址码

01

功能码

06

寄存器地址

高字节

00

低字节

50

写入值

高字节

99

低字节

88

CRC校验

低字节

E3

高字节

ED

从机返回与主机请求相同;

功能码10H:写多个保持寄存器

例如:主机要把数据0005H、2233H保存到从机地址为01H,起始寄存器地址为0020H的2个寄存器中,主机发送:

主机发送

发送数据(HEX)

地址码

01

功能码

10

起始寄存器地址

高字节

00

低字节

20

寄存器数量

高字节

00

低字节

02

写入字节数

04

0000H

寄存器待写入

高字节

00

低字节

05

0001H

寄存器待写入

高字节

22

低字节

33

CRC校验

低字节

B9

高字节

03

功能码10H操作,从机返回:

从机返回

发送数据(HEX)

地址码

01

功能码

10

起始寄存器地址

高字节

00

低字节

20

寄存器数量

高字节

00

低字节

02

CRC校验

低字节

40

高字节

02

三、解决思路

创建一个缓冲区用来存放串口每次接收到的数据,串口收到数据后,我们就直接判断缓冲区的头字节是否为头码内容,如果符合要求,则根据数据长度接收完这帧数据,之后进行CRC校验判断,若能满足,则表示这帧数据是对的。

若这帧数据不能满足校验,则说明这是一帧错误是数据,有可能我们拿到的头码是伪头码,挨个遗弃字节,直到再在缓冲区中重新找到头码,重新处理帧数据。

四、实例

准备

在modbus仿真软件中准备数据

 

 

设备地址为1

编写程序进行读取

发送为>>> 01 03 00 00 00 04 44 09

接收的为<<< 01 03 08 00 01 00 02 00 03 00 04 0D 14

实例

创建winform项目,添加一个按钮触发定时器读操作

 Cs文件代码

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows.Forms;namespace ModbusReadDemo
{public partial class Form1 : Form{List<byte> btBuf = new List<byte>(4096);//读返回数据int iReadData1 = 0;int iReadData2 = 0;int iReadData3 = 0;int iReadData4 = 0;public Form1(){InitializeComponent();}/// <字节数组转16进制字符串>/// <param name="bytes"></param>/// <returns> String 16进制显示形式</returns>public static string byteToHexStr(byte[] bytes){string returnStr = "";try{if (bytes != null){for (int i = 0; i < bytes.Length; i++){returnStr += bytes[i].ToString("X2");returnStr += " ";                       //两个16进制用空格隔开,方便看数据}}return returnStr;}catch (Exception){return returnStr;}}private void spt_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e){try{if (spt.IsOpen){int iLength = spt.BytesToRead;byte[] btData = new byte[iLength];//读数据暂存CRC CRC = new CRC();byte[] crc = new byte[2];spt.Read(btData, 0, iLength);btBuf.AddRange(btData);//缓存数据if (btBuf.Count < 8) //数据区尚未接收完整{return;}while (btBuf.Count >= 8) //至少包含帧头(地址)(1字节)、功能码(1字节)、校验位(2字节)等;最少返回8个字节{if (btBuf[0] == 0x01)//判定帧头为01{#region 读返回//btBuf[1] 功能码 读 btBuf[2]字节长度if (btBuf[1] == 0X03 & btBuf[2] == 0X08) //传输数据有帧头,用于判断{int len = btBuf[2];if (btBuf.Count < len + 5) //数据区尚未接收完整{break;}byte[] ReceiveBytes = new byte[len + 5];//读数据暂存btBuf.CopyTo(0, ReceiveBytes, 0, len + 5);CRC.CalculateCrc16(ReceiveBytes, out crc[1], out crc[0]).ToString("X");//生成验证码if ((btBuf[(len + 5) - 2] == crc[0]) & (btBuf[(len + 5) - 1] == crc[1]))//校验码验证{string strRecv = byteToHexStr(ReceiveBytes);Trace.Write("串口接收" + strRecv + "\n");try{#region  读地址的数据转化为int类型byte[] btR1 = { btBuf[4], btBuf[3], 0, 0 };//byte转化为int需要4个字节,btData[4]数据低字节, btData[3]数据高字节iReadData1 = BitConverter.ToInt32(btR1, 0);byte[] btR2 = { btBuf[6], btBuf[5], 0, 0 };iReadData2 = BitConverter.ToInt32(btR2, 0);byte[] btR3 = { btBuf[8], btBuf[7], 0, 0 };//byte转化为int需要4个字节,btData[4]数据低字节, btData[3]数据高字节iReadData3 = BitConverter.ToInt32(btR3, 0);byte[] btR4 = { btBuf[10], btBuf[9], 0, 0 };iReadData4 = BitConverter.ToInt32(btR4, 0);Trace.Write("第一个数" + iReadData1.ToString()+"\n");Trace.Write("第二个数" + iReadData2.ToString() + "\n");Trace.Write("第三个数" + iReadData3.ToString() + "\n");Trace.Write("第四个数" + iReadData4.ToString() + "\n");#endregionbtBuf.RemoveRange(0, len + 5);//数据清除}catch{btBuf.RemoveAt(0);}}else{btBuf.RemoveAt(0);}}else{btBuf.RemoveAt(0);}#endregion}else{btBuf.RemoveAt(0);}}}}// catch (Exception ex)catch{// MessageBox.Show("数据失败!"+ex, "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);}}//开始读取private void button1_Click(object sender, EventArgs e){/* 从D55-D71寄存器读 17个寄存器,30个字节,地址默认1,功能码(03为读寄存器单元),* 起始地址高位(初始化地址38,寄存器D55),起始地址低位,位数高字节,位数低字节,低位CRC校验,高位CRC校验 */spt.Open();timer1.Enabled = true;}//定时发送查询寄存器数据private void timer1_Tick(object sender, EventArgs e){if (spt.IsOpen == true){Byte[] bt = new byte[8] { 0X01, 0X03, 0X00, 0X00, 0X00, 0X04, 0X44, 0X09 };spt.Write(bt, 0, 8);//Trace.Write("串口发送");}else{//Trace.Write("串口未打开");}}}
}

 CRC代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace ModbusReadDemo
{public class CRC{private readonly byte[] _auchCRCHi = new byte[]//crc高位表{0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,0x80, 0x41, 0x00, 0xC1, 0x81, 0x40};private readonly byte[] _auchCRCLo = new byte[]//crc低位表{0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,0x43, 0x83, 0x41, 0x81, 0x80, 0x40};public ushort CalculateCrc16(byte[] buffer, out byte crcLo, out byte crcHi)//协议默认低位在前{crcHi = 0xff;  // high crc byte initializedcrcLo = 0xff;  // low crc byte initialized for (int i = 0; i < buffer.Length - 2; i++){int crcIndex = crcHi ^ buffer[i]; // calculate the crc lookup indexcrcHi = (byte)(crcLo ^ _auchCRCHi[crcIndex]);crcLo = _auchCRCLo[crcIndex];}return (ushort)(crcHi << 8 | crcLo);}}
}

 

丛机的仿真器打开,设置串口端口号等参数,开启连接,运行软件

点击读按钮,定时器触发读。

调试输出如下:

串口接收01 03 08 00 01 00 02 00 03 00 04 0D 14

第一个数1

第二个数2

第三个数3

第四个数4

 总结:通过上述实例很好的演示了接收数据不全的问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/216759.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用户案例|Milvus 助力 Credal.AI 实现 GenAI 安全与可控

AIGC 时代&#xff0c;企业流程中是否整合人工智能&#xff08;AI&#xff09;对于的企业竞争力至关重要。然而&#xff0c;随着 AI 不断发展演进&#xff0c;企业也在此过程中面临数据安全管理、访问权限、数据隐私等方面的挑战。 为了更好地解决上述问题&#xff0c;Credal.A…

【解决】Windows 11检测提示电脑不支持 TPM 2.0(注意从DTPM改为PTT)

win11升级&#xff0c;tpm不兼容 写在最前面1. 打开电脑健康状况检查2. 开启tpm3. 微星主板AMD平台开启TPM2.0解决电脑健康状况检查显示可以安装win11&#xff0c;但是系统更新里显示无法更新 写在最前面 我想在台式电脑上用win11的专注模式&#xff0c;但win10不支持 1. 打…

Scrapy爬虫学习

Scrapy爬虫学习一 1 scrapy框架1.1 scrapy 是什么1.2 安装scrapy 2 scrapy的使用2.1创建scrapy项目2.2 创建爬虫文件2.3爬虫文件的介绍2.4 运行爬虫文件 3 爬取当当网前十页数据3.1 dang.py&#xff1a;爬虫的主文件3.2 items.py 定义数据结构3.3 pipelines.py 管道3.4 执行命令…

C#实现支付宝转账功能

环境 .net 6 AlipaySDKNet.OpenAPI 2.4.0 申请证书 登录支付宝开放平台https://open.alipay.com/ 进入控制台 授权回调地址也设置一下&#xff0c;加密方式AES 新建.net 6空白的web项目 证书除了java都需要自己生成一下pkcs1的密钥 privatekey.txt就是根据应用私钥生成…

登录/验证码/注册

登录 pom文件 <!--hutool工具类--><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.9</version></dependency><!--jwt--><dependency><groupId>io.jsonw…

智慧燃气让城市能源系统高效运行

关键词&#xff1a;智慧燃气、燃气数字化、智慧燃气平台、智慧燃气解决方案、智慧燃气系统 随着我国城镇燃气行业的发展&#xff0c;燃气行业管理及服务从简单的手工运作阶段迈入数字燃气阶段&#xff0c;大量采用信息化手段管理燃气业务&#xff0c;智慧燃气应运而生。它既是…

【深度学习】注意力机制(六)

本文介绍一些注意力机制的实现&#xff0c;包括MobileVITv1/MobileVITv2/DAT/CrossFormer/MOA。 【深度学习】注意力机制&#xff08;一&#xff09; 【深度学习】注意力机制&#xff08;二&#xff09; 【深度学习】注意力机制&#xff08;三&#xff09; 【深度学习】注意…

国产数据库适配-达梦(DM)

1、通用性 达梦数据库管理系统兼容多种硬件体系&#xff0c;可运行于X86、X64、SPARC、POWER等硬件体系之上。DM各种平台上的数据存储结构和消息通信结构完全一致&#xff0c;使得DM各种组件在不同的硬件平台上具有一致的使用特性。 达梦数据库管理系统产品实现了平台无关性&…

Docker技术基础梳理 - Docker网络管理

为什么需要容器的网络管理&#xff1f; 容器的网络默认与宿主机、与其他容器相互隔离&#xff0c;且容器中可以运行一些网络应用&#xff0c;比如nginx、web应用、数据库等&#xff0c;如果需要让外部也可以访问这些容器中运行的网络应用&#xff0c;那么就需要配置网络来实现…

thinkphp连接数据库mysql 报错问题

第一 看报错日志php如果是下面这个报错的话 就是mysql 数据库没有验证连接 ​​​​​​​[2023-12-13T09:57:0108:00][error] [10501]SQLSTATE[HY000] [2054] The server requested authentication method unknown to the client 我们就可以去mysql 的文件检查 验证身份 使…

量子芯片技术:未来的计算革命

量子芯片技术&#xff1a;未来的计算革命 一、引言 随着科技的不断发展&#xff0c;人类正在进入一个全新的技术时代&#xff0c;即量子时代。量子芯片技术作为这个时代的重要代表&#xff0c;正逐渐改变我们对计算和信息处理的理解。本文将深入探讨量子芯片技术的基本原理、…

【概率方法】重要性采样

从一个极简分布出发 假设我们有一个关于随机变量 X X X 的函数 f ( X ) f(X) f(X)&#xff0c;满足如下分布 p ( X ) p(X) p(X)0.90.1 f ( X ) f(X) f(X)0.10.9 如果我们要对 f ( X ) f(X) f(X) 的期望 E p [ f ( X ) ] \mathbb{E}_p[f(X)] Ep​[f(X)] 进行估计&#xff0…

数据无效:问题和解决方案的分析

一、说明 在数字时代&#xff0c;数据已成为企业、组织和个人的基本资源。然而&#xff0c;在浩瀚的数据海洋中&#xff0c;困扰数据分析的一个常见问题是存在空值或缺失数据。数据无效是指某些数据字段中缺少信息&#xff0c;这在根据该数据进行分析和决策时可能会导致重大问题…

【计算机视觉】SIFT

在边缘提取的时候&#xff0c;用高斯一阶导对信号进行卷积&#xff0c;响应值最大的就是边界如果用高斯二阶导对信号进行卷积&#xff0c;0点就是边界点&#xff08;二阶导等于0的点&#xff0c;对应一阶导的极值点&#xff09; 如果用高斯二阶导在不同的信号上进行卷积&#x…

JS基础之作用域链

JS基础之作用域链 作用域链作用域链函数创建函数激活总结 作用域链 当JavaScript代码执行一段可执行的代码&#xff08;execution code&#xff09;时&#xff0c;会创建对应的执行上下文&#xff08;execution context&#xff09;。 对于每个执行上下文&#xff0c;都有三个重…

Linux 安装图形界面 “startx”

———————————————— 报错&#xff0c;如下&#xff1a; bash :startx command not found ———————————————— 解决方法&#xff1a; 1.先安装 — X Windows System&#xff0c;输入以下命令&#xff1a; yum groupinstall “X Window System”…

【干货分享】KingIOServer与三菱PLC的通讯的应用案例

哈喽&#xff0c;大家好&#xff0c;我是雷工&#xff01; 最近一个项目涉及用KingIOServer采集三菱PLC数据&#xff0c;特记录通讯过程方便备忘。 一、版本说明&#xff1a; 1、KingIOServer版本&#xff1a;3.7SP2 2、PLC型号&#xff1a;Q03UDV 和Q03UDE自带以太网网口。…

redis:一、面试题常见分类+缓存穿透的定义、解决方案、布隆过滤器的原理和误判现象、面试回答模板

redis面试题常见分类 缓存穿透 定义 缓存穿透是一种现象&#xff0c;引发这种现象的原因大概率是遭到了恶意攻击。具体就是查询一个一定不存在的数据&#xff0c;mysql查询不到数据也不会直接写入缓存&#xff0c;就会导致这个数据的每次请求都需要查DB&#xff0c;数据库压力…

人工智能导论习题集(3)

第五章&#xff1a;不确定性推理 题1题2题3题4题5题6题7题8 题1 题2 题3 题4 题5 题6 题7 题8

基于YOLOv8深度学习的吸烟/抽烟行为检测系统【python源码+Pyqt5界面+数据集+训练代码】目标检测、深度学习实战

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…