简介:这份基于FPGA的FSK调制解调设计报告,面向电子信息工程、通信工程专业的本科生及FPGA初学者,对应课程设计、实验报告与数字通信入门学习场景,围绕频移键控这一经典数字调制技术,解决从原理理解到VHDL代码落地、仿真验证的完整链路问题。资源为单个PDF文件,压缩包约936KB,内容涵盖FSK调制与解调的基本原理推导、Quartus II平台下的VHDL程序实现、调制与解调仿真测试及结论分析,并给出载频f1=12.5MHz、f2=2MHz、调制信号1MHz的具体参数设计与测试结果。报告从绪论、设计要求、设计方案到测试与参考文献逐章展开,配有摘要与中英文对照,便于直接参照撰写课设文档或复现实验。目前已有140人学习,适合需要一份结构完整、参数明确的FSK调制解调参考范例的读者。
1. 为什么一个 12.5MHz 载频的 FSK 要用 FPGA 来做
很多人第一次看到“FPGA 实现 FSK”会觉得绕远路:一个 555 加几个门电路就能搞定频率切换,何必上可编程逻辑。但真正做过移频通信或远程自控设备的人知道,难点从来不在“产生两个频率”,而在于频率切换点是否干净、码元边界是否对齐、解调判决门限是否随信道漂移。这个课程设计给出的参数很具体:载频 f1=12.5MHz、f2=2MHz,调制信号 1MHz,用 Quartus II 加 VHDL 在 FPGA 上跑通调制与解调。它解决的正是“用可综合的逻辑替代一堆定功能集成块加连线”的问题,适合正在做 EDA 课程设计、想搞懂数字调制到底怎么落到寄存器和计数器上的人。下面按调制原理、VHDL 实现、波形验证、工程化调试逐层拆开。
2. 频率键控法的选型依据与 FSK 调制原理
2.1 直接调频与频率键控法到底差在哪
FSK 的本质是让数字基带信号去控制载波频率。二进制情况下,“1”对应一个载频,“0”对应另一个,而振幅和初相不变。产生方式有两种,选哪种直接决定后面 RTL 怎么写。
直接调频法是拿基带矩形脉冲去调制一个调频器,正电平时改变振荡器谐振回路的电容或电感,把频率抬高到 f1,负电平时降下来。这条路产生的信号相位连续,实现简单,但频率稳定度差,频率切换速度上不去,在 FPGA 里也不太好用纯逻辑表达——你没法“调”一个 LC 回路。
频率键控法也叫频率选择法,用两个独立振荡器分别产生 f1 和 f2,基带信号控制一个二选一开关去选通。它的频率稳定度可以做得非常高,转换速度快,波形好。代价是切换瞬间两路输出电压通常不相等,uFSK(t) 在码元变换处会发生电压跳变,也就是相位不连续。
在这个设计里选的是频率键控法,原因有几个:一是 FPGA 里两个载波就是两个分频计数器,天然就是“两个独立振荡源”;二是系统不需要载波恢复,省掉复杂度;三是 FSK 是恒包络信号,信息全在过零点上,对幅度非线性失真抗性比 ASK 强。
| 对比项 | 直接调频法 | 频率键控法 |
|---|---|---|
| 实现载体 | 调频器、LC 回路 | 双分频器 + 二选一开关 |
| 相位连续性 | 连续 | 切换点不连续 |
| 频率稳定度 | 一般 | 高(取决于参考时钟) |
| 转换速度 | 受调频器限制 | 快 |
| FPGA 适配度 | 差 | 好 |
注意:相位不连续是频率键控法固有的,不是 bug。做频谱分析时会看到旁瓣,这是正常现象。
2.2 调制方框图落到逻辑上是什么
设计里的调制方框图是这样的:clk 和 start 进来,FPGA 内部一分为二,一个分频器产生载波 f1,另一个产生载波 f2,两路载波再进一个二选一选通开关,由基带信号 X 控制,输出调制信号 Y。
把它翻译成寄存器级的语言就更清楚了:
- 有一个系统时钟 CLK,所有分频都从它来。
- 分频器 1 用一个整数计数器累加,计到某个值翻转,得到 f1。
- 分频器 2 同理,用另一个计数器得到 f2。
- 选通开关在 CLK 上升沿判断 X:X=0 就把 F1 送到 Y,X=1 就把 F2 送到 Y。
关键点在于“改变计数器上限就能改变频率和占空比”。原文注释里写得很直白:改变 Q1 的阈值可以改变载波 F1 的占空比。这意味着频率参数不是焊死的,改一行代码就能重配置,这正是 FPGA 相对定功能集成块的核心价值,也是这个方案能拿去做不同频段设备的基础。占空比一般取接近 50%,过窄会让后级滤波和检波更难做。
3. 基于 VHDL 的 FSK 调制与解调程序实现
3.1 FSKTZ 调制模块的计数器分频写法
调制模块实体只有一个时钟、一个 start、一个基带输入 X 和一个调制输出 Y。里面用两个 process 分别产生 F1、F2,第三个 process 做选通。先看两个分频器的核心结构:
-- 载波 F1 的生成:Q1 从 0 数到 11,前 6 个时钟为高 PROCESS(CLK) BEGIN IF (CLK'EVENT AND CLK='1') THEN IF START='0' THEN Q1 <= 0; ELSIF Q1 <= 5 THEN F1 <= '1'; Q1 <= Q1 + 1; -- 高电平区间,决定占空比 ELSIF Q1 = 11 THEN F1 <= '0'; Q1 <= 0; -- 一个周期结束,计数器回零 ELSE F1 <= '0'; Q1 <= Q1 + 1; -- 低电平区间 END IF; END IF; END PROCESS;逻辑说明:这是一个模 12 的计数器,一个完整周期是 12 个 CLK。前 6 个时钟 F1 为高,后 6 个为低,所以占空比接近 50%,输出频率是 CLK/12。要改 F1,改计数上限 11 这个数;要调占空比,改 Q1<=5 这个比较值。
F2 那一路更短:
PROCESS(CLK) BEGIN IF (CLK'EVENT AND CLK='1') THEN IF START='0' THEN Q2 <= 0; ELSIF Q2 = 1 THEN F2 <= '0'; Q2 <= 0; -- 两拍一个周期 ELSIF Q2 <= 0 THEN F2 <= '1'; Q2 <= Q2 + 1; ELSE F2 <= '0'; Q2 <= Q2 + 1; END IF; END IF; END PROCESS;模 2 计数器,输出频率是 CLK/2,明显高于 F1。结合 f1=12.5MHz、f2=2MHz 的指标看,两路分频比刚好对应两个数量级的差距,基带 1MHz 则高于 f1,实际工程里会通过调整分频系数把各频率对齐到同一时钟源能整除的关系上。
参数速查:
| 信号 | 计数器 | 周期 | 可调项 |
|---|---|---|---|
| F1 | Q1 0~11 | 12 个 CLK | 上限改频率,比较值改占空比 |
| F2 | Q2 0~1 | 2 个 CLK | 上限改频率 |
| Y | 选通 | 跟随 X | 由 X 电平决定输出哪路 |
选通进程只有三行含义:在 CLK 上升沿,X=0 输出 F1,X=1 输出 F2。这一步完成了对基带信号的 FSK 调制,也是“1 对应 f1、0 对应 f2”这条规则在代码里的落点。
3.2 FSKJT 解调模块怎么靠计数判决出 0 和 1
解调模块的输入 X 就是调制模块的输出 Y 接过来,输出 Y 还原成基带。它没有用带通滤波器加包络检波那套模拟解调流程,而是用了一个很“数字”的思路:数一个固定窗口内 X 的脉冲个数,用数量多少来判频率高低。
-- 用时钟在 X 的上升沿采样,统计窗口内的脉冲数 PROCESS(CLK) BEGIN IF (CLK'EVENT AND CLK='1') THEN XX <= X; -- 同步一拍,降低亚稳态风险 IF START='0' THEN Q <= 0; ELSIF Q = 11 THEN Q <= 0; -- 模 12 观测窗口 ELSE Q <= Q + 1; END IF; END IF; END PROCESS; PROCESS(XX, Q) BEGIN IF Q = 11 THEN M <= 0; -- 窗口结束,M 清零,准备下一个码元 ELSIF Q = 10 THEN -- 窗口结束前一拍做判决 IF M <= 3 THEN Y <= '0'; -- 脉冲少说明频率低,判为 0 ELSE Y <= '1'; -- 脉冲多说明频率高,判为 1 END IF; ELSIF XX'EVENT AND XX='1' THEN M <= M + 1; -- 每个 X 上升沿计数加一 END IF; END PROCESS;逻辑说明:第一个进程把异步输入的 X 打一拍得到 XX,这是跨时钟域处理里最基本的同步手段。同时 Q 在 0~11 之间循环,构成一个观测窗口。第二个进程在一个窗口内统计 XX 的上升沿个数 M,窗口末拍根据 M 的大小判决输出。
这里最关键的参数是 M<=3 这个判决阈值。它必须卡在“一个码元周期内 F1 应产生的脉冲数”和“F2 应产生的脉冲数”之间,取中间偏安全的位置。阈值设太高,慢频率也会误判成 1;设太低,快频率会漏判成 0。Q 的窗口长度也要和基带码元宽度对齐,窗口比码元宽会跨码元误计,比码元窄会统计不足。
提示:M 的复位放在 Q=11,判决放在 Q=10,是刻意的顺序——先判决再清零,避免把当前窗口的最后一个脉冲丢掉。
4. Quartus II 波形仿真与 RTL 电路验证
4.1 调制波形的仿真设置步骤
编译通过不代表逻辑对,必须跑时序仿真。原文给的调制测试序列是 [1 1 0 1 0 0 1 0 1 1 0 0 1],码元宽度 480ns。整个流程是建立波形文件、输入节点、设参数、编辑激励、存盘、跑仿真。
具体操作:
- File → New → Other Files → Vector Waveform File,新建 vwf 文件。
- Edit → End Time 填 6,单位选 us;Gride Size 的 Time period 填 40ns,确定时间基准。
- View → Utility Windows → Node Finder,Filter 选 Pins:all & Registers:Post-fitting,点 List。
- 把 clk、start、x、q1、f1、q2、f2、y 拖进波形窗口。
- clk 右键 Value → Count Value,设成连续二进制,初值 0;start 右键 Forcing High 拉高;x 用 Waveform Editing 画成高低变化序列。
- File → Save as,存成 FSKTZ.vwf。
- Processing → Start Simulation,等待 Simulation was successful。
仿真时间 6us 不是随便定的。码元宽度 480ns、序列 13 位,总时长约 6.24us,设成 6us 能在窗口里看到完整的码元切换过程,又不会因为时间轴太长把细节压扁。40ns 的时间轴周期则决定采样密度,太粗会看不出频率细节。
注意:Quartus II 里波形编辑文件(*.vwf)和仿真报告(Simulation Report)是两个文件,和早期 Maxplus II 二合一的方式不一样,别找不到结果。
4.2 解调仿真与 RTL Viewer 看电路
解调仿真的做法和调制几乎一样,区别在于输入 X 要用调制的输出波形,节点换成 clk、start、x、y、q、m、xx,工程是 PL_FSK2,波形存成 FSKJT.vwf。要盯的重点是 y 的翻转时刻是否落在码元边界上,以及 m 在窗口末尾的计数值是否和该码元频率对得上。
电路层面,Quartus II 能把 VHDL 或网表文件(VHDL、Verilog、BDF、TDF、EDIF、VQM)反推成 RTL 电路图。Tools → RTL Viewer 打开,双击模块或点左侧各项可以逐层看结构。调制工程 FSKTZ 里应该能看到两个计数器和一级二选一;解调工程 PL_FSK2 里能看到计数器、比较器和判决逻辑。
用 RTL Viewer 排查问题很有效:
- 计数器没综合出来,多半是复位分支写法让工具把它优化掉了。
- 二选一被综合成一大坨组合逻辑,说明选通进程里混进了非时钟敏感信号。
- 想确认综合后到底剩多少触发器,直接看资源报告比读代码快。
5. 从仿真通过到可用的几个调试技巧
仿真波形对得上,只说明逻辑在理想时钟下成立。真要让这套 FSK 调制解调可用,几个容易翻车的地方得提前堵住。
第一个是判决阈值的标定。M<=3 是仿真里凑出来的值,实际频率一旦变化就必须重算。稳妥的做法是仿真时把 m 的波形拉出来,分别看一段纯 f1 和纯 f2 码元内 m 分别稳定在什么数值区间,阈值取两个区间的中点。这一步比反复改代码试要快得多。
第二个是输入同步。解调端的 X 是外部来的,直接拿去数上升沿会有亚稳态风险,所以代码里用 XX<=X 打一拍。如果时钟和码元速率相差不大,一拍不够,常见做法是串两级寄存器,或者干脆用一个过采样时钟。
第三个是频率余量。基带 1MHz 高于载频 f1=12.5MHz 这组参数在逻辑上可以跑通,但实际系统里基带频率必须远低于载频,否则一个码元周期内载波只振几个周期,解调端根本数不出稳定脉冲数。做参数规划时,先保证“每个码元内至少十几个载波周期”这条经验线。
第四个是资源与时钟约束。两路分频器都是模值很小的计数器,逻辑资源占用极低,真正的瓶颈在时钟质量和后级接口。用 TimeQuest 或综合报告确认分频器输出没有意外毛刺,再把输出的 Y 引出到测试引脚用示波器看眼图,比盯着仿真截图靠谱。
| 现象 | 可能原因 | 处理方向 |
|---|---|---|
| 解调输出全是 1 | 判决阈值偏低 | 拉出 m 波形重新标定 |
| 码元边界抖动 | 窗口与码元未对齐 | 调整 Q 的模值 |
| 切换处毛刺 | 相位不连续 + 组合路径过长 | 输出加一拍寄存 |
| 资源超预期 | 计数器被误综合成移位结构 | 检查复位与计数写法 |
有一点值得强调:这套设计的价值不在于“能跑仿真”,而在于它把数字调制的参数全都变成了可改的常数。占空比、两路载频、判决阈值、观测窗口长度,全都在代码里明明白白地摆着,改一个数就能试一组新参数。把每个参数和它对应的物理量对应清楚,才算真正吃透了 FSK 在 FPGA 上的实现。
本文还有配套的精品资源,点击获取