Verlog实现串口的收发功能

  1. 波特率发生器模块(baudrate_gen.v)

    // 波特率发生器:50MHz系统时钟 → 1倍波特率时钟(可配置波特率)
    module baudrate_gen #(
    parameter SYS_CLK_FREQ = 50_000_000, // 系统时钟频率(默认50MHz)
    parameter BAUD_RATE = 9600 // 目标波特率(默认9600)
    )(
    input clk, // 系统时钟
    input rst_n, // 低电平复位
    output reg baud_clk_1x // 1倍波特率时钟(高电平持续1个clk周期)
    );

    // 计算分频系数:分频值 = 系统时钟频率 / 波特率
    localparam DIV_NUM = SYS_CLK_FREQ / BAUD_RATE;
    // 计数器位宽:足够容纳分频系数即可
    localparam CNT_WIDTH = $clog2(DIV_NUM);

    reg [CNT_WIDTH-1:0] cnt; // 分频计数器

    always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
    cnt <= 'd0;
    baud_clk_1x <= 1'b0;
    end else begin
    if (cnt == DIV_NUM - 1) begin // 计数到分频值-1
    cnt <= 'd0; // 计数器清零
    baud_clk_1x <= 1'b1; // 生成1个clk周期的高电平脉冲
    end else begin
    cnt <= cnt + 1'b1; // 计数器递增
    baud_clk_1x <= 1'b0; // 其余时间为低
    end
    end
    end

    endmodule


  1. UART 发送模块(uart_tx.v)

    // UART发送模块:并行数据 → 串行UART信号
    module uart_tx (
    input clk, // 系统时钟
    input rst_n, // 低电平复位
    input baud_clk_1x, // 1倍波特率时钟
    input [7:0] tx_data, // 待发送的8位并行数据
    input tx_en, // 发送使能(高电平触发一次发送)
    output reg tx_pin, // UART发送引脚(串行输出)
    output reg tx_done // 发送完成标志
    );

    // 状态定义
    localparam IDLE = 2'b00; // 空闲状态
    localparam SEND = 2'b01; // 发送状态
    localparam DONE = 2'b10; // 发送完成状态

    // 内部寄存器
    reg [1:0] state; // 状态机寄存器
    reg [3:0] bit_cnt; // 位计数器(0-9:起始位+8数据位+停止位)
    reg [7:0] tx_data_reg; // 数据缓存寄存器

    // 状态机逻辑
    always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
    state <= IDLE;
    tx_pin <= 1'b1; // UART空闲时引脚为高
    bit_cnt <= 4'd0;
    tx_data_reg <= 8'd0;
    tx_done <= 1'b0;
    end else begin
    case (state)
    IDLE: begin
    tx_done <= 1'b0;
    if (tx_en) begin // 触发发送
    state <= SEND;
    tx_pin <= 1'b0; // 发送起始位(低电平)
    bit_cnt <= 4'd1;
    tx_data_reg <= tx_data;
    end
    end

    复制代码
             SEND: begin
                 if (baud_clk_1x) begin  // 每1个波特率时钟发送1位
                     // 逐位发送数据
                     case (bit_cnt)
                         4'd1: tx_pin <= tx_data_reg[0]; // 第1位:LSB
                         4'd2: tx_pin <= tx_data_reg[1];
                         4'd3: tx_pin <= tx_data_reg[2];
                         4'd4: tx_pin <= tx_data_reg[3];
                         4'd5: tx_pin <= tx_data_reg[4];
                         4'd6: tx_pin <= tx_data_reg[5];
                         4'd7: tx_pin <= tx_data_reg[6];
                         4'd8: tx_pin <= tx_data_reg[7]; // 第8位:MSB
                         4'd9: tx_pin <= 1'b1;           // 第9位:停止位(高电平)
                         default: ;
                     endcase
    
                     // 计数器更新
                     if (bit_cnt == 4'd9) begin  // 停止位发送完成
                         state   <= DONE;
                         bit_cnt <= 4'd0;
                     end else begin
                         bit_cnt <= bit_cnt + 4'd1;
                     end
                 end
             end
    
             DONE: begin
                 tx_done <= 1'b1;    // 置位完成标志
                 state   <= IDLE;    // 回到空闲态
             end
    
             default: state <= IDLE;
         endcase
     end

    end

    endmodule


  1. UART 接收模块(uart_rx.v)

    // UART接收模块:串行UART信号 → 并行数据
    module uart_rx (
    input clk, // 系统时钟
    input rst_n, // 低电平复位
    input baud_clk_1x, // 1倍波特率时钟
    input rx_pin, // UART接收引脚(串行输入)
    output reg [7:0] rx_data, // 接收完成的8位并行数据
    output reg rx_done // 接收完成标志
    );

    // 状态定义
    localparam IDLE = 2'b00; // 空闲状态
    localparam RECV = 2'b01; // 接收状态
    localparam DONE = 2'b10; // 接收完成状态

    // 内部寄存器
    reg [1:0] state; // 状态机寄存器
    reg [3:0] bit_cnt; // 位计数器(0-9:起始位+8数据位+停止位)
    reg [7:0] rx_data_reg; // 数据缓存寄存器

    // 状态机逻辑
    always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
    state <= IDLE;
    rx_data <= 8'd0;
    rx_data_reg <= 8'd0;
    bit_cnt <= 4'd0;
    rx_done <= 1'b0;
    end else begin
    case (state)
    IDLE: begin
    rx_done <= 1'b0;
    // 检测起始位(低电平),触发接收
    if (rx_pin == 1'b0 && baud_clk_1x) begin
    state <= RECV;
    bit_cnt <= 4'd1; // 准备接收第1位数据
    end
    end

    复制代码
             RECV: begin
                 if (baud_clk_1x) begin  // 每1个波特率时钟接收1位
                     // 逐位接收数据(跳过起始位,接收8位数据)
                     case (bit_cnt)
                         4'd1: rx_data_reg[0] <= rx_pin; // 第1位:LSB
                         4'd2: rx_data_reg[1] <= rx_pin;
                         4'd3: rx_data_reg[2] <= rx_pin;
                         4'd4: rx_data_reg[3] <= rx_pin;
                         4'd5: rx_data_reg[4] <= rx_pin;
                         4'd6: rx_data_reg[5] <= rx_pin;
                         4'd7: rx_data_reg[6] <= rx_pin;
                         4'd8: rx_data_reg[7] <= rx_pin; // 第8位:MSB
                         4'd9: ; // 停止位(仅检测,不存储)
                         default: ;
                     endcase
    
                     // 计数器更新
                     if (bit_cnt == 4'd9) begin  // 停止位接收完成
                         state   <= DONE;
                         bit_cnt <= 4'd0;
                         rx_data <= rx_data_reg; // 输出接收的数据
                     end else begin
                         bit_cnt <= bit_cnt + 4'd1;
                     end
                 end
             end
    
             DONE: begin
                 rx_done <= 1'b1;    // 置位完成标志
                 state   <= IDLE;    // 回到空闲态
             end
    
             default: state <= IDLE;
         endcase
     end

    end

    endmodule


  1. UART 顶层模块(uart_top.v)

    // UART顶层模块:整合波特率发生器、发送、接收模块
    module uart_top #(
    parameter SYS_CLK_FREQ = 50_000_000, // 系统时钟频率
    parameter BAUD_RATE = 9600 // 波特率
    )(
    input clk, // 系统时钟
    input rst_n, // 低电平复位
    // 发送接口
    input [7:0] tx_data, // 待发送数据
    input tx_en, // 发送使能
    output tx_pin, // UART发送引脚
    output tx_done, // 发送完成
    // 接收接口
    input rx_pin, // UART接收引脚
    output [7:0] rx_data, // 接收数据
    output rx_done // 接收完成
    );

    // 内部连线:波特率时钟
    wire baud_clk_1x;

    // 例化波特率发生器
    baudrate_gen #(
    .SYS_CLK_FREQ(SYS_CLK_FREQ),
    .BAUD_RATE(BAUD_RATE)
    ) u_baudrate_gen (
    .clk (clk),
    .rst_n (rst_n),
    .baud_clk_1x(baud_clk_1x)
    );

    // 例化UART发送模块
    uart_tx u_uart_tx (
    .clk (clk),
    .rst_n (rst_n),
    .baud_clk_1x(baud_clk_1x),
    .tx_data (tx_data),
    .tx_en (tx_en),
    .tx_pin (tx_pin),
    .tx_done (tx_done)
    );

    // 例化UART接收模块
    uart_rx u_uart_rx (
    .clk (clk),
    .rst_n (rst_n),
    .baud_clk_1x(baud_clk_1x),
    .rx_pin (rx_pin),
    .rx_data (rx_data),
    .rx_done (rx_done)
    );

    endmodule

相关推荐
szxinmai主板定制专家14 小时前
RK3568 + CODESYS+实时系统运动控制器PLC,支持 AI 视觉目标检测,预测性维护,混合多系统部署,多路模拟量采集
arm开发·人工智能·嵌入式硬件·fpga开发
GateWorld17 小时前
LCD显示技术完全指南:原理·制造·驱动·FPGA实现之驱动二
fpga开发·lcd显示·fpga点亮屏幕·minilvds
GateWorld19 小时前
LCD显示技术完全指南:原理·制造·驱动·FPGA实现之驱动一
fpga开发·lcd显示·minilvds·fpga点屏
XMAIPC_Robot19 小时前
深度无人机自动驾驶仪,中小型无人机硬件在环仿真飞行
运维·arm开发·人工智能·fpga开发·无人机·边缘计算
小眼睛FPGA1 天前
【紫光HiYou开源入门轻量级PCIE开发板PG2L25G】实验例程1-基于紫光FPGA 的LED 流水灯
fpga开发
不会武功的火柴1 天前
SystemVerilog语法(8)-有限状态机(FSM)
嵌入式硬件·fpga开发·自动化·ic验证·rtl·uvm方法学
Kent Gu1 天前
Lattice FPGA选型
fpga开发
Terasic友晶科技2 天前
答疑解惑|为DE25-Nano开发板配置Linux kernel时.config文件没有起作用是什么原因?
linux·服务器·fpga开发·linux kernel·de25-nano
8K超高清2 天前
CCBN展会多图回顾
人工智能·算法·fpga开发·接口隔离原则·智能硬件
小眼睛FPGA2 天前
【紫光HiYou开源入门轻量级PCIE开发板PG2L25G】实验例程5-DDR3 读写实验例程
fpga开发