尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

ModelSim 仿真记录:基于地址帧 UART 的 FPGA 多外设控制系统

ModelSim 仿真记录:基于地址帧 UART 的 FPGA 多外设控制系统
📅 发布时间:2026/7/13 22:30:47

1. 项目概述

本设计完成了一个基于 FPGA 的多外设控制系统,核心功能是通过 UART 串口协议接收控制命令,再根据命令控制开发板上的 LED、蜂鸣器、数码管、电机、8×8 点阵以及 LCD1602 本地菜单模块。

本文主要记录 ModelSim 仿真过程,包括仿真工程搭建、波形观察方法、UART 帧解析方法,以及各模块关键信号的观察思路。Quartus 综合、引脚分配和下载到开发板的部分放在后续文章中。
系统采用地址帧通信方式,串口接收的数据不再是单字节直接控制,而是按照固定格式组成一帧完整命令:

帧头 + 地址 + 命令 + 校验

例如:

66 01 11 10

其中:

  • 66:帧头,用于标识一帧数据的开始;
  • 01:设备地址,用于区分不同从机;
  • 11:控制命令,例如控制 LED 进入某种显示模式;
  • 10:校验值,用于判断地址和命令是否在传输过程中出错。

2. 开发板与外设资源

本设计使用 QC-FPGA-C1 FPGA 开发板套件。开发板板载 FPGA 芯片、时钟晶振、LED、数码管、蜂鸣器、点阵、按键、LCD1602 接口以及电机驱动接口,适合完成基础数字系统和嵌入式 FPGA 综合实验。

开发板主要资源如下:

  • FPGA:Cyclone 系列 FPGA,工程目标器件为EP1C3T144;
  • 时钟:板载 48 MHz 有源晶振,原理图中 OSC1 输出CLK0;
  • 下载器:USB-Blaster;
  • 串口通信:可使用 USB 转串口线,或蓝牙透明串口模块;
  • 显示模块:LED、四位七段数码管、8×8 LED 点阵、LCD1602;
  • 输入模块:拨码开关、矩阵按键;
  • 执行模块:无源蜂鸣器、L9110 电机驱动接口。

图 1 QC-FPGA-C1 开发板及主要外设资源

在仿真阶段,重点不是观察真实硬件现象,而是验证 RTL 逻辑是否正确。例如 UART 是否能正确接收帧,校验是否有效,命令是否能正确转换为各模块的控制信号。

3. ModelSim 仿真的作用

在 FPGA 开发流程中,ModelSim 主要用于 RTL 仿真。它可以在不下载到开发板的情况下,提前观察代码逻辑是否符合设计要求。

本设计中 ModelSim 主要用于检查以下内容:

  1. UART 接收器是否能识别起始位、数据位、校验位和停止位;
  2. 地址帧协议是否能正确识别66 + 地址 + 命令 + 校验;
  3. 校验正确时是否产生cmd_valid有效脉冲;
  4. LED、蜂鸣器、数码管、电机、点阵等模块是否根据命令切换模式;
  5. LCD1602 与按键菜单逻辑是否能独立产生本地控制命令;
  6. 顶层模块连接是否正确。

ModelSim 仿真通过测试文件 testbench 主动产生时钟、复位和 UART 输入数据,再观察输出信号是否符合预期。

4. 仿真文件结构

工程中通常包含两类文件:

src/ fpga_rs232_top.vhd 顶层模块 uart_rx.vhd UART 接收模块 uart_tx.vhd UART 发送模块 uart_frame_parser.vhd 地址帧解析模块 command_controller.vhd 命令控制模块 led_ctrl.vhd LED 控制模块 buzzer_ctrl.vhd 蜂鸣器控制模块 seg_ctrl.vhd 数码管控制模块 motor_ctrl.vhd 电机控制模块 dot_matrix_ctrl.vhd 点阵控制模块 lcd1602_ctrl.vhd LCD1602 显示模块 key_scan.vhd 矩阵按键扫描模块 sim/ tb_fpga_rs232_top.vhd 顶层仿真文件 run_msim_gui.do ModelSim 自动仿真脚本

