C#上位机与三菱FX3UPLC实现异步伪实时串口通信机制(串口类通信可参考)

news2024/11/13 9:32:36

C#上位机与三菱FX3UPLC实现异步伪实时串口通信机制(串口类通信可参考)

  • 一、串口通信概述
    • 1.1 串口通信
    • 1.2 串行通信
      • 1.2.1 串行同步通信
      • 1.2.2 串行异步通信
        • 1.2.2.1 异步通信的数据格式
        • 1.2.2.2 异步通信的数据发送过程
        • 1.2.2.3 异步通信的数据接收过程
    • 1.3 串行通讯中的TTL、RS-232、RS-485、COM口、UART、串口
    • 1.4 串口通讯协议
      • 1.4.1 物理层
      • 1.4.2数据链路层
      • 1.4.3 应用层
  • 二、三菱FX3U编程口通讯协议概述
  • 三、 C#上位机与三菱FX3UPLC实现异步伪实时串口通信
    • 3.1 通信库
    • 3.2 UI界面设计
    • 3.3 PLC的连接和断开
      • 3.3.1 PLC的连接
      • 3.3.2 PLC的断开
    • 3.4 为Form1的load事件添加相关初始化代码
    • 3.5 异步、多线程实现C#上位机周期读取三菱FX3UPLC存储区
      • 3.5.1 定义更新ui方法
      • 3.5.2 定义带参数的委托
      • 3.5.3 定时器事件处理程序/方法
  • 4. 运行测试
  • 5 源码下载链接

一、串口通信概述

1.1 串口通信

串口是串行接口(serial port)的简称,也称为 串行通信接口 或 COM接口。
串口通信(serial communication)是指采用串行通信协议在一条信号线上将数据一个比特一个比特地逐位进行传输的通信模式。
串口按电气标准及协议来划分,包括RS-232-C、RS-422、RS485等。

1.2 串行通信

在串行通信中,数据在1位宽的单条线路上进行传输,一个字节的数据要分为8次,由低位到高位按顺序一位一位的进行传送。

串行通信的数据是逐位传输的,发送方发送的每一位都具有固定的时间间隔,这就要求接收方也要按照发送方同样的时间间隔来接收每一位。不仅如此,接收方还必须能够确定一个信息组的开始和结束。

常用的两种基本串行通信方式包括同步通信和异步通信。

1.2.1 串行同步通信

同步通信(SYNC:synchronous data communication)是指在约定的通信速率下,发送端和接收端的时钟信号频率和相位始终保持一致(同步),这样就保证了通信双方在发送和接收数据时具有完全一致的定时关系。

同步通信把许多字符组成一个信息组(信息帧),每帧的开始用同步字符来指示,一次通信只传送一帧信息。在传输数据的同时还需要传输时钟信号,以便接收方可以用时针信号来确定每个信息位。

优点:传送信息的位数几乎不受限制,一次通信传输的数据有几十到几千个字节,通信效率较高。
缺点:要求在通信中始终保持精确的同步时钟,即发送时钟和接收时钟要严格的同步(常用的做法是两个设备使用同一个时钟源)。

1.2.2 串行异步通信

异步通信(ASYNC:asynchronous data communication),又称为起止式异步通信,是以字符为单位进行传输的,字符之间没有固定的时间间隔要求,而每个字符中的各位则以固定的时间传送。

在异步通信中,收发双方取得同步是通过在字符格式中设置起始位和停止位的方法来实现的。具体来说就是,在一个有效字符正式发送之前,发送器先发送一个起始位,然后发送有效字符位,在字符结束时再发送一个停止位,起始位至停止位构成一帧。停止位至下一个起始位之间是不定长的空闲位,并且规定起始位为低电平(逻辑值为0),停止位和空闲位都是高电平(逻辑值为1),这样就保证了起始位开始处一定会有一个下跳沿,由此就可以标志一个字符传输的起始。而根据起始位和停止位也就很容易的实现了字符的界定和同步。

