我学Verilog语法快一个月了,always块、阻塞非阻塞、reg和wire基本能分清,但感觉还是不会做项目。看网上有人说第一个项目做串口通信能锻炼状态机,有人说做按键消抖加LED控制更简单。我想知道从学习效率角度,哪个项目更能让我理解FPGA的时序概念和状态机设计?大概需要多少行代码?
2026年,FPGA新手想问,学完Verilog语法后,第一个实战项目选串口通信还是按键控制LED?哪个更能理解时序和状态机?
提问
回答 4

说个可能跟主流观点不太一样的建议:先做按键消抖加LED控制。串口通信看上去很『完整』,但新手容易把精力花在调试UART的比特率匹配和起始位停止位上,反而冲淡了对时序和状态机的理解。按键消抖项目虽然小,但你能真正遇到亚稳态(按键信号跨时钟域)、延时计数(消抖时间20ms)、状态跳转(按下/释放/去抖)这些基础但核心的概念。而且它的代码量大概在80~150行,一周左右能调通,成就感来得快。如果一上来就写300~500行的串口模块,中间遇到仿真波形看不懂、上板收不到数据,很容易卡住放弃。另外,你在做按键消抖的时候,可以故意不消抖,看看LED乱闪的样子,直观感受『时序违规』的后果——这种触感是串口给不了的。等按键项目跑通了,再回头做串口发送,你会发现状态机那套思路其实是一样的。追问一句:你手头的开发板是什么型号?不同板子晶振频率和按键电气特性会影响消抖计数的值,这个细节很多人到调不通才意识到。

我的建议是直接上串口,而且只做串口发送,先不管接收。理由很简单:按键消抖本质上是一个有限状态机加上一个计数器,它能教的『时序』概念非常有限——基本就是同步复位、计数器溢出判断这些。但串口发送,哪怕是最简单的8N1格式,你必须在每个比特的中间采样,这就要求你理解波特率时钟的产生(分频计数)、比特位计数、帧结束判断,这些才是FPGA时序设计的真实场景。更关键的是,串口的状态机天然就是『空闲→起始位→数据位0→数据位1→……→停止位→空闲』这种循环跳转,你写出来的状态图几乎和协议波形图一模一样,学完立刻能看懂大部分通信协议的状态机写法。代码量方面,纯发送模块大约200行,你花两周啃下来,之后看I2C、SPI、甚至DDR的状态机都不会觉得陌生。有一个常见误区是觉得串口『复杂』,其实它只是步骤多,每一步的逻辑都很简单,你把它拆成波特率生成、数据移位、状态机三个always块,每个块单独仿真,调试难度比按键消抖高不了太多。而且,做完串口之后,你再回头看按键消抖,会发现它那个状态机其实是一个简化版的『通信协议』——按下是起始位,释放是停止位,消抖时间就是位宽。两个项目本质相通,只是串口让你站在更高的抽象层理解这个道理。如果时间特别紧,可以只写发送,接收先抄别人的模块直接用,重点学发送那部分的设计思路。

先别急着选项目,先问自己一个问题:你手上有仿真工具吗?如果只有开发板没有仿真,那我强烈建议你从按键消抖做起。理由很简单,串口通信一旦波特率不对、起始位没对齐,上板后你看到的全是乱码,但你看不到内部状态机到底跳到了哪个状态——没有仿真波形,你只能靠猜。按键消抖就不一样,你按下按键,LED亮灭变化是肉眼可见的,调试反馈几乎是即时的。就算没有仿真,你也能通过改变消抖计数器阈值(比如从20ms改到10ms),观察LED闪烁行为的变化,反向理解'计数器延时'这个概念。代码量方面消抖项目大概120~150行,一周能跑通。串口项目如果纯发送模块大概250~300行,但调试周期可能拖到三周以上,而且中间有一半时间在跟串口调试助手较劲。你现在的阶段,需要的是'能跑通'的成就感来建立信心,而不是被协议细节卡到怀疑人生。还有一个替代做法:先做按键消抖,然后在这个项目的基础上,把'按键按下时LED亮'改成'按键按下时LED以1Hz频率闪烁',这样你就自然引入了分频计数的概念,等于用同一个板子把时序的两个核心都练到了。追问一句:你平时写代码会用仿真吗?还是直接烧录上板试?

直接上串口发送模块,只做发送,不管接收。给你一个具体的理由:按键消抖虽然能练到计数器,但它练不到'比特级时序对齐'这个FPGA最核心的能力。你写串口发送,本质上是在用主时钟去拼凑一个9600bps的波特率时钟,你必须在每个比特的中点采样或驱动——这意味着你不仅要会写计数器,还要理解什么时候该让计数器归零、什么时候该改变状态、什么时候该拉高或拉低数据线。这些判断条件组合起来,就是最标准的状态机:空闲状态等待触发,进入起始位状态计数半个比特时间,然后每计满一个完整比特时间就切到下一个数据位状态,直到停止位状态结束回到空闲。这个状态图你画出来,几乎和课本里的UART时序图一模一样。很多新手觉得串口'复杂',其实它只是步骤多,每一步的逻辑都很简单——你花两周啃下这个模块,之后看I2C、SPI甚至DDR的状态机,会发现骨架都是同一套东西,只是节拍数和数据宽度不同。代码量方面,纯发送模块大概200行出头,你完全可以分三步走:第一步只写一个固定的波特率发生器,用示波器或者LED验证分频是否准确;第二步写一个简单的状态机,把起始位和停止位驱动出来,暂时不管数据位;第三步再把8个数据位塞进去。每步都能独立仿真验证,不会一上来就被300行代码吓住。有一个容易被忽略的点:串口发送的调试工具链很成熟,你用仿真软件看波形,或者用逻辑分析仪抓板子上的TX脚,都能清晰看到你写的状态机是否正确切换。相比之下,按键消抖的'调好了看起来正常,调坏了也看起来正常'的模糊反馈,反而容易让你养成'差不多就行'的习惯。你学Verilog一个月,正是建立'时序必须精确到每个时钟周期'这个认知的关键期,别绕远路。建议你去搜一下'FPGA UART 8N1 状态机 代码'这类关键词,找一份不超过250行的开源代码,逐行读通后自己重写一遍,不要复制粘贴。如果你手头有逻辑分析仪或者带逻辑分析功能的示波器,调试效率会高很多——你平时用什么工具抓波形?
发表回答
登录后可在本页底部提交回答
