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

相关推荐
萨文 摩尔杰8 小时前
GPS原理学习
学习·fpga开发
Huangichin9 小时前
跟着Gemini学System Verilog
fpga开发
LCMICRO-1331084774611 小时前
长芯微LDC90810完全P2P替代ADC128D818,是一款八通道系统监控器,专为监控复杂系统状态而设计。
stm32·单片机·嵌入式硬件·fpga开发·硬件工程·模数转换芯片adc
s090713614 小时前
保姆级教程十二:USB摄像头接入!ZYNQ+OpenCV+FPGA硬件加速图像处理实战(视觉终极篇)
图像处理·opencv·fpga开发·zynq·硬件加速
CoderIsArt18 小时前
FPGA-based 量子电路仿真
fpga开发
碎碎思1 天前
升级版流水灯:用FPGA控制上千颗RGB LED
fpga开发
FPGA-ADDA1 天前
第二篇:Xilinx 7系列FPGA详解——从Spartan到Virtex
fpga开发·fpga·sdr·rfsoc
逐步前行1 天前
STM32_SysTick_寄存器操作
stm32·嵌入式硬件·fpga开发
良许Linux2 天前
FPGA的选型和应用
数据库·图像处理·计算机视觉·fpga开发
上班最快乐2 天前
基于FPGA的APS6404L-3SQR QSPI PSRAM驱动设计(3)
fpga开发