uart串口接收模块

news2024/11/24 19:34:59

uart串口接收模块

1、UART(异步串行接口)

  串行通信:指利用一条数据线将资料一位位的顺序传输。
  异步通信:以一个字符为传输单位,通信中两个字符间的时间间隔是不固定的,然而在同一个字符的两个相邻位代码间的时间间隔是固定的。
  通信协议:指通信双方约定的一些规则。在使用串口通信的时候,规定有:空闲位、起始位、数据位、奇偶校验位、停止位。

2、串口通信时序

  这个协议在 FPGA 内部是除 SPI 之外最简单的接口吧,其实就是发送方与接收方相互认定的协议(暗号),这种接口数据一般是单向传输,所以发送方和接收方通信一般需要两根数据线。
在这里插入图片描述

图1 URAT时序图

  数据线在没有数据传输时保持高电平,当需要传输数据时,发送方把数据线拉低一段时间,告诉接收方开始传输数据了。之后把数据从低位到高位或者高位到低位(这个根据通信双方的要求确定)依次发送给对方(数据的位数双方应该事先确认好,通常5~8位数据)。数据发送完,可能会发送一位奇偶校验(这部分在下一节构建完整UART协议时细说)。最后就是将数据线拉高一段时间表示数据传输结束。

  在这之间就会有疑问,每位数据电平持续时间到底是多久?

  这就引出波特率,通常就是说每秒能传输多少位数据,比如波特率为9600bit/s,就是指1秒传输9600位数据(当然这是包含起始位,校验位,停止位在内的,所以有效数据其实并没有这么多)。当使用该波特率时,那每个电平持续时间不就是1/9600秒么。

3、串口接收模块设计

  首先确定模块接口信号,肯定有个串口的输入信号uart_rx吧,然后时钟信号clk和复位信号rst_n也是不可能少的。接收到数据后肯定要输出吧,所以在加一个uart_rx,注意该信号位宽应该是可以改变的(因为串口协议的数据位可以改变)。一般还要有一个信号用于指示接收到的数据什么时候是有效的,便于后续模块使用uart_rx,即uart_tx_vld(为高电平时,表示uart_rx有效)。
表1 端口信号

信号输入输出位宽定义
clkI1系统时钟,50MHZ
rst_nI1系统复位,低电平有效
uart_rxI1UART接口输入信号
rx_dataO8数据输出信号
rx_vldO1数据有效指示信号,高电平有效

  模块总体思路:有了输入输出信号后,模块内部就是根据输入信号生成输出信号而已。通过观察图1时序知道,每位数据传输需要使用 1/波特率 的时间,每次需要传输的 “数据” 包括起始位,数据位,校验位,结束位。那么以上是不是就对应两个计数器?所以使用计数器data_num来计数一位数据传输需要的时间(需要将1/波特率转换为系统时钟个数作为data_num的结束条件),使用计数器cnt来计数目前传输的第几位数据了。整体思路就是如此,大致如下图,接下来就是细节:

在这里插入图片描述

