• 野火FPGA强化(1):串口


    第31讲:串口RS232

    通用异步收发传输器(Universal Asynchronous Receiver/Transmitter,简称UART)
    UART是一种通用的数据通信协议,也是异步串行通信口(串口)的总称,它在发送数据时将并行数据转换成串行数据来传输,在接收数据时将接收到的串行数据转换成并行数据。
    包括RS232、RS499、RS423、RS422和RS485等接口标准规范和总线标准规范。

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


    实验目标
    在这里插入图片描述
    顶层模块设计
    在这里插入图片描述
    子功能模块设计
    在这里插入图片描述
    系统框图
    在这里插入图片描述

    串口数据接收模块:Uart_rx

    串口数据接收模块
    在这里插入图片描述

    `timescale  1ns/1ns
    
    module  uart_rx
    #(
        parameter   UART_BPS    =   'd9600,         //串口波特率
        parameter   CLK_FREQ    =   'd50_000_000    //时钟频率
    )
    (
        input   wire            sys_clk     ,   //系统时钟50MHz
        input   wire            sys_rst_n   ,   //全局复位
        input   wire            rx          ,   //串口接收数据
    
        output  reg     [7:0]   po_data     ,   //串转并后的8bit数据
        output  reg             po_flag         //串转并后的数据有效标志信号
    );
    
    //localparam    define
    localparam  BAUD_CNT_MAX    =   CLK_FREQ/UART_BPS   ;
    
    //reg   define
    reg         rx_reg1     ;
    reg         rx_reg2     ;
    reg         rx_reg3     ;
    reg         start_nedge ;
    reg         work_en     ;
    reg [12:0]  baud_cnt    ;
    reg         bit_flag    ;
    reg [3:0]   bit_cnt     ;
    reg [7:0]   rx_data     ;
    reg         rx_flag     ;
    
    //插入两级寄存器进行数据同步,用来消除亚稳态
    //rx_reg1:第一级寄存器,寄存器空闲状态复位为1
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            rx_reg1 <= 1'b1;
        else
            rx_reg1 <= rx;
    
    //rx_reg2:第二级寄存器,寄存器空闲状态复位为1
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            rx_reg2 <= 1'b1;
        else
            rx_reg2 <= rx_reg1;
    
    //rx_reg3:第三级寄存器和第二级寄存器共同构成下降沿检测
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            rx_reg3 <= 1'b1;
        else
            rx_reg3 <= rx_reg2;
    
    //start_nedge:检测到下降沿时start_nedge产生一个时钟的高电平
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            start_nedge <= 1'b0;
        else    if((~rx_reg2) && (rx_reg3))
            start_nedge <= 1'b1;
        else
            start_nedge <= 1'b0;
    
    //work_en:接收数据工作使能信号
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            work_en <= 1'b0;
        else    if(start_nedge == 1'b1)
            work_en <= 1'b1;
        else    if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
            work_en <= 1'b0;
    
    //baud_cnt:波特率计数器计数,从0计数到BAUD_CNT_MAX - 1
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            baud_cnt <= 13'b0;
        else    if((baud_cnt == BAUD_CNT_MAX - 1) || (work_en == 1'b0))
            baud_cnt <= 13'b0;
        else    if(work_en == 1'b1)
            baud_cnt <= baud_cnt + 1'b1;
    
    //bit_flag:当baud_cnt计数器计数到中间数时采样的数据最稳定,
    //此时拉高一个标志信号表示数据可以被取走
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            bit_flag <= 1'b0;
        else    if(baud_cnt == BAUD_CNT_MAX/2 - 1)
            bit_flag <= 1'b1;
        else
            bit_flag <= 1'b0;
    
    //bit_cnt:有效数据个数计数器,当8个有效数据(不含起始位和停止位)
    //都接收完成后计数器清零
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            bit_cnt <= 4'b0;
        else    if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
            bit_cnt <= 4'b0;
         else    if(bit_flag ==1'b1)
             bit_cnt <= bit_cnt + 1'b1;
    
    //rx_data:输入数据进行移位
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            rx_data <= 8'b0;
        else    if((bit_cnt >= 4'd1)&&(bit_cnt <= 4'd8)&&(bit_flag == 1'b1))
            rx_data <= {rx_reg3, rx_data[7:1]};
    
    //rx_flag:输入数据移位完成时rx_flag拉高一个时钟的高电平
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            rx_flag <= 1'b0;
        else    if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
            rx_flag <= 1'b1;
        else
            rx_flag <= 1'b0;
    
    //po_data:输出完整的8位有效数据
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            po_data <= 8'b0;
        else    if(rx_flag == 1'b1)
            po_data <= rx_data;
    
    //po_flag:输出数据有效标志(比rx_flag延后一个时钟周期,为了和po_data同步)
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            po_flag <= 1'b0;
        else
            po_flag <= rx_flag;
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131

    tb_uart_rx.v

    `timescale  1ns/1ns
    module  tb_uart_rx();
    
    //reg   define
    reg             sys_clk;
    reg             sys_rst_n;
    reg             rx;
    
    //wire  define
    wire    [7:0]   po_data;
    wire            po_flag;
    
    //初始化系统时钟、全局复位和输入信号
    initial begin
            sys_clk    = 1'b1;
            sys_rst_n <= 1'b0;
            rx        <= 1'b1;
            #20;
            sys_rst_n <= 1'b1;
    end
    
    //模拟发送8次数据,分别为0~7
    initial begin
            #200
            rx_bit(8'd0);  //任务的调用,任务名+括号中要传递进任务的参数
            rx_bit(8'd1);
            rx_bit(8'd2);
            rx_bit(8'd3);
            rx_bit(8'd4);
            rx_bit(8'd5);
            rx_bit(8'd6);
            rx_bit(8'd7);
    end
    
    //sys_clk:每10ns电平翻转一次,产生一个50MHz的时钟信号
    always #10 sys_clk = ~sys_clk;
    
    //定义一个名为rx_bit的任务,每次发送的数据有10位
    //data的值分别为0~7由j的值传递进来
    //任务以task开头,后面紧跟着的是任务名,调用时使用
    task rx_bit(
        //传递到任务中的参数,调用任务的时候从外部传进来一个8位的值
            input   [7:0]   data
    );
            integer i;      //定义一个常量
    //用for循环产生一帧数据,for括号中最后执行的内容只能写i=i+1
    //不可以写成C语言i=i++的形式
            for(i=0; i<10; i=i+1) begin
                case(i)
                    0: rx <= 1'b0;
                    1: rx <= data[0];
                    2: rx <= data[1];
                    3: rx <= data[2];
                    4: rx <= data[3];
                    5: rx <= data[4];
                    6: rx <= data[5];
                    7: rx <= data[6];
                    8: rx <= data[7];
                    9: rx <= 1'b1;
                endcase
                #(5208*20); //每发送1位数据延时5208个时钟周期
            end
    endtask         //任务以endtask结束
    
    //------------------------uart_rx_inst------------------------
    uart_rx uart_rx_inst(
            .sys_clk    (sys_clk    ),  //input           sys_clk
            .sys_rst_n  (sys_rst_n  ),  //input           sys_rst_n
            .rx         (rx         ),  //input           rx
                    
            .po_data    (po_data    ),  //output  [7:0]   po_data
            .po_flag    (po_flag    )   //output          po_flag
    );
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75

    串口数据发送模块:Uart_tx

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

    `timescale  1ns/1ns
    
    module  uart_tx
    #(
        parameter   UART_BPS    =   'd9600,         //串口波特率
        parameter   CLK_FREQ    =   'd50_000_000    //时钟频率
    )
    (
         input   wire            sys_clk     ,   //系统时钟50MHz
         input   wire            sys_rst_n   ,   //全局复位
         input   wire    [7:0]   pi_data     ,   //模块输入的8bit数据
         input   wire            pi_flag     ,   //并行数据有效标志信号
     
         output  reg             tx              //串转并后的1bit数据
    );
    
    //localparam    define
    localparam  BAUD_CNT_MAX    =   CLK_FREQ/UART_BPS   ;
    
    //reg   define
    reg [12:0]  baud_cnt;
    reg         bit_flag;
    reg [3:0]   bit_cnt ;
    reg         work_en ;
    
    //work_en:接收数据工作使能信号
    always@(posedge sys_clk or negedge sys_rst_n)
            if(sys_rst_n == 1'b0)
                work_en <= 1'b0;
            else    if(pi_flag == 1'b1)
                work_en <= 1'b1;
            else    if((bit_flag == 1'b1) && (bit_cnt == 4'd9))
                work_en <= 1'b0;
    
    //baud_cnt:波特率计数器计数,从0计数到BAUD_CNT_MAX - 1
    always@(posedge sys_clk or negedge sys_rst_n)
            if(sys_rst_n == 1'b0)
                baud_cnt <= 13'b0;
            else    if((baud_cnt == BAUD_CNT_MAX - 1) || (work_en == 1'b0))
                baud_cnt <= 13'b0;
            else    if(work_en == 1'b1)
                baud_cnt <= baud_cnt + 1'b1;
    
    //bit_flag:当baud_cnt计数器计数到1时让bit_flag拉高一个时钟的高电平
    always@(posedge sys_clk or negedge sys_rst_n)
            if(sys_rst_n == 1'b0)
                bit_flag <= 1'b0;
            else    if(baud_cnt == 13'd1)
                bit_flag <= 1'b1;
            else
                bit_flag <= 1'b0;
    
    //bit_cnt:数据位数个数计数,10个有效数据(含起始位和停止位)到来后计数器清零
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            bit_cnt <= 4'b0;
        else    if((bit_flag == 1'b1) && (bit_cnt == 4'd9))
            bit_cnt <= 4'b0;
        else    if((bit_flag == 1'b1) && (work_en == 1'b1))
            bit_cnt <= bit_cnt + 1'b1;
    
    //tx:输出数据在满足rs232协议(起始位为0,停止位为1)的情况下一位一位输出
    always@(posedge sys_clk or negedge sys_rst_n)
            if(sys_rst_n == 1'b0)
                tx <= 1'b1; //空闲状态时为高电平
            else    if(bit_flag == 1'b1)
                case(bit_cnt)
                    0       : tx <= 1'b0;
                    1       : tx <= pi_data[0];
                    2       : tx <= pi_data[1];
                    3       : tx <= pi_data[2];
                    4       : tx <= pi_data[3];
                    5       : tx <= pi_data[4];
                    6       : tx <= pi_data[5];
                    7       : tx <= pi_data[6];
                    8       : tx <= pi_data[7];
                    9       : tx <= 1'b1;
                    default : tx <= 1'b1;
                endcase
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81

    tb_uart_tx.v

    `timescale  1ns/1ns
    module  tb_uart_tx();
    
    //reg   define
    reg         sys_clk;
    reg         sys_rst_n;
    reg [7:0]   pi_data;
    reg         pi_flag;
    
    //wire  define
    wire        tx;
    
    //初始化系统时钟、全局复位
    initial begin
            sys_clk    = 1'b1;
            sys_rst_n <= 1'b0;
            #20;
            sys_rst_n <= 1'b1;
    end
    
    //模拟发送7次数据,分别为0~7
    initial begin
            pi_data <= 8'b0;
            pi_flag <= 1'b0;
            #200
            //发送数据0
            pi_data <= 8'd0;
            pi_flag <= 1'b1;
            #20
            pi_flag <= 1'b0;
    //每发送1bit数据需要5208个时钟周期,一帧数据为10bit
    //所以需要数据延时(5208*20*10)后再产生下一个数据
            #(5208*20*10);
            //发送数据1
            pi_data <= 8'd1;
            pi_flag <= 1'b1;
            #20
            pi_flag <= 1'b0;
            #(5208*20*10);
            //发送数据2
            pi_data <= 8'd2;
            pi_flag <= 1'b1;
            #20
            pi_flag <= 1'b0;
            #(5208*20*10);
            //发送数据3
            pi_data <= 8'd3;
            pi_flag <= 1'b1;
            #20
            pi_flag <= 1'b0;
            #(5208*20*10);
            //发送数据4
            pi_data <= 8'd4;
            pi_flag <= 1'b1;
            #20
            pi_flag <= 1'b0;
            #(5208*20*10);
            //发送数据5
            pi_data <= 8'd5;
            pi_flag <= 1'b1;
            #20
            pi_flag <= 1'b0;
            #(5208*20*10);
            //发送数据6
            pi_data <= 8'd6;
            pi_flag <= 1'b1;
            #20
            pi_flag <= 1'b0;
            #(5208*20*10);
            //发送数据7
            pi_data <= 8'd7;
            pi_flag <= 1'b1;
            #20
            pi_flag <= 1'b0;
    end
    
    //sys_clk:每10ns电平翻转一次,产生一个50MHz的时钟信号
    always #10 sys_clk = ~sys_clk;
    
    //------------------------uart_rx_inst------------------------
    uart_tx uart_tx_inst(
            .sys_clk    (sys_clk    ),  //input           sys_clk
            .sys_rst_n  (sys_rst_n  ),  //input           sys_rst_n
            .pi_data    (pi_data    ),  //output  [7:0]   pi_data
            .pi_flag    (pi_flag    ),  //output          pi_flag
    
            .tx         (tx         )   //input           tx
    );
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90

    底层模块:rs232

    `timescale  1ns/1ns
    
    module  rs232
    (
        input   wire    sys_clk     ,   //系统时钟50MHz
        input   wire    sys_rst_n   ,   //全局复位
        input   wire    rx          ,   //串口接收数据
    
        output  wire    tx              //串口发送数据
    );
    
    //parameter define
    parameter   UART_BPS    =   14'd9600        ,   //比特率
                CLK_FREQ    =   26'd50_000_000  ;   //时钟频率
    
    //wire  define
    wire    [7:0]   po_data;
    wire            po_flag;
    
    //------------------------ uart_rx_inst ------------------------
    uart_rx
    #(
        .UART_BPS    (UART_BPS  ),  //串口波特率
        .CLK_FREQ    (CLK_FREQ  )   //时钟频率
    )
    uart_rx_inst
    (
        .sys_clk    (sys_clk    ),  //input             sys_clk
        .sys_rst_n  (sys_rst_n  ),  //input             sys_rst_n
        .rx         (rx         ),  //input             rx
                
        .po_data    (po_data    ),  //output    [7:0]   po_data
        .po_flag    (po_flag    )   //output            po_flag
    );
    
    //------------------------ uart_tx_inst ------------------------
    uart_tx
    #(
        .UART_BPS    (UART_BPS  ),  //串口波特率
        .CLK_FREQ    (CLK_FREQ  )   //时钟频率
    )
    uart_tx_inst
    (
        .sys_clk    (sys_clk    ),  //input             sys_clk
        .sys_rst_n  (sys_rst_n  ),  //input             sys_rst_n
        .pi_data    (po_data    ),  //input     [7:0]   pi_data
        .pi_flag    (po_flag    ),  //input             pi_flag
                    
        .tx         (tx         )   //output            tx
    );
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    tb_rs232.v

    `timescale  1ns/1ns
    module  tb_rs232();
    
    //wire  define
    wire    tx          ;
    
    //reg   define
    reg     sys_clk     ;
    reg     sys_rst_n   ;
    reg     rx          ;
    
    //初始化系统时钟、全局复位和输入信号
    initial begin
        sys_clk    = 1'b1;
        sys_rst_n <= 1'b0;
        rx        <= 1'b1;
        #20;
        sys_rst_n <= 1'b1;
    end
    
    //调用任务rx_byte
    initial begin
        #200
        rx_byte();
    end
    
    //sys_clk:每10ns电平翻转一次,产生一个50MHz的时钟信号
    always #10 sys_clk = ~sys_clk;
    
    //创建任务rx_byte,本次任务调用rx_bit任务,发送8次数据,分别为0~7
    task    rx_byte();  //因为不需要外部传递参数,所以括号中没有输入
        integer j;
        for(j=0; j<8; j=j+1)    //调用8次rx_bit任务,每次发送的值从0变化7
            rx_bit(j);
    endtask
    
    //创建任务rx_bit,每次发送的数据有10位,data的值分别为0到7由j的值传递进来
    task    rx_bit(
        input   [7:0]   data
    );
        integer i;
        for(i=0; i<10; i=i+1)   begin
            case(i)
                0: rx <= 1'b0;
                1: rx <= data[0];
                2: rx <= data[1];
                3: rx <= data[2];
                4: rx <= data[3];
                5: rx <= data[4];
                6: rx <= data[5];
                7: rx <= data[6];
                8: rx <= data[7];
                9: rx <= 1'b1;
            endcase
            #(5208*20); //每发送1位数据延时5208个时钟周期
        end
    endtask
    
    //------------------------ rs232_inst ------------------------
    rs232   rs232_inst
    (
        .sys_clk    (sys_clk    ),  //input         sys_clk
        .sys_rst_n  (sys_rst_n  ),  //input         sys_rst_n
        .rx         (rx         ),  //input         rx
    
        .tx         (tx         )   //output        tx
    );
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69



    第32讲:使用SignalTap II嵌入式逻辑分析仪在线调试

    看视频讲解:https://www.bilibili.com/video/BV17z411i7er



    第33讲:串口RS485

    RS485是双向、半双工通信协议,信号采用差分传输方式,允许多个驱动器和接收器挂接在总线上,其中每个驱动器都能够脱离总线。
    在这里插入图片描述
    在这里插入图片描述


    实现目标
    在这里插入图片描述
    在这里插入图片描述
    系统框图
    在这里插入图片描述
    控制板波形
    在这里插入图片描述
    被控制板波形
    在这里插入图片描述

    key_filter

    `timescale  1ns/1ns
    
    module  key_filter
    #(
        parameter CNT_MAX = 20'd999_999 //计数器计数最大值
    )
    (
        input   wire    sys_clk     ,   //系统时钟50Mhz
        input   wire    sys_rst_n   ,   //全局复位
        input   wire    key_in      ,   //按键输入信号
    
        output  reg     key_flag        //key_flag为1时表示消抖后检测到按键被按下
                                        //key_flag为0时表示没有检测到按键被按下
    );
    
    //reg   define
    reg     [19:0]  cnt_20ms    ;   //计数器
    
    //cnt_20ms:如果时钟的上升沿检测到外部按键输入的值为低电平时,计数器开始计数
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            cnt_20ms <= 20'b0;
        else    if(key_in == 1'b1)
            cnt_20ms <= 20'b0;
        else    if(cnt_20ms == CNT_MAX && key_in == 1'b0)  //为低电平且已经达到最大值,不再进行清零
            cnt_20ms <= cnt_20ms;
        else
            cnt_20ms <= cnt_20ms + 1'b1;
    
    //key_flag:当计数满20ms后产生按键有效标志位
    //且key_flag在999_999时拉高,维持一个时钟的高电平
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            key_flag <= 1'b0;
        else    if(cnt_20ms == CNT_MAX - 1'b1)
            key_flag <= 1'b1;
        else
            key_flag <= 1'b0;
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    water_led

    `timescale  1ns/1ns
    
    module  water_led
    #(
        parameter CNT_MAX = 25'd24_999_999
    )
    (
        input   wire            sys_clk     ,   //系统时钟50Mh
        input   wire            sys_rst_n   ,  //全局复位
    
        output  wire    [3:0]   led_out        //输出控制led灯
    );
    
    //reg   define
    reg     [24:0]  cnt         ;
    reg             cnt_flag    ;
    reg     [3:0]   led_out_reg ;
    
    //cnt:计数器计数1s
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            cnt <= 25'b0;
        else    if(cnt == CNT_MAX)
            cnt <= 25'b0;
        else
            cnt <= cnt + 1'b1;
    
    //cnt_flag:计数器计数满1s标志信号
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            cnt_flag <= 1'b0;
        else    if(cnt == CNT_MAX - 1)
            cnt_flag <= 1'b1;
        else
            cnt_flag <= 1'b0;
    
    //led_out_reg:led循环流水
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            led_out_reg <=  4'b0001;
        else    if(led_out_reg == 4'b1000 && cnt_flag == 1'b1)
            led_out_reg <=  4'b0001;
        else    if(cnt_flag == 1'b1)
            led_out_reg <=  led_out_reg << 1'b1; //左移
    
    assign  led_out = ~led_out_reg;
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    breath_led

    `timescale  1ns/1ns
    
    module  breath_led
    #(
        parameter CNT_1US_MAX = 6'd49   ,
        parameter CNT_1MS_MAX = 10'd999 ,
        parameter CNT_1S_MAX  = 10'd999
    )
    (
        input   wire    sys_clk     ,   //系统时钟50Mhz
        input   wire    sys_rst_n   ,   //全局复位
    
        output  reg     led_out         //输出信号,控制led灯
    );
    
    //reg define
    reg [5:0]   cnt_1us     ;
    reg [9:0]   cnt_1ms     ;
    reg [9:0]   cnt_1s      ;
    reg         cnt_1s_flag ;
    
    //cnt_1us:1us计数器
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            cnt_1us <= 6'b0;
        else    if(cnt_1us == CNT_1US_MAX)
            cnt_1us <= 6'b0;
        else
            cnt_1us <= cnt_1us + 1'b1;
    
    //cnt_1ms:1ms计数器
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            cnt_1ms <= 10'b0;
        else    if(cnt_1ms == CNT_1MS_MAX && cnt_1us == CNT_1US_MAX)
            cnt_1ms <= 10'b0;
        else    if(cnt_1us == CNT_1US_MAX)
            cnt_1ms <= cnt_1ms + 1'b1;
    
    //cnt_1s:1s计数器
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            cnt_1s <= 10'b0;
        else    if(cnt_1s == CNT_1S_MAX && cnt_1ms == CNT_1MS_MAX 
                                            && cnt_1us == CNT_1US_MAX)
            cnt_1s <= 10'b0;
        else    if(cnt_1ms == CNT_1MS_MAX && cnt_1us == CNT_1US_MAX)
            cnt_1s <= cnt_1s + 1'b1;
    
    //cnt_1s_flag:1s计数器标志信号
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            cnt_1s_flag <= 1'b0;
        else    if(cnt_1s == CNT_1S_MAX && cnt_1ms == CNT_1MS_MAX 
                                                && cnt_1us == CNT_1US_MAX)
            cnt_1s_flag <= ~cnt_1s_flag;
    
    //led_out:输出信号连接到外部的led灯
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            led_out <= 1'b0;
        else    if((cnt_1s_flag == 1'b1 && cnt_1ms < cnt_1s) || 
                                (cnt_1s_flag == 1'b0 && cnt_1ms > cnt_1s))
            led_out <= 1'b0;
        else
            led_out <= 1'b1;
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68

    led_ctrl

    `timescale  1ns/1ns
    
    module  led_ctrl
    (
        input   wire            sys_clk         ,   //模块时钟,50MHz 
        input   wire            sys_rst_n       ,   //复位信号,低有效
        input   wire            water_key_flag  ,   //流水灯按键有效信号
        input   wire            breath_key_flag ,   //呼吸灯按键有效信号
        input   wire    [3:0]   led_out_w       ,   //流水灯
        input   wire            led_out_b       ,   //呼吸灯
        input   wire    [7:0]   po_data         ,   //接收数据
    
        output  wire            pi_flag         ,   //发送标志信号
        output  wire    [7:0]   pi_data         ,   //发送数据
        output  reg     [3:0]   led_out             //输出led灯
    );
    
    //reg   define
    reg     water_led_flag  ;   //流水灯标志信号,作为pi_data[0]发送
    reg     breath_led_flag ;   //呼吸灯标志信号,作为pi_data[1]发送
    
    //按下呼吸灯按键或流水灯按键时,开始发送数据
    assign  pi_flag =   water_key_flag | breath_key_flag;
    
    //低两位数据为led控制信号
    assign  pi_data =   {6'd0,breath_led_flag,water_led_flag};
    
    //water_key_flag:串口发送的控制信号,高时流水灯,低时停止(按键控制)
    always@(posedge sys_clk or  negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            water_led_flag  <=  1'b0;
        else    if(breath_key_flag == 1'b1)
            water_led_flag  <=  1'b0;
        else    if(water_key_flag == 1'b1)
            water_led_flag  <=  ~water_led_flag;
    
    //breath_key_flag:串口发送的控制信号,高时呼吸灯灯,低时停止(按键控制)
    always@(posedge sys_clk or  negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            breath_led_flag  <=  1'b0;
        else    if(water_key_flag == 1'b1)
            breath_led_flag  <=  1'b0;
        else    if(breath_key_flag == 1'b1)
            breath_led_flag  <=  ~breath_led_flag;
    
    //led_out:当传入的流水灯有效时,led灯为流水灯,同理呼吸灯也是如此
    always@(posedge sys_clk or  negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            led_out <=  4'b1111;
        else    if(po_data[0] == 1'b1 )
            led_out <=  led_out_w;
        else    if(po_data[1] == 1'b1 )
        //使四个led灯都显示呼吸灯状态
            led_out <=  {led_out_b,led_out_b,led_out_b,led_out_b};
        else
            led_out <=  4'b1111; 
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    uart_rx

    `timescale  1ns/1ns
    
    module  uart_rx
    #(
        parameter   UART_BPS    =   'd9600,         //串口波特率
        parameter   CLK_FREQ    =   'd50_000_000    //时钟频率
    )
    (
        input   wire            sys_clk     ,   //系统时钟50MHz
        input   wire            sys_rst_n   ,   //全局复位
        input   wire            rx          ,   //串口接收数据
    
        output  reg     [7:0]   po_data     ,   //串转并后的8bit数据
        output  reg             po_flag         //串转并后的数据有效标志信号
    );
    
    //localparam    define
    localparam  BAUD_CNT_MAX    =   CLK_FREQ/UART_BPS   ;
    
    //reg   define
    reg         rx_reg1     ;
    reg         rx_reg2     ;
    reg         rx_reg3     ;
    reg         start_nedge ;
    reg         work_en     ;
    reg [12:0]  baud_cnt    ;
    reg         bit_flag    ;
    reg [3:0]   bit_cnt     ;
    reg [7:0]   rx_data     ;
    reg         rx_flag     ;
    
    //插入两级寄存器进行数据同步,用来消除亚稳态
    //rx_reg1:第一级寄存器,寄存器空闲状态复位为1
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            rx_reg1 <= 1'b1;
        else
            rx_reg1 <= rx;
    
    //rx_reg2:第二级寄存器,寄存器空闲状态复位为1
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            rx_reg2 <= 1'b1;
        else
            rx_reg2 <= rx_reg1;
    
    //rx_reg3:第三级寄存器和第二级寄存器共同构成下降沿检测
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            rx_reg3 <= 1'b1;
        else
            rx_reg3 <= rx_reg2;
    
    //start_nedge:检测到下降沿时start_nedge产生一个时钟的高电平
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            start_nedge <= 1'b0;
        else    if((~rx_reg2) && (rx_reg3))
            start_nedge <= 1'b1;
        else
            start_nedge <= 1'b0;
    
    //work_en:接收数据工作使能信号
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            work_en <= 1'b0;
        else    if(start_nedge == 1'b1)
            work_en <= 1'b1;
        else    if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
            work_en <= 1'b0;
    
    //baud_cnt:波特率计数器计数,从0计数到BAUD_CNT_MAX - 1
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            baud_cnt <= 13'b0;
        else    if((baud_cnt == BAUD_CNT_MAX - 1) || (work_en == 1'b0))
            baud_cnt <= 13'b0;
        else    if(work_en == 1'b1)
            baud_cnt <= baud_cnt + 1'b1;
    
    //bit_flag:当baud_cnt计数器计数到中间数时采样的数据最稳定,
    //此时拉高一个标志信号表示数据可以被取走
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            bit_flag <= 1'b0;
        else    if(baud_cnt == BAUD_CNT_MAX/2 - 1)
            bit_flag <= 1'b1;
        else
            bit_flag <= 1'b0;
    
    //bit_cnt:有效数据个数计数器,当8个有效数据(不含起始位和停止位)
    //都接收完成后计数器清零
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            bit_cnt <= 4'b0;
        else    if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
            bit_cnt <= 4'b0;
         else    if(bit_flag ==1'b1)
             bit_cnt <= bit_cnt + 1'b1;
    
    //rx_data:输入数据进行移位
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            rx_data <= 8'b0;
        else    if((bit_cnt >= 4'd1)&&(bit_cnt <= 4'd8)&&(bit_flag == 1'b1))
            rx_data <= {rx_reg3, rx_data[7:1]};
    
    //rx_flag:输入数据移位完成时rx_flag拉高一个时钟的高电平
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            rx_flag <= 1'b0;
        else    if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
            rx_flag <= 1'b1;
        else
            rx_flag <= 1'b0;
    
    //po_data:输出完整的8位有效数据
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            po_data <= 8'b0;
        else    if(rx_flag == 1'b1)
            po_data <= rx_data;
    
    //po_flag:输出数据有效标志(比rx_flag延后一个时钟周期,为了和po_data同步)
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            po_flag <= 1'b0;
        else
            po_flag <= rx_flag;
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131

    uart_tx

    `timescale  1ns/1ns
    
    module  uart_tx
    #(
        parameter   UART_BPS    =   'd9600,           //串口波特率
        parameter   CLK_FREQ    =   'd50_000_000      //时钟频率
    )
    (
        input   wire            sys_clk     ,   //系统时钟50Mhz
        input   wire            sys_rst_n   ,   //全局复位
        input   wire    [7:0]   pi_data     ,   //并行数据
        input   wire            pi_flag     ,   //并行数据有效标志信号
                
        output  reg             work_en     ,   //发送使能,高有效
        output  reg             tx              //串口发送数据
    );
    
    //localparam    define
    localparam  BAUD_CNT_MAX    =   CLK_FREQ/UART_BPS   ;
            
    //reg   define
    reg     [12:0]  baud_cnt    ;   
    reg             bit_flag    ;   
    reg     [3:0]   bit_cnt     ;    
    
    //work_en:接收数据工作使能信号
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            work_en <= 1'b0;
        else    if(pi_flag == 1'b1)	
            work_en <= 1'b1;
        else    if((bit_flag == 1'b1) && (bit_cnt == 4'd9))
            work_en <= 1'b0;
    
    //baud_cnt:波特率计数器计数,从0计数到5207
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            baud_cnt <= 13'b0;
        else    if((baud_cnt == BAUD_CNT_MAX - 1) || (work_en == 1'b0))
            baud_cnt <= 13'b0;
        else    if(work_en == 1'b1)
            baud_cnt <= baud_cnt + 1'b1;
    
    //bit_flag:当baud_cnt计数器计数到1时让bit_flag拉高一个时钟的高电平
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            bit_flag <= 1'b0;
        else    if( /* baud_cnt == 13'd1 */baud_cnt == BAUD_CNT_MAX - 1 )
            bit_flag <= 1'b1;
        else
            bit_flag <= 1'b0;
    
    //bit_cnt:数据位数个数计数,10个有效数据(含起始位和停止位)到来后计数器清零
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            bit_cnt <= 4'b0;
        else    if((bit_flag == 1'b1) && (bit_cnt == 4'd9))	
            bit_cnt <= 4'b0;
        else    if((bit_flag == 1'b1) && (work_en == 1'b1))
            bit_cnt <= bit_cnt + 1'b1;
                                    
    //tx:输出数据在满足rs232协议(起始位为0,停止位为1)的情况下一位一位输出
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            tx <= 1'b1;	//空闲状态时为高电平
        else    if(/* bit_flag == 1'b1 */work_en == 1'b1)
            case(bit_cnt)
                0       : tx <= 1'b0;
                1       : tx <= pi_data[0];
                2       : tx <= pi_data[1];
                3       : tx <= pi_data[2];
                4       : tx <= pi_data[3];
                5       : tx <= pi_data[4];
                6       : tx <= pi_data[5];
                7       : tx <= pi_data[6];
                8       : tx <= pi_data[7];
                9       : tx <= 1'b1;
                default : tx <= 1'b1;
            endcase
                    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81

    rs485

    `timescale  1ns/1ns
    
    module  rs485
    (
        input   wire            sys_clk     ,   //系统时钟,50MHz
        input   wire            sys_rst_n   ,   //复位信号,低有效
        input   wire            rx          ,   //串口接收数据
        input   wire    [1:0]   key         ,   //两个按键
    
        output  wire            work_en     ,   //发送使能,高有效
        output  wire            tx          ,   //串口接收数据
        output  wire    [3:0]   led             //led灯
    );
    
    //parameter define
    parameter   UART_BPS    =   14'd9600;       //比特率
    parameter   CLK_FREQ    =   26'd50_000_000; //时钟频率
    
    //wire  define
    wire    [7:0]   po_data         ;   //接收数据
    wire    [7:0]   pi_data         ;   //发送数据
    wire            pi_flag         ;   //发送标志信号
    wire            water_key_flag  ;   //流水灯按键有效信号
    wire            breath_key_flag ;   //呼吸灯按键有效信号
    wire    [3:0]   led_out_w       ;   //流水灯
    wire            led_out_b       ;   //呼吸灯
    
    //--------------------uart_rx_inst------------------------
    uart_rx
    #(
        .UART_BPS    (UART_BPS  ),   //串口波特率
        .CLK_FREQ    (CLK_FREQ  )    //时钟频率
    )
    uart_rx_inst(
        .sys_clk     (sys_clk   ),   //系统时钟50Mhz
        .sys_rst_n   (sys_rst_n ),   //全局复位
        .rx          (rx        ),   //串口接收数据
    
        .po_data     (po_data   ),   //串转并后的8bit数据
        .po_flag     (          )    //接收数据完成标志信号没用到可不接
    );
    
    //--------------------uart_tx_inst------------------------
    uart_tx
    #(
        .UART_BPS    (UART_BPS  ),   //串口波特率
        .CLK_FREQ    (CLK_FREQ  )    //时钟频率
    )
    uart_tx_inst(
        .sys_clk     (sys_clk   ),   //系统时钟50Mhz
        .sys_rst_n   (sys_rst_n ),   //全局复位
        .pi_data     (pi_data   ),   //并行数据
        .pi_flag     (pi_flag   ),   //并行数据有效标志信号
    
        .work_en     (work_en   ),   //发送使能,高有效
        .tx          (tx        )    //串口发送数据
    );
    
    //--------------------key_filter_inst------------------------
    //两个按键信号例化两次
    key_filter  key_filter_w
    (
        .sys_clk        (sys_clk        ),    //系统时钟50Mhz
        .sys_rst_n      (sys_rst_n      ),    //全局复位
        .key_in         (key[0]         ),    //按键输入信号
    
        .key_flag       (water_key_flag)  //key_flag为1时表示消抖后按键有效
    );
    key_filter  key_filter_b
    (
        .sys_clk        (sys_clk        ),    //系统时钟50Mhz
        .sys_rst_n      (sys_rst_n      ),    //全局复位
        .key_in         (key[1]         ),    //按键输入信号
    
        .key_flag       (breath_key_flag) //key_flag为1时表示消抖后按键有效
    );
    
    //--------------------key_ctrl_inst------------------------
    led_ctrl    led_ctrl_inst
    (
        .sys_clk         (sys_clk        ),   //模块时钟,50MHz
        .sys_rst_n       (sys_rst_n      ),   //复位信号,低有效
        .water_key_flag  (water_key_flag ),   //流水灯按键有效信号
        .breath_key_flag (breath_key_flag),   //呼吸灯按键有效信号
        .led_out_w       (led_out_w      ),   //流水灯
        .led_out_b       (led_out_b      ),   //呼吸灯
        .po_data         (po_data        ),   //接收数据
    
        .pi_flag         (pi_flag        ),   //发送标志信号
        .pi_data         (pi_data        ),   //发送数据
        .led_out         (led            )    //输出led灯
    );
    
    //--------------------water_led_inst------------------------
    water_led   water_led_inst
    (
        .sys_clk         (sys_clk   ),   //系统时钟50Mh
        .sys_rst_n       (sys_rst_n ),   //全局复位
    
        .led_out         (led_out_w )    //输出控制led灯
    );
    
    //--------------------breath_led_inst------------------------
    breath_led  breath_led_inst
    (
        .sys_clk         (sys_clk   ),   //系统时钟50Mhz
        .sys_rst_n       (sys_rst_n ),   //全局复位
    
        .led_out         (led_out_b )    //输出信号,控制led灯
    );
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112

    tb_rs485

    `timescale  1ns/1ns
    module  tb_rs485();
    
    //wire  define
    wire            rx1         ;
    wire            work_en1    ;
    wire            tx1         ;
    wire    [3:0]   led1        ;
    wire            work_en2    ;
    wire            tx2         ;
    wire    [3:0]   led2        ;
    
    //reg   define
    reg             sys_clk     ;
    reg             sys_rst_n   ;
    reg     [1:0]   key1        ;
    reg     [1:0]   key2        ;
    
    //对sys_clk,sys_rst赋初值,并模拟按键抖动
    initial
        begin
                sys_clk     =   1'b1 ;
                sys_rst_n   <=  1'b0 ;
                key1        <=  2'b11;
                key2        <=  2'b11;
        #200    sys_rst_n   <=  1'b1 ;
    //按下流水灯按键
        #2000000    key1[0]      <=  1'b0;//按下按键
        #20         key1[0]      <=  1'b1;//模拟抖动
        #20         key1[0]      <=  1'b0;//模拟抖动
        #20         key1[0]      <=  1'b1;//模拟抖动
        #20         key1[0]      <=  1'b0;//模拟抖动
        #200        key1[0]      <=  1'b1;//松开按键
        #20         key1[0]      <=  1'b0;//模拟抖动
        #20         key1[0]      <=  1'b1;//模拟抖动
        #20         key1[0]      <=  1'b0;//模拟抖动
        #20         key1[0]      <=  1'b1;//模拟抖动
    //按下呼吸灯按键
        #2000000    key1[1]      <=  1'b0;//按下按键
        #20         key1[1]      <=  1'b1;//模拟抖动
        #20         key1[1]      <=  1'b0;//模拟抖动
        #20         key1[1]      <=  1'b1;//模拟抖动
        #20         key1[1]      <=  1'b0;//模拟抖动
        #200        key1[1]      <=  1'b1;//松开按键
        #20         key1[1]      <=  1'b0;//模拟抖动
        #20         key1[1]      <=  1'b1;//模拟抖动
        #20         key1[1]      <=  1'b0;//模拟抖动
        #20         key1[1]      <=  1'b1;//模拟抖动
    //按下呼吸灯按键
        #2000000    key1[1]      <=  1'b0;//按下按键
        #20         key1[1]      <=  1'b1;//模拟抖动
        #20         key1[1]      <=  1'b0;//模拟抖动
        #20         key1[1]      <=  1'b1;//模拟抖动
        #20         key1[1]      <=  1'b0;//模拟抖动
        #200        key1[1]      <=  1'b1;//松开按键
        #20         key1[1]      <=  1'b0;//模拟抖动
        #20         key1[1]      <=  1'b1;//模拟抖动
        #20         key1[1]      <=  1'b0;//模拟抖动
        #20         key1[1]      <=  1'b1;//模拟抖动
    //按下呼吸灯按键
        #2000000    key1[1]      <=  1'b0;//按下按键
        #20         key1[1]      <=  1'b1;//模拟抖动
        #20         key1[1]      <=  1'b0;//模拟抖动
        #20         key1[1]      <=  1'b1;//模拟抖动
        #20         key1[1]      <=  1'b0;//模拟抖动
        #200        key1[1]      <=  1'b1;//松开按键
        #20         key1[1]      <=  1'b0;//模拟抖动
        #20         key1[1]      <=  1'b1;//模拟抖动
        #20         key1[1]      <=  1'b0;//模拟抖动
        #20         key1[1]      <=  1'b1;//模拟抖动
    //按下流水灯灯按键
        #2000000    key1[0]      <=  1'b0;//按下按键
        #20         key1[0]      <=  1'b1;//模拟抖动
        #20         key1[0]      <=  1'b0;//模拟抖动
        #20         key1[0]      <=  1'b1;//模拟抖动
        #20         key1[0]      <=  1'b0;//模拟抖动
        #200        key1[0]      <=  1'b1;//松开按键
        #20         key1[0]      <=  1'b0;//模拟抖动
        #20         key1[0]      <=  1'b1;//模拟抖动
        #20         key1[0]      <=  1'b0;//模拟抖动
        #20         key1[0]      <=  1'b1;//模拟抖动
    //按下流水灯灯按键
        #2000000    key1[0]      <=  1'b0;//按下按键
        #20         key1[0]      <=  1'b1;//模拟抖动
        #20         key1[0]      <=  1'b0;//模拟抖动
        #20         key1[0]      <=  1'b1;//模拟抖动
        #20         key1[0]      <=  1'b0;//模拟抖动
        #200        key1[0]      <=  1'b1;//松开按键
        #20         key1[0]      <=  1'b0;//模拟抖动
        #20         key1[0]      <=  1'b1;//模拟抖动
        #20         key1[0]      <=  1'b0;//模拟抖动
        #20         key1[0]      <=  1'b1;//模拟抖动
        end
    
    //sys_clk:模拟系统时钟,每10ns电平取反一次,周期为20ns,频率为50Mhz
    always #10 sys_clk = ~sys_clk;
    
    //重新定义参数值,缩短仿真时间仿真
    //发送板参数
    defparam    rs485_inst1.key_filter_w.CNT_MAX         =   5      ;
    defparam    rs485_inst1.key_filter_b.CNT_MAX         =   5      ;
    defparam    rs485_inst1.uart_rx_inst.UART_BPS        =   1000000;
    defparam    rs485_inst1.uart_tx_inst.UART_BPS        =   1000000;
    defparam    rs485_inst1.water_led_inst.CNT_MAX       =   4000   ;
    defparam    rs485_inst1.breath_led_inst.CNT_1US_MAX  =   4      ;
    defparam    rs485_inst1.breath_led_inst.CNT_1MS_MAX  =   9      ;
    defparam    rs485_inst1.breath_led_inst.CNT_1S_MAX   =   9      ;
    //接收板参数
    defparam    rs485_inst2.key_filter_w.CNT_MAX         =   5      ;
    defparam    rs485_inst2.key_filter_b.CNT_MAX         =   5      ;
    defparam    rs485_inst2.uart_rx_inst.UART_BPS        =   1000000;
    defparam    rs485_inst2.uart_tx_inst.UART_BPS        =   1000000;
    defparam    rs485_inst2.water_led_inst.CNT_MAX       =   4000   ;
    defparam    rs485_inst2.breath_led_inst.CNT_1US_MAX  =   4      ;
    defparam    rs485_inst2.breath_led_inst.CNT_1MS_MAX  =   99     ;
    defparam    rs485_inst2.breath_led_inst.CNT_1S_MAX   =   99     ;
    
    //发送板
    //-------------rs485_inst1-------------
    rs485   rs485_inst1
    (
        .sys_clk     (sys_clk    ),   //系统时钟,50MHz
        .sys_rst_n   (sys_rst_n  ),   //复位信号,低有效
        .rx          (rx1        ),   //串口接收数据
        .key         (key1       ),   //两个按键
    
        .work_en     (work_en1   ),   //发送使能,高有效
        .tx          (tx1        ),   //串口发送数据
        .led         (led_tx1    )    //led灯
    );
    
    //接收板
    //-------------rs485_inst2-------------
    rs485   rs485_inst2
    (
        .sys_clk     (sys_clk    ),   //系统时钟,50MHz
        .sys_rst_n   (sys_rst_n  ),   //复位信号,低有效
        .rx          (tx1        ),   //串口接收数据
        .key         (key2       ),   //两个按键
    
        .work_en     (work_en2   ),   //发送使能,高有效
        .tx          (tx2        ),   //串口发送数据
        .led         (led_rx2    )    //led灯
    );
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
  • 相关阅读:
    LeetCode 36. 有效的数独
    乒乓球廉价底板及套胶评测5
    GBASE 8C——SQL参考6 sql语法(10)
    JSON Web Tokens (JWT) 在线解密工具
    基于ISO智能交通系统框架的 LTE-V2X技术规范
    Java如何实现消费数据隔离?
    《Web安全基础》07. 反序列化漏洞
    如何手写一个单向链表?看这里
    Java手写ArrayList和拓展案例
    星戈瑞FITC-PEG-SH的化学结构和组成
  • 原文地址:https://blog.csdn.net/qq_39236499/article/details/127983475