名称:串口 FIFO 发送控制 FPGA 设计 Verilog Vivado VHDL
软件:Vivado
语言:VHDL
功能介绍
本设计实现 FPGA 端 UART 串口发送功能,面向需要将内部数据通过 RS232/串口链路输出到上位机或串口调试工具的场景。顶层提供时钟、复位、串口发送引脚以及 FIFO 写入接口,上位模块可通过写使能和 8bit 写数据端口把待发送字节送入发送 FIFO,再由 UART 发送模块按串口时序输出。 设计重点是将数据缓存与串口发送解耦。FIFO 作为发送缓冲区,负责承接前级模块写入的数据;UART 发送逻辑根据 FIFO 空标志和读使能取数,配合波特率时钟完成逐字节发送。这样可以避免前级数据产生节奏与串口发送速率不一致时直接耦合带来的丢数或时序控制复杂问题。 文档中的扩展需求还描述了基于乒乓 RAM 的帧发送思路:当有效信号到来时保存 position 数据,利用 sop/eop 标志在两个 RAM 之间切换缓存,再将 32bit position 拆分为 4 个字节,组成以 8'hAA 开始、备用字节和 8'hFF 结束的 7 字节帧,通过串口发送。该思路适合连续数据分帧输出,并要求帧与帧之间保持约 100ms 的间隔,便于串口调试工具清晰接收与显示。
运行环境
开发软件:Vivado。 设计语言:Verilog。 工程包含 Vivado 项目文件、Verilog 源码、FIFO IP 相关文件、XDC 约束文件以及行为仿真生成文件。顶层模块为 my_uart_top,主要接口包括 50MHz 主时钟 clk、低电平复位 rst_n、串口发送输出 rs232_tx、FIFO 写使能 tx_fifo_wr_en 和 8bit FIFO 写数据 tx_fifo_wr_data。
设计思路
整体设计采用“数据缓存 + 波特率节拍 + UART 发送”的结构。前级模块不直接驱动串口发送状态机,而是先把待发送的 8bit 数据写入 FIFO;发送端根据 FIFO empty 状态判断是否有数据可取,并在合适的串口发送节拍下产生读使能 rd_en,读取 FIFO 输出 rd_data 后送入 UART TX 模块。该结构便于处理突发数据写入,也便于后续扩展为多字节帧发送。 波特率产生部分由 speed_select 模块完成,输出 clk_bps 作为串口发送过程中的位时序参考。UART 发送模块 my_uart_tx 接收 clk_bps、FIFO 读数据、FIFO 空标志等信号,完成起始位、数据位和停止位的串行输出控制。顶层 my_uart_top 负责把 speed_select、my_uart_tx 和 FIFO_8_256 连接起来,形成完整的发送链路。 对于帧化发送需求,uart_ctrl 可作为更高层串口控制模块使用:有效数据到来时将 position 写入缓存,利用 sop/eop 标记区分当前缓存区的起止,并在两个 RAM 之间进行乒乓切换。发送时将缓存的 32bit position 拆分为 4 个信息字节,外加帧头 8'hAA、一个 8'h00 备用字节和帧尾 8'hFF,形成 56bit、7 字节一帧的数据格式。帧间加入 100ms 间隔,有利于上位机端按帧观察数据,避免连续帧显示在同一行导致调试困难。
模块结构
主要模块包括: my_uart_top:串口 FIFO 发送顶层,连接波特率模块、UART 发送模块和 8bit FIFO。 speed_select:产生 UART 发送所需的波特率时钟节拍 clk_bps。 my_uart_tx:UART 发送模块,根据 FIFO 数据和读使能完成 RS232 串行发送。 FIFO_8_256:8bit 宽度、256 深度发送 FIFO,用于缓存待发送字节。 uart_ctrl:串口控制顶层模块,可用于组织更高层的帧发送控制。 tx_data_ctrl、timer_100ms:用于发送数据组织和帧间定时控制的相关逻辑。 my_uart_rx:UART 接收模块,文档中说明 rx 部分可忽略。
开发板验证
工程包含顶层 XDC 管脚约束文件,可用于 Vivado 中进行引脚分配和开发板下载验证。串口发送信号通过约束后的 rs232_tx 引脚输出,配合外部串口调试工具可观察发送帧数据;文档中的预期现象为串口端能够接收到以 AA 开始、按字节发送的帧数据,并通过帧间隔避免连续帧混在同一行显示。
演示视频
包含演示视频,可用于查看工程运行和串口发送效果。
演示视频请关注公众号后获取对应资料查看。
仿真图/仿真说明/设计文档图片
包含设计说明文档、工程文件截图、程序文件截图、编译结果、RTL 图和仿真图等说明材料,可辅助理解 UART FIFO 发送流程、帧格式以及 Vivado 工程结构。仿真工程中包含 xsim 行为仿真文件和波形数据库,可作为查看发送时序与模块连接关系的参考。
部分代码
以下展示顶层模块my_uart_top的部分代码,完整代码可关注下方公众号卡片获取。
module my_uart_top(clk,rst_n,rs232_tx,tx_fifo_wr_en,tx_fifo_wr_data); input clk; // 50MHz主时钟 input rst_n; //低电平复位信号 output rs232_tx; // RS232发送数据信号 input tx_fifo_wr_en;//fifo写使能 input [7:0] tx_fifo_wr_data;//fifo写数据 wire bps_start; //接收到数据后,波特率时钟启动信号置位 wire clk_bps; // clk_bps的高电平为接收或者发送数据位的中间采样点 wire[7:0] rx_data; //接收数据寄存器,保存直至下一个数据来到 wire rx_en; //接收数据有效 wire[7:0] rd_data; //接收数据寄存器,保存直至下一个数据来到 wire rd_en; //接收数据有效 wire empty; //---------------------------------------------------- //波特率选择模块 speed_select speed_select( .clk(clk), .rst_n(rst_n), .clk_bps(clk_bps) ); //发送数据模块 my_uart_tx my_uart_tx( .clk(clk), //发送数据模块 .rst_n(rst_n), .clk_bps(clk_bps), .rd_data(rd_data), .rd_en(rd_en), .empty(empty), .rs232_tx(rs232_tx) ); //发送数据FIFO FIFO_8_256 FIFO_8_256_tx ( .clk(clk), // input wire clk .srst(~rst_n), // input wire srst .din(tx_fifo_wr_data), // input wire [7 : 0] din .wr_en(tx_fifo_wr_en), // input wire wr_en .rd_en(rd_en), // input wire rd_en .dout(rd_data), // output wire [7 : 0] dout .full(), // output wire full .empty(empty) // output wire empty ); endmodule
代码获取:点击下方公众号卡片