图2 计数器架构

  计数器data_num该从什么时候计数?
  当发送方发送起始位时会把数据线拉低,并且在之后一段时间内发送起始位,数据位等数据,那么data_num在此期间都要计数,直到停止位接收完成为止。由此引入一个标志信号flag,该信号为高电平时,计数器data_num就计数,当计数到时钟频率/波特率(1/波特率对应的时钟个数)时清零。

  故计数器data_num初始值为0,计数条件add_data_num = flag,结束条件为end_data_num = add_data_num && data_num == BSP_NUM - 1。

  flag当然就是检测到数据线下降沿时拉高,当计数器cnt计数结束时拉低,其余时间保持不变了。

  故flag拉高条件:检测到uart_rx下降沿,拉低条件为end_cnt。

  接下来就是计数器cnt了,cnt表示数据线此时传输的是第几位数据了。当计数器data_num计数结束时,表示一位数据传输完成了,此时cnt就应该加一了。当计数器计数到 起始位数+数据位数+校验位数+停止位数 时表示数据传输完成了,此时cnt计数结束并清零,其余时间保持不变。

  故计数器cnt初始值为0,计数条件add_cnt = end_data_num,计数器清零条件end_data_num = add_cnt && cnt == CNT_W - 1。CNT_W = 起始位数+数据位数+校验位数+停止位数 。

  接下来就是接收数据并产生输出信号了,一般会在计数器data_num计数的中部将数据线上的数据取下来进行保存,此时的数据是比较稳定的。由于最终需要输出的只是数据位,本文不考虑校验位,传输第0位是起始位,不需要保存。cnt==1时表示传输第1位数据,需要保存到输出信号上的最低位(这是由于串口调试助手是先发的最低位,实际情况要看发送方先发高位还是低位)。

  flag拉高后,计数器data_num进行计数,当计数完一位数据后清零,并且cnt计数器进行计数,当cnt大于等于1,小于等于8时,表示此时接收的是数据位,将接收到的数据保存到rx_data对应位(最好是在data_num为容量的一半时进行保存),当cnt计数器计数完成,表示一组数据接收完成,此时有效指示信号拉高,并且flag信号拉低,结束一组数据的接收;所以当cnt=1 && data_num == BSP_CNT/2-1时(BSP_CNT表示波特率对应的时钟个数),有rx_data[0] <= uart_rx。

  经过对其它位的详细分析,最终会得到这样的结果:当cnt >=1 && cnt <= DATA_W && data_num == BSP_CNT/2-1 && add_data_num 时(DATA_W表示每次发送的数据位位数),rx_data[cnt - 1] <= uart_rx;这样就产生了输出数据信号。

  之后就是产生输出有效指示信号,该信号当然是接收完数据时产生的,其实可以在计数器cnt计数结束时产生。但数据在接收完数据位后,其实数据就已经接收完成了,此时就可以把输出有效指示信号拉高了,这样后续模块就可以提前使用接收到的数据。所以当cnt == DATA_W && add_data_num && data_num == BSP_NUM/2-1时将rx_data_vld拉高,其余时间拉低。
  如果想要保证输出数据线上数据比较干净,不出现接收过程中的无效数据,那么可以将rx_data和rx_data_vld在rx_data_vld有效时才进行输出,其余时间保持不变。

  最后还要注意,数据线是其他芯片或者设备输入的信号,为了减小亚稳态出现的机率,一般需要将数据线上的信号通过寄存器寄存两个时钟。由于还需要检测数据线的下降沿,所以还要把该信号延迟一个时钟,最终将接收到的信号uart_rx打三拍(前两拍用于同步处理,最后一拍用于检测输入信号的下降沿),然后通过uart_rx_ff1和uart_rx_ff2检测出下降沿,把标志信号flag拉高。
在这里插入图片描述

图3 接收标志信号产生

  上述将模块内部信号讲完了,如果要实现功能完全够了,但是在调用模块时,我们往往不习惯去改模块内部的参数,这就需要通过parameter和localparam添加一些参数,来自动设置计数器位宽,计数器结束条件等等。其实人为需要设置的就是波特率、数据位位数、校验位数、停止位数(起始位是必须的,故不考虑设置参数),由于计算波特率对应是时钟个数时还需要知道系统时钟频率,所以增加一个系统时钟频率参数。

  所以parameter就定义波特率BPS、时钟频率FCLK、数据位数DATA_W、校验位数CHECK_W 、停止位数STOP_W 。而localparam需要通过parameter定义的参数得到波特率对应的 时钟数BPS_CNT=时钟频率FCLK/波特率BPS ,计数器data_num需要计数到BPS_CNT,所以需要通过BPS_CNT计算出计数器data_num的位宽BPS_CNT_W,可以通过以下函数实现。

function integer clogb2(input integer depth);begin
    if(depth==0)
        clogb2 = 1;
    else if(depth!=0)
        for(clogb2=0;depth>0;clogb2=clogb2+1)
            depth=depth>>1;
    end
