news 2026/4/20 12:34:25

从Arduino到FPGA:我的第一个Verilog项目踩坑实录(always/assign用法详解)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从Arduino到FPGA:我的第一个Verilog项目踩坑实录(always/assign用法详解)

从Arduino到FPGA:我的第一个Verilog项目踩坑实录

第一次把Arduino的流水灯代码移植到FPGA开发板时,屏幕上的波形仿真让我彻底懵了——八个LED灯居然同时亮起!这个看似简单的项目暴露了嵌入式软件工程师转向硬件描述语言时最典型的思维误区。本文将用真实项目中的五个关键错误,带你重新理解Verilog的并行世界。

1. 当顺序执行思维遇上硬件并行性

在Arduino上实现流水灯,我们会习惯性地写出这样的C代码:

void loop() { for(int i=0; i<8; i++) { digitalWrite(ledPins[i], HIGH); delay(500); digitalWrite(ledPins[i], LOW); } }

当我试图用类似的思路编写Verilog时,灾难开始了。最初的尝试是这样的:

always @(posedge clk) begin for(i=0; i<8; i=i+1) begin led <= 8'b1 << i; #500; // 试图模拟延时 end end

这个代码会产生三个致命问题:

  1. #500延时语法只能在测试基准中使用
  2. for循环在硬件中会展开为并行电路
  3. 非阻塞赋值<=导致所有LED同时变化

硬件设计的第一个思维转换:必须用状态机替代顺序流程。修正后的方案:

reg [2:0] state; always @(posedge clk) begin case(state) 0: led <= 8'b00000001; 1: led <= 8'b00000010; // ...其他状态 7: led <= 8'b10000000; default: led <= 8'b00000000; endcase state <= (state == 7) ? 0 : state + 1; end

2. always块的触发条件陷阱

第二个坑出现在按键消抖模块。参考Arduino的写法,我最初实现了这样的检测逻辑:

always begin if(button_pressed) begin debounced <= 1; #20; // 试图消抖 debounced <= 0; end end

这个代码的问题在于:

  • 缺少敏感列表导致仿真挂起
  • 延时语句会阻塞整个always块
  • 多个非阻塞赋值产生竞争条件

正确的消抖方案应该使用时钟同步:

reg [19:0] counter; always @(posedge clk) begin if(button_pressed) begin if(counter < 1000000) // 约20ms@50MHz counter <= counter + 1; end else begin counter <= 0; debounced <= 0; end if(counter == 999999) debounced <= 1; end

3. assign与always的职责边界

最让我困惑的是何时使用assign,何时用always。在实现PWM调光时,我曾错误地将组合逻辑放在always块中:

// 错误示例 always @(*) begin pwm_out = (counter < duty_cycle) ? 1'b1 : 1'b0; end

虽然仿真通过,但综合后的电路占用了额外触发器。黄金法则

  • assign用于纯组合逻辑连线
  • always @(*)用于需要if/case的复杂组合逻辑
  • always @(posedge clk)用于时序逻辑

优化后的PWM生成:

// 计数器用时序逻辑 always @(posedge clk) counter <= (counter >= period) ? 0 : counter + 1; // 比较用组合逻辑 assign pwm_out = (counter < duty_cycle);

4. 阻塞与非阻塞赋值的血泪教训

在实现状态机时,我曾混合使用两种赋值方式导致仿真与硬件行为不一致:

// 危险代码 always @(posedge clk) begin if(condition) begin a = b & c; // 阻塞赋值 d <= a | e; // 非阻塞赋值 end end

必须遵守的编码规范

赋值类型使用场景示例综合结果
阻塞(=)组合逻辑always块a = b & c;直接连线
非阻塞(<=)时序逻辑always块q <= d;D触发器

修正后的安全写法:

always @(posedge clk) begin a <= b & c; // 全部使用非阻塞 d <= a | e; end always @(*) begin x = y | z; // 组合逻辑用阻塞 end

5. 信号类型的认知升级

从软件转硬件最难理解的概念莫过于wire和reg的区别。我曾错误地认为:

  • reg等同于变量
  • wire等同于常量

实际上它们的本质区别是:

  • wire表示物理连线,必须由assign或模块端口驱动
  • reg表示存储单元,但不一定综合成寄存器

典型错误案例:

wire counter; // 错误!计数器需要状态保持 always @(posedge clk) counter <= counter + 1;

正确的信号声明原则:

reg [31:0] counter; // 需要时钟更新的信号 wire data_ready; // 组合逻辑输出 assign data_ready = (counter == MAX_COUNT);

6. 实战:重构流水灯项目

综合以上教训,这是最终优化的流水灯实现:

module led_flow( input clk, output reg [7:0] leds ); reg [24:0] counter; reg [2:0] state; always @(posedge clk) begin counter <= (counter >= 5000000) ? 0 : counter + 1; if(counter == 0) begin case(state) 0: leds <= 8'b00000001; 1: leds <= 8'b00000010; // ...省略其他状态 7: leds <= 8'b10000000; default: leds <= 8'b00000000; endcase state <= (state == 7) ? 0 : state + 1; end end endmodule

关键优化点:

  1. 使用25位计数器实现精确时序控制
  2. 状态机替代for循环
  3. 统一使用非阻塞赋值
  4. 明确的reg/wire类型声明

移植过程中最深的体会是:FPGA开发不是编写软件,而是在用代码"画电路图"。每个always块都对应着实际的硬件模块,每行代码都会变成门电路或触发器。这种思维转换的痛苦期大约持续了两周,但突破之后,看到自己设计的电路在示波器上完美运行时,那种成就感是单片机编程无法比拟的。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/20 12:33:22

3分钟掌握VADER情感分析:让Python读懂社交媒体情绪的秘密武器

3分钟掌握VADER情感分析&#xff1a;让Python读懂社交媒体情绪的秘密武器 【免费下载链接】vaderSentiment VADER Sentiment Analysis. VADER (Valence Aware Dictionary and sEntiment Reasoner) is a lexicon and rule-based sentiment analysis tool that is specifically a…

作者头像 李华
网站建设 2026/4/20 12:31:18

SolidWorks模型转DXF导入嘉立创专业版全流程(附3D视图验证技巧)

SolidWorks模型转DXF导入嘉立创专业版全流程&#xff08;附3D视图验证技巧&#xff09; 作为一名长期使用SolidWorks进行机械设计的工程师&#xff0c;我深刻理解将3D模型精准转换为2D板框对于PCB设计的重要性。特别是在使用嘉立创专业版进行电路板设计时&#xff0c;如何确保转…

作者头像 李华
网站建设 2026/4/20 12:27:40

Codex for almost everything:当 AI 成为你的全能编程搭档

Codex for almost everything&#xff1a;当 AI 成为你的全能编程搭档 在软件开发的世界里&#xff0c;我们总是在寻找那个能让我们从繁琐细节中解脱出来的“银弹”。从早期的 IDE 自动补全&#xff0c;到后来的代码片段生成&#xff0c;再到如今基于大语言模型&#xff08;LLM…

作者头像 李华
网站建设 2026/4/20 12:26:47

5分钟上手「THE LEATHER ARCHIVE」:零基础打造你的AI时尚杂志大片

5分钟上手「THE LEATHER ARCHIVE」&#xff1a;零基础打造你的AI时尚杂志大片 关键词&#xff1a;AI时尚设计、皮革穿搭、Anything V5、LoRA模型、AI杂志排版、Stable Diffusion应用 摘要&#xff1a;本文将带你快速掌握「THE LEATHER ARCHIVE」AI时尚设计工具的使用方法。无需…

作者头像 李华