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 > 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通讯协议的实现。同时,我们也需要注意一些细节问题,如如何进行奇偶校验,如何判断起始位和停止位等等。这些问题对于保证数据传输的正确性非常重要。

原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/309896.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
小蓝小蓝
上一篇 2025-01-04 19:31
下一篇 2025-01-04 19:31

相关推荐

  • Linux sync详解

    一、sync概述 sync是Linux中一个非常重要的命令,它可以将文件系统缓存中的内容,强制写入磁盘中。在执行sync之前,所有的文件系统更新将不会立即写入磁盘,而是先缓存在内存…

    编程 2025-04-25
  • 神经网络代码详解

    神经网络作为一种人工智能技术,被广泛应用于语音识别、图像识别、自然语言处理等领域。而神经网络的模型编写,离不开代码。本文将从多个方面详细阐述神经网络模型编写的代码技术。 一、神经网…

    编程 2025-04-25
  • nginx与apache应用开发详解

    一、概述 nginx和apache都是常见的web服务器。nginx是一个高性能的反向代理web服务器,将负载均衡和缓存集成在了一起,可以动静分离。apache是一个可扩展的web…

    编程 2025-04-25
  • Python输入输出详解

    一、文件读写 Python中文件的读写操作是必不可少的基本技能之一。读写文件分别使用open()函数中的’r’和’w’参数,读取文件…

    编程 2025-04-25
  • Linux修改文件名命令详解

    在Linux系统中,修改文件名是一个很常见的操作。Linux提供了多种方式来修改文件名,这篇文章将介绍Linux修改文件名的详细操作。 一、mv命令 mv命令是Linux下的常用命…

    编程 2025-04-25
  • 详解eclipse设置

    一、安装与基础设置 1、下载eclipse并进行安装。 2、打开eclipse,选择对应的工作空间路径。 File -> Switch Workspace -> [选择…

    编程 2025-04-25
  • MPU6050工作原理详解

    一、什么是MPU6050 MPU6050是一种六轴惯性传感器,能够同时测量加速度和角速度。它由三个传感器组成:一个三轴加速度计和一个三轴陀螺仪。这个组合提供了非常精细的姿态解算,其…

    编程 2025-04-25
  • Python安装OS库详解

    一、OS简介 OS库是Python标准库的一部分,它提供了跨平台的操作系统功能,使得Python可以进行文件操作、进程管理、环境变量读取等系统级操作。 OS库中包含了大量的文件和目…

    编程 2025-04-25
  • git config user.name的详解

    一、为什么要使用git config user.name? git是一个非常流行的分布式版本控制系统,很多程序员都会用到它。在使用git commit提交代码时,需要记录commi…

    编程 2025-04-25
  • Java BigDecimal 精度详解

    一、基础概念 Java BigDecimal 是一个用于高精度计算的类。普通的 double 或 float 类型只能精确表示有限的数字,而对于需要高精度计算的场景,BigDeci…

    编程 2025-04-25

发表回复

登录后才能评论