串口通信整理:一、8位数据发送


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

工程描述:构建串口发送模块,并进行仿真测试, 串口仿真通过后,上板测试。
具体工程如下:
串口测试 : 8bit数据流发送:两个设计模块(serial: 底层,serial_test:顶层)一个tb模块:serial_test_tb

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_test模块:

`timescale 1ns/1ns
module serial_test(clk,reset_n,uart_tx);
    input clk;
    input reset_n;
    output uart_tx;
    reg send_go;
    reg [7:0]data;
    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),
    .baud_set(4)
    );
    
    //设置计数器每满10ms send_en拉高
    reg[18:0]cnt;
    always@(posedge clk,negedge reset_n)begin
        if(!reset_n)
            cnt<=0;
        else if(cnt==499999)
            cnt<=0;
        else
            cnt=cnt+1;                
    end    
    always@(posedge clk,negedge reset_n)begin
        if(!reset_n)
            send_go<=0;
        else if(cnt==1)
            send_go<=1;
        else
            send_go<=0;       
    end
    always@(posedge clk,negedge reset_n)begin
       if(!reset_n)
            data<=0;
       else if(tx_done)
            data<=data+1;            
    end        
endmodule

serial_test_tb:

`timescale 1ns / 1ns
module serial_test_tb(  );
reg clk;
reg reset_n;
wire uart_tx;
serial_test s2(
.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;
    #50000000;
 end
endmodule

仿真结果图:

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

在这里插入图片描述

图3:
在这里插入图片描述
如上图1 所示,当send_go 为一个时钟周期的高电平时(图3),send_en立马拉高,串口通信位uart_tx立马置低电平,意味着起始位,开始发送数据,直到停止位拉高,之后tx_done立马拉高一个时钟周期(图2),此时send_en立马拉低,至此意味着一个8比特数据的发送结束。同时,可以根据bps_cnt(1,2,3,4,5,6,7,8,9,a)定位查看uart_tx发送的每个比特位,从起始位到停止位对应的是0010000001十位数据,去掉左右两端,再将其翻转正好是0000_0010,也就是02。需要保证tx_done标志位为一个时钟周期,否则会导致数据流发送延迟。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值