Verilog:UART串口发送模块

UART串口协议Verilog实现与仿真
该文章已生成可运行项目,

目录

一、UART串口协议时序图

二、Verilog 实现

(1)设计要求

(2)设计模块

(3)测试模块

(4)仿真波形

一、UART串口协议时序图

        概括:起始位0 + 8位数据位 + 停止位1(空闲状态输出高电平)

                   每一位输出时间=1s/波特率(波特率为一秒发送数据个数)       

二、Verilog 实现

(1)设计要求

        1.可设置波特率(115200、9600等等)

        2.起始位0 + 8位数据位 + 停止位1(空闲状态输出高电平)

        3.无校验位

(2)设计模块

`timescale 1ns / 1ps
module uart_tx(//串口数据发送模块,可设置波特率,串行输出
    input wire clk,             //50MHz 20ns
    input wire rst_n,          
    input wire tx_start,        //开始发送标志信号
    input wire [7:0] data,      //待发送数据
    input wire [2:0] baud_rate, //设置波特率
    output reg tx,              //串行数据输出
    output reg tx_done          //发送结束标志信号
);
    reg tx_en  = 1'b0;          //发送使能信号
    reg [7:0] data_reg  = 8'b0; //待发送数据寄存器
    reg [3:0] data_bit  = 4'd0; //计数当前输出位数
    reg [17:0]count     = 18'd1;//分频计数
    reg [17:0]count_max = 18'd1;//分频计数上限,18位由波特率300算出(1s/300/20ns=166666个clk周期)
    
always@(posedge clk or negedge rst_n) begin //收到开始发送信号高电平脉冲,将待发送数据存入寄存器(避免信号中途有误)
    if(!rst_n) 
        data_reg <= 8'b0;
    else if(tx_start)
        data_reg <= data;
    else 
        data_reg <= data_reg;
end
 
always@(posedge clk or negedge rst_n) begin //发送使能信号
    if(!rst_n) 
        tx_en <= 1'b0;
    else if(tx_start)
        tx_en <= 1'b1;//收到开始发送标志位高电平脉冲,发送使能信号置1
    else if(tx_done)
        tx_en <= 1'b0;//收到发送结束标志位高电平脉冲,发送使能信号置0
end
 
always@(*) begin //根据波特率设置波特率分频器计数上限
    if(!rst_n)
        count_max <= 18'd434;//默认波特率=115200
    else begin 
        case(baud_rate)
            3'b000:  count_max <= 18'd434;   //115200
            3'b001:  count_max <= 18'd868;   //57600
            3'b010:  count_max <= 18'd1302;  //38400
            3'b011:  count_max <= 18'd2604;  //19200
            3'b100:  count_max <= 18'd5208;  //9600
            3'b101:  count_max <= 18'd20833; //2400
            3'b110:  count_max <= 18'd41666; //1200
            3'b111:  count_max <= 18'd166666;//300
            default: count_max <= 18'd434;
        endcase
    end
end
 
always@(posedge clk or negedge rst_n) begin //波特率分频器(tx_en使能),计满一次发送一位
    if(!rst_n || !tx_en)//复位或未使能
        count  <= 18'd1;
    else if(tx_en)begin
        if(count == count_max)
            count  <= 18'd1;
        else 
            count  <= count + 18'd1;
    end
end
 
always@(posedge clk or negedge rst_n) begin //位计数器,对应当前发送的位数
    if(!rst_n)
        data_bit <= 4'd0;//1-10为有效状态
    else if(count == count_max)begin//计满一次
        if(data_bit == 4'd9)
            data_bit <= 4'd0;
        else 
            data_bit <= data_bit + 4'd1;
    end
end
 
always@(*) begin //串行发送数据(空闲高电平,起始位0,从低位发送,停止位1)
    if(!rst_n || !tx_en)
        tx <= 1'b1; //复位或未使能为空闲高电平
    else begin
        case(data_bit)
            0:  tx <= 1'b0;//起始位0               
            1:  tx <= data_reg[0];  
            2:  tx <= data_reg[1];  
            3:  tx <= data_reg[2];  
            4:  tx <= data_reg[3];  
            5:  tx <= data_reg[4];  
            6:  tx <= data_reg[5];  
            7:  tx <= data_reg[6]; 
            8:  tx <= data_reg[7];
            9:  tx <= 1'b1;//停止位1 
            default: tx <= 1'b1;           
        endcase
    end
end
 
always@(*) begin //结束发送标志信号
    if(!rst_n)
        tx_done <= 1'b0;
    else if(data_bit == 9 && count == count_max)//停止位输出结束时
        tx_done <= 1'b1;
    else 
        tx_done <= 1'b0;
end
endmodule

(3)测试模块

        以波特率115200发送两次信息,第一次发送01011011,第二次发送01111110

`timescale 1ns / 1ps
module uart_tx_tb();
    reg clk_tb;             //clk为 50MHz 20ns
    reg rst_n_tb;          
    reg tx_start_tb;        //发送开始标志位信号
    reg [7:0] data_tb;      //待发送数据
    reg [2:0] baud_rate_tb; //设置波特率
    wire tx_tb;             //串行数据输出
    wire tx_done_tb;        //发送完成标志位信号
        
always #10 clk_tb =~clk_tb;

initial begin
    clk_tb   = 1'b0;
    rst_n_tb = 1'b0;
    #15; 
    rst_n_tb = 1'b1;
    data_tb[7:0] = 8'b0101_1011;
    baud_rate_tb[2:0] = 3'b000;//baud rate = 115200
    tx_start_tb = 1'b1;
    #20
    tx_start_tb = 1'b0;
    #100000;
     
    data_tb[7:0] = 8'b0111_1110;
    tx_start_tb = 1'b1;
    #20
    tx_start_tb = 1'b0;
    #100000;

    $finish;
end

uart_tx uart_tx(
    .clk       (clk_tb),
    .rst_n     (rst_n_tb),
    .baud_rate (baud_rate_tb),
    .tx_start  (tx_start_tb),
    .data      (data_tb),
    .tx        (tx_tb),
    .tx_done   (tx_done_tb)
);
endmodule

(4)仿真波形

        完整波形如图所示:测试中共发送两次信息,波特率经测量为正确,同时 tx 两次发送数据结果格式与内容无误,空闲状态均为高电平。最后发送结束标志位tx_done有一个高电平。

本文章已经生成可运行项目
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值