news 2026/4/12 11:42:01

Verilog实现4位全加器并控制七段数码管显示

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Verilog实现4位全加器并控制七段数码管显示

从加法器到数码管:用Verilog打造一个“会算数”的FPGA小系统

你有没有想过,计算机是怎么做加法的?
不是打开计算器App那种“做”,而是从最底层的晶体管和逻辑门开始,一步一步把0和1变成我们看得懂的数字。今天,我们就来亲手实现这个过程——在一块FPGA上,用Verilog写一个4位全加器,并让它驱动七段数码管,实时显示计算结果。

这不只是“点亮LED”那么简单。这是一个完整的数字系统雏形:有输入、有运算、有输出。它像一台微型计算机,虽然只能算加法,但麻雀虽小,五脏俱全。


为什么是“4位全加器”?

在数字电路的世界里,加法器是算术逻辑单元(ALU)的灵魂。无论是手机还是超级计算机,它们最基础的加减乘除,都是从一个个小小的加法器堆出来的。

而“4位”是个很巧妙的选择:

  • 够简单:适合初学者理解;
  • 够实用:能表示0~15,足够展示基本功能;
  • 易扩展:掌握了4位,8位、16位自然水到渠成。

更重要的是,当我们把两个4位二进制数相加时,结果最大为1111 + 1111 = 11110(即十进制30),这意味着我们需要处理进位问题——而这正是全加器存在的意义。

半加器 vs 全加器:差一个“进位”而已?

半加器只能加两个一位数(A 和 B),输出和(Sum)与进位(Cout)。但它不支持来自低位的进位输入,所以无法级联。

全加器则多了一个输入 Cin(Carry In),让它可以“接力”工作。四个全加器串起来,就能组成一个4位加法器。

它的核心公式其实很简单:

Sum = A ⊕ B ⊕ Cin Cout = (A & B) | (Cin & (A ^ B))

别被符号吓到,这就是异或和与或操作。关键在于:每一位的输出不仅取决于当前位的两个输入,还依赖前一位的进位。这种“连锁反应”就是所谓的“串行进位”(Ripple Carry)。

虽然现代CPU早已不用这种方式(太慢了!),但在教学和小规模设计中,它是理解硬件并行性的绝佳入口。


搭建你的第一个4位加法器模块

我们采用模块化设计思路:先做一个单个全加器,再把它复用四次。

// 单个全加器 module full_adder( input A, input B, input Cin, output Sum, output Cout ); assign Sum = A ^ B ^ Cin; assign Cout = (A & B) | (Cin & (A ^ B)); endmodule

代码清晰得就像教科书一样。接下来是重头戏——把四个这样的模块连起来:

module adder_4bit( input [3:0] A, input [3:0] B, input Cin, output [3:0] Sum, output Cout ); wire [3:0] carry; full_adder fa0 (.A(A[0]), .B(B[0]), .Cin(Cin), .Sum(Sum[0]), .Cout(carry[0])); full_adder fa1 (.A(A[1]), .B(B[1]), .Cin(carry[0]), .Sum(Sum[1]), .Cout(carry[1])); full_adder fa2 (.A(A[2]), .B(B[2]), .Cin(carry[1]), .Sum(Sum[2]), .Cout(carry[2])); full_adder fa3 (.A(A[3]), .B(B[3]), .Cin(carry[2]), .Sum(Sum[3]), .Cout(Cout)); endmodule

注意这里的carry[3:0]是内部信号,用来传递进位。最低位使用外部输入 Cin(通常接0),最高位产生最终进位 Cout。

🛠️调试小贴士:如果你发现高位加法出错,比如7+8=0,那大概率是进位线没接对。建议在仿真时重点观察carry[0]carry[2]的变化是否符合预期。


让结果“看得见”:七段数码管怎么控制?

再强大的计算,如果没人看得到,也就失去了意义。这时候就需要七段数码管登场了。

它由 a~g 七个LED段组成,通过不同组合点亮来显示数字0~9。常见的有两种类型:

类型公共端连接点亮方式
共阴极接地(GND)给段送高电平点亮
共阳极接电源(VCC)给段送低电平点亮

大多数FPGA开发板使用的是共阳极数码管,这点非常重要!因为这意味着我们的译码器输出必须是低电平有效

如何把二进制结果变成“亮灯模式”?

假设加法结果是4'd5,我们要让数码管显示“5”。查一下真值表:

abcdefg
1011011

但这只是逻辑状态。对于共阳极来说,要让某段亮,就得输出0;不亮就输出1。所以我们实际输出应该是:

a=0, b=1, c=0, d=0, e=1, f=0, g=0 → 7'b0100100

为了简化管理,我们可以建立一张“编码表”:

module seg_decoder( input [3:0] bcd, output reg [6:0] seg ); always @(*) begin case(bcd) 4'd0: seg = 7'b1000000; // 共阳极:a~f亮,g灭 → 输出0对应亮 4'd1: seg = 7'b1111001; 4'd2: seg = 7'b0100100; 4'd3: seg = 7'b0110000; 4'd4: seg = 7'b0011001; 4'd5: seg = 7'b0010010; 4'd6: seg = 7'b0000010; 4'd7: seg = 7'b1111000; 4'd8: seg = 7'b0000000; 4'd9: seg = 7'b0010000; default: seg = 7'b1111111; // 全灭 endcase end endmodule

⚠️ 注意:上面的编码是针对共阳极数码管的。如果你的开发板是共阴极,请将所有值取反。

这里用了always @(*)来描述组合逻辑,综合工具会自动将其映射为查找表(LUT)。虽然也可以用assign+? :实现,但case更直观、易维护。


把它们连起来:构建完整系统

现在我们有两个核心模块:

  • adder_4bit:负责计算
  • seg_decoder:负责显示

只需要一个顶层模块把它们串联起来即可:

