从单片机转FPGA:我用一个交通灯项目搞懂了‘并行’和‘时钟’到底咋回事
从单片机转FPGA我用一个交通灯项目搞懂了‘并行’和‘时钟’到底咋回事第一次用Verilog写交通灯控制器时我盯着仿真波形发呆了半小时——为什么所有always块都在同时工作这和STM32里一行行执行的C语言完全不同。直到数码管突然亮起倒计时才真正理解FPGA的并行世界与单片机顺序执行的本质差异。1. 思维转换从顺序执行到硬件并行单片机开发者常陷入代码即指令的思维定式。在STM32中我们这样实现交通灯倒计时while(1) { red_light ON; countdown(10); red_light OFF; yellow_light ON; // ... 后续代码 }而在Verilog中所有always块都是并行执行的硬件电路描述。当我写下这样的代码时三个状态机实际上在同步运行always (posedge clk) begin // 状态机1 case(current_state) RED: if(timer0) next_state YELLOW; // ...其他状态转换 endcase end always (posedge clk) begin // 状态机2 if(current_state RED) timer timer - 1; end always (*) begin // 组合逻辑 rgb_led (current_state RED) ? 3b100 : (current_state YELLOW) ? 3b010 : 3b001; end关键差异对比特性单片机实现FPGA实现执行方式顺序执行并行执行时间控制依赖延时函数靠时钟边沿触发状态保持变量存储当前值触发器寄存当前状态外设驱动调用库函数直接操作硬件引脚2. 时钟时序逻辑的心跳机制在调试时我曾错误地将数码管显示写成always (*) begin // 错误示范 seg_data counter_value; end结果数码管显示乱码——因为没有时钟同步组合逻辑持续变化导致显示不稳定。正确的做法是always (posedge clk_1khz) begin // 每1ms刷新一次 case(display_pos) 0: begin seg_data time_remaining[3:0]; dig_sel 4b1110; end 1: begin seg_data time_remaining[7:4]; dig_sel 4b1101; end // ...其他位选 endcase end时钟设计要点主时钟如50MHz需分频得到不同频率的时钟域跨时钟域信号需要同步处理动态扫描频率建议在100Hz-1kHz之间避免闪烁注意非阻塞赋值()是保证时序逻辑正确的关键它模拟了硬件触发器在时钟边沿同时更新的特性3. 状态机设计交通灯的核心逻辑交通灯控制器本质是一个Moore型状态机。我的最终设计包含这些状态localparam S_RED 3d0; localparam S_YELLOW 3d1; localparam S_GREEN 3d2; localparam S_FLASH 3d3; reg [2:0] current_state, next_state; // 状态转移逻辑 always (posedge clk or negedge rst_n) begin if(!rst_n) current_state S_RED; else current_state next_state; end // 次态逻辑 always (*) begin case(current_state) S_RED: next_state (timer0) ? S_YELLOW : S_RED; S_YELLOW: next_state (timer0) ? S_GREEN : S_YELLOW; // ...其他状态转移 endcase end状态机实现技巧明确状态编码二进制/独热码分离现态寄存器和次态组合逻辑每个状态对应明确的输出添加安全状态如异常时返回RED4. 调试经验从仿真到实物当代码下载到MAXII CPLD后遇到三个典型问题数码管显示暗淡原因位选信号驱动能力不足解决增加74HC245缓冲驱动倒计时速度异常// 错误的分频计算 localparam DIV_1S 50_000_000; // 实际应为50M-1修正localparam DIV_1S 49_999_999;按钮消抖失效添加如下消抖模块reg [19:0] debounce_cnt; always (posedge clk) begin if(btn_in ! btn_sync) debounce_cnt 0; else if(debounce_cnt 1_000_000) debounce_cnt debounce_cnt 1; else btn_out btn_sync; end推荐调试工具链Quartus II SignalTap逻辑分析仪Modelsim功能仿真自制LED调试信号灯5. 学习资源与进阶建议从单片机过渡到FPGA我整理出这条学习路径基础入门1-2周Verilog语法重点掌握阻塞/非阻塞赋值简单组合逻辑设计如译码器时序逻辑基础触发器、计数器项目实战2-3周交通灯控制器UART通信PWM波形生成进阶提升AXI总线协议DDR3内存控制器数字信号处理FIR滤波器等推荐实验平台入门Altera MAX10成本低资源适中进阶Xilinx Artix-7支持DDR3、千兆以太网高阶Intel Cyclone 10GX支持PCIe Gen3