显然,采用异步通信时,发送端和接收端可以由各自的时钟来控制数据的发送和接收,这两个时钟源彼此独立,可以互不同步。

下面简单的说说异步通信的数据发送和接收过程。

1.2.2.1 异步通信的数据格式

在介绍异步通信的数据发送和接收过程之前,有必要先弄清楚异步通信的数据格式。

异步通信规定传输的数据格式由起始位(start bit)、数据位(data bit)、奇偶校验位(parity bit)和停止位(stop bit)组成,如图1所示(该图中未画出奇偶校验位,因为奇偶检验位不是必须有的,如果有奇偶检验位,则奇偶检验位应该在数据位之后,停止位之前)。
数据格式

起始位:起始位必须是持续一个比特时间的逻辑0电平,标志传输一个字符的开始,接收方可用起始位使自己的接收时钟与发送方的数据同步。

数据位:数据位紧跟在起始位之后,是通信中的真正有效信息。数据位的位数可以由通信双方共同约定,一般可以是5位、7位或8位,标准的ASCII码是0 ~127(7位),扩展的ASCII码是0 ~255(8位)。传输数据时先传送字符的低位,后传送字符的高位。

奇偶校验位:奇偶校验位仅占一位,用于进行奇校验或偶校验,奇偶检验位不是必须有的。如果是奇校验,需要保证传输的数据总共有奇数个逻辑高位;如果是偶校验,需要保证传输的数据总共有偶数个逻辑高位。

举例来说,假设传输的数据位为01001100,如果是奇校验,则奇校验位为0(要确保总共有奇数个1),如果是偶校验,则偶校验位为1(要确保总共有偶数个1)。

由此可见,奇偶校验位仅是对数据进行简单的置逻辑高位或逻辑低位,不会对数据进行实质的判断,这样做的好处是接收设备能够知道一个位的状态,有可能判断是否有噪声干扰了通信以及传输的数据是否同步。

停止位:停止位可以是是1位、1.5位或2位,可以由软件设定。它一定是逻辑1电平,标志着传输一个字符的结束。

空闲位:空闲位是指从一个字符的停止位结束到下一个字符的起始位开始,表示线路处于空闲状态,必须由高电平来填充。

1.2.2.2 异步通信的数据发送过程

清楚了异步通信的数据格式之后,就可以按照指定的数据格式发送数据了,发送数据的具体步骤如下:

初始化后或者没有数据需要发送时,发送端输出逻辑1,可以有任意数量的空闲位。

当需要发送数据时,发送端首先输出逻辑0,作为起始位。

接着就可以开始输出数据位了,发送端首先输出数据的最低位D0,然后是D1,最后是数据的最高位。

如果设有奇偶检验位,发送端输出检验位。

最后,发送端输出停止位(逻辑1)。

如果没有信息需要发送,发送端输出逻辑1(空闲位),如果有信息需要发送,则转入步骤(2)。

1.2.2.3 异步通信的数据接收过程

在异步通信中,接收端以接收时钟和波特率因子决定每一位的时间长度。下面以波特率因子等于16(接收时钟每16个时钟周期使接收移位寄存器移位一次)为例来说明。

开始通信,信号线为空闲(逻辑1),当检测到由1到0的跳变时,开始对接收时钟计数。
当计到8个时钟的时候,对输入信号进行检测,若仍然为低电平,则确认这是起始位,而不是干扰信号。

接收端检测到起始位后,隔16个接收时钟对输入信号检测一次,把对应的值作为D0位数据。
再隔16个接收时钟,对输入信号检测一次,把对应的值作为D1位数据,直到全部数据位都输入。
检验奇偶检验位。

接收到规定的数据位个数和校验位之后,通信接口电路希望收到停止位(逻辑1),若此时未收到逻辑1,说明出现了错误,在状态寄存器中置“帧错误”标志;若没有错误,对全部数据位进行奇偶校验,无校验错时,把数据位从移位寄存器中取出送至数据输入寄存器,若校验错,在状态寄存器中置“奇偶错”标志。

