上位机学习之串口通信与温湿度项目实战

文章目录

  • 一、串口通信与温湿度项目实战
      • 1、学习串口通信硬件:巩固RS-485串口硬件和通信基础知识
        • 1.1、串行通信的数据流和格式
        • 1.2、串口通信参数设置
        • 1.3、modbus协议基础
        • 1.4、数据存储和功能代码
        • 1.5、modbus通信报文分析
      • 2、主-从通信仿真测试
        • 2.1、组件设计
        • 2.2、创建温湿度测试项目
        • 2.3、添加控制台项目Modbus_base用于测试
        • 2.4、将功能封装成类库moudbusRTU通信库
        • 2.5、用通信库完成项目开发

一、串口通信与温湿度项目实战

请添加图片描述

请添加图片描述
仿真软件
请添加图片描述

modbus poll 、modbus slave、虚拟串口软件

下载网址:https://blog.csdn.net/hanhui22/article/details/108344006

xcom串口助手

下载网址:https://blog.csdn.net/mshlc0728/article/details/109472277

请添加图片描述

1、学习串口通信硬件:巩固RS-485串口硬件和通信基础知识

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

1.1、串行通信的数据流和格式

在这里插入图片描述

原理:串行通信是将字节byte拆分成一个个的位bit后,在传输出去,收到数据的一方,再将这些位组合成原来的字节。要求传输格式必须统一,传输方式(节拍)必须一致。

在这里插入图片描述

起始位:通常用0表示,位于字符帧开头

数据位:通常包括5到8位数据,在起始位之后,先发送低位,后发送高位

奇偶校验位:用来检验数据传输过程中的是否有错误,站一位,包括偶校验(O)奇校验(E)无校验(N)

停止位:通常用1表示,便于接收端确定下一帧的起始位

1.2、串口通信参数设置

波特率: 表示每秒传输的位(比特,bit)的个数,也就是没秒传输的0和1的个数。常见波特率:4800b/s、9600b/s、19200b/s、38400b/s、115200b/s

串行通信格式(单字节协议):常用:(9600,N,8,1)波特率9600b/s,无奇偶校验位,8位数据位,1位停止位

1.3、modbus协议基础

通信协议:不同设备之间交换数据要遵循的规范。就好比人与人之间交流用的语言,必须要有语法。通常情况下,串行通信遵守Modbus协议,串口硬件(RS-232、RS-485、RS-422)都是按照Modbus协议。但是Modbus也可以用于以太网TCP/IP通信。

modbus与串口关系:1、串行通信物理接口:RS-232、RS-485、RS-422接口,是硬件。2、Modbus是国际标准的串行通信协议,是软件。

modbus与串行通信的关系

1、前面所讲串行通信格式:表示一个字节的传输协议(9600,N,8,1),实际应用中数据传送都是多个串行字节组合到一起。问题:如何识别多个字节?也就是对多个串行字节传输和解析的标准怎么规定?Modbus就是这个作用。

2、Modbus:就是如何用串口一次连续传输多个有序字节的协议。它规定了一次发送多少给字节,以及字节顺序如何排列。

modbus网络传输的三种模式

1、ASCII模式:MG标准信息交换码(0-9,a-z,A-Z),数据中的每8个位的字节都用ASCII码发送。

2、RTU模式:(Remote Terminal Unit,RTU)远程终端单元模式通信,针对通信距离较长和工业现场环境恶劣而设计的通信结构,特点:消息中每个8 bit的字节都包含量4bit的十六进制字符。

3、TCP模式:通过以太网和互联网连接传输数据使用的是TCP/IP协议,称为TCP模式,硬件接口就是以太网接口

Modbus RTU消息帧格式

在这里插入图片描述

注意:3.5字符时间间隔是作区别前后两帧数据的分隔符,只针对RTU模式有效。

计算: 串行通信中,一个字符包括:1个起始位+8个数据位+1个校验位(可选)+1个停止位(一般情况)这样,一个字符帧就包括11位,3.5个字符就是3.5*11=38.5位

地址域:用来定位设备。一个字节的从站地址,范围是:1~247

功能码:指定存储区域的操作类型。1个字节构成,取值范围是:1~255(十进制)