module top_module( input [3:0] sw_a, // 开关输入A input [3:0] sw_b, // 开关输入B output [6:0] seg_out // 连接到数码管a~g ); wire [3:0] sum_result; wire carry_out; // 实例化加法器 adder_4bit u_adder ( .A(sw_a), .B(sw_b), .Cin(1'b0), .Sum(sum_result), .Cout(carry_out) ); // 实例化译码器 seg_decoder u_decoder ( .bcd(sum_result), .seg(seg_out) ); endmodule

就这么简单?没错!

当然,现实不会总是这么理想。比如当sw_a = 4'd9,sw_b = 4'd7时,结果是16'd16,超出了单个数码管的显示范围(0~9)。这时你会看到什么?可能是乱码,也可能是熄灭。

怎么办?

方案一:只显示低4位,忽略溢出

这是最简单的做法,适合教学演示。用户自己意识到“哦,超过9就不准了”。

方案二:双数码管动态扫描

如果你想显示“16”,那就需要两个数码管。我们可以引入位选信号(sel[1:0]),并通过快速切换(>50Hz)实现视觉暂留效果。

但这已经属于进阶内容了,涉及状态机和定时控制。本文暂不展开,但你可以把它作为下一步挑战目标。


实际部署中的那些“坑”

纸上谈兵容易,真正在板子上跑通才是硬道理。以下是几个常见陷阱:

❌ 误区1:直接拿FPGA引脚接数码管,烧了IO口

FPGA的IO驱动能力有限(一般每脚不超过16mA)。而每个LED段的工作电流可能在5~20mA之间。如果没有限流电阻,轻则亮度异常,重则损坏芯片。

✅ 正确做法:每个段都串联一个220Ω~1kΩ的限流电阻。推荐470Ω,既能保证亮度又安全。

❌ 误区2:忘了开发板是共阳还是共阴

很多同学写完代码烧进去,发现“该亮的不亮,不该亮的全亮”。原因往往就是搞错了数码管类型。

✅ 解决办法:查阅开发板原理图,确认公共端接法。或者用万用表测通断判断。

❌ 误区3:按键抖动导致输入错误

如果用按键代替拨码开关作为输入,可能会遇到“按一次变多次”的问题。这是因为机械开关存在“抖动”现象。

✅ 解决方案:加入消抖电路,可以用延时检测,也可以用状态机实现软件消抖。


这个项目教会了我们什么?

表面上看,这只是个“小学生项目”——会加法、会显示。但实际上,它涵盖了数字系统设计的核心思想:

  1. 模块化设计:把复杂系统拆解为可复用的小模块;
  2. 数据通路构建:从原始输入到最终输出,形成闭环;
  3. 软硬协同验证:代码逻辑必须与物理世界匹配;
  4. 边界条件处理:溢出、无效输入、电平兼容等问题不可忽视;
  5. 调试思维养成:学会分段隔离问题,是工程师的基本功。

更重要的是,当你拨动开关,看到数码管跳出了正确的数字时,那种“我造了个会思考的东西”的成就感,是任何理论课都无法替代的。


下一步你可以做什么?

别停下!这个项目只是一个起点。试试这些升级方向:

  • ✅ 改成8位加法器,看看资源占用变化;
  • ✅ 加一个减法模式(用补码实现);
  • ✅ 用两个数码管显示完整结果(0~30);
  • ✅ 添加时钟,实现自动累加(计数器模式);
  • ✅ 引入按键控制清零或启动;
  • ✅ 用Verilog状态机实现简易计算器。

甚至有一天,你可以用类似的方法,搭建一个能运行简单程序的CPU。


如果你也在学习FPGA,不妨今晚就动手试一试。找块开发板,敲几行代码,连几根线,然后——让你的第一个“数字大脑”开始工作吧。

💬 你在实现过程中踩过哪些坑?欢迎留言分享你的调试经历!

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

手把手教你部署Open-AutoGLM,2小时快速搭建AI自动化系统

第一章:智普Open-AutoGLM项目概述 智普AI推出的Open-AutoGLM是一个面向自动化自然语言处理任务的开源框架,旨在降低大模型应用开发门槛,提升从数据准备到模型部署的全流程效率。该项目基于GLM系列大语言模型构建,支持零样本、少样…

作者头像 李华
网站建设 2026/3/28 10:12:07

解锁系统重装新境界:一键自动化工具的完整实战指南

解锁系统重装新境界:一键自动化工具的完整实战指南 【免费下载链接】reinstall 又一个一键重装脚本 项目地址: https://gitcode.com/GitHub_Trending/re/reinstall 还在为服务器系统重装而烦恼吗?传统的系统重装过程不仅耗时耗力,还容…

作者头像 李华
网站建设 2026/4/10 23:30:04

3分钟掌握ModAssistant:Beat Saber模组安装终极指南

3分钟掌握ModAssistant:Beat Saber模组安装终极指南 【免费下载链接】ModAssistant Simple Beat Saber Mod Installer 项目地址: https://gitcode.com/gh_mirrors/mo/ModAssistant ModAssistant是专为Beat Saber玩家打造的PC模组管理神器,支持一键…

作者头像 李华
网站建设 2026/4/1 12:56:59

FSearch:Linux文件搜索工具的终极使用指南

FSearch:Linux文件搜索工具的终极使用指南 【免费下载链接】fsearch A fast file search utility for Unix-like systems based on GTK3 项目地址: https://gitcode.com/gh_mirrors/fs/fsearch 还在为寻找Linux系统中的文件而烦恼吗?FSearch这款快…

作者头像 李华
网站建设 2026/4/9 22:04:06

双拼输入法:从打字困扰到效率达人的蜕变之路

双拼输入法:从打字困扰到效率达人的蜕变之路 【免费下载链接】Shuang :pencil2: 双拼练习 项目地址: https://gitcode.com/gh_mirrors/sh/Shuang 还记得那些年被全拼输入法支配的恐惧吗?每次输入都要敲击四五个键位,效率低下不说&…

作者头像 李华