功能描述:

1.每隔3ms以115200波特率的速度发送一个遵循uart协议的数据。每次发送数据增大1(从0开始即可).

2.数据 来自数据采集器,每采集一个数据,发送一个脉冲告知串口,串口对这个数据进行发送。

学习:

1.在上一次底层设计中,我们把发送使能端send_en作为input,不能在底层为它赋值。但是我们在顶层新建一个模块,调用底层模块时,可以把send_en作为顶层的内部变量,这样子就可以赋值了。

2.如果触发条件是脉冲的,我们可以设计一个内部变量en,用脉冲把en置一,让它控制数据发送的使能。再用结束位置零。这样子在外部上看就起到了用脉冲触发的效果。

3.用顶层调用底层时(例化)在顶层中同样是设计逻辑,用到与底层同个变量时,顶层和底层的逻辑是并行执行的。只不过变量在两个地方的地位不一样,在底层中无法赋值的input,在顶层中可以作为 可赋值的reg。

4.可以用x=!x把x置为脉冲型。

5.调试的基本思路是:查看仿真波形,看哪个变量的波形不对劲,回到源码中找到该变量的逻辑语句进行分析。一般先看关键变量的波形,具体来说就是输出的波形是否与预期相符。再由输出推到与其联系的相关变量的逻辑。

6.最好每一个变量都用独立的always来描述逻辑变化。

  • 1