1.4、数据存储和功能代码

线圈和寄存器

电气控制中,接触器和中间继电器都是靠得电和失电来控制触点闭合(1)和断开(0)实现两种状态。所以,用线圈表示布尔量(1/0)。寄存器在计算机中就是用来存储数据的,所以,非布尔量的数据,放到寄存器中。

读写类型

以西门子PLC为例,I和Q都表示线圈,但是他们的分工是不同的,I表示输入,Q表示输出,输入意味着该存储区里的值必须由外部设备接入,是只读的;输出表示输出结果给外部设备,是可读可写的。

在这里插入图片描述

设备地址:一般采用10进制,一般是5位,第一位表示寄存器类型。

Modbus协议地址:指通信时使用的寄存器寻址地址。注意:设备地址是40001对应寻址地址就是0x0000;40002对应0x0001

功能码

用来表示不同区域,执行不同的读写操作,读写2种操作,存储区4个,但是输入线圈和输入寄存器只能读取,不能写入,出去这两种,会有6种不同的操作,但是对写入操作又做了两种细分,最后形成了8种具体操作

在这里插入图片描述

1.5、modbus通信报文分析

读取保持/输出寄存器,功能码:03H用于输出参数或者设备设定的参数,AO模拟量输出 类型:字

说明:一个寄存器就是一个字,一个字包含两个字节(16位11111111 11111111,最大值是65535)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

设备文档

在这里插入图片描述

在这里插入图片描述

Tx:019-01 03 00 00 00 02 C4 0B
Rx:020-01 03 04 00 FE 00 AF DB BF

询问帧:01地址码 03功能码 0000起始地址 0002数据长度 C40B 校验码

应答帧:01地址码 03 功能码 04应答码 00FE温度值 00AF湿度值

串口助手调试:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

主站发送:01 03 00 00 00 02 C4 0B 从站响应:01 03 04 00 7B 02 4D 4B 7F

主站发送的消息(01 03 00 00 00 02 C4 0B):

  • 01:设备地址(Slave Address),表示目标从设备的地址是 1
  • 03:功能码(Function Code),表示读取保持寄存器(Read Holding Registers)。功能码 0x03 通常用于请求从设备的保持寄存器。
  • 00 00:起始地址(Starting Address)。表示读取从地址 0x0000 开始的寄存器。
  • 00 02:读取的寄存器数量(Number of Registers)。这里请求读取 2 个寄存器。
  • C4 0B:校验和(CRC)。这是消息的 CRC 校验码,确保消息在传输中没有错误。

返回的响应(01 03 04 00 7B 02 4D 4B 7F ):

  • 01:设备地址(Slave Address)。表示返回响应的从设备是 1
  • 03:功能码(Function Code)。与请求的功能码一致,表示是 读取保持寄存器 的响应。
  • 04:字节数(Byte Count)。这里返回 4 个字节的数据(即 2 个寄存器,每个寄存器占 2 字节)。
  • 00 7B:第一个寄存器的数据。表示第一个寄存器的值是 0x007B,即十进制的 123
  • 02 4D:第二个寄存器的数据。表示第二个寄存器的值是 0x004D,即十进制的 77
  • 4B 7F:这部分应该是额外的或校验错误的部分,可能与消息的 CRC 校验码或数据一致性有关,具体要看通讯协议的要求。

在这里插入图片描述

2、主-从通信仿真测试

只给出大概的步骤,具体步骤看课程
在这里插入图片描述

2.1、组件设计

创建一个类库用于组件设计

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

设置控件的属性:

 //设置温湿度显示
 private int barHight=188;
 public double setValue
 {
     set{
         if (value < 0 || value > 70)
         {
             MessageBox.Show("温度值必须在0到70之间");
         }
         else
         {
             //实际值显示的高度
             double realValue = barHight - (barHight / 70.0)*value;
             //上面空白部分遮罩高度
             this.whiteBar.Height = Convert.ToInt32(realValue);
         }
     }
 }

 //设置温湿度背景颜色
 public BgColor bgColor;
 public BgColor SetBgColor
 {
     get { return bgColor; }
     set
     {
         if (value == BgColor.Green)
         {
             this.panel1.BackgroundImage = Properties.Resources.one;
         }
         else
         {
             this.panel1.BackgroundImage = Properties.Resources.two;
         }
         bgColor = value;
     }

 }