其中tb_fpga_rs232_top.vhd不会下载到 FPGA 中,它只用于仿真。真正烧入开发板的是src目录下的设计文件。

5. UART 地址帧协议

5.1 串口字节格式

UART 是异步串行通信方式。空闲时,串口线保持高电平;发送一个字节时,先拉低产生起始位,然后从低位到高位依次发送 8 位数据,再发送校验位,最后发送停止位。

本设计采用 8E1 格式:

1 位起始位 + 8 位数据位 + 1 位偶校验位 + 1 位停止位

也就是:

Start + D0 D1 D2 D3 D4 D5 D6 D7 + Even Parity + Stop

需要注意,UART 的 8 位数据是串行传输的,但接收完成后会在 FPGA 内部形成一个 8 位并行数据rx_data。因此报告中出现“8 位并行数据”并不是说 UART 线上同时传输了 8 根数据线,而是指接收模块完成串并转换后的内部数据。

5.2 地址帧格式

单个 UART 字节只能表示一个数据。为了让通信更可靠,也方便以后扩展多机通信,系统增加了帧头、地址和校验。

本设计使用的帧格式为:

66 ADDR CMD CHECK

例如 LED 跑马灯命令:

66 01 11 10

校验采用异或方式:

CHECK = ADDR xor CMD

所以:

01 xor 11 = 10

接收模块只有在帧头、地址和校验都正确时,才会输出有效命令。这样可以避免串口误码或错误数据直接控制外设。

6. ModelSim 仿真基本流程

6.1 打开 ModelSim

进入工程目录后,可以在 ModelSim 中执行.do脚本,也可以手动创建工程并添加文件。为了减少重复操作,推荐使用脚本方式。

常用脚本示例如下:

vlib work vmap work work vcom ../src/uart_rx.vhd vcom ../src/uart_tx.vhd vcom ../src/uart_frame_parser.vhd vcom ../src/command_controller.vhd vcom ../src/led_ctrl.vhd vcom ../src/buzzer_ctrl.vhd vcom ../src/seg_ctrl.vhd vcom ../src/motor_ctrl.vhd vcom ../src/dot_matrix_ctrl.vhd vcom ../src/fpga_rs232_top.vhd vcom tb_fpga_rs232_top.vhd vsim work.tb_fpga_rs232_top

如果 Transcript 窗口中显示:

Errors: 0

说明语法编译通过,可以继续观察波形。

6.2 添加波形信号

进入仿真后,需要把关键信号加入 Wave 窗口。常见信号如下:

add wave -divider "Clock and Reset" add wave /tb_fpga_rs232_top/clk add wave /tb_fpga_rs232_top/rst_n add wave -divider "UART" add wave /tb_fpga_rs232_top/uart_rxd add wave /tb_fpga_rs232_top/uart_txd add wave /tb_fpga_rs232_top/uut/rx_data add wave /tb_fpga_rs232_top/uut/rx_valid add wave -divider "Frame Parser" add wave /tb_fpga_rs232_top/uut/cmd_data add wave /tb_fpga_rs232_top/uut/cmd_valid add wave /tb_fpga_rs232_top/uut/resp_code add wave -divider "Outputs" add wave /tb_fpga_rs232_top/uut/led_mode add wave /tb_fpga_rs232_top/LedOut add wave /tb_fpga_rs232_top/uut/buzzer_mode add wave /tb_fpga_rs232_top/Bell add wave /tb_fpga_rs232_top/uut/seg_value add wave /tb_fpga_rs232_top/dataout add wave /tb_fpga_rs232_top/en add wave /tb_fpga_rs232_top/uut/dot_mode add wave /tb_fpga_rs232_top/dot_row add wave /tb_fpga_rs232_top/dot_col

添加完成后运行:

run 4 ms

如果仿真时间太短,可能只能看到 UART 接收过程,看不到 LED、蜂鸣器、点阵等慢速模块的明显变化。对于慢速显示模块,可以适当延长仿真时间,或者在 testbench 中使用加速参数。

