当前位置: 首页 > news >正文

先扔个效果图镇楼。板子上电后打开串口助手,发送“0x55“直接回显,实测115200波特率下收发稳定。下面咱们掰开揉碎说代码实现

verilog实现UART:RS232串口的收发。 RTL代码及仿真代码100%每行全注释,不用担心看不懂。 FPGA:开发工具ISE,或者QUARTUS。 功能:将电脑上使用串口调试助手发送的数据进行接收,再将接收到的数据发送回去,在串口调试助手界面显示。 RS232协议:1位起始位+8位数据位+1位停止位。 顶层模块和分模块均有modelsim仿真文件及仿真结果波形,便于学习验证及应用。 已下载到板验证通过。

----

UART的核心在于精准的波特率控制。先看时钟分频模块,拿50MHz时钟生成115200波特率为例:

module baud_generator( input clk_50m, output reg baud_clk ); // 分频计数器 reg [15:0] cnt; parameter CLK_DIV = 50_000_000 / 115200 / 2; always @(posedge clk_50m) begin if(cnt == CLK_DIV-1) begin // 注意-1修正 baud_clk <= ~baud_clk; // 翻转生成方波 cnt <= 0; end else begin cnt <= cnt + 1'b1; end end endmodule

这里有个坑:实际计算分频值时记得考虑双边沿采样,所以分母要乘2。比如50MHz时钟下115200波特率的分频系数应该是50M/(115200*2)=217,实测这个值能精准匹配电脑端的波特率。

接收模块的状态机是重点,看这个有限状态机实现:

module uart_rx( input rx_pin, input baud_clk, output reg [7:0] data_out, output reg data_valid ); // 状态编码 localparam IDLE = 2'b00; localparam START = 2'b01; localparam DATA = 2'b10; localparam STOP = 2'b11; reg [2:0] state; reg [3:0] bit_cnt; always @(posedge baud_clk) begin case(state) IDLE: if(!rx_pin) begin // 检测起始位下降沿 state <= START; bit_cnt <= 0; end START: state <= DATA; // 等待到起始位中间点 DATA: begin data_out[bit_cnt] <= rx_pin; // 低位优先存储 if(bit_cnt == 7) begin state <= STOP; end bit_cnt <= bit_cnt + 1; end STOP: begin data_valid <= 1'b1; // 有效信号持续1周期 state <= IDLE; end endcase end endmodule

关键点在于起始位检测后的相位对齐。代码里在START状态停留一个周期,刚好让采样点落在数据位中间,这是对抗时钟偏差的经典操作。

verilog实现UART:RS232串口的收发。 RTL代码及仿真代码100%每行全注释,不用担心看不懂。 FPGA:开发工具ISE,或者QUARTUS。 功能:将电脑上使用串口调试助手发送的数据进行接收,再将接收到的数据发送回去,在串口调试助手界面显示。 RS232协议:1位起始位+8位数据位+1位停止位。 顶层模块和分模块均有modelsim仿真文件及仿真结果波形,便于学习验证及应用。 已下载到板验证通过。

发送模块需要注意时序对齐:

module uart_tx( input [7:0] data_in, input send_en, output reg tx_pin, output reg ready ); reg [3:0] state; reg [7:0] shift_reg; always @(posedge baud_clk) begin case(state) 0: if(send_en) begin tx_pin <= 0; // 起始位 shift_reg <= data_in; state <= 1; ready <= 0; end 1: begin tx_pin <= shift_reg[0]; // 发送LSB shift_reg <= shift_reg >> 1; if(state == 8) begin // 发送完8位数据 state <= 9; end else begin state <= state + 1; end end 9: begin tx_pin <= 1; // 停止位 ready <= 1; state <= 0; end endcase end endmodule

这里采用移位寄存器实现串行化,注意发送顺序是低位在前。状态机从0到9刚好对应1+8+1位的传输结构。

仿真时重点关注时序对齐问题:

// 测试用例片段 initial begin #100 rx_pin = 0; // 起始位 #8680 rx_pin = 1; // 发送0x55的二进制10101010 #8680 rx_pin = 0; repeat(6) begin // 构造交替信号 #8680 rx_pin = ~rx_pin; end #8680 rx_pin = 1; // 停止位 end

Modelsim波形里要检查:接收端在停止位阶段data_valid是否拉高,发送端在ready信号恢复时能否立即响应新数据。

最后说两个硬件调试的坑:一是PC端串口芯片的电压可能和FPGA不匹配,记得加电平转换电路;二是发送完成后如果不释放总线,会出现回环数据被自己锁存的情况,解决办法是在顶层模块里用状态机控制收发切换时机。

完整代码已打包,包含自动测试脚本和约束文件。拿回去直接烧录,串口助手设置成十六进制显示,体验一把硬核数据回传的快感吧!

http://www.jsqmd.com/news/461594/

相关文章:

  • 记录 | 个人开发库推送至PyPi流程梳理(ChatGPT to Markdown 工具发布完整流程)
  • 软考高项通关实测:拒绝论文套路,3个月从焦虑到持证的真实备考经验
  • 2026年剖析唐山华冶钢管制造基本信息,看它为何受市场认可 - 工业品牌热点
  • 我把一个生产Bug的排查过程,交给AI处理——20分钟后我关掉了它
  • 2026年权威盘点:钢塑复合管行业TOP5机构,谁才是性价比
  • Linux内核SLUB调试功能
  • 【Agent Skills】教程!大模型入门到进阶,一套全解决(10)
  • 探讨双工位木纹转印机价格,华宜家在广东费用多少? - 工业设备
  • Docker单容器部署Dify
  • 什么是MIPI SoundWire
  • 28 超越默认:深入理解 Byte Buddy 的自定义 Assigner 与类型转换魔法
  • 2026年山东靠谱的管道支架制造厂排名揭晓 - myqiye
  • 总结国强和茂公司信誉、环保方面及物流配送,如何选择 - 工业推荐榜
  • 【Agent Skills】教程!大模型入门到进阶,一套全解决(11)
  • 告别工具堆砌!桌面智能体KeyVox全能AI助手,办公、创作、生活一站式搞定
  • 从删库到跑路→数据拯救师:测试工程师的涅槃转型
  • 2026成渝老旧小区消防改造服务商推荐榜 - 优质品牌商家
  • Nature Electronics 仿视网膜成像芯片-一种曲面剪纸结构的神经形态成像器
  • Flutter 组件 test_track 适配鸿蒙 HarmonyOS 实战:全链路追踪与灰度治理,构建全场景 A/B 测试与特性分发架构
  • 2026京津冀口碑好的钢管销售公司排名,价格合理的有哪些 - mypinpai
  • 深入理解One-Class SVM:无监督异常检测的精准利器
  • 基于FPGA实现高清HDMI视频输出的实践与探究
  • 从人工到自动:巡检工作的“解放”与“进化”
  • 安全超自动化的终极目标:实现自适应安全防护
  • 机器学习——随机森林
  • 基于plc的病床呼叫系统,全部采用博途仿真完成,提供画面,及参考文档 实现功能(详见上方演示视...
  • 拒绝“高开低走”:开盘半小时,看透主力意图的9个实战密码
  • 纺织巨头指定青岛福尔蒂UV-Stabilizer原因:新疆棉纺帐篷布三年暴晒实测
  • 数据泄露应急响应演练:从SQL注入到大规模信息窃取及防御
  • 2026年比较好的五折洗脸巾设备厂家推荐:点断式洗脸巾设备厂家选购参考建议 - 品牌宣传支持者