FPGA串口通信之Uart发送(基础及应用)

一、Uart 发送模块编写和测试

​
`timescale 1ns / 1ps

module uart_tx(
    clk         ,
    rst         ,
    baud_set    ,
    send_go     ,
    data        ,
    uart_tx     ,
    tx_done     
);

input               clk         ;
input               rst         ;
input[2:0]          baud_set    ;
input               send_go     ;
input[7:0]          data        ;
output              uart_tx     ;
output              tx_done     ;

reg                 r_uart_tx     ;
reg                 r_tx_done     ;


reg[17:0]           baud_cnt     ; 
reg[17:0]           baud_counter ;
reg[3:0]            counter1     ;
reg                 bps_clk      ;
reg                 send_en      ;
reg[7:0 ]           r_data       ;

assign              uart_tx    =  r_uart_tx     ;
assign              tx_done    =  r_tx_done     ;

always@(*)begin //波特率选择
    case (baud_set)
        3'd0: baud_cnt <= 1_000_000_000 / 4800 /20    ;
        3'd1: baud_cnt <= 1_000_000_000 / 9600 /20    ;
        3'd2: baud_cnt <= 1_000_000_000 / 14400 /20   ;
        3'd3: baud_cnt <= 1_000_000_000 / 19200 /20   ;
        3'd4: baud_cnt <= 1_000_000_000 / 38400 /20   ;
        3'd5: baud_cnt <= 1_000_000_000 / 56000 /20   ;
        3'd6: baud_cnt <= 1_000_000_000 / 57600 /20   ;
        3'd7: baud_cnt <= 1_000_000_000 / 115200 /20  ;
        default: baud_cnt <= 1_000_000_000 / 4800 /20 ;
    endcase
end
always@(posedge clk,negedge rst)begin
    if(!rst)
        send_en <= 0;
    else if(send_go)
        send_en <= 1;
    else if(tx_done)
        send_en <= 0;
    else
        send_en <= send_en;
end
always@(posedge clk ,negedge rst)begin //波特率计数器,最小计时单位
    if(!rst)
        baud_counter <= 0;
    else if(send_en)begin
        if(baud_counter == baud_cnt - 1)
            baud_counter <= 0;
        else
            baud_counter <= baud_counter + 1;
    end
    else
         baud_counter <= 0;
end
always@(posedge clk ,negedge rst)begin //波特率时钟生成
    if(!rst)
        bps_clk <= 0;
    else if(baud_counter ==  1)
        bps_clk <= 1;
    else
        bps_clk <= 0;
end
always@(posedge clk ,negedge rst)begin
    if(!rst)
        counter1 <= 0;
    else if(send_en) begin
        if(counter1 == 11 && baud_counter == 1)
            counter1 <= 0;
        else if(baud_counter == 1)
            counter1 <= counter1 + 1;
        else
            counter1 <= counter1;
    end
    else
        counter1 <= 0;
end

always@(posedge clk ,negedge rst)begin
    if(!rst)
        r_data <= 0;
    else if(send_go)
        r_data <= data;
    else
        r_data <= r_data;
end

always@(posedge clk ,negedge rst)begin
    if(!rst)
            r_uart_tx <= 1;
    else begin
        case (counter1)
            4'd1: r_uart_tx <= 0;
            4'd2: r_uart_tx <= r_data[0];
            4'd3: r_uart_tx <= r_data[1];
            4'd4: r_uart_tx <= r_data[2];
            4'd5: r_uart_tx <= r_data[3];
            4'd6: r_uart_tx <= r_data[4];
            4'd7: r_uart_tx <= r_data[5];
            4'd8: r_uart_tx <= r_data[6];
            4'd9: r_uart_tx <= r_data[7];
            4'd10: r_uart_tx <= 1;
            4'd11: r_uart_tx <= 1; 
            default:r_uart_tx <= 1;  
        endcase
    end 
end
always@(posedge clk ,negedge rst)begin
    if(!rst)
        r_tx_done <= 0;
    else if(bps_clk==1 && counter1 == 11)
        r_tx_done <= 1;
    else
        r_tx_done <= 0;
end

 

endmodule

​

PS: 1.在编写代码是,counter1从1开始传输起始位,是为了避免ounter1==0时与空闲状态重合。 

2.baud_counter == 1是为了缩小起始位的到达时间,这样就可以很快的进入到counter1== 1 的状态,从而实现起始位的传输。

二、利用uart发送模块设计一个数据发送器

测试实现每10ms以115200的波特率发送一次数据,发送的数据每次+1

uart_tx_tset 的顶层调用

`timescale 1ns / 1ps

