uart的发送器模块verilog

UART

什么是UART?

UART(Universal Asynchronous Receiver/Transmitter)通用异步收发器,是一种串行通信协议。
以上是官方说法,通俗的讲,这是一种传输数据的方式,即一串二进制数是以串行的方式按时间的先后传输的(通常低位在前,高位在后)

基础概念

  • 波特率:单位是bps,即每秒传输的比特数
  • BLCK:波特率时钟,数据线传输数据需要有自己的节奏,而FPGA时钟频率较高,所以我们需要根据比特率对时钟进行分频,然后作为数据线的时钟BLCK
  • 起始位:数据传输的起始标志,通常为0
  • 数据位:数据传输的内容,通常为8位
  • 奇偶校验位:用于检查传输的数据是否正确,通常为1位
  • 停止位:数据传输的结束标志,通常为1

bclk和clk的关系
在这里插入图片描述

发送器模块说明

定义:发送器是将并行数据转换为串行数据,将数据一位一位的发送出去,同时发送状态信号,表示数据正在传输。

  • 输入信号:
    • clk:时钟信号,频率为50MHz,用于分频,作为BLCK时钟
    • rst_n:复位信号,低电平有效
    • [7:0]data: 需要发送的数据
    • tx_en: 发送使能信号,高电平有效
  • 输出信号:
    • td: 输出的数据
    • tx_state: 发送器的状态,高电平表示正在传输数据

在这里插入图片描述

发送器verilog代码

//无校验位,时钟信号50mhz, 比特率115200


module uart_tx(
    input wire clk,
    input wire uart_rst_n, 
    input wire uart_en,
    input wire [7:0] tx_data,

    output reg txd,
    output reg tx_state //检测状态信号
);

//波特率定义模块
parameter   Clk_Fre = 50_000_000; //这里以50MHz为例
parameter BAUD = 115200; //比特率
parameter BAUD_DIV = Clk_Fre / BAUD; //发送一个bit的时钟周期个数

reg uart_en_d0;
reg uart_en_d1; //两级寄存器

wire en_flag; //开始传输标志

assign en_flag = (~uart_en_d1) & (uart_en_d0);

reg [7:0] uart_din; //寄存尚未传输的数据


reg [15:0] clk_cnt;
reg [3:0] tx_cnt;

//为了防止信号的亚稳态,需要两级寄存器,即打两拍,来降低出现亚稳态的频率

// 使能信号状态模块
always@(posedge clk or negedge uart_rst_n)begin
    if(!uart_rst_n)begin
        uart_en_d0 <= 1'b0;
        uart_en_d1 <= 1'b0;
    end

    else begin
        uart_en_d0 <= uart_en;
        uart_en_d1 <= uart_en_d0;
    end

end



