第一次看到自己编写的VHDL代码让开发板上的数码管亮起数字时,那种成就感至今难忘。很多刚接触FPGA开发的工程师都能写出基本的计数器模块,但当需要将这些模块组合成一个完整系统,并最终在硬件上运行时,常常会遇到各种困惑:为什么仿真正确的代码下载到板子上没反应?数码管的位选和段选信号该怎么接?时钟频率设置多少合适?
四位十进制计数器的核心思想并不复杂——用四个CNT10模块分别表示个、十、百、千位,每个模块计满10就向高位进位。但在FPGA实现时,需要考虑更多工程细节。
我们的系统需要三个关键模块协同工作:
CNT10:基础十进制计数器
CTRLS:动态扫描控制器
DISPLAY:七段译码与显示驱动
在Quartus II中创建原理图时,关键信号连接如下:
| 信号名 | 类型 | 位宽 | 连接关系 |
|---|---|---|---|
| CLK1 | 输入 | 1 | 主计数时钟(1-10Hz为宜) |
| CLK2 | 输入 | 1 | 扫描时钟(≥24Hz) |
| DOUT | 内部 | 16 | 连接四个CNT10的输出 |
| COM[7:0] | 输出 | 8 | 数码管公共端 |
| SEG[7:0] | 输出 | 8 | 七段码(a-g+小数点) |
提示:CLK2频率不宜过高,否则可能导致数码管亮度不足。建议在24Hz-1kHz范围内调试。
vhdl复制PROCESS(CLK,CLR,ENA) IS
BEGIN
IF CLR='1' THEN
CQI<="0000";
ELSIF CLK'EVENT AND CLK='1' THEN
IF ENA='1' THEN
IF CQI="1001" THEN
CQI<="0000";
ELSE
CQI<=CQI+'1';
END IF;
END IF;
END IF;
END PROCESS;
这段代码实现了带异步清零的同步计数器。几个关键点:
DISPLAY模块中的这段代码实现了数码管轮询:
vhdl复制PROCESS(SEL) IS
BEGIN
CASE SEL IS
WHEN "000" => COM<="11111110"; -- 点亮第1个数码管
WHEN "001" => COM<="11111101"; -- 点亮第2个数码管
-- 其他位选省略...
END CASE;
END PROCESS;
人眼存在视觉暂留效应,当扫描频率足够高时,看起来就像所有数码管同时显示。实际调试时,可以用示波器观察COM信号,确认扫描是否均匀。
创建工程
bash复制# Quartus安装后需要设置环境变量
export QUARTUS_ROOTDIR=/opt/intelFPGA/20.1/quartus
添加源文件
引脚分配技巧
在Pin Planner中,EP3C55-FBGA484的关键引脚对应:
| 网络名 | FPGA引脚 | 开发板接口 |
|---|---|---|
| CLK1 | P20 | 扩展口P6 |
| CLK2 | AB16 | 扩展口P8 |
| SEG[0] | AA15 | 数码管a段 |
注意:不同开发板引脚定义可能不同,务必查阅原理图
问题1:下载后数码管不亮
问题2:显示数字错乱
问题3:计数器速度异常
当计数器频率较高时(>10MHz),需要注意:
在Compilation Report中查看EP3C55的资源使用:
| 资源类型 | 使用量 | 总量 |
|---|---|---|
| 逻辑单元 | 82 | 55856 |
| 寄存器 | 48 | 55856 |
| 引脚 | 24 | 484 |
对于这种简单设计,资源占用很少,但养成查看报告的习惯对复杂项目很重要。
基于当前框架,可以轻松实现更多功能:
添加启动/暂停控制
vhdl复制entity DTCNT9999 is
port(
PAUSE : in std_logic; -- 新增暂停信号
-- 其他端口不变...
);
实现预置数功能
vhdl复制signal PRESET : std_logic_vector(15 downto 0) := "0000000000000000";
增加闪烁效果
vhdl复制process(CLK2) is
variable cnt : integer range 0 to 50000000 := 0;
begin
if rising_edge(CLK2) then
cnt := cnt + 1;
if cnt = 25000000 then
SEG <= (others => '0'); -- 半秒熄灭一次
end if;
end if;
end process;
在调试EP3C55开发板时,最让我印象深刻的是第一次看到动态扫描的数码管显示效果。起初我设置了过高的扫描频率(约10kHz),结果数码管亮度明显不足。后来通过逐步降低频率,最终在约200Hz时获得了最佳显示效果——这比单纯看理论计算要直观得多。