本帧信息全部接收完,把线路上出现的高电平作为空闲位。

当信号再次变为低时,开始进入下一帧的检测。

1.3 串行通讯中的TTL、RS-232、RS-485、COM口、UART、串口

串口、UART口、COM口、USB口是指的物理接口形式(物理硬件)。

而TTL、RS-232、RS-485是指的电平标准(电信号)。

串口:串口是一个泛称,UART,TTL,RS232,RS485都遵循类似的通信时序协议,因此都被通称为串口。

UART接口:通用异步收发器(Universal Asynchronous Receiver/Transmitter),UART是串口收发的逻辑电路,这部分可以独立成芯片,也可以作为模块嵌入到其他芯片里,单片机、SOC、PC里都会有UART模块。

COM口:特指台式计算机或一些电子设备上的D-SUB外形(一种连接器结构,VGA接口的连接器也是D-SUB)的串行通信口,应用了串口通信时序和RS232的逻辑电平。

TTL,RS232,RS485都是一种逻辑电平的表示方式

TTL:TTL指双极型三极管逻辑电路,市面上很多“USB转TTL”模块,实际上是“USB转TTL电平的串口”模块。这种信号0对应0V,1对应3.3V或者5V。与单片机、SOC的IO电平兼容。不过实际也不一定是TTL电平,因为现在大部分数字逻辑都是CMOS工艺做的,只是沿用了TTL的说法。我们进行串口通信的时候从单片机直接出来的基本是都是 TTL 电平。

TTL电平:全双工(逻辑1: 2.4V–5V逻辑0: 0V–0.5V)
硬件框图如下,TTL用于两个MCU间通信
TTL接口
‘0’和‘1’表示
TTL电平0和1表示

RS232:是电子工业协会(Electronic Industries Association,EIA) 制定的异步传输标准接口,同时对应着电平标准和通信协议(时序),其电平标准:+3V~+15V对应0,-3V~-15V对应1。

RS232 的逻辑电平和TTL 不一样但是协议一样。

RS-232电平:全双工(逻辑1:-15V–5V 逻辑0:+3V–+15V)

硬件框图如下,RS232用于MCU与PC机之间通信
RS232硬件框图
‘0’和‘1’表示
RS232 0和1表示
RS485:RS485是一种串口接口标准,为了长距离传输采用差分方式传输,传输的是差分信号,抗干扰能力比RS232强很多。两线压差为-(26)V表示0,两线压差为+(26)V表示1

RS-485:半双工、(逻辑1:+2V–+6V 逻辑0:-6V—2V)这里的电平指AB 两线间的电压差。

硬件框图如下
RS485硬件框图
‘0’和‘1’表示
RS485 0和1表示

1.4 串口通讯协议

串口协议是一种基于串行通信的数据传输协议。它通过串口接口将数据以串行的方式传输。串口协议通常包括物理层、数据链路层和应用层三个部分,其中物理层主要定义了串口接口的电气特性,数据链路层定义了数据的传输方式和错误检测机制,应用层定义了具体的数据格式和通信协议。

1.4.1 物理层

串口协议的物理层主要定义了串口接口的电气特性,包括传输速率、数据位、停止位、奇偶校验等。常见的串口接口有RS-232、RS-422、RS-485等。

1.4.2数据链路层

串口协议的数据链路层定义了数据的传输方式和错误检测机制。串口通信采用异步传输方式,即每个数据字节之间没有固定的时间间隔。在数据传输时,每个字节都以一个起始位和一个或多个停止位作为帧定界符,以便接收端能够识别每个字节的开始和结束。

串口协议还包括奇偶校验机制和流控制机制。奇偶校验机制可以检测数据传输过程中的错误,流控制机制可以控制数据的传输速率,防止数据丢失或溢出。

