您的位置:

UART Verilog详解

一、UART简介

UART是通用异步收发传输器(Universal Asynchronous Receiver/Transmitter)的缩写,它是一种串行通讯接口标准。相比较其他串行通信方式,UART具有性能高、成本低的优点,在单片机、嵌入式系统、计算机外围设备中被广泛应用。

UART使用一种异步方式,即发送数据和接收数据的时钟不同步,通过指定数据位,停止位,奇偶校验位等参数,可以保证数据正确无误地传输。

下面我们来详细了解一下UART的工作原理以及在Verilog中的实现。

二、UART的工作原理

UART的工作原理可以分为两个阶段:

1、发送数据

module uart_tx(
    input clk, //system clock
    input reset, //system reset
    input enable, //tx enable signal
    input [7:0] data_in, //data to be sent
    output tx //tx output signal
);
   ......
endmodule

2、接收数据

module uart_rx(
    input clk, //system clock
    input reset, //system reset
    input enable, //rx enable signal
    input rx, //rx input signal
    output reg [7:0] data_out, //received data
    output reg receive_done //receive done signal
);
   ......
endmodule

三、UART Verilog实现

1、发送数据实现

UART发送数据的核心是将发送的数据按照指定的协议进行封装,然后通过TX引脚发送出去。

以下是一个基本的UART发送模块:

module uart_tx(
    input clk, //system clock
    input reset, //system reset
    input enable, //tx enable signal
    input [7:0] data_in, //data to be sent
    output tx //tx output signal
);

    parameter BAUD_RATE = 9600 ; //波特率
    parameter SYS_CLK = 50000000 ; //系统时钟频率
    parameter TICK = SYS_CLK / BAUD_RATE ;

    reg [3:0] state ; //状态机
    reg [7:0] data_reg ; //数据寄存器
    reg [3:0] bit_count ; //计数器
    reg tx_reg ; //TX寄存器

    always@(posedge clk) begin
        if(reset) begin
            state <= 4'd0 ;
            tx_reg <= 1'b1 ; //发送起始位
            data_reg <= 8'h00 ;
            bit_count <= 4'd0 ;
        end else begin
            case(state)
                4'd0 : begin //等待TX越过起始位
                    if(enable) begin
                        state <= 4'd1 ;
                    end
                end
                4'd1 : begin //发送8位数据位
                    tx_reg <= data_in[0] ;
                    data_reg <= data_in >> 1 ;
                    bit_count <= bit_count + 4'd1 ;
                    if(bit_count == 4'd8) begin
                        bit_count <= 4'd0 ;
                        state <= 4'd2 ;
                    end
                 end
                 4'd2 : begin //发送校验位(这里使用奇偶校验)
                    tx_reg <= ~(^data_in) ;
                    bit_count <= bit_count + 4'd1 ;
                    if(bit_count == 4'd1) begin
                        bit_count <= 4'd0 ;
                        state <= 4'd3 ;
                     end
                  end
                  4'd3 : begin //发送停止位
                    tx_reg <= 1'b0 ;
                    bit_count <= bit_count + 4'd1 ;
                    if(bit_count == 4'd1) begin
                        bit_count <= 4'd0 ;
                        state <= 4'd4 ;
                    end
                 end
                 4'd4 : begin //等待下一次发送
                    if(enable) begin
                        state <= 4'd1 ;
                    end
                 end
            endcase
        end
    end

    assign tx = tx_reg ;

endmodule

2、接收数据实现

UART接收数据的核心是按照指定协议从RX引脚接收信号,并解析出数据内容。

一个基本的UART接收模块如下所示:

module uart_rx(
    input clk, //system clock
    input reset, //system reset
    input enable, //rx enable signal
    input rx, //rx input signal
    output reg [7:0] data_out, //received data
    output reg receive_done //receive done signal
);

    parameter BAUD_RATE = 9600 ; //波特率
    parameter SYS_CLK = 50000000 ; //系统时钟频率
    parameter TICK = SYS_CLK / BAUD_RATE ;

    reg [3:0] state ; //状态机
    reg [7:0] data_reg ; //数据寄存器
    reg [3:0] bit_count ; //计数器
    reg rx_reg ; //RX寄存器
    reg odd_parity ; //奇校验位判断

    always@(posedge clk) begin
        if(reset) begin
            state <= 4'd0 ;
            data_reg <= 8'h00 ;
            bit_count <= 4'd0 ;
            rx_reg <= 1'b1 ; //等待起始位
        end else begin
            case(state)
                4'd0 : begin //等待起始位
                    if(~rx & enable) begin
                        state <= 4'd1 ;
                        rx_reg <= rx ;
                        data_reg <= 8'h00 ;
                        bit_count <= 4'd0 ;
                        odd_parity <= 1'b0 ;
                    end
                end
                4'd1 : begin //接收8位数据位
                    rx_reg <= rx ;
                    data_reg <= {data_reg[6:0], rx} ;
                    bit_count <= bit_count + 4'd1 ;
                    odd_parity <= odd_parity ^ rx ; //奇偶校验
                    if(bit_count == 4'd7) begin
                        state <= 4'd2 ;
                    end
                end
                4'd2 : begin //接收校验位(这里使用奇偶校验)
                    rx_reg <= rx ;
                    odd_parity <= odd_parity ^ rx ; //奇偶校验
                    bit_count <= bit_count + 4'd1 ;
                    if(bit_count == 4'd1) begin
                        state <= 4'd3 ;
                    end
                end
                4'd3 : begin //接收停止位
                    rx_reg <= rx ;
                    receive_done <= 1'b1 ; //数据接收完成
                    data_out <= data_reg ; //输出数据
                    if(rx) begin
                        //停止位必须是逻辑0,否则认为停止位错误
                        state <= 4'd4 ;
                    end
                end
                4'd4 : begin //等待下一次数据接收
                    receive_done <= 1'b0 ;
                    if(~rx & enable) begin
                        state <= 4'd1 ;
                        rx_reg <= rx ;
                        data_reg <= 8'h00 ;
                        bit_count <= 4'd0 ;
                        odd_parity <= 1'b0 ;
                    end
                end
            endcase
        end
    end

endmodule

四、小结

本文主要介绍了UART通讯的基本原理,以及在Verilog中的实现方式。通过实现发送和接收两个模块,我们可以完成对UART通讯协议的实现。同时,我们也需要注意一些细节问题,如如何进行奇偶校验,如何判断起始位和停止位等等。这些问题对于保证数据传输的正确性非常重要。