【Verilog硬件语言学习笔记4】FPGA串口通信

串口通信是系统设计中比较基部分,其原理其实也很通俗易懂。单次建立通信会传输8个bit,其时序也很简单,这里就不再赘述了。其对应的实例代码如下所示;

首先是接受部分(因为我的变量命名也很规范,通俗易懂,所以我不再详细介绍):

复制代码
`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2025/03/13 12:00:48
// Design Name: 
// Module Name: uart_rx
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//

module uart_rx(
    input                               clk                        ,
    input                               rst_n                      ,
    input                               uart_rxd                   ,

    output reg                          uart_rx_done               ,
    output reg         [   7: 0]        uart_rx_data                
    );

// parameter to define
    parameter                           CLK_FREQ                   = 50000000;
    parameter                           UART_BPS                   = 115200;
    localparam                          BAUD_CNT_MAX               = CLK_FREQ / UART_BPS;

// reg define
    reg                                 uart_rxd_d0                 ;
    reg                                 uart_rxd_d1                 ;
    reg                                 uart_rxd_d2                 ;
    reg                                 rx_flag                     ;
    reg                [   3: 0]        rx_cnt                      ;
    reg                [  15: 0]        baud_cnt                    ;
    reg                [   7: 0]        rx_data_t                   ;

// wire define
    wire                                start_en                    ;
// Main Code
// Because the sign fall from high to low, use this to catch the signal;
    assign                              start_en                    = uart_rxd_d2 & (~uart_rxd_d1) & (~rx_flag);

// aiming to asynchronous signal processing
always @(posedge clk or negedge rst_n)
begin
    if (!rst_n) begin
        uart_rxd_d0 <= 0;
        uart_rxd_d1 <= 0;
        uart_rxd_d2 <= 0;
    end
    else begin
        uart_rxd_d0 <= uart_rxd;
        uart_rxd_d1 <= uart_rxd_d0;
        uart_rxd_d2 <= uart_rxd_d1;
    end
end

// define the rx_flag
always @(posedge clk or negedge rst_n)
begin
    if (!rst_n)
        rx_flag <= 0;
    else if (start_en)
        rx_flag <= 1'b1;
    else if ((rx_cnt == 4'd9) && (baud_cnt == BAUD_CNT_MAX / 2 - 1'b1))
        rx_flag <= 0;
    else
        rx_flag <= rx_flag;
end

// Baud rate counter amplitude
always @(posedge clk or negedge rst_n)
begin
    if (!rst_n)
        baud_cnt <= 0;
    else if (rx_flag) begin
        if (baud_cnt <= BAUD_CNT_MAX - 1)
            baud_cnt <= baud_cnt + 1;
        else
            baud_cnt <= 0;
    end
    else
        baud_cnt <= 0;
end

// Accept data(rx_cnt) assignment
always @(posedge clk or negedge rst_n)
begin
    if (!rst_n)
        rx_cnt <= 0;
    else if (rx_flag) begin
        if (baud_cnt == BAUD_CNT_MAX-1) begin
            rx_cnt <= rx_cnt + 1;
        end
        else
            rx_cnt <= rx_cnt;
    end
    else
        rx_cnt <= 0;
end

// based on the rx_cnt to restore the rxd data
always @(posedge clk or negedge rst_n)
begin
    if (!rst_n)
        rx_data_t <= 0;
    else if (rx_flag) begin
        if (baud_cnt == BAUD_CNT_MAX / 2 - 1) begin
            case (rx_cnt)
                4'd1: rx_data_t[0] <= uart_rxd_d2;
                4'd2: rx_data_t[1] <= uart_rxd_d2;
                4'd3: rx_data_t[2] <= uart_rxd_d2;
                4'd4: rx_data_t[3] <= uart_rxd_d2;
                4'd5: rx_data_t[4] <= uart_rxd_d2;
                4'd6: rx_data_t[5] <= uart_rxd_d2;
                4'd7: rx_data_t[6] <= uart_rxd_d2;
                4'd8: rx_data_t[7] <= uart_rxd_d2;
                default: ;
            endcase
        end
        else
            rx_data_t <= rx_data_t;
    end
    else
        rx_data_t <= 0;
end

// assignment the data received
always @(posedge clk or negedge rst_n)
begin
    if (!rst_n) begin
        uart_rx_done <= 0;
        uart_rx_data <= 0;
    end
    else if (rx_cnt == 4'd9 && baud_cnt == BAUD_CNT_MAX / 2 - 1) begin
        uart_rx_done <= 1;
        uart_rx_data <= rx_data_t;
    end
    else begin
        uart_rx_done <= 0;
        uart_rx_data <= uart_rx_data;
    end
end

endmodule

然后是发送部分:

复制代码
`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2025/03/13 17:14:19
// Design Name: 
// Module Name: uart_tx
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module uart_tx(
    input                               clk                        ,
    input                               rst_n                      ,
    input                               uart_tx_en                 ,
    input              [   7: 0]        uart_tx_data               ,
    output reg                          uart_txd                   ,
    output reg                          uart_tx_busy                
    );