1.4.3 应用层

串口协议的应用层定义了具体的数据格式和通信协议。常见的串口协议有Modbus(ascii,RTU)、三菱FX系列编程口专用协议、西门子S7-200系列PLC PPI专用协议、西门子USS协议(USS协议(USS Protocol)是西门子公司推出的用于控制器(PLC/PG/PC)与驱动装置之间数据交换的通信协议)、自定义协议等等。不同的应用场景需要使用不同的串口协议。

二、三菱FX3U编程口通讯协议概述

三菱FX3u编程口用于PLC程序的下载和上传、程序调试监控、和其它设备(变频器、上位机、打印机等等)的通信,数据通信使用三菱FX3u编程口专用协议。

通过专用协议,可以实现:

  • PLC内部存储区(X、Y、M、S、T、C、D)数据的单个、批量读、写操作
  • PLC程序的上传和下载
  • 控制PLC的run、stop状态
    具体的通信数据格式参考《三菱FX编程口协议.pdf》链接地址

三、 C#上位机与三菱FX3UPLC实现异步伪实时串口通信

3.1 通信库

根据《三菱FX编程口协议.pdf》文档,可以手动封装各读写命令数据帧,也可以使用第三方通信库。

这里使用HslCommunication通信库,官方网址链接,能够实现三菱PLC的读写、西门子PLC的读写、欧姆龙PLC读写、Modbus Tcp读写、Modbus服务器开发、日志记录功能。

HslCommunication通信库的使用可以参考1)C# Demo源代码地址;2)通讯库使用说明blog。

3.2 UI界面设计

(1). 新建工程
打开vs2019,新建windowsForm应用。
(2). 使用nuget添加HslCommunication通信库
打开NuGet
添加hslcommunication通信库
打开Form1.cs代码编辑器界面,添加HslCommunication相关命名空间的引用

using HslCommunication;
using HslCommunication.Profinet.Melsec;

(3). UI界面设计
在UI界面设计器中,使用label、Textbox、ComboBox、button、groupBox设计如下的界面。
UI界面
其中端口号使用textbox控件,使用时根据使用计算机com口实际使用端口号,手动输入。
波特率comboBox手动添加两个item,9600和115200。
(4) 添加全局字段

        //定义PLC对象
        private MelsecFxSerial FxSerial = new MelsecFxSerial();
        //定义obj用于进程锁
        private object obj = new object();
        //定义定时器,用于周期读取X、Y、M区变量
        System.Timers.Timer timer = new System.Timers.Timer();

3.3 PLC的连接和断开

3.3.1 PLC的连接

为“连接”按钮添加如下代码:

        /// <summary>
        /// 连接串口
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            FxSerial.SerialPortInni(sp =>
            {
                sp.PortName = tbx_port.Text;
                sp.BaudRate = int.Parse(cbx_baud.Text) ;
                sp.DataBits = 7;
                sp.StopBits = System.IO.Ports.StopBits.One;
                sp.Parity = System.IO.Ports.Parity.Even;
            }
            );
            try
            {
                FxSerial.Open();
                timer.Start();
                MessageBox.Show("串口打开!");
            }
            catch (Exception ex)
            {

                MessageBox.Show(ex.Message);
            }

        }

3.3.2 PLC的断开

为“断开”按钮添加如下代码:

        /// <summary>
        /// 关闭串口
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, EventArgs e)
        {
            FxSerial.Close();
            FxSerial.Dispose();
            timer.Stop();
            MessageBox.Show("串口关闭");
        }

3.4 为Form1的load事件添加相关初始化代码

