UART串口发送_verilog学习6

一、UART基本概念

UART(Universal Asynchronous Receiver/Transmitter)是一种异步串行通信协议,采用单工或半双工模式,通过两根信号线(TX发送、RX接收)实现数据传输。其核心规则包括:

  1. 波特率:传输速率,如9600、115200等,收发双方需严格同步。
  2. 数据帧格式
    • 起始位:1位逻辑0,标志传输开始
    • 数据位:5-8位(通常为8位),从低位到高位发送
    • 校验位:1位奇偶校验(可选)
    • 停止位:1/1.5/2位逻辑1,标志传输结束
    • 空闲位:持续高电平
  3. 分频系数

    公式:                         分频系数=系统时钟频率 / 波特率

二、FPGA实现

module uart_byte_tx(
    clk,
    rst,
    Data,
    send_en,
    Baud_set,
    uart_tx,
    Tx_done
    );
    
    input clk,rst;
    input [7:0]Data;
    input [2:0]Baud_set;
    input send_en;
    output reg uart_tx;
    output reg Tx_done;
    
    //Baud_set=0 波特率=9600
//             1       19200
//             2       38400
//             3       57600
//             4       115200
    
    reg [17:0]div_counter;
    reg [17:0]bps_DR;
    
    always@(*)
        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
    
    always@(posedge clk,negedge rst)
    begin
        if (!rst)
            div_counter<=0;
        else if (send_en==1)begin   //send_en高电平开始计数
            if(div_counter==bps_DR-1)
                div_counter<=0;
            else                
                div_counter<=div_counter+1;
         end
    end
    
    reg [3:0]bps_cnt;
    
    always@(posedge clk,negedge rst)            //定义大计数器11位的
    begin
        if (!rst)
            bps_cnt<=0;                                         
        else if(send_en)
        begin
            if (div_counter==bps_DR-1) 
            begin
                if(bps_cnt==10)
                   bps_cnt<=0;
                else 
                    bps_cnt<=bps_cnt+1;
            end
        end
        else 
            bps_cnt<=0;
    end
    
    always@(posedge clk,negedge rst)
        if(!rst)
        begin
            uart_tx<=1;
            Tx_done<=0;
        end
        else
            begin
            case(bps_cnt)
            0:begin uart_tx<=0;Tx_done<=0; end  //Tx_done置为0
            1:uart_tx<=Data[0];
            2:uart_tx<=Data[1];
            3:uart_tx<=Data[2];
            4:uart_tx<=Data[3];
            5:uart_tx<=Data[4];
            6:uart_tx<=Data[5];
            7:uart_tx<=Data[6];
            8:uart_tx<=Data[7];
            9:uart_tx<=1;
            10:begin uart_tx<=1;Tx_done<=1;end //uart_tx默认是保持高电平的
            default:uart_tx<=1;
            endcase
        end  
        
endmodule

 仿真验证代码

