串口通信整理:二、数据发送之多位数据发送

本文详细介绍了基于UART协议的串口发送模块设计,包括8位数据流串口发送底层模块和40位数据发送顶层模块。通过状态机控制发送流程,实现数据的分组发送,并通过仿真验证了正确性。在仿真过程中,观察到了发送标志位的正确拉高和数据的正确传输,验证了40位数据的完整性和顺序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文基于前一篇串口模块基础版进一步对串口发送数据整理,并通过仿真进行验证,所有代码都可直接跑通,注意各个模块名字。

首先再次回顾一下通信协议UART
本质就是并行数据转串行数据
关键参数:起始位(0)、数据位(非任意位)、停止位(1)
假设发送8位数据,那实际上要发送10位数据,上升沿有效的话,需经历11个上升沿。
波特率计数计算:假设时钟周期为20ns,波特率为115200: 1000000000/115200/20=bps
接口规范: RS232、RS449、RS423、RS422、RS485

工程描述:构建串口发送模块,并进行仿真测试(此部分已在上述链接验证过),串口仿真通过后,采用此串口模块构建40位数据发送模块,并对其上板测试。

具体工程如下:
主要模块 : 两个设计模块:1、8bit数据流串口发送模块 serial(底层) 2、40位数据发送模块 serial_40(顶层) 一个tb模块:serial_40_tb
工程分析:
每次信号到来就引入模块发送五次8位的数据,五次结束后立马要由对应的标志位(trans_done)产生一个时钟周期的脉冲信号
两种情况:
1、没有开始发送(包含上一次的发送已经完成,新的40位数据的发送请求没有出现)
2、来了一个发送40位请求,依次发送数据中,采用状态机
总的来说,循环五次等待最终的trans_go,每次8位数据的发送data40[7:0]给串口模块的uart_tx发送,并产生send_go信号,开始发送,等待tx_done信号。循环5 次,发送完40位数据,回到第一个状态继续等待trans_go。

serial模块:

module serial(
    clk,
    reset_n,
    data,  send_go,
    //串行信号带
    uart_tx,
    //发送结束标志
    tx_done,
    //可设置多种波特率
    baud_set
    );
    input clk,reset_n;
    input[7:0] data;
    reg send_en;
    //典型波特率有300,1200,2400,9600,19200,115200
    //设置5种模式 0:9600,1:19200,2:38400,3:57600,4:115200
    input[2:0] baud_set;
    input send_go;
    output reg uart_tx;
    output reg tx_done;
    wire bps_clk;
    assign bps_clk=(div_cnt==bps_dr-1);
   //计数器 之五种模式设置的值
    reg[17:0] bps_dr;
    always@(*)begin
        case(baud_set)
            0:bps_dr=1000000000/9600/20;
            1:bps_dr=1000000000/19200/20;
            2:bps_dr=1000000000/38400/20;
            3:bps_dr=1000000000/57600/20;
            4:bps_dr=1000000000/115200/20;
            default:bps_dr=1000000000/9600/20;
        endcase
    end
    
   always@(posedge clk,negedge reset_n)begin
        if(!reset_n)
            send_en<=0;
        else if(send_go)
            send_en<=1;
        else if(tx_done)
            send_en<=0;    
    end  
    reg [7:0] datacache;
    always@(posedge clk)begin
        if(send_go)
            datacache<=data;
        else
            datacache<=datacache;    
    end     
    
    //计数器
    reg[17:0] div_cnt;
    always@(posedge clk,negedge reset_n)begin
        if(!reset_n)
            div_cnt<=0;
        else if(send_en)begin
            if(bps_clk)
                div_cnt<=0;
            else
                div_cnt<=div_cnt+1; 
            end   
        else
            div_cnt<=0;            
    end 
       
    reg[3:0] bps_cnt;
    always@(posedge clk,negedge reset_n)begin
        if(!reset_n)
            bps_cnt<=0;
        else if(send_en)begin
            if(div_cnt==1)begin
            if(bps_cnt==12)
                bps_cnt<=0;
            else    
                bps_cnt<=bps_cnt+1'b1;
            end  
            end 
        else
            bps_cnt<=0;           
    end
    
  //发送数据
  always@(posedge clk,negedge reset_n)begin
    if(!reset_n)
        begin
        uart_tx<=1;
        tx_done<=0;
        end
    else begin
        case(bps_cnt)
            1:uart_tx<=0;
            2:uart_tx<=datacache[0];
            3:uart_tx<=datacache[1];
            4:uart_tx<=datacache[2];
            5:uart_tx<=datacache[3];
            6:uart_tx<=datacache[4];
            7:uart_tx<=datacache[5];
            8:uart_tx<=datacache[6];
            9:uart_tx<=datacache[7]; 
            10:uart_tx<=1;
            11:begin
                uart_tx<=1;
            end
           default:uart_tx<=1;
        endcase
    end
  end  
  always@(posedge clk,negedge reset_n)begin
    if(!reset_n)
        tx_done<=0;   
    else if((bps_clk)&&(bps_cnt==10))
        tx_done<=1;
    else
        tx_done<=0;                  
  end
