【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 -正点原子 达芬奇开发板教程

相关推荐
我的xiaodoujiao27 分钟前
API 接口自动化测试详细图文教程学习系列32--Allure测试报告2
python·学习·测试工具·pytest
破碎的南瓜2 小时前
sqli--sql注入过关笔记(1,2,3,4,5,9)
数据库·笔记·sql
你想知道什么?2 小时前
线性回归-学习笔记
笔记·学习·线性回归
鱼毓屿御2 小时前
从「只会聊」到「边想边做」的跃迁
前端·学习·react.js
谙弆悕博士2 小时前
系统集成项目管理工程师教程(第3版)笔记——第17章:法律法规和标准规范
笔记·职场和发展·学习方法·业界资讯·软考·法律·法规
XMAIPC_Robot3 小时前
软硬协同实时控制|RK3588业务调度+FPGA硬件时序,ethercat实现半导体设备微秒级响应(125us)
linux·arm开发·人工智能·fpga开发
AOwhisky3 小时前
Python 学习笔记(第十五期)——运维自动化(下·后篇):堡垒机实战——paramiko高阶篇
运维·python·学习·云原生·自动化·运维开发
upper20203 小时前
从零开始设计riscv cpu记录之七
fpga开发·riscv·riscv设计·btb·分支预测
谙弆悕博士4 小时前
系统集成项目管理工程师教程(第3版)笔记——第4章:信息系统架构
笔记·系统架构·项目管理·创业创新·学习方法·业界资讯·物理
minglie15 小时前
zynq中linux系统的自动登录和免密登录
学习