7. Wave 窗口观察方法

7.1 波形放大与缩小

ModelSim 的 Wave 窗口中,常用观察方法如下:

  • 点击放大镜+:放大当前时间区域;
  • 点击放大镜-:缩小当前时间区域;
  • 点击Zoom Full:显示完整仿真时间;
  • 用鼠标在时间轴上拖选一段区域,再选择Zoom Range;
  • 使用黄色 Cursor 定位某一时刻,观察左侧信号当前值。

UART 的每一位持续时间较短,而 LED 和数码管扫描时间相对较长,所以不能用同一个缩放比例观察所有模块。观察 UART 时要放大到微秒级,观察 LED 或蜂鸣器时可以缩小到毫秒级。

7.2 单独显示 Wave 窗口

ModelSim 默认会把 Source、Objects、Wave 等窗口放在同一个界面中。为了截图更清晰,可以把 Wave 窗口单独显示:

  1. 打开菜单View -> Wave;
  2. 找到下方或中间的Wave标签页;
  3. 拖动 Wave 标签到屏幕空白区域,形成独立窗口;
  4. 或者使用Window -> Tile Vertically将窗口平铺;
  5. 调整左侧变量名区域宽度,保证变量名完整显示。

截图时建议只保留当前模块相关信号,不要把所有信号全部放在一张图里。这样变量名、数值和波形变化都会更清楚。

7.3 设置信号显示进制

总线信号默认可能显示为二进制,也可能显示为十六进制。观察 UART 命令时建议设置为十六进制。

设置方法:

  1. 在 Wave 左侧选中信号;
  2. 右键选择Radix;
  3. UART 数据、命令码选择Hexadecimal;
  4. LED、点阵行列可以选择Binary;
  5. 计数器可以选择Unsigned。

例如:

  • rx_data显示为8'h66、8'h01、8'h11;
  • LedOut显示为3'b001、3'b010;
  • dot_row、dot_col显示为二进制更直观。

8. UART 接收波形分析

UART 接收时,重点观察uart_rxd、rx_data和rx_valid。

当 testbench 发送命令:

66 01 11 10

波形中可以看到uart_rxd先后出现 4 个字节的串行波形。每个字节都包含起始位、8 位数据位、偶校验位和停止位。

接收完成一个字节后:

  • rx_data更新为当前收到的字节;
  • rx_valid产生一个时钟周期的高电平;
  • 帧解析模块继续判断该字节属于帧头、地址、命令还是校验。

图 2 UART 接收 66 01 11 10 地址帧波形

图中需要重点观察:

  • uart_rxd:串口输入线,空闲为高电平;
  • rx_data:接收完成后的 8 位数据;
  • rx_valid:字节接收完成标志;
  • cmd_data:解析出的命令字节;
  • cmd_valid:完整帧校验通过后的命令有效脉冲。

如果只看rx_data,会感觉数据突然变成了8'h66或8'h11。这是正常现象,因为rx_data是串并转换后的结果;真正一位一位传输的过程要看uart_rxd。

9. 地址帧解析波形分析

帧解析模块收到 UART 字节后,会按照状态机依次判断:

等待帧头 -> 接收地址 -> 接收命令 -> 接收校验 -> 输出有效命令

以命令:

66 01 11 10

为例,解析过程如下:

  1. 收到66,认为一帧开始;
  2. 收到地址01,与本机地址一致;
  3. 收到命令11,暂存为待执行命令;
  4. 收到校验10,计算结果正确;
  5. 输出cmd_valid = 1,同时cmd_data = 8'h11。

图 3 地址帧解析与 cmd_valid 输出波形

cmd_valid一般只保持一个系统时钟周期,它的作用是通知后级控制模块:“当前命令有效,可以执行”。
如果校验错误,cmd_valid不会拉高,外设状态也不会变化。

10. LED 控制波形分析

LED 模块根据led_mode选择不同显示方式。常见模式包括跑马灯、流水灯和呼吸灯。

例如发送:

66 01 11 10

解析成功后,led_mode进入对应模式,LedOut开始按照设定节奏变化。