module uart_1(  //设计输入
    clk,//时钟
    reset,//复位
    data,//数据
    send_en,//使能
    baud_rate,//波特率
    uart_tx,//串口输出
    tx_done//结束信号
);
    input clk;
    input reset;
    input [7:0]data;
    input send_en;
    input [2:0]baud_rate;
    output reg uart_tx;
    output reg tx_done;
    
     reg [17:0]bit_tim;
    
    //设计逻辑
    //把波特率转化为一位的持续时间  //单位时间内通过信道传输的码元数称为码元传输速率,即波特率,码元/s,一个码元可能由多个位组成。而比特率即 ‘位/s’
    always@(baud_rate)  //在这里一个 码元由一位组成,所以波特率=比特率
        begin
            case(baud_rate)         //常见的串口传输波特率
            3'd0 : bit_tim = 1000000000/300/20 ; //波特率为300
            3'd1 : bit_tim = 1000000000/1200/20 ; //波特率为1200
            3'd2 : bit_tim = 1000000000/2400/20 ; //波特率为2400
            3'd3 : bit_tim = 1000000000/9600/20 ; //波特率为9600
            3'd4 : bit_tim = 1000000000/19200/20 ; //波特率为19200
            3'd5 : bit_tim = 1000000000/115200/20 ; //波特率为115200
            default bit_tim = 1000000000/9600/20 ;   //多余的寄存器位置放什么:默认速率
            endcase
        end
    
    reg [17:0]counter1 ;//用来计数每一位的持续时间
    always@(posedge clk or negedge reset)
        begin
            if(!reset)//复位清零
                counter1 <=17'b0 ;
            else if (send_en )//使能端有效,计数
                begin
                if( counter1 == bit_tim - 1'b1 )//位持续时间到达时归零
                    counter1 <= 17'b0 ;
                else
                    counter1 <= counter1 + 1'b1 ;//位持续时间没达到时继续进行
                end
            else counter1 <= 17'b0 ;            //使能端无效时,清零
        end 
    
    reg [3:0]counter2 ; //输出第几位。如果忘了考虑归零,那么计数器会出现溢出归零,在这里是加到15然后归零
    always@(posedge clk or negedge reset)
        begin
            if(!reset)//复位
                counter2 <= 4'b0 ;
            else if ( send_en )//使能端有效
                begin
                if(counter2 == 0)//消耗20ns,进入起始位。这个挺重要的,没有这个的话得消耗一位的时间进入起始位
                    counter2 <= counter2 +1'b1 ;
                else if( counter1 == bit_tim - 1'b1 )//开始进行位移
                    counter2 <= counter2 + 4'b1 ;   
                else
                    counter2 <= counter2 ;
                end
            else//使能端无效,归零,进入空闲位
                counter2 <= 4'b0 ;    
        end                

    always@(posedge clk or negedge reset)
        begin
            if(!reset)//复位
                begin
                    uart_tx <= 4'b1 ; 
                end  
            else if ( send_en )//使能端有效,输出每一位
                    case(counter2)
                        0:begin uart_tx <= 1'b1 ; end//设定第一位为空闲位。没有空闲位的话,使能端无效时,counter停留在0,不能保持输出高电平(取决于要输出的数据),不符合要求。
                        1:uart_tx <= 1'b0 ;//起始位
                        2:uart_tx <= data[0] ;
                        3:uart_tx <= data[1] ;
                        4:uart_tx <= data[2] ;
                        5:uart_tx <= data[3] ;
                        6:uart_tx <= data[4] ;
                        7:uart_tx <= data[5] ;
                        8:uart_tx <= data[6] ;
                        9:uart_tx <= data[7] ;
                        10:uart_tx <= 1'b1 ;//结束位
                        11:begin uart_tx <= 1'b1 ;  end//为了让结束位跑满,设置11,作为第11个点,定第十位长度。
                        default uart_tx <= 1'b1 ;
                    endcase
           else 
                uart_tx <= 1'b1 ;         
        end 
        
        always@(posedge clk or negedge reset)
        begin
            if(!reset)//复位清零
                tx_done <= 1'b0 ;
            else if (send_en )//使能端有效
                begin
                if( counter2 == 0 )//
                     tx_done <= 1'b0 ;
                else if ( counter2 == 11 )
                     tx_done <= 1'b1 ;
                end
            else if (tx_done == 1'b1)
                tx_done <= 1'b0 ;
        end 
endmodule
module uart_2(//使能端信号为电平型
    Clk,
    Reset,
    uart_tx
    );

    input Clk ;
    input Reset ;
    reg [7:0]data ;
    reg send_en ;
    wire [2:0]baud_rate ;
    output wire uart_tx ;
    wire tx_done ; 
    
    uart_1 uart_1_send(  //设计输入
        .clk(Clk),//时钟
        .reset(Reset),//复位
        .data(data),//数据
        .send_en(send_en),//使能
        .baud_rate(baud_rate),//波特率
        .uart_tx(uart_tx),//串口输出
        .tx_done(tx_done)//结束信号
    );  

    assign baud_rate = 3'b101 ;
    
    reg [18:0]counter ;
    
    always@(posedge Clk or negedge Reset)
        begin
            if(!Reset)//复位清零
                counter <= 1'd0 ;
            else if (counter == 19'd149000 )//
                counter <= 1'b0 ;//
            else 
                counter <= counter + 1'b1 ;    
        end 
        
    always@(posedge Clk or negedge Reset)
        begin
            if(!Reset)//复位清零
                send_en <= 1'd0 ;
            else if (counter == 19'd1 )//
                send_en <= 1'b1 ;//
            else if  (tx_done == 1'b1 )//
                send_en <= 1'b0 ;
        end 
        
    always@(posedge Clk or negedge Reset)
        begin
            if(!Reset)//复位清零
                 data <= 8'd0 ;
            else if (counter == 19'd149000 )//
                begin
                 data <= data + 1'b1 ;               
                end
            else
                 data <= data ;//
        end 

endmodule
module uart_3(//使能端信号为脉冲型
    Clk,
    Reset,
    send_pulse,
    data1,
    uart_tx
    );

    input Clk ;
    input Reset ;
    input send_pulse ;
    input [7:0]data1 ;
    output wire uart_tx ;
    
    wire tx_done ; 
    reg send_en ;
    wire [2:0]baud_rate ;
    wire [7:0]data ;
    
    uart_1_1 uart_1_1send(  //设计输入
        .clk(Clk),//时钟
        .reset(Reset),//复位
        .data(data),//数据
        .send_en(send_en),//使能
        .baud_rate(baud_rate),//波特率
        .uart_tx(uart_tx),//串口输出
        .tx_done(tx_done)//结束信号
    );  

    assign baud_rate = 3'b101 ;
    assign data = data1 ;
    reg [18:0]counter ;
    
    always@(posedge Clk or negedge Reset)
        begin
            if(!Reset)//复位清零
                counter <= 1'd0 ;
            else if (counter == 19'd149000 )//
                counter <= 1'b0 ;//
            else 
                counter <= counter + 1'b1 ;    
        end 
        
    always@(posedge Clk or negedge Reset)
        begin
            if(!Reset)//复位清零
                send_en <= 1'd0 ;
            else if (send_pulse == 1'd1 )//
                send_en <= 1'b1 ;//
            else if  (tx_done == 1'b1 )//
                send_en <= 1'b0 ;
        end 
        

endmodule
`timescale 1ns / 1ns

module uart_3_tb ();
    reg Clk ;
    reg Reset ;
    reg send_pulse;
    reg [7:0]data1 ;
    wire uart_tx ;
    
    uart_3 uart_3_sim(
    .Clk(Clk),
    .Reset(Reset),
    .send_pulse(send_pulse),
    .data1(data1),
    .uart_tx(uart_tx)
    );

    initial Clk = 1 ;
    always #10 Clk = ! Clk ;
    initial 
        begin
        Reset = 0 ;
        data1 = 8'b0 ;
        send_pulse = 1'b0 ;
        #201 ;
        Reset = 1 ;
        data1 = 8'b0110_1001 ;
        send_pulse = 1'b1 ;
        #20
        send_pulse = !send_pulse  ;
        #3100000 ;
        data1 = 8'b1001_1101 ;
        send_pulse = 1'b1 ;
        #20
        send_pulse = !send_pulse  ;
        #3100000 ;
        $stop ;
        end
        
endmodule