module uart_tx_test(
    clk         ,
    rst         ,
    uart_tx     
);

input               clk         ;
input               rst         ;
output              uart_tx     ;

reg[19:0]    counter;
reg          send_go;
reg[7:0]     data   ;
wire         tx_done;

uart_tx uart_tx_u0(
    .clk            (   clk   ) ,
    .rst            (   rst   ) ,
    .baud_set       (    7    ) ,
    .send_go        (send_go  ) ,
    .data           (data     ) ,
    .uart_tx        (uart_tx  ) ,
    .tx_done        (tx_done  ) 
);

always@(posedge clk,negedge rst)begin
    if(!rst)
        counter <= 0;
    else if(counter == 499_999)
        counter <= 0;
    else
        counter <= counter + 1; 
end

always@(posedge clk,negedge rst)begin
    if(!rst)
        send_go <= 0;
    else if(counter == 1)
        send_go <= 1;
    else
        send_go <=0;
end

always@(posedge clk,negedge rst)begin
    if(!rst)
        data <= 8'd0;
    else if(counter == 499_999)
        data <= data + 1; 
    else 
        data <= data;
end

endmodule

TB文件

`timescale 1ns / 1ps
module uart_tx_test_tb();

reg             clk       ;
reg             rst       ;
wire            uart_tx   ;

uart_tx_test uart_tx_test_u0(
    .clk     (clk      )    ,
    .rst     (rst      )    ,
    .uart_tx (uart_tx  )    
);
initial clk = 0;
always #10 clk =~clk;

initial begin
  rst = 0;
  #201;
  rst = 1;
  #50_000_000;
end
endmodule

测试波形

三、实现多字节的传输

利用一个字节的传输子模块,发送5字节的数据

利用状态机(只需关注输入,输出)

`timescale 1ns / 1ps

module uart_tx_5byte(
    clk     ,
    rst     ,
    Data40  ,
    Trans_go,
    uart_tx ,
    Trans_done
    );
input         clk     ;
input         rst     ;
input[39:0]   Data40  ;
input         Trans_go;
output        uart_tx ;
output        Trans_done;

reg[7:0]      data    ;
reg           send_go ;
wire          tx_done ;
reg           Trans_done;
reg[2:0]      state;

uart_tx uart_tx_u0(
    .clk        (clk    ) ,
    .rst        (rst    ) ,
    .baud_set   ( 7     ) ,
    .send_go    (send_go) ,
    .data       (data   ) ,
    .uart_tx    (uart_tx) ,
    .tx_done    (tx_done) 
);


