【verilog】UART串口发送(FPGA)

简述

串口发送是以一定速率发送单bit数据,通常一组数据为10bit。空闲状态为高电平,起始位为0,中间以低位在前的方式发送8bit数据,终止位为1。
采用计数器 [cnt_baud] 对系统时钟进行计数,计满值即为预设的波特率值 [baud_num]
在这个计数过程中,每当计数值为1时,就产生一个标志值 [flag1]
采用计数器 [cnt_for_flag1] 对flag1进行计数11次,当计数值达到11时,同步清零。
所以cnt_for_flag1 = 11 只能维持1个系统时钟,并不能维持一个baud_num。
能维持一个baud_num的为计数值1~10。利用cnt_for_flag1作为多路器的选择端分别发送出10个bit的数据。
当cnt_for_flag1值为11时,代表一次发送完成,产生done信号。

核心代码

module ser_tx(data,en,clk,rst,tx,done);
    input [7:0] data;
    input en;
    input clk;
    input rst;

    output reg tx;
    output reg done;

    reg [15:0] baud_num = 16'd5207; //5207=9600、2603=19200、1301=38400、867=57600、433=115200

    /*将引脚 <input [7:0] data> 进行一级寄存 -> reg_data*/
    reg [7:0]reg_data;   
    always@(posedge clk or negedge rst) begin
        if(!rst)
            reg_data <= 8'b0;
        else if(en)begin 
            reg_data <= data;     
        end                  
        else
            reg_data <= data;
    end

    /*计数器:0~5207~0~5207....*/
    reg [15:0]cnt_baud;
    always@(posedge clk or negedge rst)
    begin
        if(!rst)
            cnt_baud <= 1'b0;
        else if(cnt_baud == baud_num)
            cnt_baud <= 1'b0;
        else
            cnt_baud <= cnt_baud + 1'b1;          
    end

    /*0~5207这个过程中,每当计数到1的时候就产生一个flag*/
    reg flag1;
    always@(posedge clk or negedge rst)
    begin
        if(!rst)
            flag1 <= 1'b0;
        else if(cnt_baud == 16'd1)
            flag1 <= 1'b1;
        else
            flag1 <= 1'b0;         
    end

    /*对flag1进行计数,计数11次,但11只能维持1个clk,并不能维持9600bps,然后就被清0*/
    reg [3:0] cnt_for_flag1;
    always@(posedge clk or negedge rst)
    begin
        if(!rst)
            cnt_for_flag1 <= 1'b0;
        else if(cnt_for_flag1 == 4'd11)
            cnt_for_flag1 <= 1'b0;    
        else if(flag1 == 1'd1)
            cnt_for_flag1 <= cnt_for_flag1 + 1'b1;
        else
            cnt_for_flag1 <= cnt_for_flag1;
    end


    /*依次发送起始位、数据位、终止位*/
    always@(posedge clk or negedge rst)
    begin
        if(!rst)
        tx <= 1'd1; //根据时序图,tx的闲时状态是高电平。
        else
            begin
                case (cnt_for_flag1)
                    4'd0: tx <= 1'd1;  //空闲状态
                
                    4'd1: tx <= 1'd0;  //起始位
                
                    4'd2: tx <= reg_data[0]; //低位在前
                    4'd3: tx <= reg_data[1]; 
                    4'd4: tx <= reg_data[2];    
                    4'd5: tx <= reg_data[3]; 
                    4'd6: tx <= reg_data[4]; 
                    4'd7: tx <= reg_data[5]; 
                    4'd8: tx <= reg_data[6]; 
                    4'd9: tx <= reg_data[7]; 

                    4'd10: tx <= 1'd1; //终止位
                    default:tx <= 1'd1;//空闲状态
                endcase               
            end
     end

    //每次计数器“cnt_for_flag1”值为11时,代表一次发送完成,产生done信号。
    always@(posedge clk or negedge rst) begin
        if(!rst)
            done <= 1'd0;
        else if(cnt_for_flag1 == 4'd11) //cnt_to_10计数到11自动清零
            done <= 1'd1;                 
        else
            done <= 1'd0;
    end

endmodule

仿真测试

发送8bit的 data1 = 8’b01001101 作为测试!

`timescale 1ns/1ns
module ser_tx_tb;

    reg [7:0] data1;
    reg en1;
    reg clk1;
    reg rst1;

    wire  tx1;
    wire  done1;

    
    ser_tx txer
                (
                .data(data1),
                .en(en1),
                .clk(clk1),
                .rst(rst1),
                .tx(tx1),
                .done(done1)
                );

    initial clk1 = 1'b1;
    always#10 clk1 = ~clk1;

    initial begin
    rst1 = 1'b0;    //未运行状态

    #400;
    rst1 = 1'b1;

    data1 = 8'b01001101;

    en1 = 1;
    #20;//一个时钟周期
    en1 = 0;

    #4000000;

     $stop;

    end
endmodule

在这里插入图片描述

在这里插入图片描述

  • 8
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

搞IC的那些年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值