C#使用Resources资源文件,添加图片资源https://blog.csdn.net/weixin_44710358/article/details/144627373

2.2、创建温湿度测试项目

创建windows窗体应用

在这里插入图片描述

右键控件项目生成,在温湿度控制项目会生成上面完成的组件

在这里插入图片描述

在这里插入图片描述

2.3、添加控制台项目Modbus_base用于测试

在这里插入图片描述

   static void Main(string[] args)
   {
       SerialPort serialPort = new SerialPort();

       //设置96N81
       serialPort.PortName="COM2";
       serialPort.BaudRate = 9600;
       serialPort.Parity = Parity.None;
       serialPort.DataBits = 8;
       serialPort.StopBits = StopBits.One;

       //打开串口
       serialPort.Open();
       while (true)
       {
           Thread.Sleep(2000);
           //创建字节数组,拼接报文
           List<byte> sendBits = new List<byte>();
           sendBits.Add(0x01);//站地址
           sendBits.Add(0x03);//功能码
           sendBits.Add(0x00);//起始寄存器高位
           sendBits.Add(0x00);//低位
           sendBits.Add(0x00);//寄存器数量高位
           sendBits.Add(0x02);//低位
           sendBits.Add(0xC4);//CRC校验
           sendBits.Add(0x0B);
           //发送报文
           serialPort.Write(sendBits.ToArray(), 0, sendBits.Count);//发送字节数组,偏移量为0
                                                                   //接收报文
           Thread.Sleep(100);//延迟100毫秒
           byte[] saveBits = new byte[serialPort.BytesToRead];//获取缓冲区字节数
           serialPort.Read(saveBits, 0, saveBits.Length);//接收缓冲区全部的字节

           //验证接收数据
           if (saveBits[0] == 0x01)
           {
               //观察报文01 03 04 00 7B 02 4D 4B 7F
               //接收报文1  3  4 00 123 2 77 75 127
               //数据索引0  1  2  3  4  5  6  7  8
               //字节到10进制高低位转换:
               //123 和 589 如何转换的 123 和 2 77 
               //  123/256 + 123%256      589/256 + 589%256
               //转换成温度、湿度(1个高字节*256+一个低字节)=十进制数
               int humidity = saveBits[3] * 256 + saveBits[4];
               int temperature = saveBits[5] * 256 + saveBits[6];
               Console.WriteLine($"湿度{humidity * 0.1}%" + $"温度{temperature * 0.1}℃");
           }
       }            
   }
2.4、将功能封装成类库moudbusRTU通信库

在这里插入图片描述

功能实现:将功能的实现分为字段、构造方法、属性、方法

namespace Modbus_RTU
{
    /// <summary>
    /// moudbusRTU通信库
    /// </summary>
    public class modbusRTU
    {
        //串口对象
        private SerialPort serialPort = null;
        //构造方法
        public modbusRTU()
        {

        }
        /// <summary>
        /// 接收构造方法
        /// </summary>
        /// <param name="delay">接收报文延迟</param>
        public modbusRTU(int delay)
        {
            this.ReceiveDelay = delay;
        }
        //属性
        //private int ReceiveDelay { get; set; }没有对数据进行限制
        private int _receiveDelay = 100;
        public int ReceiveDelay
        {
            get { return _receiveDelay; }
            set
            {
                if (value < 10||value>2000)//根据实际情况定义
                {
                    _receiveDelay = 100;
                }
                else
                {
                    _receiveDelay = value;
                }
            }
        }
        //方法
        //打开串口
        /// <summary>
        /// 打开串口
        /// </summary>
        /// <param name="portName">串口号</param>
        /// <param name="baudRate">波特率</param>
        /// <param name="parity">校验位</param>
        /// <param name="dataBits">数据位</param>
        /// <param name="stopBits">停止位</param>
        public void Connect(string portName,int baudRate=9600,Parity parity=Parity.None,int dataBits=8,StopBits stopBits=StopBits.One)
        {
            //实例化串口对象
            serialPort = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
            try
            {
                serialPort.Open();
            }
            catch (Exception e)
            {
                throw new Exception("串口打开失败"+e);
            }

        }
        //关闭串口
        public void DisConnect()
        {
            if (serialPort!=null && serialPort.IsOpen)
            {
                serialPort.Close();
            }
        }