`timescale 1ns / 1ns
module uart_byte_tx_tb();

    reg clk,rst;
    reg [7:0]Data;
    reg [2:0]Baud_set;
    reg send_en;
    wire uart_tx;
    wire Tx_done;

    uart_byte_tx uart_byte_tx(
        .clk(clk),
        .rst(rst),
        .Data(Data),
        .send_en(send_en),
        .Baud_set(Baud_set),
        .uart_tx(uart_tx),
        .Tx_done(Tx_done)
        );
    
    initial clk=1;
    always #10 clk=~clk;
    
    initial begin
        rst=0;
        Data=0;
        send_en=0;
        Baud_set=4;
        #201;
        rst=1;
        #100;
        Data=8'h57;
        send_en=1;
        #20;  
        @(posedge Tx_done);
        send_en=0; 
        #20000;
        Data=8'h75;
        send_en=1;
        #20;
        @(posedge Tx_done); 
        #20000;
        send_en=0;
        $stop;
    end
    
endmodule

 

但此时有一些问题,在uart_tx在空闲状态应该是高电平。

放大会发现此时uart_tx变为零是因为bps_cnt等于0导致的。因为下列语句导致的

            case(bps_cnt)
            0:begin uart_tx<=0;Tx_done<=0; end  //Tx_done置为0
            1:uart_tx<=Data[0];

经过调试后:波形符合理论结果

调试后的代码如下:

module uart_byte_tx(
    clk,
    rst,
    Data,
    send_en,
    Baud_set,
    uart_tx,
    Tx_done
    );
    
    input clk,rst;
    input [7:0]Data;
    input [2:0]Baud_set;
    input send_en;
    output reg uart_tx;
    output reg Tx_done;
    
    //Baud_set=0 波特率=9600
//             1       19200
//             2       38400
//             3       57600
//             4       115200
    
    reg [17:0]div_counter;
    reg [17:0]bps_DR;
    
    always@(*)
        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
    
    always@(posedge clk,negedge rst)
    begin
        if (!rst)
            div_counter<=0;
        else if (send_en==1)begin   //send_en高电平开始计数
            if(div_counter==bps_DR-1)
                div_counter<=0;
            else                
                div_counter<=div_counter+1;
         end
         else
            div_counter<=0;
    end
    
    reg [3:0]bps_cnt;
    
    always@(posedge clk,negedge rst)            //定义大计数器11位的
    begin
        if (!rst)
            bps_cnt<=0;                                         
        else if(send_en)
        begin
            if (div_counter==1) 
            begin
                if(bps_cnt==11)
                   bps_cnt<=0;
                else 
                    bps_cnt<=bps_cnt+1;
            end
        end
        else 
            bps_cnt<=0;
    end
    
    always@(posedge clk,negedge rst)
        if(!rst)
        begin
            uart_tx<=1;
            Tx_done<=0;
        end
        else
            begin
            case(bps_cnt)
            1:begin uart_tx<=0;Tx_done<=0; end  //Tx_done置为0
            2:uart_tx<=Data[0];
            3:uart_tx<=Data[1];
            4:uart_tx<=Data[2];
            5:uart_tx<=Data[3];
            6:uart_tx<=Data[4];
            7:uart_tx<=Data[5];
            8:uart_tx<=Data[6];
            9:uart_tx<=Data[7];
            10:uart_tx<=1;
            11:begin uart_tx<=1;Tx_done<=1;end //uart_tx默认是保持高电平的
            default:uart_tx<=1;
            endcase
        end  
        
endmodule

三、设计一个数据发送器每10ms以115200的波特率发送给数据,每次发送的数据比之前遥感数据大1

底层模块:

module uart_byte_tx(
    clk,
    rst,
    Data,
    send_en,
    Baud_set,
    uart_tx,
    Tx_done
    );
    
    input clk,rst;
    input [7:0]Data;
    input [2:0]Baud_set;
    input send_en;
    output reg uart_tx;
    output reg Tx_done;
    
    reg [17:0]div_counter;
    reg [17:0]bps_DR;
    
    always@(*)
        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
    
    wire bps_clk;
    assign bps_clk=(div_counter==1);
    
    always@(posedge clk,negedge rst)
    begin
        if (!rst)
            div_counter<=0;
        else if (send_en==1)begin   //send_en高电平开始计数
            if(div_counter==bps_DR-1)
                div_counter<=0;
            else                
                div_counter<=div_counter+1;
         end
         else
            div_counter<=0;
    end
    
    reg [3:0]bps_cnt;
    
    always@(posedge clk,negedge rst)            //定义大计数器11位的
    begin
        if (!rst)
            bps_cnt<=0;                                         
        else if(send_en)
        begin
            if (div_counter==1) 
            begin
                if(bps_cnt==11)
                   bps_cnt<=0;
                else 
                    bps_cnt<=bps_cnt+1;
            end
        end
        else 
            bps_cnt<=0;
    end
    
    always@(posedge clk,negedge rst)
        if(!rst)
            uart_tx<=1;            //默认为高电平输出
        else
            begin
            case(bps_cnt)
            1:uart_tx<=0;  //Tx_done置为0
            2:uart_tx<=Data[0];
            3:uart_tx<=Data[1];
            4:uart_tx<=Data[2];
            5:uart_tx<=Data[3];
            6:uart_tx<=Data[4];
            7:uart_tx<=Data[5];
            8:uart_tx<=Data[6];
            9:uart_tx<=Data[7];
            10:uart_tx<=1;
            11:uart_tx<=1; //uart_tx默认是保持高电平的
            default:uart_tx<=1;
            endcase
        end  

    always@(posedge clk,negedge rst)
        if(!rst)
            Tx_done<=0;
        else if((bps_clk==1)&&(bps_cnt==10))
            Tx_done<=1;
        else
            Tx_done<=0;
        
endmodule

顶层模块:

module uart_tx_test(
    clk,
    rst,
    uart_tx
    );

    input clk;
    input rst;
    output uart_tx;

    reg  send_en;
    reg [7:0]Data;

    uart_byte_tx uart_byte_tx(
        .clk(clk),
        .rst(rst),
        .Data(Data),
        .send_en(send_en),
        .Baud_set(3'd4),    //波特率为11520
        .uart_tx(uart_tx),
        .Tx_done(Tx_done)
        );
        
    reg [18:0]counter;
    always@(posedge clk,negedge rst)
    begin
        if (!rst)
            counter<=0;
        else if (counter==499999) //10ms
                counter<=0;
            else                
                counter<=counter+1;
    end     
    
    always@(posedge clk,negedge rst)      
        if(!rst)
            send_en<=0;
        else if (counter==1)
            send_en<=1;
        else if(Tx_done)
            send_en<=0;
         
    always@(posedge clk,negedge rst)
        if(!rst) Data<=0;
        else if(Tx_done)
            Data<=Data+1;
        
endmodule      

 

仿真测试代码

`timescale 1ns / 1ps
module uart_tx_test_tb(

    );
    
    reg clk,rst;
    wire uart_tx;
    
    uart_tx_test uart_tx_test(
        .clk(clk),
        .rst(rst),
        .uart_tx(uart_tx)
        );

    initial clk=1;
    always #10 clk=~clk;
    
    initial begin
        rst=0;
        #201;
        rst=1;
        #50000000;
        $stop;
        end        
        
endmodule

 

放大

做到了每10ms发送一次数据,且Data逐次+1 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值