主要完成两个任务:1)定时器初始化;2)3组label的初始化(因为相关属性基本一致,使用代码完成属性设置更快;这里每个label的mouseDown事件调用同一个方法)。
X、Y、M三组label的text属性和变量地址对应

        private void Form1_Load(object sender, EventArgs e)
        {
            //定时器初始化
            timer.Elapsed += new System.Timers.ElapsedEventHandler(onTimerTrig);
            timer.AutoReset = true;
            timer.Interval = 500;
            timer.Enabled = false;

            lbl_y0.BackColor = Color.Red;
            lbl_y1.BackColor = Color.Red;
            lbl_y2.BackColor = Color.Red;
            lbl_y3.BackColor = Color.Red;
            lbl_y4.BackColor = Color.Red;
            lbl_y5.BackColor = Color.Red;
            lbl_y6.BackColor = Color.Red;
            lbl_y7.BackColor = Color.Red;

            lbl_y0.MouseDown += Lbl_MouseDown;
            lbl_y1.MouseDown += Lbl_MouseDown;
            lbl_y2.MouseDown += Lbl_MouseDown;
            lbl_y3.MouseDown += Lbl_MouseDown;
            lbl_y4.MouseDown += Lbl_MouseDown;
            lbl_y5.MouseDown += Lbl_MouseDown;
            lbl_y6.MouseDown += Lbl_MouseDown;
            lbl_y7.MouseDown += Lbl_MouseDown;

            lbl_m0.BackColor = Color.Red;
            lbl_m1.BackColor = Color.Red;
            lbl_m2.BackColor = Color.Red;
            lbl_m3.BackColor = Color.Red;
            lbl_m4.BackColor = Color.Red;
            lbl_m5.BackColor = Color.Red;
            lbl_m6.BackColor = Color.Red;
            lbl_m7.BackColor = Color.Red;

            lbl_m0.MouseDown += Lbl_MouseDown;
            lbl_m1.MouseDown += Lbl_MouseDown;
            lbl_m2.MouseDown += Lbl_MouseDown;
            lbl_m3.MouseDown += Lbl_MouseDown;
            lbl_m4.MouseDown += Lbl_MouseDown;
            lbl_m5.MouseDown += Lbl_MouseDown;
            lbl_m6.MouseDown += Lbl_MouseDown;
            lbl_m7.MouseDown += Lbl_MouseDown;
        }

Lbl_MouseDown方法代码:

        private void Lbl_MouseDown(object sender, MouseEventArgs e)
        {
            if(e.Button == MouseButtons.Right)
            {
            	//根据label的text属性值作为变量地址,根据背景色决定即将写入的bool值
                Write_Bool(((Label)sender).Text, (((Label)sender).BackColor == Color.Red) ? true : false);
            }
        }
        
        private bool Write_Bool(string addr,bool bVal)
        {
            bool res = false;
            //FxSerial同一时间只能有一个线程独占使用,使用lock语句获取并独占对FxSerial的使用权
            lock (obj)
            {
                if (FxSerial.IsOpen() == true)
                {
                    OperateResult Write_res = FxSerial.Write(addr, bVal);
                    if (Write_res.IsSuccess)
                    {
                        //MessageBox.Show("写入成功");
                        res=  true;
                    }
                }
                else
                {
                    timer.Stop();
                    MessageBox.Show("串口已关闭");
                }
                return res;
            }
        }

3.5 异步、多线程实现C#上位机周期读取三菱FX3UPLC存储区