跑马灯模式:

流水灯模式:

呼吸灯模式:

图 4 LED 控制模式与 LedOut 输出波形

观察 LED 波形时需要注意:

  • cmd_valid出现后,led_mode才会更新;
  • LedOut不一定马上快速变化,因为 LED 显示通常经过分频;
  • 如果仿真时间太短,可能只能看到模式切换,看不到完整流水效果;
  • 在仿真中可以缩短 LED 分频计数值,使波形更容易观察。

硬件上 48 MHz 时钟非常快,人眼无法直接分辨每个时钟周期,因此 LED 模块必须使用计数器分频。假设某模式计数到N后移动一次,则流水灯频率约为:

f_led = 48 MHz / N

实际报告中应根据代码里的计数值计算具体频率。

11. 蜂鸣器控制波形分析

无源蜂鸣器不能直接写入一个固定高低电平来播放不同音调,而是需要 FPGA 输出一定频率的方波。不同频率对应不同音高。

蜂鸣器模块一般包含两类功能:

  • 报警模式:输出固定频率的间歇方波;
  • 电子琴模式:根据音符命令输出不同频率的方波。

例如进入电子琴模式后,再发送音符命令:

66 01 22 23 66 01 31 30

其中22表示进入电子琴模式,31表示播放某个音符。

图 5 蜂鸣器模式与 Bell 输出波形

观察时重点看:

  • buzzer_mode是否进入对应模式;
  • Bell是否输出周期性方波;
  • 不同音符命令下,Bell的周期是否发生变化。

频率计算公式为:

f_bell = 48 MHz / (2 × half_period)

其中half_period是蜂鸣器方波半周期计数值。因为一个完整方波包含高电平和低电平两个半周期,所以公式中需要乘以 2。

12. 数码管控制波形分析

四位数码管通常采用动态扫描方式。FPGA 在很短时间内轮流点亮不同位数码管,由于人眼视觉暂留,看起来像四位同时显示。

数码管相关信号一般包括:

  • seg_value:需要显示的数据;
  • dataout:段选信号;
  • en:位选信号。

数码管段码由 a、b、c、d、e、f、g、dp 等段组成。
例如显示数字0时,一般需要点亮 a、b、c、d、e、f,关闭 g;显示数字1时,只需要点亮 b、c。具体高低电平是否取反,要根据开发板原理图判断数码管是共阳还是共阴。

图 6 数码管输出波形
仿真中重点不是看人眼显示效果,而是看:
  1. en是否周期性切换不同位;
  2. dataout是否随当前位显示内容改变;
  3. 输入数字命令后,seg_value是否正确更新。

13. 点阵控制波形分析

8×8 点阵同样采用扫描显示。FPGA 逐行或逐列刷新点阵,通过快速扫描形成完整图案。

点阵相关信号通常包括:

  • dot_mode:点阵显示模式;
  • dot_row:行选择;
  • dot_col:列数据。

图 10 8×8 点阵扫描波形

点阵代码中通常会把图案写成 8 个字节,每个字节对应一行或一列。例如某一行数据为:

00111100

表示该行中间 4 个 LED 点亮,两侧 LED 熄灭。
如果显示爱心、笑脸等图案,本质上就是把每一行的亮灭状态提前写入 ROM 数组,然后由扫描计数器循环输出。

14. 常见波形问题分析

14.1 为什么波形里只看到8'hA1、8'hA3之类的数据?

这些通常是系统返回码,不是乱码。
例如命令执行成功后,发送模块可能返回:

66 01 A1 A0

其中A1表示 LED 命令应答,校验字节仍然由地址和返回码计算得到。

14.2 为什么rx_data看不到每一位变化?

rx_data是接收完成后的并行结果。
如果要看 UART 每一位的传输过程,需要观察uart_rxd;如果要看接收完成后的字节结果,就观察rx_data和rx_valid。

14.3 为什么时钟看起来太密集?

系统时钟为 48 MHz,周期约为:

1 / 48 MHz ≈ 20.83 ns