endfunction

  接下来就是cnt计数器的结束条件了,可以由localparam定义CNT_NUM=DATA_W + CHECK_W + STOP_W。在利用上面函数计算出该计数器的位宽CNT_NUM_W就行了,内部信号根据这些常量变化即可。
  由此设计的模块在例化时,只需要修改parameter的几个常量即可,不要对模块内部代码做任何处理,这部分操作不会占用额外资源,在综合工具对齐进行综合时就会处理,不会消耗FPGA的除法器之类的资源。

  根据以上分析,直接得到以下代码,基本上不需要仿真调试。

4、参考代码

//--###############################################################################################
//--# Designer : 发送一位数据所需系统时钟数计算方式BPS_CNT = 1000_000_000/(Tclk*比特率),
//Tclk是系统时钟周期,单位ns。
//--###############################################################################################
module uart_rx #(
    parameter       FLCK    =       50_000_000  ,//系统时钟频率,默认50MHZ;
    parameter       BPS     =       9600        ,//串口波特率;
    parameter       DATA_W  =       8           ,//接收数据位数以及输出数据位宽;
    parameter       CHECK_W =       0           ,//校验位,0代表无校验位;
    parameter       STOP_W  =       1            //1位停止位;
)(
    input                           clk         ,//系统工作时钟50MHZ
    input                           rst_n       ,//系统复位信号,低电平有效

    input                           uart_rx     ,//UART接口输入信号
    output reg  [DATA_W-1:0]        rx_out      ,//数据输出信号
    output reg                      rx_out_vld   //数据有效指示信号
    );
    
    localparam      BPS_CNT   =     FLCK/BPS;//波特率为9600bit/s,当波特率为115200bit/s时,DATA_115200==434;
    localparam      BPS_CNT_W =     clogb2(BPS_CNT-1);//根据BPS_CNT调用函数自动计算计数器data_num位宽;
    localparam      CNT_NUM   =     DATA_W + CHECK_W + STOP_W;//计数器计数值;
    localparam      CNT_NUM_W =     clogb2(CNT_NUM);//根据计数器cnt的值,利用函数自动计算此计数器的位宽;

    reg                             rx_vld          ;//表示接收完一组串口发来的数据了;
    reg                             uart_rx_ff0     ;
    reg                             uart_rx_ff1     ;
    reg                             uart_rx_ff2     ;
    reg                             flag            ;
    reg     [BPS_CNT_W-1:0]         data_num        ;
    reg     [CNT_NUM_W-1:0]         cnt             ;
    reg     [DATA_W-1:0]            rx_data         ;

    wire                            add_data_num    ;
    wire                            end_data_num    ;
    wire                            add_cnt         ;
    wire                            end_cnt         ;

    /******************注释开始******************
    自动计算信号位宽;
     ******************注释结束******************/
    function integer   clogb2(input integer depth);begin
        if(depth==0)
            clogb2 = 1;
        else if(depth!=0)
            for(clogb2=0;depth>0;clogb2=clogb2+1)
                depth=depth>>1;
        end
    endfunction

    /******************注释开始******************
    接收一位数据所用时间计数器data_num,初始值为0,当接收到数据时进行计数,
    当一位数据接收完成时清零;
    ******************注释结束******************/
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            data_num <= {{BPS_CNT_W}{1'b0}};
        end
        else if(add_data_num)begin
            if(end_data_num)
                data_num <= {{BPS_CNT_W}{1'b0}};
            else
                data_num <= data_num + {{{BPS_CNT_W-1}{1'b0}},1'b1};
        end
    end

    assign add_data_num = flag;       
    assign end_data_num = add_data_num && data_num==BPS_CNT-1;

    //接受一组数据所用时间;
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            cnt <= {{CNT_NUM_W}{1'b0}};
        end
        else if(add_cnt)begin
            if(end_cnt)
                cnt <= {{CNT_NUM_W}{1'b0}};
            else
                cnt <= cnt + {{{CNT_NUM_W-1}{1'b0}},1'b1};
        end
    end

    assign add_cnt = end_data_num;       
    assign end_cnt = add_cnt && cnt== CNT_NUM-1;

    /******************注释开始******************
    PC端相对应于FPGA为异步接口,为预防亚稳态产生,对接收数据进行打两拍处理,由于需要采集信号下降沿,故打三拍处理;
    ******************注释结束******************/
    always@(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin//三个寄存器组成移位寄存器,初始化为0;
            {uart_rx_ff2,uart_rx_ff1,uart_rx_ff0} <= 3'd0;
        end
        else begin//时钟上升沿时,将uart_rx信号移入移位寄存器,其余位左移一位;
            {uart_rx_ff2,uart_rx_ff1,uart_rx_ff0} <= {uart_rx_ff1,uart_rx_ff0,uart_rx};
        end
    end

    always@(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            flag <= 1'b0;
        end
        else if(uart_rx_ff2==1 && uart_rx_ff1==0)begin//取UART_RX信号下降沿
            flag <= 1'b1;
        end
        else if(end_cnt)begin//一组数据接收完毕;
            flag <= 1'b0;
        end
    end

    //在中间时刻对输入数据进行采集,并且将数据存入rx_data;
    always@(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            rx_data <= {{DATA_W}{1'b0}};
        end
        else if(cnt>=1 && cnt<=DATA_W && add_data_num && data_num==BPS_CNT/2-1)begin
            rx_data[cnt-1] <= uart_rx_ff2;
        end
    end

    //在接收完数据后,指示产生rx_data信号有效;
    always@(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            rx_vld <= 1'b0;
        end
        else begin
            rx_vld <= (cnt==CNT_NUM-1 && add_data_num && data_num==BPS_CNT/2-1);
        end
    end

    //当接收完一组数据后,将接收到的数据经过一组触发器暂存后输出;
    always@(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin//
            rx_out <= 0;
        end
        else if(rx_vld)begin
            rx_out <= rx_data;
        end
    end

    //在接收完数据后,拉高一个时钟,指示产生rx_out信号有效;
    always@(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            rx_out_vld <= 1'b0;
        end
        else begin
            rx_out_vld <= rx_vld;
        end
    end

    endmodule

5、modelism仿真

  仿真部分的代码,通过一个任务task实现串口数据的发送,由于上述设计不支持校验位,所以这个模块设置校验位也是没有用的,将在下篇文章里面加入校验位,以及1.5位停止位之类的数据位。
  发送数据只需要调用tx();任务即可,内部直接输入待发送数据,数据位宽依旧通过DATA_W设置,波特率BPS设置。
参考代码:

`timescale 1 ns/1 ns
module uart_rx_test();
    parameter	CYCLE		= 20;//The unit is ns. The default value is 10ns;
    parameter	RST_TIME	= 10;//Reset time: Reset 3 clock widths by default;
    parameter	STOP_TIME	= 1000;//Time for simulation running after reset (unit: clock cycle). Simulation stops after 1000 clocks are run by default;

    // uart_rx Parameters
    parameter   FCLK        = 50_000_000;//系统时钟频率;
    parameter   BPS         = 9600      ;//串口波特率;
    parameter   BPS_CNT     = FCLK/BPS  ;
    parameter   DATA_W      = 8         ;//接收数据位数以及输出数据位宽;
    parameter   CHECK_W     = 0         ;//校验位,0代表无校验位;
    parameter   STOP_W      = 1         ;//1位停止位;

    // uart_rx Inputs
    reg                     clk         ;
    reg                     rst_n       ;
    reg                     uart_tx     ;

    // uart_rx Outputs
    wire  [DATA_W-1:0]      rx_out      ;
    wire                    rx_out_vld  ;

    uart_rx #(
        .FLCK       (FCLK       ),
        .BPS        (BPS        ),
        .DATA_W     (DATA_W     ),
        .CHECK_W    (CHECK_W    ),
        .STOP_W     (STOP_W     ))
    u_uart_rx (
        .clk        ( clk           ),
        .rst_n      ( rst_n         ),
        .uart_rx    ( uart_tx       ),
        .rx_out     ( rx_out        ),
        .rx_out_vld ( rx_out_vld    )
    );

    //The local clock is generated at 100 MB;
    initial begin
        clk = 0; 
        forever #(CYCLE/2) clk=~clk;
    end

    //Generate reset signal;
    initial begin
        rst_n = 1;
        #2; rst_n = 0;
        #(RST_TIME*CYCLE);//复位完成;
        rst_n = 1;
    end

    //Input signal din assignment method;
    initial begin
        #1;uart_tx = 1; //初始化时输入高电平;
        #(100*CYCLE);   //Start assigning values;
        tx(8'ha5);      //以串口形式发送8'h5a;
        #(500*CYCLE);   //发送完成后延迟500个时钟;
        tx(8'h5a);      //之后发送数据8'h59;
        $stop;          //Stop simulation;
    end

    //模拟串口发送函数,1位起始位,1位停止位,无校验位,8位数据,先发低位;
    integer i;//用于控制循环次数;
    task tx(
        input   [DATA_W-1:0]   data//串口待发送数据;
    );
        begin
            @(posedge clk);//延迟一个时钟后发送起始位;
            #1; uart_tx = 1'b0;
            repeat(BPS_CNT) @(posedge clk);//延迟BPS_CNT个时钟;
            for(i=0 ; i<8 ; i=i+1)begin
		            #1; uart_tx = data[i];
		            repeat(BPS_CNT) @(posedge clk);//延迟BPS_CNT个时钟;
            end
            @(posedge clk);//延迟一个时钟后发送停止位;
            #1; uart_tx = 1'b1;
            repeat(BPS_CNT) @(posedge clk);//延迟BPS_CNT个时钟;
        end
    endtask

endmodule

  仿真运行结果(rx_out先接收到8’ha5,后接收到8’h5a):
在这里插入图片描述

图4 仿真结果

  查看细节:开始接收数据(起始位)片段:
在这里插入图片描述

图5 起始位仿真

  接收最低位数据仿真如下:
在这里插入图片描述

图6 接收第一位数据

  接收最后一位数据,并且产生输出有效指示信号,下一个时钟将数据输出,此时串口传输实际上并没有完成,最后一位数据才传输一半(data_num计数器才2603==5208/2-1),但已经接收到完整数据,所以直接输出,节省时间,但flag信号依旧位高电平,表示该模块还处于工作状态。

图7 接收完最后一位数据

  计数器data_num计数到5208-1并且计数器cnt计数器到8,表示一次传输完成,flag信号拉低,并且两个计数器清零,表示完成传输,仿真如下:
在这里插入图片描述

图8 接收完停止位

6、综合测试

  这个工程很久了,之前学的时候使用quartus综合的,综合效果如下所示:
在这里插入图片描述

图9 quartus综合工程

  对应的RTL模块视图(由于时钟频率FCLK和波特率BPS参数设置会影响计数器cnt和data_num的位宽,所以不同数据汇总和出不同的电路,下图为时钟频率50MHZ,波特率9600的RTL视图):
在这里插入图片描述

图10 RTL视图

  对系统时钟频率进行约束后,最大时钟频率为120.86MHZ,远大于实际的50MHZ,满足时序要求;
在这里插入图片描述

图11 系统最大工作时钟频率

sigtap II 测试

  将程序下载到FPGA,打开串口调试助手,设置波特率9600,发送数据0XA5,使用signal tap II抓取数据8’hA5。
在这里插入图片描述

图12 串口助手发送数据

  串口调试助手发送数据0XB3,使用signal tap II抓取数据8’hB3。
在这里插入图片描述

图13 signal tap接收串口助手发送数据

  串口调试助手发送数据0X5a,使用signal tap II抓取数据8’h5A。
在这里插入图片描述

图14 调试

7、总结

  其实最主要的就是能够根据协议找到合适的主架构,然后根据该架构去产生输出信号。本文就利用两个计数器作为主架构,根据计数器的状态生成输出信号,切记我们需要的并不是计数器,而是计数器生成的输出信号,如果使用parameter要考虑模块内部各种会改变的数据与这些参数的关系,最好不要留需要手动修改的数据,这种数据如果忘记修改,会对后续设计造成很大影响,浪费调试时间。

  本模块还需要完善奇偶校验以及停止位,放在下文处理,需要原工程的自取。

  工程链接:https://pan.baidu.com/s/1oMLYvioXl496p9KH3rFy4w

  提取码:98qn

  时序图采用TimeGen所画,如果需要该软件,后台回复即可。

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

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

相关文章

【微信小程序】-- 页面事件 - 下拉刷新(二十五)

&#x1f48c; 所属专栏&#xff1a;【微信小程序开发教程】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &…

高盐废水除钙镁的技术解析

高盐废水指含有机物和至少总溶解固体(totaldissolvedsolids&#xff0c;tds)的质量分数大于3.5&#xff05;的废水&#xff0c;具有水量大&#xff0c;无机盐离子k、na、ca2、mg2、cl-、so42-等含量高&#xff0c;水质水量变化大&#xff0c;成分复杂&#xff0c;难生化降解等特…

2023年中职网络安全竞赛——CMS网站渗透解析

需求环境可私信博主 解析如下: CMS网站渗透 任务环境说明: 服务器场景:Server2206(关闭链接) 服务器场景操作系统:未知 1.使用渗透机对服务器信息收集,并将服务器中网站服务端口号作为flag提交; Flag:8089

华为套件生态

华为套件生态前言蓝牙设备华为耳机华为鼠标智慧互联超级终端多屏协同远程访问文件共享华为电脑管家我的设备控制中心前言 华为的手机、平板、电脑、耳机、手环、手表等设备可以组成华为生态。以下分享一些生态体验。 蓝牙设备 华为耳机 快速连接 在手机/电脑附近打开华为耳…

里奇RIDGID管线定位仪/探测仪维修SR-20 SR-24 SR-60

美国里奇SeekTech SR-20管线定位仪对于初次使用定位仪的用户或经验丰富的用户&#xff0c;都同样可以轻易上手使用SR-20。SR-20提供许多设置和参数&#xff0c;使得大多数复杂的定位工作变得很容易。此外&#xff0c;当你在不复杂的环境下完成些基本的定位工作时&#xff0c;这…

软件测试7

一 CS和BS软件架构 CS&#xff1a;客户端-服务器端&#xff0c;BS&#xff1a;浏览器端-服务器端 区别总结&#xff1a; 1.效率&#xff1a;c/s效率高&#xff0c;某些内容已经安装在系统中了&#xff0c;b/s每次都要加载最新的数据 2.升级&#xff1a;b/s无缝升级&#xff0c…

【Maven】(五)Maven模块的继承与聚合 多模块项目组织构建

文章目录1.前言2.模块的继承2.1.可继承的标签2.2.超级POM2.3.手动引入自定义父POM3.模块的聚合3.1.聚合的注意事项3.2.反应堆(reactor)4.依赖管理及属性配置4.1.依赖管理4.2.属性配置5.总结1.前言 本系列文章记录了 Maven 从0开始到实战的过程&#xff0c;Maven 系列历史文章清…

三天吃透SpringMVC面试八股文

本文已经收录到Github仓库&#xff0c;该仓库包含计算机基础、Java基础、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等核心知识点&#xff0c;欢迎star~ Github地址&#xff1a;https://github.com/…

【操作系统原理实验】命令解释器模拟实现

选择一种高级语言如C/C等&#xff0c;编写一类似于DOS、UNIX中的命令行解释程序。 1)设计系统命名行提示符&#xff1b; 2)自定义命令集&#xff08;8-10个&#xff09;&#xff1b; 3)用户输入help命令以查找命令的帮助&#xff1b; 4)列出命令的功能&#xff0c;区分内部命令…

fuse文件系统调试环境

libfuse源码&#xff1a;GitHub - libfuse/libfuse: The reference implementation of the Linux FUSE (Filesystem in Userspace) interface 一、ubuntu20.04挂载fuse文件系统 1&#xff0c;安装编译工具 apt install ninja-build apt install meson apt install build-ess…

4. C#语法基础

一、cs文件结构 上面程序的各个部分说明如下&#xff1a; 程序的第一行using System; 其中【using】关键字用于在程序中包含 System 命名空间。一个程序一般有多个 using 语句。程序的第七行是 namespace 声明。一个 namespace 是一系列的类&#xff0c;MyFirstWinFormApp 命名…

SQL语句大全(MySQL入门到精通——基础篇)(基础篇——进阶篇——运维篇)

文章目录前言MySQL——基础篇一、SQL分类二、图形化界面工具三、DDL&#xff08;Data Definition Language|数据定义语言&#xff09;1.SQL-DDL-数据库操作2.SQL-DDL-表操作&查询3.SQL-DDL-数据类型3.SQL-DDL-表操作-修改&删除四、DML&#xff08;Data Manipulation La…

经典模型LeNet跑Fashion-MNIST 代码解析

测试6.6. 卷积神经网络&#xff08;LeNet&#xff09; — 动手学深度学习 2.0.0 documentation import torch from torch import nn from d2l import torch as d2lnet nn.Sequential(#输入通道1表示黑白 输出通道6表示6组取不同特征的卷积核 因为卷积核是5*5,原始图片单通道黑…

面向对象设计模式:行为型模式之模板方法模式

一、模板方法引入&#xff1a;泡茶与冲咖啡 泡茶 烧水泡茶倒入杯子加入柠檬 冲咖啡 烧水冲咖啡倒入杯子加入牛奶和糖 二、模板方法&#xff0c;TemplateMethod 2.1 Intent 意图 Define the skeleton of an algorithm in an operation, deferring some steps to lets subclas…

【深度学习】BERT变体—BERT-wwm

1.BERT-wwm 1-1 Whole Word Masking Whole Word Masking (wwm)是谷歌在2019年5月31日发布的一项BERT的升级版本&#xff0c;主要更改了原预训练阶段的训练样本生成策略。 原有基于WordPiece的分词方式会把一个完整的词切分成若干个子词&#xff0c;在生成训练样本时&#xff…

路由传参含对象数据刷新页面数据丢失

目录 一、问题描述 二、 解决办法 一、问题描述 【1】众所周知&#xff0c;在veu项目开发过程中&#xff0c;我们常常会用到通过路由的方式在页面中传递数据。但是用到this.$route.query.ObjectData的页面&#xff0c;刷新后会导致this.$route.query.ObjectData数据丢失。 …

(小甲鱼python)函数笔记合集七 函数(IX)总结 python实现汉诺塔详解

一、基础复习 函数的基本用法 创建和调用函数 函数的形参与实参等等函数的几种参数 位置参数、关键字参数、默认参数等函数的收集参数*args **args 解包参数详解函数中参数的作用域 局部作用域 全局作用域 global语句 嵌套函数 nonlocal语句等详解函数的闭包&#xff08;工厂函…

【LeetCode每日一题】——1323.6 和 9 组成的最大数字

文章目录一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【解题思路】七【题目提示】八【时间频度】九【代码实现】十【提交结果】一【题目类别】 贪心算法 二【题目难度】 简单 三【题目编号】 1323.6 和 9 组成的最大数字 四【题目描述】 …

【mediasoup】RtpStreamRecv 对rtp 序号的验证

mediasoup 接收到rtp包D:\XTRANS\soup\mediasoup_offical\worker\src\RTC\RtpStreamRecv.cpp代码竟然跟 https://tools.ietf.org/html/rfc3550#appendix-A.1 stuff. 一样的。RtpStreamRecv的 ReceivePacket(RTC::RtpPacket* packet) 处理收到的rtp包 可能会丢弃 判断丢帧 回卷后…

项目团队沟通管理 5大沟通原则

1、沟通内外有别 沟通需要区分团队内和团队外&#xff0c;在团队对外进行沟通时&#xff0c;团队作为一个整体&#xff0c;对外意见需要一致&#xff0c;一个团队需用一种声音说话。 沟通管理5大原则&#xff1a;沟通内外有别​ 2、重视非正式沟通 非正式的沟通有助于关…