always@(posedge clk , negedge rst)begin
    if(!rst)begin
        state   <= 0;
        data    <= 0;
        send_go <= 0;
        Trans_done <= 0;
    end
    else
        case (state)
            0:  if(Trans_go)begin
                    data    <= Data40[7:0];
                    send_go <= 1;
                    state   <= 1;
                end
                else begin
                    data    <= 0;
                    send_go <= 0;
                    state   <= 0;
                    Trans_done <= 0;
                end
            1:  if(tx_done)begin
                    data    <= Data40[15:8];
                    send_go <= 1;
                    state   <= 2;
                end
                else begin
                    data    <= data;
                    send_go <= 0;
                    state   <= 1;
                end

            2:  if(tx_done)begin
                    data    <= Data40[23:16];
                    send_go <= 1;
                    state   <= 3;
                end
                else begin
                    data    <= data;
                    send_go <= 0;
                    state   <= 2;
                end
            
            3:  if(tx_done)begin
                    data    <= Data40[31:24];
                    send_go <= 1;
                    state   <= 4;
                end
                else begin
                    data    <= data;
                    send_go <= 0;
                    state   <= 3;
                end
            4:  if(tx_done)begin
                    data    <= Data40[39:32];
                    send_go <= 1;
                    state   <= 5;
                end
                else begin
                    data    <= data;
                    send_go <= 0;
                    state   <= 4;
                end
            5:  if(tx_done)begin
                    data    <= 0;
                    send_go <= 0;
                    state   <= 0;
                    Trans_done <= 1;
                end
                else begin
                    data    <= data;
                    send_go <= 0;
                    state   <= 5;
                end                
            default: begin
                        state   <= 0;
                        data    <= 0;
                        send_go <= 0;
                        Trans_done <= 0;
                     end
        endcase
end
endmodule

TB文件

`timescale 1ns / 1ps


module uart_tx_5byte_tb();
reg                    clk     ;
reg                    rst     ;
reg[39:0]              Data40  ;
reg                    Trans_go;
wire                   uart_tx ;
wire                   Trans_done;
uart_tx_5byte uart_tx_5byte_u0(
    .clk           (clk     ),
    .rst           (rst     ),
    .Data40        (Data40  ),
    .Trans_go      (Trans_go),
    .uart_tx       (uart_tx ),
    .Trans_done    (Trans_done)
    );

initial clk = 0;
always #10 clk =~clk;

initial begin
    rst      = 0;
    Data40   = 0;
    Trans_go = 0;
    #201;
    rst      = 1;
    #200;
    Data40   = 40'h123456789a;
    Trans_go = 1;
    #20;
    Trans_go = 0;
    @(posedge Trans_done);
    #20000;
    Data40   = 40'ha987654321;
    Trans_go = 1;
    #20;
    Trans_go = 0;
    @(posedge Trans_done);
    #20000;
    $stop;
end
endmodule

仿真结果


always@(posedge clk,negedge rst)begin
    if(!rst)
        s_counter <= 0;
    else if(s_counter == 5)
        s_counter <= 0;
    else if(tx_done)
        s_counter <= s_counter + 1;
    else
        s_counter <= s_counter;
end
always@(posedge clk,negedge rst)begin
    if(!rst)
        r_Data40 <= 0;
    else if(Trans_go)
        r_Data40 <= Data40;
    else if(tx_done)
        r_Data40 <= r_Data40 >> 8;
    else
        r_Data40 <= r_Data40;
end

always@(posedge clk ,negedge rst)begin
    if(!rst)
        state <= 0;
    else
        state <= n_state;
end

always@(*)begin
  case (state)
    0:  if(Trans_go)
            n_state <= 1;
        else 
            n_state <= 0;
    1:  if(s_counter == 5)
            n_state <= 0;
        else 
            n_state <= 1; 
    default: n_state <= 2'bxx;
  endcase
end
always@(posedge clk ,negedge rst)begin
    if(!rst)
        data <= 0;
    else if(state == 0)
        data <= Data40[7:0];
    else if(state == 1 && tx_done == 1)
        data <= r_Data40[15:8];
    else
        data <= data;
end
always@(posedge clk ,negedge rst)begin
    if(!rst)
        send_go <= 0;
    else if(s_counter == 4 && tx_done)
        send_go <= 0;
    else if((state ==1 && tx_done == 1)||Trans_go)
        send_go <= 1;
    else
        send_go <= 0;
end
always@(posedge clk ,negedge rst)begin
    if(!rst)
        Trans_done <= 0;
    else if(s_counter == 4 && tx_done)
        Trans_done <= 1;
    else
        Trans_done <= 0;
end

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值