//寄存待发送的数据,开始寄存,防止数据在传输结果中有变化
always@(posedge clk or negedge uart_rst_n)begin
    if(!uart_rst_n)begin
        uart_din <= 8'b0;
        tx_state <= 1'b0;
    end

    else if(en_flag) begin
        uart_din <= tx_data;
        tx_state <= 1'b1;
    end

    else if(tx_cnt == 'd9 && clk_cnt == BAUD_DIV - BAUD_DIV / 16)begin
        uart_din <= 0;
        tx_state <= 1'b0;
    end

    else begin
        uart_din <= uart_din;
        tx_state <= tx_state;
    end

end



//计数器模块 tx_cnt, clk_cnt
    always @(posedge clk or negedge uart_rst_n)begin
        if(!uart_rst_n)begin
            tx_cnt <= 0;
        end
        else if(tx_state)begin
            if(clk_cnt == BAUD_DIV - 1)begin //时间到达输出一个bit,bit位加一
                tx_cnt <= tx_cnt + 1;
            end
            else
                tx_cnt <= tx_cnt;
        end

        else  tx_cnt <= 0;
    end

    //bclk产生模块
    always @(posedge clk or negedge uart_rst_n)begin
        if(!uart_rst_n)begin
            clk_cnt <= 0;
        end
        else if(tx_state)begin
            if(clk_cnt == BAUD_DIV - 1)  clk_cnt <= 0;
            else clk_cnt <= clk_cnt + 1;
        end
        else clk_cnt <= 0;
    end

//数据输出模块
always @(posedge clk or negedge uart_rst_n)begin
    if(!uart_rst_n)begin
        txd <= 1;
    end
    else if(tx_state) begin
        case(tx_cnt)
            0: txd <= 0;
            1: txd <= uart_din[0];
            2: txd <= uart_din[1];
            3: txd <= uart_din[2];
            4: txd <= uart_din[3];
            5: txd <= uart_din[4];
            6: txd <= uart_din[5];
            7: txd <= uart_din[6];
            8: txd <= uart_din[7];
            9: txd <= 1;
            default: txd <= 1;
        endcase
    end

    else 
        txd <= 1;    
end

endmodule

测试

module tb_uart_tx;

  // 参数定义
  parameter Clk_Period = 20; // 时钟周期,单位为ns
  parameter BAUD = 115200;
  parameter Clk_Fre = 50_000_000;
  parameter BAUD_DIV = Clk_Fre / BAUD;

  // 信号定义
  reg clk;
  reg uart_rst_n;
  reg uart_en;
  reg [7:0] tx_data;

  wire txd;
  wire tx_state;

  // 实例化被测试的模块
  uart_tx uut (
    .clk(clk),
    .uart_rst_n(uart_rst_n),
    .uart_en(uart_en),
    .tx_data(tx_data),
    .txd(txd),
    .tx_state(tx_state)
  );

  // 时钟生成
  always begin
    #10 clk = ~clk;
  end

  // 激励模块
  initial begin
    // 初始化
    clk = 0;
    uart_rst_n = 0;
    uart_en = 0;
    tx_data = 8'b0;

    // 复位后等待一段时间
    #100 uart_rst_n = 1;

    // 发送一个字节的数据
    uart_en = 1;
    tx_data = 8'b11011010; // 任意数据

    // 等待一段时间,可以观察输出
    #100;

    // 关闭使能信号
    uart_en = 0;

    // 模拟测试结束
    #100 $finish;
  end

endmodule
  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的UART控制模块Verilog实现,用于串行通信。 ```verilog module uart_control( input clk, input reset, input tx_start, input [7:0] tx_data, output tx_busy, output tx_done, input rx_start, output [7:0] rx_data, output rx_done ); parameter BAUD_RATE = 9600; // 波特率 reg [3:0] tx_state = 4'b0000; // 发送状态机状态 reg [3:0] rx_state = 4'b0000; // 接收状态机状态 reg [7:0] tx_reg; // 发送寄存器 reg [7:0] rx_reg; // 接收寄存器 reg tx_busy; // 发送忙 reg tx_done; // 发送完成 reg rx_done; // 接收完成 wire rx_valid = (rx_state == 4'b1111); // 接收有效 // 波特率发生器,用于产生时钟和位时钟 reg [15:0] baud_counter = 16'b0000000000000000; reg bit_counter; // 位时钟 // 发送状态机 always @(posedge clk) begin if (reset) begin tx_state <= 4'b0000; tx_busy <= 0; tx_done <= 0; tx_reg <= 8'b00000000; end else begin case (tx_state) 4'b0000: begin // 空闲状态 if (tx_start) begin tx_state <= 4'b0001; tx_reg <= tx_data; tx_busy <= 1; tx_done <= 0; end end 4'b0001: begin // 启动位 if (baud_counter == (BAUD_RATE / 2) - 1) begin baud_counter <= 0; tx_state <= 4'b0010; end else begin baud_counter <= baud_counter + 1; end end 4'b0010: begin // 数据位 if (baud_counter == BAUD_RATE - 1) begin baud_counter <= 0; bit_counter <= bit_counter + 1; tx_state <= (bit_counter == 8) ? 4'b0011 : 4'b0010; end else begin baud_counter <= baud_counter + 1; end end 4'b0011: begin // 停止位 if (baud_counter == BAUD_RATE - 1) begin baud_counter <= 0; tx_state <= 4'b0000; tx_busy <= 0; tx_done <= 1; end else begin baud_counter <= baud_counter + 1; end end endcase end end // 接收状态机 always @(posedge clk) begin if (reset) begin rx_state <= 4'b0000; rx_reg <= 8'b00000000; rx_done <= 0; end else begin case (rx_state) 4'b0000: begin // 空闲状态 if (rx_start) begin rx_state <= 4'b0001; bit_counter <= 0; end end 4'b0001: begin // 启动位 if (baud_counter == (BAUD_RATE / 2) - 1) begin baud_counter <= 0; rx_state <= 4'b0010; end else begin baud_counter <= baud_counter + 1; end end 4'b0010: begin // 数据位 if (baud_counter == BAUD_RATE - 1) begin baud_counter <= 0; rx_reg[bit_counter] <= rx_start; bit_counter <= bit_counter + 1; rx_state <= (bit_counter == 8) ? 4'b0011 : 4'b0010; end else begin baud_counter <= baud_counter + 1; end end 4'b0011: begin // 停止位 if (baud_counter == BAUD_RATE - 1) begin baud_counter <= 0; rx_state <= 4'b0000; rx_done <= 1; end else begin baud_counter <= baud_counter + 1; end end endcase end end // 位时钟 always @(posedge clk) begin if (reset) begin bit_counter <= 0; end else begin if (tx_state == 4'b0010 || rx_state == 4'b0010) begin if (baud_counter == BAUD_RATE - 1) begin baud_counter <= 0; bit_counter <= bit_counter + 1; end else begin baud_counter <= baud_counter + 1; end end end end // 输出数据 assign tx_data = tx_reg; assign rx_data = rx_reg; // 输出状态 assign tx_busy = tx_busy; assign tx_done = tx_done; assign rx_done = rx_done; endmodule ``` 该模块实现了一个简单的UART控制器,用于串行通信。它包括一个发送状态机和一个接收状态机,通过波特率发生器产生时钟和位时钟,并使用寄存器存储发送和接收的数据。在发送数据时,它将数据转换为序列,并在发送完成后发出完成信号。在接收数据时,它将序列转换为数据,并在接收完成后发出完成信号。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值