// parameter define
    parameter                           CLK_FREQ                   = 50000000;
    parameter                           UART_BPS                   = 115200;
    localparam                          BAUD_CNT_MAX               = CLK_FREQ/UART_BPS;

// reg define
    reg                [   7: 0]        tx_data_t                   ;
    reg                [   3: 0]        tx_cnt                      ;
    reg                [  15: 0]        baud_cnt                    ;

// Main Code
always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)     begin
            tx_data_t<=0;
            uart_tx_busy<=0;
        end
        else if(uart_tx_en)        begin
            tx_data_t<=uart_tx_data;
            uart_tx_busy<=1;
        end
        else if(tx_cnt==4'd9&&baud_cnt==BAUD_CNT_MAX-1) begin
            tx_data_t<=0;
            uart_tx_busy<=0;
        end
        else begin
            tx_data_t<=tx_data_t;
            uart_tx_busy<=uart_tx_busy;
        end
    end

// Baud counter
always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            baud_cnt<=0;
        else if(uart_tx_en)
            baud_cnt<=0;
        else if(uart_tx_busy) begin
            if(baud_cnt<BAUD_CNT_MAX-1)
                baud_cnt<=baud_cnt+1;
            else
                baud_cnt<=0;
        end
        else
            baud_cnt<=0;
    end

// assign the tx_cnt
always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            tx_cnt<=0;
        else if(uart_tx_busy) begin
            if(baud_cnt==BAUD_CNT_MAX-1)
                tx_cnt<=tx_cnt+1;
            else
                tx_cnt<=tx_cnt;
        end
        else
            tx_cnt<=0;
    end

always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            uart_txd<=1;
        else if(uart_tx_busy) begin
            case(tx_cnt)
                4'd0: uart_txd<=1'b0;
                4'd1: uart_txd<=tx_data_t[0];
                4'd2: uart_txd<=tx_data_t[1];
                4'd3: uart_txd<=tx_data_t[2];
                4'd4: uart_txd<=tx_data_t[3];
                4'd5: uart_txd<=tx_data_t[4];
                4'd6: uart_txd<=tx_data_t[5];
                4'd7: uart_txd<=tx_data_t[6];
                4'd8: uart_txd<=tx_data_t[7];
                4'd9: uart_txd<=1;
                default: uart_txd<=1;
            endcase
        end
        else
            uart_txd<=1'b1;
    end

endmodule

参考文献:

达芬奇之 FPGA 开发指南 V2.2 -正点原子 达芬奇开发板教程

相关推荐
你好~每一天1 分钟前
2025年B端产品经理进阶指南:掌握这些计算机专业技能,决胜职场!
java·人工智能·经验分享·学习·产品经理·大学生
努力打怪升级5 分钟前
容器学习day05_k8s(二)
学习·容器·kubernetes
叫我Zoe就行12 分钟前
MySQL集群——主从复制
linux·数据库·学习·mysql
Source.Liu17 分钟前
【Python基础】 19 Rust 与 Python if 语句对比笔记
笔记·python·rust
维斯路35 分钟前
ANSYS 热力耦合计算
学习
程序员Xu1 小时前
【LeetCode热题100道笔记】二叉树的中序遍历
笔记·算法·leetcode
Source.Liu2 小时前
【Python基础】 18 Rust 与 Python print 函数完整对比笔记
笔记·python·rust
闻道且行之2 小时前
嵌入式|Linux中打开视频流的两种方式V4l2和opencv
linux·笔记·opencv·嵌入式
于顾而言2 小时前
【笔记】Software Engineering at Google
笔记·log4j·软件工程
悠哉悠哉愿意3 小时前
【数学建模学习笔记】机器学习分类:XGBoost分类
学习·机器学习·数学建模