3.5.1 定义更新ui方法

        /// <summary>
        /// X区、Y区、M区 lbl背景色更新(用来指示各存储区位变量状态)
        /// </summary>
        /// <param name="bool_res"></param>
        /// <param name="addrType"></param>
        public void UpdateForm(bool[] bool_res, string addrType)
        {
            switch (addrType)
            {
                case "X":
                    if (this.IsHandleCreated)
                    {
                        this.Invoke(new Action(() =>
                        {
                            foreach (var c in groupBox3.Controls)
                            {
                                if (c is Label)
                                {
                                    ((Label)c).BackColor = bool_res[int.Parse(((Label)c).Text.Substring(1, 1))] ? Color.Green : Color.Red;
                                }
                            }
                        }));
                    }
                    break;
                case "M":
                    if (this.IsHandleCreated)
                    {
                        this.Invoke(new Action(() =>
                        {
                            foreach (var c in groupBox5.Controls)
                            {
                                if (c is Label)
                                {
                                    ((Label)c).BackColor = bool_res[int.Parse(((Label)c).Text.Substring(1, 1))] ? Color.Green : Color.Red;
                                }
                            }
                        }));
                    }
                    break;
                case "Y":
                    if (this.IsHandleCreated)
                    {
                        this.Invoke(new Action(() =>
                        {
                            foreach (var c in groupBox4.Controls)
                            {
                                if (c is Label)
                                {
                                    ((Label)c).BackColor = bool_res[int.Parse(((Label)c).Text.Substring(1, 1))] ? Color.Green : Color.Red;
                                }
                            }
                        }));
                    }
                    break;
                default:
                    break;
            }

        }

3.5.2 定义带参数的委托

        /// <summary>
        /// 声明一个带参数的委托
        /// </summary>
        /// <param name="bool_res"></param>
        /// <param name="addrType"></param>
        public delegate void MyInvoke(bool[] bool_res,string addrType);

3.5.3 定时器事件处理程序/方法

        /// <summary>
        /// 定时器事件处理程序
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void onTimerTrig(object sender, ElapsedEventArgs e)
        {
            //周期读取变量
            //这里的sw用于计算以下代码执行时间
            sw.Restart();
            lock (obj)
            {
                if (FxSerial.IsOpen() == true)
                {
                    // 读M区
                    try
                    {
                        OperateResult<bool[]> Read_res = FxSerial.ReadBool("m0", 8);
                        if (Read_res.IsSuccess)
                        {
                            bool[] read_bool_res = Read_res.Content;
                            MyInvoke mi = new MyInvoke(UpdateForm);
                            this.BeginInvoke(mi, new Object[] { read_bool_res, "M" });
                        }
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }

                    // 读Y区
                    try
                    {
                        OperateResult<bool[]> Read_res = FxSerial.ReadBool("y0", 8);
                        if (Read_res.IsSuccess)
                        {
                            bool[] read_bool_res = Read_res.Content;
                            MyInvoke mi = new MyInvoke(UpdateForm);
                            this.BeginInvoke(mi, new Object[] { read_bool_res, "Y" });
                        }
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }

                    // 读X区
                    try
                    {
                        OperateResult<bool[]> Read_res = FxSerial.ReadBool("x0", 8);
                        if (Read_res.IsSuccess)
                        {
                            bool[] read_bool_res = Read_res.Content;
                            MyInvoke mi = new MyInvoke(UpdateForm);
                            this.BeginInvoke(mi, new Object[] { read_bool_res, "X" });
                        }
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }

                }
                else
                {
                    MessageBox.Show("串口已关闭");
                    timer.Stop();
                }

            }
            //这里的sw用于计算以下代码执行时间
            sw.Stop();
            Console.WriteLine("time= {0}", sw.ElapsedMilliseconds.ToString());
        }

4. 运行测试

运行后,初始化界面如下:
初始化界面
运行操作动画:
主要演示了PLC的连接和关闭;
PLC改变存储区变量值,上位机可以同步修改;在上位机右键单击Y区和M区label,对应的label标签背景色相应反转,同时PLC对应地址值也发生变化。操作过程中界面无卡顿。
操作动画
通过输出窗口,可以看到定时器事件处理程序一次执行大概消耗130ms。
在这里插入图片描述

5 源码下载链接

单击打开源码下载链接
不定期分享c#、wpf上位机开发学习经验,欢迎交流。
点赞、收藏加关注,让你永远不迷路。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis如何保障缓存与数据库的数据一致性问题?

目录 一.最经典的数据库加缓存的双写双删模式 二. 高并发场景下的缓存数据库双写不一致问题分析与解决方案设计 三、上面高并发的场景下&#xff0c;该解决方案要注意的问题 一.最经典的数据库加缓存的双写双删模式 1.1 Cache Aside Pattern概念以及读写逻辑 &#xff08;…

