资讯动态

FPGA豆浆机面板设计:状态机、按键消抖与数码管扫描实战

发布时间:2026/9/8 3:33:54 来源:尧图企业网站定制
简介FPGA豆浆机面板设计课程设计工程包面向正在完成FPGA/Verilog课程设计的高校学生解决豆浆机控制器中按键选择五谷、湿豆、干豆、果汁、米糊玉米汁六档功能LED状态显示电机与加热器工作模拟温度传感器实时监测以及防溢出、防干烧蜂鸣报警等设计难题。整个工程共188个文件压缩包大小约4.51MB包含Verilog源码中的控制模块与显示模块、Quartus工程与引脚约束、编译后的SOF/POF烧录文件以及VWF仿真激励与波形记录、设计说明文档等可支撑从编码设计到综合实现与下载验证的完整流程。已有811人学习下载特别适合需要完整参考豆浆机面板状态机设计或用较少时间理解项目结构的读者。包内文件按工程目录组织附有工程备份与写好的设计文档拿来稍作调整便可作为课设报告素材也便于在此基础上扩展功能或移植到其他FPGA开发板。 拿到“豆浆机面板设计”这个课设题目的时候我第一反应是这不就是个状态机加数码管展示嘛。真正把需求拆开、把代码写完、再在板子上把每个按键和显示都调到不“抽风”之后才发现这类面板设计的坑全藏在细节里。这篇文章就把我完整的设计思路、模块划分、状态机实现和上板调试经验整理出来给正在做同类题目的同学作个参考。1. 拿到课题之后先别急着打开Vivado很多同学一看到“豆浆机面板”几个字想到的就是数码管显示、几个按键、蜂鸣器然后直接开始写代码。我建议先把需求从头到尾捋一遍把“面板”最核心的工作模式搞清楚再动手写RTL。1.1 一张面板背后隐藏的信号列表豆浆机面板作为课设核心要模拟的是这几个动作待机状态数码管可以显示待机提示比如全灭或显示横杠。模式选择至少支持2~3种工作模式比如“干豆”“湿豆”“米糊”每种模式对应的总时长不同。启动/暂停/取消这是典型的按键输入涉及消抖、单次触发和状态机的暂停恢复。阶段指示加热、打磨、煮沸、保温等阶段要用LED或者数码管段位体现出来。倒计时显示数码管显示剩余时间或当前阶段倒计时这是面板最直观的输出。完成提示蜂鸣器响若干声数码管显示“End”或“00”。实际操作经验开发板上的LED数量往往有限而面板阶段指示需要至少4~5个状态灯。我的建议是用数码管第一位显示模式编号后两位显示倒计时用2颗LED分别表示“加热/打磨”和“煮沸/保温”实在不够就用数码管的小数点来扩展指示位。合理分配引脚资源是课设里容易被低估的一环。1.2 顶层架构几个子模块各管一摊把豆浆机面板拆开后顶层模块需要例化5个功能模块按键消抖模块处理启动、模式、取消等按键信号输出干净的按键脉冲。状态机控制模块整个设计的核心负责工作流程的切换、阶段计时和暂停逻辑。定时器模块为每个阶段提供精确的倒计时或者直接放在状态机内实现。数码管显示模块动态扫描刷新把模式号和剩余时间显示出来。蜂鸣器驱动模块完成提示音和按键反馈音。信号设计上顶层只用6个按键、8个数码管段选信号、4~6个位选信号、2颗LED和一个蜂鸣器输出。这样接线也方便综合实现时也不容易出现引脚冲突。2. 状态机的设计是整个项目的灵魂豆浆机面板的本质是一个多阶段流程控制器想清楚状态怎么流转代码只是体力活。如果一上来就写always块很容易把流程写死在两三个if-else里后面加模式或者加阶段就会非常痛苦。2.1 状态定义与编码选择我把工作流程设计成这样一个链路待机 → 模式选择 → 加热 → 打磨 → 煮沸 → 保温 → 完成后面实际编码时又把加热拆成“加热到工作温度”和“持续加热”打磨阶段又做了电机间歇转停的模拟。最终的状态列表如下状态编码说明IDLE5‘b00000待机等待按键MODE_SEL5’b00001模式选择显示当前模式编号HEAT_PRE5‘b00010预热阶段加热管工作GRIND5’b00011打磨阶段电机间歇运行BOIL5‘b00100煮沸阶段继续加热KEEP_WARM5’b00101保温阶段间歇加热维持温度FINISH5‘b00110完成等待取消/重新启动编码选择这里有个经验课设规模用二进制编码最省寄存器但如果状态比较多或者后续要做时序分析独热码one-hot查找组合逻辑更简单也不会产生竞争风险。我这版用二进制编码因为模块不大但状态跳转条件写得极其清晰。答辩时候老师大概率会问“为什么用这种编码”提前把两种编码的优缺点想明白比背代码有价值得多。2.2 三段式状态机的写法要点很多人在课设里用一段式状态机也就是把状态转移、输出、状态寄存全部放在一个always块里。我推荐三段式// 第一段状态寄存 always (posedge clk or negedge rst_n) begin if (!rst_n) cur_state IDLE; else cur_state next_state; end // 第二段组合逻辑判断下一状态 always (*) begin case (cur_state) IDLE: begin if (key_mode_pulse) next_state MODE_SEL; else if (key_start_pulse) next_state HEAT_PRE; else next_state IDLE; end // ... endcase end // 第三段时序逻辑输出状态相关信号 always (posedge clk or negedge rst_n) begin if (!rst_n) // 初始化所有输出 else begin // 根据 cur_state 给 LED、数码管、蜂鸣器赋值 end end三段式的优势在于组合逻辑与时序逻辑分离仿真调试的时候能直接看到“next_state”的跳转意图不会把时序问题全部混在一起。而且第三段输出用的是cur_state不会产生组合逻辑毛刺。这是面试和答辩时的一个加分点。2.3 阶段计时与模式切换的衔接阶段计时主要依靠计数器完成。我的开发板时钟是50MHz在状态机内部每次进入一个阶段时加载该阶段的时钟周期数每过一个时钟周期减1。这里有个大坑计数器位宽。豆浆机的加热阶段动辄几十秒用20位的计数器才够50MHz下20位可以数到约1048576个周期约21ms。但显示倒计时需要“秒”这个单位所以我单独做了一个1Hz的时钟使能信号秒数用10位二进制表示。具体做法是先用分频器产生一个clk_1k用于按键消抖和数码管扫描。在状态机内用一个计数器对clk_1k再计数1000次产生tick_1s。状态机内的阶段剩余秒数在tick_1s有效时减1同时送到数码管显示。这样逻辑清晰做仿真验证时也可以把分频参数改小比如让tick_1s快100倍立刻就能看出状态是否按预期跳转。3. 按键消抖和数码管扫描面板交互最容易翻车的地方这两块不属于核心逻辑但课设的大部分调试时间都花在这上面。按键没消抖会一次按出好几个模式数码管扫描时序不对会显示闪烁或者亮度不均。下面说说我在实际工程里的处理办法。3.1 按键消抖的工程做法机械按键按下和松开的瞬间电平会有10~20ms的抖动期。如果在抖动期采集信号状态机会把一次按键识别成多次。我用的消抖方法是经典的“延时确认”reg [19:0] cnt_key; reg key_flag; always (posedge clk or negedge rst_n) begin if (!rst_n) begin cnt_key 0; key_flag 0; end else if (key_in 1b0) begin // 按键按下为低电平 if (cnt_key 20d150000) cnt_key cnt_key 1b1; else key_flag 1b1; // 稳定按下超过3ms认为有效 end else begin cnt_key 0; key_flag 0; end end这里以50MHz时钟为例计数150000个周期是3ms实测足够滤除大部分抖动。要注意的是输出给状态机的不是电平而是单周期脉冲key_pulse否则状态机会一直处于跳转条件中。assign key_pulse key_flag (key_in 1b1); // 或者用打拍的方式在按键释放时产生脉冲防止连按放连按的细节如果按住不放这个设计会反复触发。我在实际项目里加了“仅在按下时产生一个脉冲松开后不允许再次触发”的逻辑也就是在key_flag1之后不再置位直到检测到松开后再重新使能。这个细节在演示时特别重要——演示老师按住按键多看了两秒结果模式飞速切换很尴尬。3.2 动态扫描的刷新时序面板上有3位数码管要显示模式号两位秒数如果每一位单独接一套段选信号IO不够用。动态扫描的原理是轮流点亮3位利用视觉暂留让人感觉3位同时在亮。我设计的扫描逻辑用clk_1k做扫描基准分给每位数码管约333Hz的刷新率。每位数码管亮的时间约1ms3位一轮约3ms完全看不出闪烁。在切换位选之前先让段选端口全部输出0消隐避免前一位的残影串到后一位。always (posedge clk_1k or negedge rst_n) begin if (!rst_n) begin seg_out 8b0; sel_out 4b1110; // 选中第一位 end else begin case (sel_out) 4b1110: begin seg_out seg_data[7:0]; sel_out 4b1101; end 4b1101: begin seg_out seg_data[15:8]; sel_out 4b1011; end 4b1011: begin seg_out seg_data[23:16]; sel_out 4b1110; end default: sel_out 4b1110; endcase end end注意这里切换的瞬间要先把seg_out清零即在下一次位选打开之前插入一两个时钟周期的空段码。我第一次写扫描代码时没加消隐数字显示带有轻微拖影虽然不影响功能但答辩时老师盯着看就会减分。4. 仿真验证把时间压缩到毫秒级跑通全流程仿真不是“写完了再跑一下看看”而是应该在每个模块完成后单独仿真最后再把顶层拉起来做整体验证。这里说说我在做豆浆机面板仿真时的几个实用做法。4.1 搭建顶层testbench的技巧顶层testbench的骨架很简单例化DUT、产生时钟和复位、模拟按键输入。关键在于如何缩短时间参数。正常的课设代码里加热阶段是60秒煮沸是30秒如果直接在仿真器里等90秒的虚拟时间虽然也跑得完但波形繁琐且看不到关键跳转边界。我的做法是把分频参数和阶段时长都定义成parameterparameter HEAT_TIME 60; // 秒 parameter BOIL_TIME 30;testbench里直接给DUT传一个小的参数或者在编译时用defparam覆盖。这样仿真时HEAT_TIME3、BOIL_TIME2几十个时钟周期就能看到完整状态回圈。还有一个小技巧testbench里产生按键脉冲要模拟真实按键的抖动。也就是让按键信号在10ms内反复跳变几下再稳定到低电平。这样仿真出来的波形才真正验证了消抖逻辑而不是直接用理想的脉冲信号绕过消抖模块。4.2 波形里最值得关注的几条信号跑完整仿真后重点看这几条信号cur_state是否按预期在IDLE→MODE_SEL→HEAT_PRE→GRIND→BOIL→KEEP_WARM→FINISH之间流转。cnt_1s和tick_1s秒脉冲是否精确倒计时数值是否单调递减。key_pulse按键在抖动下是否只产生一个脉冲。seg_out和sel_out切换位选时有没有消隐会不会出现串位显示。我当时在仿真中抓到一个很隐蔽的问题在加热阶段结束后直接跳到打磨阶段打磨阶段的第一秒显示总时长时最低位会丢失一个计数原因是计时器的同步复位和状态跳转发生在同一个时钟沿。解决办法是把计数器的清零放在进入新状态的第一个周期而不是状态跳转沿。这个微妙的时序问题不跑完整仿真很难发现。5. 上板调试我实际踩过的三个坑仿真全绿上来板子总会有问题。这是FPGA课设的常规节奏。下面这三个坑是我做豆浆机面板时真实遇到的每一个都花了不少时间排查写出来给各位省点劲。5.1 状态机复位后乱跳上电后我没有手动按复位键面板数码管就开始乱闪LED状态乱跳。排查后发现是复位引脚悬空导致FPGA内部上电后的复位状态不确定。更隐蔽的原因是我在顶层例化状态机时用了异步复位但开发板上的全局复位按键和某些信号存在竞争复位释放瞬间状态机采样到了非IDLE状态。解决方法有两个把复位改成“异步复位、同步释放”或者干脆在上电后用一个计数器自动产生几百毫秒的复位脉冲保证初始状态稳。状态机的第二段组合逻辑里一定要写default: next_state IDLE;防止未定义状态挂死。这个问题提醒我一个原则任何状态机都必须在编译时能回到初始状态。这也是答辩时的经典问题务必实现好。5.2 数码管亮度不均跟“鬼影”实际显示时第一位明显比后两位亮第二位还隐隐能看到旁边数字的影子。原因分析每一位点亮时间如果不完全相等亮度就不平衡。位选信号切换和段选信号切换同时发生时前一位的段码泄漏到后一位。修复方案统一扫描周期让每一位的导通时间都是1ms占空比完全一致。在段选切换后、位选打开前插入至少1个时钟周期的消隐时间让泄漏的电荷释放干净。另外扫描基频不要低于500Hz否则人眼能感知到闪烁。这个在拍照演示时特别明显——相机拍出来的照片上数码管是半暗的非常难看。5.3 蜂鸣器响个不停蜂鸣器在完成阶段应该响短暂几声但实际运行时持续发出微弱的声音即使状态已经回到IDLE也没完全停止。后来发现是蜂鸣器驱动信号和LED驱动信号共用了同一个计数器但是蜂鸣器模块的时钟域不同产生了频率极低的振荡信号。修法也简单蜂鸣器只响应FINISH状态的连续N个tick_1s脉冲其他状态强制输出静音电平。这里一个通用经验输出到外部器件的信号尽量在顶层模块里加一级寄存器输出不要直接把内部组合逻辑信号引出到引脚。这样既能避免毛刺也方便后面加约束和查看波形。所有外部输出统一打一拍抗干扰效果立竿见影。6. 补充报告和答辩中需要准备的两个扩展点课设不只是代码报告和答辩占的分数往往不低。这里提两个方向准备一下会非常加分。6.1 状态机编码方式对比的说明答辩老师如果问“为什么不用独热码”可以这样回答豆浆机面板的状态数量不到8个二进制编码用的寄存器最少独热码虽能减少组合逻辑级数但在小规模设计里优势不明显。同时再说明自己用三段式写法输出不产生毛刺这就能体现对数字电路设计有一定理解。6.2 扩展思路加温度传感器或PWM调速如果课设要求“创新点”可以考虑在面板中加入一个温度状态显示比如用一个ADC读取电位器模拟温度传感器数码管第二行显示温度。或者用PWM模拟加热管功率调节打磨阶段输出不同占空比的PWM。这些扩展改动不大但会让整个设计从“固定流程演示”变成“带闭环控制逻辑的系统”性价比非常高。我个人实际做完这版豆浆机面板设计之后最大的体会是课设题目越小越值得把细节做扎实。状态机怎么拆分、按键怎么消抖、数码管怎么扫描每一个点拿出来都能写几千字但真正把它们组合在一起不打架考验的才是工程思维。上面这些都是我踩过坑之后总结下来的希望可以帮大家少走点弯路。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价