endmodule

serial_40模块:

`timescale 1ns / 1ns
module serial_40(clk,reset_n,uart_tx,data40,trans_go,trans_done);
input clk;
input reset_n;
output  uart_tx;
input [39:0]data40;
output reg trans_done;
reg[7:0] data;
reg send_go;
wire tx_done;
 serial s1(
    .clk(clk),
    .reset_n(reset_n),
    .data(data),
    .send_go(send_go),
    //串行信号带
    .uart_tx(uart_tx),
    //响应标志
    .tx_done(tx_done),
    //可设置8种波特率
    .baud_set(4)
    );

reg[2:0] state;
always@(posedge clk,negedge reset_n)begin
    if(!reset_n)begin
        trans_done<=0;
        state<=0;
        data<=0;
        send_go<=0;   
    end
    else if(state==0)begin
        trans_done<=0;
        if(trans_go)begin
            data<=data40[7:0];
            send_go<=1; 
            state<=1;        
        end
        else begin
            data<=data;
            send_go<=0;
            state<=0;
        end
    end
    else if(state==1)begin   
         if(tx_done)begin
             data<=data40[15:8];
             send_go<=1;  
             state<=2;    
        end
        else begin
            data<=data;
            send_go<=0;
            state<=1;
        end
    end
    else if(state==2)begin   
         if(tx_done)begin
             data<=data40[23:16];
             send_go<=1;  
             state<=3;    
        end
        else begin
            data<=data;
            send_go<=0;
            state<=2;
        end
    end
    else if(state==3)begin   
         if(tx_done)begin
             data<=data40[31:24];
             send_go<=1;  
             state<=4;    
        end
        else begin
            data<=data;
            send_go<=0;
            state<=3;
        end
    end
    else if(state==4)begin   
         if(tx_done)begin
             data<=data40[39:32];
             send_go<=1;  
             state<=5;    
        end
        else begin
            data<=data;
            send_go<=0;
            state<=4;
        end
    end
    else if(state==5)begin   
         if(tx_done)begin
             trans_done<=1;
             send_go<=0;  
             state<=0;    
        end
        else begin
            data<=data;
            send_go<=0;
            state<=5;
        end
    end            
end
endmodule

serial_40_tb:

`timescale 1ns / 1ns
module serial_40_tb();
reg clk;
reg reset_n;
wire uart_tx;
reg [39:0]data40;
reg trans_go;
wire trans_done; 
serial_40 u5(
clk,
reset_n,
uart_tx,
data40,
trans_go,
trans_done
);

initial clk=1;
always #10 clk=~clk;
initial begin
    reset_n=0;
    data40=0;
    trans_go=0;
    #201;
    reset_n=1;
    #200;
    data40=40'h123456789a;
    trans_go=1;
    #20
    trans_go=0;
    @(posedge trans_done);
    #2000000;
     data40=40'h187654329a;
    trans_go=1;
    #20
    trans_go=0;
    @(posedge trans_done);
    #2000000;
    $stop;
end
    
endmodule

仿真结果图:

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

图2:

在这里插入图片描述

详细分析:**

通过图1,我们可以看到:当传输数据为187654329A时,当数据开始发送,即uart_tx出现第一个下降沿时,40位数据发送标志位trans_go和底层模块中的8位数据发送标志位send_go都立马拉高一个时钟周期(可见图2),在40位数据发送完成标志位trans_done到来之前,send_go 一共出现五次脉冲,有趣的是,对应时钟周期内的send_en也被拉低,这恰好说明,调用底层模块一共发送5次数据,对应的数据流波形如uart_tx显示那样,每一次send_go和tx_done之间对应10位数据,除去起始位和停止位,共8位数据,而每次穿书都是从高位传到低位,因此靠近左侧的数据流是低位,靠近右侧的是高位,根据uart_tx的波形从左往右可以读出对应数据共50位:0010110011_0010011001_0001010101_0011011101_0000110001 ,每组数据去掉首末位置的01,再将其拼起来,再反转过来为:0001100001110110010101000011001010011010,转换成十进制正好是 187654329A,至此便验证了此次工程的正确性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值