redis非关系型数据库部署和使用(linux)

1.概念 NoSQL非关系型数据库是一种不使用关系模型来组织数据的数据库&#xff0c;通常用于存储非结构化或半结构化的数据&#xff0c;不支持或只部分支持SQL语言&#xff0c;满足最终一致性。非关系型数据库有多种类型&#xff0c;例如键值数据库、文档数据库、列式数据库、图形…

Shopee、Grab、Gojek 打造超级app已成为主流

超级App的概念在全球范围内逐渐被接受和采用。 超级App是指一种综合性的应用程序&#xff0c;允许用户在同一个平台上访问多个不同的服务&#xff0c;包括支付、社交媒体、出行、点餐等等。它的发源地是东南亚地区&#xff0c;如中国的微信、印度的Paytm和印尼的Gojek等应用&a…

Spring入门案例--bean的生命周期

bean的生命周期 关于bean的相关知识还有最后一个是bean的生命周期,对于生命周期&#xff0c;我们主要围绕着bean生命周期控 制 来讲解: 首先理解下什么是生命周期? 从创建到消亡的完整过程,例如人从出生到死亡的整个过程就是一个生命周期。 bean生命周期是什么? bean对…

C++ | 说说类中的static成员

【概念】&#xff1a;声明为static的类成员称为类的静态成员&#xff0c;用static修饰的成员变量&#xff0c;称之为静态成员变量&#xff1b;用static修饰的成员函数&#xff0c;称之为静态成员函数。静态成员变量一定要在类外进行初始化 文章目录 一、面试题引入二、static特…

5个实用的JavaScript原生API

本文带来5个难得一见的JavaScript原生API&#xff0c;为我们的前端开发带来意想不到的便利。 1. getBoundingClientRect() Element.getBoundingClientRect() 方法返回一个 DOMRect 对象&#xff0c;该对象提供有关元素大小及其相对于视口的位置的信息。 domRect element.ge…

Java笔记_11(常用API)

Java笔记_11 一、常用的API1.1、MathMath练习 1.2、System1.3、Runtime1.4、Object1.5、浅克隆、深克隆1.6、对象工具类的Objects1.7、BigInteger&#xff08;大整数&#xff09;1.8、BigDecimal&#xff08;大小数&#xff09; 二、正则表达式2.1、正则表达式基础知识2.2、正则…

关于WordPress的20个有趣事实

时值 2022 年&#xff0c;互联网格局和 WordPress 的流行发生了重大变化。COVID-19 流行几乎影响到人类生存的方方面面&#xff0c;包括我们的互联网习惯&#xff0c;这也不例外。 到 2022 年&#xff0c;我们在家工作的人数显着增加&#xff0c;下岗或发现自己有更多空闲时间…

Python基础实战3-Pycharm安装简介

Pycharm下载、安装与使用 1.打开pycharm官网&#xff1a;下载 PyCharm&#xff1a; Python IDE for Professional Developers by JetBrains 2.选择自己对应的操作系统&#xff0c;点击Download&#xff0c;默认是最新版本&#xff0c;想安装其他版本可以选择Other versions下载…

【iOS】—— Masonry源码学习(浅看,未完)

Masonry 文章目录 MasonryNSLayoutConstraint用法Masonry源码 Masonry在我们之前的学习中是一个非常有用的第三方库。 Masonry是一种基于Objective-C语言的轻量级布局框架&#xff0c;它可以简化iOS应用程序中的自动布局任务。Masonry提供了一个方便的API&#xff0c;可以编写更…

Kubernetes Service、Ingress

Service&#xff08;4层负载均衡器&#xff09; 1、K8S 可以保证任意 Pod 挂掉时自动从任意节点启动一个新的Pod进行代替&#xff0c;以及某个Pod超负载时动态对Pod进行扩容。每当 Pod 发生变化时其 IP地址也会发生变化&#xff0c;且Pod只有在K8S集群内部才可以被访问&#xf…