        //读取保存寄存器数据
        /// <summary>
        /// 读取保存寄存器
        /// </summary>
        /// <param name="slaveId">从站id</param>
        /// <param name="startAddress">寄存器起始地址</param>
        /// <param name="count">寄存器数量</param>
        /// <returns>返回只有数据的数组</returns>
        /// <exception cref="Exception"></exception>
        public byte[] ReadData(byte slaveId,int startAddress,int count)
        {
            //第一封装请求报文
            byte[] sendBytes = new byte[8];
            sendBytes[0] = slaveId;
            sendBytes[1] = 0x03;
            sendBytes[2] = (byte)(startAddress / 256);
            sendBytes[3] = (byte)(startAddress % 256);
            sendBytes[4] = (byte)(count / 256);
            sendBytes[5] = (byte)(count % 256);
            //封装CRC校验
            byte[] CRC = CRC16(sendBytes,6);
            sendBytes[6] = CRC[0];
            sendBytes[7] = CRC[1];//CRC校验有问题,找不到合适的校验
            //sendBytes[6] = 0XC4;
            //sendBytes[7] = 0X0B;
            //第二发送请求报文
            byte[] receiveBytes = null;
            try
            {
                serialPort.Write(sendBytes,0,sendBytes.Length );//发送报文
                Thread.Sleep(ReceiveDelay);//延时接收
                //第三 接收返回报文
                receiveBytes=new byte[serialPort.BytesToRead];
                serialPort.Read(receiveBytes,0,receiveBytes.Length);//从缓冲区接收所有数据到指定位置

            }
            catch (Exception e)
            {
                throw new Exception("发送报文异常" + e);
            }

            //第四 分析返回数据
            int byteLength = count * 2;
            if (receiveBytes.Length == 5 + byteLength)//报文长度合理
            {
                //进一步校验
                if (CheckCRC(receiveBytes) && receiveBytes[1] == 0x03 && receiveBytes[2] == byteLength)
                {
                    //截取数据部分
                    byte[] partData = new byte[byteLength];
                    //返回截取数组,只包括数据(从索引3开始,去掉地址,功能码,字节数组,目的数组,从0开始,复制数据长度)
                    Array.Copy(receiveBytes, 3, partData, 0, byteLength);
                    return partData;
                }
                else return null;

            }
            else return null;
        }
        #region CRC校验
        private static readonly byte[] aucCRCHi =
        {
   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 static readonly byte[] aucCRCLo =
        {
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
        };

        private byte[] CRC16(byte[] pucFrame, int usLen)
        {
            int i = 0;
            byte[] res = new byte[2] { 0xFF, 0xFF };
            ushort index;

            while (usLen-- > 0)
            {
                index = (ushort)(res[0] ^ pucFrame[i++]);
                res[0] = (byte)(res[1]^ aucCRCHi[index]);
                res[1] = aucCRCLo[index];
            }

            return res;
        }

        private bool CheckCRC(byte[] value)
        {
            if (value == null) return false;
            if (value.Length <= 2) return false;

            int length = value.Length;
            byte[] buf = new byte[length - 2];
            Array.Copy(value, 0, buf, 0, buf.Length);

            byte[] CRCbuf = CRC16(buf, buf.Length);

            if (CRCbuf[0] == value[length - 2] && CRCbuf[1] == value[length - 1])
                return true;

            return false;
        }

        #endregion
    }
}

在这里插入图片描述
在这里插入图片描述

2.5、用通信库完成项目开发

在这里插入图片描述

项目总结:首先通过对modbus协议的学习,modbus报文分为地址码、功能码、数据码和校验码、知道了了数据是怎样的发送和接受。同时通过对modbus slave 、modbus poll、串口助手工具的使用,能够更好的测试数据的传输、还学习了一些组件的使用,学会了用Windows Forms设计一个简单的窗口界面。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深度求索—DeepSeek API的简单调用(Java)

DeepSeek简介 DeepSeek&#xff08;深度求索&#xff09;是由中国人工智能公司深度求索&#xff08;DeepSeek Inc.&#xff09;研发的大规模语言模型&#xff08;LLM&#xff09;&#xff0c;专注于提供高效、智能的自然语言处理能力&#xff0c;支持多种场景下的文本生成、对…

Zotero7 从下载到安装

Zotero7 从下载到安装 目录 Zotero7 从下载到安装下载UPDATE2025.2.16 解决翻译api异常的问题 下载 首先贴一下可用的链接 github官方仓库&#xff1a;https://github.com/zotero/zotero中文社区&#xff1a;https://zotero-chinese.com/官网下载页&#xff1a;https://www.z…

沃德校园助手系统php+uniapp

一款基于FastAdminThinkPHPUniapp开发的为校园团队提供全套的技术系统及运营的方案&#xff08;目前仅适配微信小程序&#xff09;&#xff0c;可以更好的帮助你打造自己的线上助手平台。成本低&#xff0c;见效快。各种场景都可以自主选择服务。 更新日志 V1.2.1小程序需要更…

Spring Boot (maven)分页3.0版本 通用版

前言&#xff1a; 通过实践而发现真理&#xff0c;又通过实践而证实真理和发展真理。从感性认识而能动地发展到理性认识&#xff0c;又从理性认识而能动地指导革命实践&#xff0c;改造主观世界和客观世界。实践、认识、再实践、再认识&#xff0c;这种形式&#xff0c;循环往…

解锁机器学习算法 | 线性回归:机器学习的基石

在机器学习的众多算法中&#xff0c;线性回归宛如一块基石&#xff0c;看似质朴无华&#xff0c;却稳稳支撑起诸多复杂模型的架构。它是我们初涉机器学习领域时便会邂逅的算法之一&#xff0c;其原理与应用广泛渗透于各个领域。无论是预测房价走势、剖析股票市场波动&#xff0…

广告深度学习计算:阿里妈妈大模型服务框架HighService

一、背景 HighService(High-Performance Pythonic AI Service) 是在支持阿里妈妈业务过程中&#xff0c;不断提炼抽象出的高性能Python AI服务框架&#xff0c;支持视频、图文、LLM等多种模型&#xff0c;能够显著加快模型的推理速度&#xff0c;提高集群的资源利用效率。随着S…

稀土抑烟剂——为汽车火灾安全增添防线

一、稀土抑烟剂的基本概念 稀土抑烟剂是一类基于稀土元素&#xff08;如稀土氧化物和稀土金属化合物&#xff09;开发的高效阻燃材料。它可以显著提高汽车内饰材料的阻燃性能&#xff0c;减少火灾发生时有毒气体和烟雾的产生。稀土抑烟剂不仅能提升火灾时的安全性&#xff0c;…

如何下载AndroidStudio的依赖的 jar,arr文件到本地

一、通过jitpack.io 下载依赖库 若需要下载 com.github.xxxxx:yy-zzz:0.0.2 的 jar则 https://jitpack.io/com/github/xxxxx/yy-zzz/0.0.2/ 下会列出如下build.logyy-zzz-0.0.2.jaryy-zzz-0.0.2.pomyy-zzz-0.0.2.pom.md5yy-zzz-0.0.2.pom.sha1jar 的下载路径为https://jitpack…

【仪器仪表专题】案例:示波器控制通道开关SCPI命令不同的原因

背景 在文章【仪器仪表专题】仪器支持SCPI控制,要怎么验证命令是否正确?-CSDN博客中我们提到SCPI命令的历史。并且提到了关于制造商为控制仪器而使用的命令,除了公共命令外,并没有统一的规则。比如同一位制造商生产的不同型号仪器甚至会采用不同的规则。 如下所示的众多仪器…

【Deepseek 零门槛指南】DeepSeek 教程和常见问题解答 | 大白技术控

粉丝朋友们大家好&#xff0c;我是极客学长。最近一直在玩 DeepSeek&#xff0c;积累了一点经验&#xff0c;用它提高写作的效率挺好用的。 在使用DeepSeek的过程中&#xff0c;也遇到了如下几个问题(相信很多小伙伴也遇到了)&#xff1a; DeepSeek 官网卡顿&#xff0c;突然出…

2025年SEO工具有哪些?老品牌SEO工具有哪些

随着2025年互联网的发展和企业线上营销的日益重要&#xff0c;SEO&#xff08;搜索引擎优化&#xff09;逐渐成为了提高网站曝光率和流量的重要手段。SEO的工作不仅仅是简单地通过关键词优化和内容发布就能够实现的&#xff0c;它需要依赖一系列专业的SEO工具来帮助分析、监测和…

怎么让DeepSeek自动化写作文案

在数字化时代&#xff0c;内容创作已成为企业争夺用户注意力的核心竞争力。面对海量信息需求&#xff0c;企业往往面临内容创作效率低下、质量参差不齐、周期长等问题。如何用技术手段解决这些痛点&#xff0c;成为企业迫切需要破解的难题。今天&#xff0c;我们将以DeepSeek为…

【vue3】实现pdf在线预览的几种方式

今天一天对当前可用的pdf预览插件做了测试&#xff0c;主要需求是只能预览不能下载&#xff0c;但对于前端来说&#xff0c;没有绝对的禁止&#xff0c;这里只罗列实现方式。 目前采用vue3版本为&#xff1a;3.2.37 iframevue-officepdfjs-dist iframe 先说最简单的&#xf…

软件测试之接口测试理论知识

文章目录 前言接口的定义接口的分类 接口测试什么是接口测试接口测试的基本原理为什么要进行接口测试&#xff1f;接口测试的测试范围&#xff08;测试维度&#xff09; 接口测试的流程1.需求分析2.接口文档分析接口文档分析要素 3.编写接口测试计划4.编写接口测试用例&评审…

生成式人工智能:技术革命与应用图景

(这文章有些地方看不懂很正常&#xff0c;因为有太多生词&#xff0c;需要对 计算机/人工智能 研究至深的人才能看懂&#xff0c;遇到不会的地方用浏览器搜索或跳过&#xff09; 引言 2023年被称我们为"生成式AI元年"&#xff0c;以GPT-4、DALL-E 3、Stable Diffusi…

计算机组成原理—— 总线系统(十二)

不要害怕失败&#xff0c;因为每一次跌倒都是站起来的前奏&#xff1b;不要畏惧未知&#xff0c;因为在探索的过程中你会发现未曾预见的美好。你的每一步努力都在为未来的成功铺路&#xff0c;即使现在看不到成果&#xff0c;但请相信积累的力量。那些看似平凡的努力&#xff0…

两步在 Vite 中配置 Tailwindcss

第一步&#xff1a;安装依赖 npm i -D tailwindcss tailwindcss/vite第二步&#xff1a;引入 tailwindcss 更改配置 // src/main.js import tailwindcss/index// vite.config.js import vue from vitejs/plugin-vue import tailwindcss from tailwindcss/viteexport default …

DeepSeek 通过 API 对接第三方客户端 告别“服务器繁忙”

本文首发于只抄博客&#xff0c;欢迎点击原文链接了解更多内容。 前言 上一期分享了如何在本地部署 DeepSeek R1 模型&#xff0c;但通过命令行运行的本地模型&#xff0c;问答的交互也要使用命令行&#xff0c;体验并不是很好。这期分享几个第三方客户端&#xff0c;涵盖了桌…

ros:ur机械臂初识

这是用来可视化的launch文件 比如&#xff0c;我运行 roslaunch ur_description view_ur3.launch ur3模型 ur3e模型 ur5模型 ur5e模型 ur10模型 ur20模型 ur30模型 后来我搜了一下 UR5 和 UR10 都是由 Universal Robots&#xff08;简称 UR&#xff09;生产的协作机器人&…

数据结构——二叉树(2025.2.12)

目录 一、树 1.定义 &#xff08;1&#xff09;树的构成 &#xff08;2&#xff09;度 2.二叉树 &#xff08;1&#xff09;定义 &#xff08;2&#xff09;二叉树的遍历 &#xff08;3&#xff09;遍历特性 二、练习 1.二叉树 &#xff08;1&#xff09;创建二叉树…