在毫秒级波形窗口里,时钟当然会密成一整条。
观察 UART 或外设状态时,不需要一直盯着clk,只需要确认时钟存在即可。分析重点应放在rx_valid、cmd_valid、cmd_data和外设输出信号上。

14.4 为什么运行很久 LED 也没明显变化?

原因通常有两个:

  1. LED 分频计数较大,仿真时间不够;
  2. 多条 UART 命令发送间隔太短,模式刚切换又被下一条命令覆盖。

解决方法:

  • 对 LED 单独写 testbench;
  • 在仿真参数中缩短分频计数;
  • 延长命令之间的等待时间;
  • 对目标时间段使用 Wave 缩放观察。

14.5 UART 接收为什么需要很多个时钟?

UART 必须按照波特率采样。
如果系统时钟是 48 MHz,波特率是 9600,则每个 UART bit 需要的系统时钟数约为:

48,000,000 / 9600 = 5000

所以“5000 个时钟”不是额外等待,而是 9600 波特率本身对应的采样周期。
如果波特率改为 115200,则每 bit 约为:

48,000,000 / 115200 ≈ 416.7

因此波特率越高,每个 bit 对应的系统时钟数越少,通信速度也越快。

15. 仿真结论

通过 ModelSim 仿真可以确认:

  1. UART 接收模块能够正确识别起始位、数据位、偶校验位和停止位;
  2. 地址帧协议能够正确解析66 + 地址 + 命令 + 校验;
  3. 校验正确时,系统能够输出cmd_valid有效脉冲;
  4. LED、蜂鸣器、数码管、点阵、电机等模块能够根据命令切换工作状态;
  5. LCD1602 本地菜单模块可以通过按键产生本地控制逻辑;
  6. ModelSim 波形能够在下载开发板前提前暴露时序、协议和模块连接问题。

ModelSim 仿真的重点不是“看到和实物完全一样的效果”,而是通过波形确认每一级逻辑是否按预期工作。对于 UART 这类串行协议,重点观察起始位、数据位、校验位、停止位,以及接收完成后的rx_data和rx_valid;对于外设模块,重点观察模式寄存器和最终输出信号是否正确变化。

后续进入 Quartus 流程时,可以在 ModelSim 仿真通过的基础上继续完成综合、引脚分配、时序检查和 FPGA 下载。

相关新闻

  • Arduino UNO硬件设计原理深度解析:从芯片选型到PCB布局
  • 智搜 GEO 对比传统 SEO、竞价,三大核心优势解析
  • Power BI 视觉对象深度对比:折线图、仪表、切片器等5种核心图表应用场景与性能分析

最新新闻

  • QQ邮箱与163邮箱SMTP服务配置对比:3步获取授权码与5个关键参数详解
  • MSYS2 + MinGW-w64 GCC 13.2.0 配置:Windows VSCode C++20 开发环境一键升级
  • Mendeley 自定义 CSL 文件:从在线编辑到本地加载的 4 个关键步骤与避坑点
  • 梯度下降算法详解:从原理到Python实战实现
  • 【小程序计算机毕业设计案例】移动端医疗挂号查询与预约服务系统的设计与实现 基于小程序的医院就诊流程优化预约系统的设计与实现(程序+文档+讲解+定制)
  • 2026年福建2+2本硕连读/高中澳洲留学直通车,集美大学诚毅学院国际本科招生,低分升学海外名校渠道推荐! - 甄选服务推荐

日新闻

  • AI推荐结果怎么优化:适合深圳少儿素质培训机构的GEO服务商哪家好?全程零代码SAAS操作
  • RAG 实战教学完全指南
  • 企业级API网关架构深度解析:IBM Microgateway的技术实现与选型指南

周新闻

  • IX9104 PCIe5.0 高速交换芯片@ACP#完整规格 + 应用场景总结
  • Unity游戏集成Coze智能体:实现NPC智能对话与知识库联动
  • SAP EPIC 建行回单查询:从标准类CL_EPIC_EXAMPLE_CN_CCB_GHTD到Z类的5处关键修改

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号