1. 从单片机到FPGA的思维转换第一次接触FPGA开发时我习惯性地用单片机思维去理解Verilog代码结果踩了不少坑。比如总想着用顺序执行的思路去写状态机导致综合出来的电路完全不符合预期。后来才发现FPGA开发更像是用代码画电路图需要彻底转变思维方式。最明显的区别就是并行处理能力。在单片机上我们需要精心安排每个任务的执行顺序而在FPGA中所有模块都是同时工作的。举个例子循迹小车的红外传感器处理、电机PWM生成、蜂鸣器驱动这些功能在单片机上要分时处理但在FPGA里可以设计成完全独立的硬件电路。硬件描述语言Verilog也和我们熟悉的C语言有很大不同。刚开始我总把always块当成函数来用直到看到综合报告里一堆锁存器警告才明白问题所在。后来总结出一个技巧写Verilog时要时刻想着你是在描述电路连接而不是编写执行流程。2. Ego1开发板快速上手Xilinx Ego1这块板子对初学者特别友好自带的外设正好够做循迹小车项目。我第一次拿到板子时花了半天时间研究各个接口的位置。这里有个小技巧板载的数码管、按键和LED灯可以用来快速验证基础功能比直接调电机更安全。Vivado的环境配置也有讲究。建议安装时勾选WebPACK版本就够了完全免费且包含所有必要功能。创建工程时要注意选择正确的芯片型号Ego1用的是XC7A35TCPG236-1。我有次选错型号烧录时直接报错折腾了好久才发现问题。板载的时钟源是50MHz对于PWM生成来说频率太高了。我通常会用时钟分频模块先降到1MHz左右这样后续的计数器设计会更方便。记得在约束文件里正确定义时钟引脚否则时序分析会出问题。3. 循迹小车的硬件系统设计这个小车的硬件架构花了我不少时间调试。核心是五个模块红外传感器阵列、TB6612电机驱动、编码器电机、舵机和蜂鸣器。最开始我用L298N驱动电机发现发热严重后来换成TB6612就稳定多了。红外传感器的布局很有讲究。我试过三种安装高度最终确定离地1.5cm时检测效果最好。五路传感器的间距建议在2-3cm之间太近容易误判太宽会漏检赛道。有个坑要注意不同颜色的赛道反射率不同需要调整传感器上的电位器。电源管理是另一个关键点。电机启动时的电流冲击很大我加了多个100μF的电容做缓冲。后来发现用单独的稳压模块给FPGA供电更稳定避免电机干扰导致FPGA重启。4. Verilog模块化设计实战4.1 PWM电机控制模块写PWM模块时我参考了单片机的实现方式但用Verilog写出来完全是另一种思路。核心是一个计数器和比较器通过调整比较值来改变占空比。这里有个细节电机需要的PWM频率通常在1-5kHz之间频率太低电机会抖动太高则驱动芯片可能不响应。module pwm_gen( input clk, input [7:0] duty, output reg pwm_out ); reg [7:0] counter; always (posedge clk) begin counter counter 1; pwm_out (counter duty) ? 1b1 : 1b0; end endmodule对于循迹小车我实际使用了两个PWM模块一个控制电机转速另一个控制舵机转向。舵机需要50Hz的PWM信号脉宽在0.5-2.5ms之间变化这个要特别注意。4.2 红外传感器处理五路红外传感器的信号处理我用了状态机来实现。基本思路是根据传感器阵列的输入模式输出转向控制信号。比如11000表示车身偏左需要向右转。case(sensor_in) 5b11000: steer RIGHT_MAX; 5b11100: steer RIGHT_MID; 5b11110: steer RIGHT_MIN; 5b00011: steer LEFT_MAX; 5b00111: steer LEFT_MID; 5b01111: steer LEFT_MIN; default: steer CENTER; endcase调试时发现传感器信号会有抖动后来在代码里加了20ms的消抖逻辑。还有个经验夜间环境光会影响红外传感器最好给传感器加上遮光罩。5. 多模块系统集成把各个模块整合成完整系统是最有挑战的部分。我采用分层设计底层是各个硬件驱动模块中间层是运动控制模块顶层是系统整合模块。这样结构清晰调试时也好定位问题。时钟域处理是个大坑。不同模块可能需要不同频率的时钟直接使用多个时钟会导致综合时报时序违例。我的解决方案是用一个主时钟然后通过使能信号来控制各模块的工作节奏。资源分配也要注意。Ego1的FPGA资源有限当使用太多查找表(LUT)时会出现布局布线失败。有次我加了太多调试用的LED显示结果综合不通过最后只能精简功能。6. 调试与性能优化6.1 Vivado调试技巧学会使用ILA(Integrated Logic Analyzer)能极大提升调试效率。我通常在代码中插入几个ILA核实时观察关键信号。比如监控PWM输出和传感器输入的关系比用LED灯观察直观多了。遇到综合失败时首先要看日志里的第一个报错。后面的错误往往是由第一个引发的。我有次被一堆报错吓到结果只是约束文件里写错了一个引脚编号。6.2 性能优化经验优化后的循迹算法响应速度比最初版本快了三倍。关键是把部分计算提前到传感器输入阶段而不是在控制循环里处理。比如直接把传感器模式映射到预设的转向角度省去了实时计算的开销。资源优化也有窍门。发现某些寄存器只用到了部分位宽时可以合并使用。比如我把电机速度和转向状态合并到一个8位寄存器里传输节省了不少布线资源。7. 程序固化与脱机运行代码调试完成后需要固化到Flash里才能脱机运行。Vivado里生成MCS文件时要注意选择正确的Flash型号Ego1用的是n25q64。我第一次选错型号烧录后程序完全没反应。烧录完成后要记得验证。有个检查技巧断电重启后观察板载LED的初始状态如果和设计一致通常说明固化成功。遇到问题时可以尝试重新生成bit文件有时候是综合时出的问题。最后分享一个实用技巧在代码里添加版本标记比如用特定的LED闪烁模式。这样当小车在赛道上运行时一眼就能知道烧录的是哪个版本的固件。
从单片机思维到FPGA实战:基于Xilinx-Ego1的循迹小车系统设计与调试全记录
1. 从单片机到FPGA的思维转换第一次接触FPGA开发时我习惯性地用单片机思维去理解Verilog代码结果踩了不少坑。比如总想着用顺序执行的思路去写状态机导致综合出来的电路完全不符合预期。后来才发现FPGA开发更像是用代码画电路图需要彻底转变思维方式。最明显的区别就是并行处理能力。在单片机上我们需要精心安排每个任务的执行顺序而在FPGA中所有模块都是同时工作的。举个例子循迹小车的红外传感器处理、电机PWM生成、蜂鸣器驱动这些功能在单片机上要分时处理但在FPGA里可以设计成完全独立的硬件电路。硬件描述语言Verilog也和我们熟悉的C语言有很大不同。刚开始我总把always块当成函数来用直到看到综合报告里一堆锁存器警告才明白问题所在。后来总结出一个技巧写Verilog时要时刻想着你是在描述电路连接而不是编写执行流程。2. Ego1开发板快速上手Xilinx Ego1这块板子对初学者特别友好自带的外设正好够做循迹小车项目。我第一次拿到板子时花了半天时间研究各个接口的位置。这里有个小技巧板载的数码管、按键和LED灯可以用来快速验证基础功能比直接调电机更安全。Vivado的环境配置也有讲究。建议安装时勾选WebPACK版本就够了完全免费且包含所有必要功能。创建工程时要注意选择正确的芯片型号Ego1用的是XC7A35TCPG236-1。我有次选错型号烧录时直接报错折腾了好久才发现问题。板载的时钟源是50MHz对于PWM生成来说频率太高了。我通常会用时钟分频模块先降到1MHz左右这样后续的计数器设计会更方便。记得在约束文件里正确定义时钟引脚否则时序分析会出问题。3. 循迹小车的硬件系统设计这个小车的硬件架构花了我不少时间调试。核心是五个模块红外传感器阵列、TB6612电机驱动、编码器电机、舵机和蜂鸣器。最开始我用L298N驱动电机发现发热严重后来换成TB6612就稳定多了。红外传感器的布局很有讲究。我试过三种安装高度最终确定离地1.5cm时检测效果最好。五路传感器的间距建议在2-3cm之间太近容易误判太宽会漏检赛道。有个坑要注意不同颜色的赛道反射率不同需要调整传感器上的电位器。电源管理是另一个关键点。电机启动时的电流冲击很大我加了多个100μF的电容做缓冲。后来发现用单独的稳压模块给FPGA供电更稳定避免电机干扰导致FPGA重启。4. Verilog模块化设计实战4.1 PWM电机控制模块写PWM模块时我参考了单片机的实现方式但用Verilog写出来完全是另一种思路。核心是一个计数器和比较器通过调整比较值来改变占空比。这里有个细节电机需要的PWM频率通常在1-5kHz之间频率太低电机会抖动太高则驱动芯片可能不响应。module pwm_gen( input clk, input [7:0] duty, output reg pwm_out ); reg [7:0] counter; always (posedge clk) begin counter counter 1; pwm_out (counter duty) ? 1b1 : 1b0; end endmodule对于循迹小车我实际使用了两个PWM模块一个控制电机转速另一个控制舵机转向。舵机需要50Hz的PWM信号脉宽在0.5-2.5ms之间变化这个要特别注意。4.2 红外传感器处理五路红外传感器的信号处理我用了状态机来实现。基本思路是根据传感器阵列的输入模式输出转向控制信号。比如11000表示车身偏左需要向右转。case(sensor_in) 5b11000: steer RIGHT_MAX; 5b11100: steer RIGHT_MID; 5b11110: steer RIGHT_MIN; 5b00011: steer LEFT_MAX; 5b00111: steer LEFT_MID; 5b01111: steer LEFT_MIN; default: steer CENTER; endcase调试时发现传感器信号会有抖动后来在代码里加了20ms的消抖逻辑。还有个经验夜间环境光会影响红外传感器最好给传感器加上遮光罩。5. 多模块系统集成把各个模块整合成完整系统是最有挑战的部分。我采用分层设计底层是各个硬件驱动模块中间层是运动控制模块顶层是系统整合模块。这样结构清晰调试时也好定位问题。时钟域处理是个大坑。不同模块可能需要不同频率的时钟直接使用多个时钟会导致综合时报时序违例。我的解决方案是用一个主时钟然后通过使能信号来控制各模块的工作节奏。资源分配也要注意。Ego1的FPGA资源有限当使用太多查找表(LUT)时会出现布局布线失败。有次我加了太多调试用的LED显示结果综合不通过最后只能精简功能。6. 调试与性能优化6.1 Vivado调试技巧学会使用ILA(Integrated Logic Analyzer)能极大提升调试效率。我通常在代码中插入几个ILA核实时观察关键信号。比如监控PWM输出和传感器输入的关系比用LED灯观察直观多了。遇到综合失败时首先要看日志里的第一个报错。后面的错误往往是由第一个引发的。我有次被一堆报错吓到结果只是约束文件里写错了一个引脚编号。6.2 性能优化经验优化后的循迹算法响应速度比最初版本快了三倍。关键是把部分计算提前到传感器输入阶段而不是在控制循环里处理。比如直接把传感器模式映射到预设的转向角度省去了实时计算的开销。资源优化也有窍门。发现某些寄存器只用到了部分位宽时可以合并使用。比如我把电机速度和转向状态合并到一个8位寄存器里传输节省了不少布线资源。7. 程序固化与脱机运行代码调试完成后需要固化到Flash里才能脱机运行。Vivado里生成MCS文件时要注意选择正确的Flash型号Ego1用的是n25q64。我第一次选错型号烧录后程序完全没反应。烧录完成后要记得验证。有个检查技巧断电重启后观察板载LED的初始状态如果和设计一致通常说明固化成功。遇到问题时可以尝试重新生成bit文件有时候是综合时出的问题。最后分享一个实用技巧在代码里添加版本标记比如用特定的LED闪烁模式。这样当小车在赛道上运行时一眼就能知道烧录的是哪个版本的固件。