Flink高手之路4-Flink流批一体

文章目录 Flink高手之路4-Flink流批一体API开发一、流批一体相关的概念1.数据的时效性2.流处理和批处理1)批处理2)流处理3)两者对比 3.流批一体API4.流批一体的编程模型 二、Data Source1.预定义的Source1)基于集合的Sources(1)API(2)演示 2)基于文件的Source(1)API(2)演示 3)基…

2023.4.19 + 4.20

文章目录 String类1&#xff1a;介绍&#xff1a;2&#xff1a;String类实现了很多的接口&#xff1a;3&#xff1b;String类常用构造器4&#xff1a;不同方式创建String类对象的区别&#xff08;1&#xff09;直接赋值的方式&#xff08;2&#xff09;常规new的方式&#xff0…

【筛质数】——朴素筛,埃式筛,欧拉筛

题目描述&#xff1a; 题目分析&#xff1a; 这道题可以用&#xff0c;朴素筛&#xff0c;埃氏筛&#xff0c;欧拉筛来写。 普通筛&#xff1a; 时间复杂度&#xff1a;O(n logn) 时间复杂度太高&#xff0c;会超时的&#xff01;&#xff01;&#xff08;9/10&#xff09; #…

Keil5----显示空白符和设置使用空白格表示Tab键

一、Keil5界面----显示空白符 首先打开Keil5-MDK界面&#xff0c;然后按照下面步骤操作。 步骤1&#xff1a;点击 Edit(编辑)&#xff0c;然后点击 Configuration(配置) 步骤2&#xff1a;勾选 View White Spaces(查看空白) 步骤3&#xff1a;显示设置后的结果 具体显示结果分…

Git添加SSH密钥本地仓库上传远程GitHub库

1、前言 现在想要从本地设备将本地仓库上传到GitHub上需要用到SSH密钥&#xff0c;接下来讲解大致的步骤&#xff0c;本文默认读者已经掌握基本的Git知识 2、详细步骤 2.1 创建密钥 在本地项目仓库根目录下&#xff0c;输入下面的命令&#xff1a; ssh-keygen -t rsa命令输…

深度学习 Day 31——YOLOv5-Backbone模块实现

深度学习 Day 31——YOLOv5-Backbone模块实现 文章目录 深度学习 Day 31——YOLOv5-Backbone模块实现一、前言二、我的环境三、什么是YOLOv5-Backbone模块&#xff1f;四、搭建包含Backbone模块的模型1、模型整体代码2、模型每一部分详解3、模型详情 五、模型训练六、最终结果1…

计算机|网页设计 |七大罪动漫主题|作品分享

文章目录 一、主题介绍二、截图展示三、源代码获取 一、主题介绍 计算机&#xff5c;网页设计 &#xff5c;七大罪动漫主题&#xff5c;作品分享 一个关于七大罪动漫主题的网页设计。共4页 图片文字都可修改&#xff01; 二、截图展示 三、源代码获取 本次的分享就到这里啦&…

双指针【算法推导、背模板】——最长连续不重复子序列

799. 最长连续不重复子序列 - AcWing题库 通常情况双指针就是需要将O(N^2^)&#xff0c;利用某些单调性质实现O(N) 通用代码模板 for(int i 0 , j 0; i < n ; i ){while(j < i && check(i , j ) ) j ;// 需要处理的逻辑 }check判断是否构成 算法推导 题目中…

LLM总结(持续更新中)

引言 当前LLM模型火出天际&#xff0c;但是做事还是需要脚踏实地。此文只是日常学习LLM&#xff0c;顺手整理所得。本篇博文更多侧重对话、问答类LLM上&#xff0c;其他方向&#xff08;代码生成&#xff09;这里暂不涉及&#xff0c;可以去看综述来了解。 之前LLM模型梳理 …