2. 串口发送数据任务——基于FPGA的串口发送数据实验

发布时间 2023-09-22 20:02:23作者: daqiaobugong

1. 串口发送数据任务

  • 任务要求
    使用上一节课设计的串口发送模块,设计一个数据发送器,每10ms以115200的波特率发送一个比特,每次发送的数据比前一个数据大1(计数器)

1.1 设计思路

  • 模块化设计,使用上一节课设计好的发送模块

1.2 设计开始

  1. 设计Uart_Byte_Tx(单字节发送)模块
    选择使用以下变量
  • Clk
  • Reset_N
  • Uart_Tx
  • cnt 10ms个数计数器
  1. 代码和仿真代码如下

代码:

module Uart_Tx(
    Clk,
    Reset_N,
    Uart_Tx
    );
    
    input Clk;
    input Reset_N;
    output Uart_Tx;
    reg [7:0]Data;
    reg Send_En;
    wire Tx_Done;
    
    Uart_Byte_Tx Uart_Byte_Tx(
        .Clk(Clk),
        .Reset_N(Reset_N),
        .Data(Data),
        .Send_En(Send_En),
        .Baud_Set(3'd4),
        .Uart_Tx(Uart_Tx),
        .Tx_Done(Tx_Done)
    );
    
    reg [18:0]cnt;
    always@(posedge Clk or negedge Reset_N)
        if(!Reset_N)
            cnt <= 0;
        else if(cnt == 499999)
            cnt <= 0;
        else
            cnt <= cnt + 1'b1;
    
    always@(posedge Clk or negedge Reset_N)
        if(!Reset_N)
            Send_En <= 0;
        else if(cnt == 1)
            Send_En <= 1'b1;
        else if(Tx_Done)
            Send_En <= 0;

    always@(posedge Clk or negedge Reset_N)
        if(!Reset_N)
            Data <= 0;
        else if(Tx_Done)
            Data <= Data + 1'b1;
        else
            Data <= Data;
endmodule

仿真代码:

`timescale 1ns / 1ns
module Uart_Tx_tb;
    
    reg Clk;
    reg Reset_N;
    wire Uart_tx;

    Uart_Tx Uart_Tx(
        .Clk(Clk),
        .Reset_N(Reset_N),
        .Uart_Tx(Uart_tx)
        );

    initial Clk = 1;
    always #10 Clk = ~Clk;
    
    initial begin
        Reset_N = 0;
        #201;
        Reset_N = 1;
        #20000000;
        $stop;
    end
        
endmodule

1.3 仿真结果

仿真结果如图所示:

图1-1

  1. 遇到的问题

    • 仅能正常传输第一个码字
    • Send_En在传输完成后一直为低电平
    • Tx_Done传输完成后一直为高电平
  2. 问题分析

  • 通过查看Uart_Tx代码可知,Send_En的值受Tx_Done控制。在Uart_Byte_Tx代码中,码字命中case(11)情况后使得Tx_Done = 1,导致Send_En无法使能。Send_En一直为低使得计数器Div_cntBps_cnt无法增加,进而无法命中情况case(1)。而case(1)又是使得Tx_Done = 0的唯一可能。
  1. 解决方案
  • 为了使得Tx_Done = 0情况出现,加入情况case(0),在命中0时让Tx_Done = 0。更改部分的Uart_Byte_Tx代码如下:
    always@(posedge Clk or negedge Reset_N)
        if(!Reset_N)begin
            Uart_Tx <= 1'b1;
            Tx_Done <= 0;
        end
        else
        case(Bps_cnt)
            0: Tx_Done <= 0;
            1: Uart_Tx <= 0;
            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
                Tx_Done <= 1'b1;
                Uart_Tx <= 1'b1;
            end
            default: Uart_Tx <= 1'b1;
        endcase

仿真结果:
图1-2


图1-3

1.4 修改后结果分析

  1. 遇到的问题

    • 在1.3的第一张仿真图中,可以看到第二个比特可以正常传输了
    • 传输的第二个码字却是3
  2. 问题分析

    • 通过观察1.3的第二张仿真图可以看到,短时间内Data增加了两次,接着分析这两次增加为什么产生。
    • 通过查看Uart_Tx代码可知,Data的值在Tx_Done == 1时自增。图中可以看到Tx_Done维持了三个高电平,使得增加了三次。因此考虑Tx_Done = 1维持一个高电平。
  3. 解决方案

  • 维持一个高电平的解决方案。观察1.3的第二张仿真图可知,信号Bps_Clk维持了一个高电平,考虑从此处下手。

  • 更改部分的Uart_Byte_Tx代码如下:

    always@(posedge Clk or negedge Reset_N)
        if(!Reset_N)begin
            Uart_Tx <= 1'b1;
            Tx_Done <= 0;
        end
        else
        case(Bps_cnt)
            1: Uart_Tx <= 0;
            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: Uart_Tx <= 1'b1;
            default: Uart_Tx <= 1'b1;
        endcase
            
    always@(posedge Clk or negedge Reset_N)
        if(!Reset_N)
            Tx_Done <= 0;
        else if((Bps_cnt == 10) && Bps_Clk)
            Tx_Done <= 1'b1;
        else
            Tx_Done <= 0;

1.5 仿真结果

图1-4

  • 可以看到数据传输基本正常