当前位置: 首页 > news >正文

实战指南:基于Verilog HDL的24进制计数器设计与FPGA实现

1. 24进制计数器设计基础

数字电路设计中,计数器是最基础也最实用的模块之一。24进制计数器在日常生活中随处可见,比如电子钟的小时显示部分就是典型的24进制计数应用。相比常见的10进制或16进制计数器,24进制的设计需要一些特殊处理,这正是本教程要解决的核心问题。

Verilog HDL作为硬件描述语言中的"瑞士军刀",能让我们用代码的方式描述硬件电路的行为。我刚开始学FPGA时,总觉得计数器设计很抽象,直到自己动手实现了第一个24进制计数器,才真正理解同步时序电路的精妙之处。下面我会用最直白的语言,带大家从零开始完成这个设计。

先明确几个关键概念:

  • D触发器:数字电路的记忆单元,每个时钟边沿锁存输入数据
  • 同步计数:所有触发器共享同一个时钟信号,避免竞争冒险
  • 反馈清零:计数器达到特定值时自动复位,这是实现任意进制的关键

2. D触发器设计与验证

2.1 Verilog实现D触发器

任何计数器的基础都是D触发器。这里我们采用行为级描述方式,代码既简洁又直观:

module d_ff( input clk, // 时钟信号 input rst_n, // 异步复位(低有效) input d, // 数据输入 output reg q // 数据输出 ); always @(posedge clk or negedge rst_n) begin if(!rst_n) q <= 1'b0; // 异步复位 else q <= d; // 时钟上升沿锁存数据 end endmodule

这段代码有几个关键点需要注意:

  1. 使用posedge clk表示上升沿触发
  2. rst_n是低电平有效的异步复位信号
  3. 非阻塞赋值(<=)确保时序正确性

2.2 功能仿真验证

设计完成后必须进行仿真验证。我推荐使用ModelSim或者Quartus自带的仿真工具。测试脚本(testbench)可以这样写:

`timescale 1ns/1ps module tb_d_ff; reg clk, rst_n, d; wire q; d_ff uut(.*); // 实例化被测模块 initial begin clk = 0; forever #5 clk = ~clk; // 100MHz时钟 end initial begin rst_n = 0; d = 1; #15 rst_n = 1; // 15ns后释放复位 #10 d = 0; #10 d = 1; #20 $stop; end endmodule

仿真时重点关注两个时间点:

  • 复位释放后第一个时钟上升沿(15ns)应该采样d=1
  • 25ns时的时钟上升沿应该采样d=0

3. 构建24进制计数器

3.1 使用74161计数器芯片

74161是经典的4位二进制计数器,我们可以利用它构建更复杂的计数器。两个74161级联可以实现最大256进制计数器,对于24进制绰绰有余。

先看单个74161的Verilog实现:

module my74161( input clk, // 时钟 input ldn, // 同步置数(低有效) input rdn, // 异步清零(低有效) input ep, et, // 计数使能 input [3:0] d, // 并行数据输入 output [3:0] q, // 计数器输出 output co // 进位输出 ); reg [3:0] cnt; assign q = cnt; assign co = (cnt == 4'b1111) & et; always @(posedge clk or negedge rdn) begin if(!rdn) cnt <= 4'b0000; else if(!ldn) cnt <= d; else if(ep && et) cnt <= cnt + 1; end endmodule

3.2 24进制实现方案

实现24进制有两种主流方法:

  1. 反馈清零法:计数到24时立即清零
  2. 同步置数法:计数到23时下一周期置入0

实测发现同步置数法更可靠,避免出现竞争冒险。具体实现如下:

module counter24( input clk, input rst_n, output [7:0] q, // 8位输出(两个4位计数器) output carry // 进位信号 ); wire [3:0] q_low, q_high; wire co_low, co_high; wire reset_cond = (q_high == 2) && (q_low == 3); // 检测23 my74161 low( .clk(clk), .ldn(~reset_cond), .rdn(rst_n), .ep(1'b1), .et(1'b1), .d(4'b0000), .q(q_low), .co(co_low) ); my74161 high( .clk(clk), .ldn(~reset_cond), .rdn(rst_n), .ep(co_low), .et(co_low), .d(4'b0000), .q(q_high), .co(co_high) ); assign q = {q_high, q_low}; assign carry = reset_cond; endmodule

关键设计点:

  • 低位计数器每计满16次产生进位(co_low)
  • 高位计数器只在低位进位时计数
  • 当计数达到23(0x17)时,下一周期同步置零

4. 仿真验证与调试

4.1 测试平台搭建

完整的测试脚本应该覆盖以下场景:

  1. 上电复位功能
  2. 正常计数过程
  3. 进位条件触发
  4. 边界条件(22→23→0的转换)
`timescale 1ns/1ps module tb_counter24; reg clk, rst_n; wire [7:0] q; wire carry; counter24 uut(.*); initial begin clk = 0; forever #10 clk = ~clk; // 50MHz时钟 end initial begin rst_n = 0; #100 rst_n = 1; // 100ns后释放复位 #500 $stop; // 观察5个完整计数周期 end endmodule

4.2 常见问题排查

在实际项目中遇到过几个典型问题:

  1. 计数器不工作:检查时钟是否连接正确,使能信号是否有效
  2. 提前复位:确认比较条件是否准确(应该是23而非24)
  3. 显示乱码:数码管译码逻辑需要单独验证

仿真波形中要特别关注:

  • 从23跳转到0的时刻是否干净利落
  • 进位信号(carry)的脉冲宽度是否合适
  • 复位信号的优先级是否最高

5. FPGA实现与显示驱动

5.1 引脚分配与约束

以常见的Cyclone IV EP4CE6为例,引脚约束文件(.qsf)关键内容:

set_location_assignment PIN_23 -to clk set_location_assignment PIN_24 -to rst_n set_location_assignment PIN_50 -to q[0] ... set_location_assignment PIN_57 -to q[7] set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to *

5.2 七段数码管驱动

将二进制输出转换为数码管显示需要译码器。这里给出共阳极数码管的驱动代码:

module seg7_decoder( input [7:0] bin, // 8位二进制输入 output reg [6:0] seg // 7段输出(a-g) ); always @(*) begin case(bin % 10) // 取个位数 0: seg = 7'b1000000; 1: seg = 7'b1111001; 2: seg = 7'b0100100; 3: seg = 7'b0110000; 4: seg = 7'b0011001; 5: seg = 7'b0010010; 6: seg = 7'b0000010; 7: seg = 7'b1111000; 8: seg = 7'b0000000; 9: seg = 7'b0010000; default: seg = 7'b1111111; endcase end endmodule

实际项目中还需要考虑:

  • 动态扫描消除闪烁
  • 消抖处理
  • 多位数码管间的同步

5.3 上板实测技巧

在开发板上验证时,建议逐步调试:

  1. 先用LED显示低4位,确认基本计数功能
  2. 添加数码管显示,先测试静态显示
  3. 最后实现动态扫描显示
  4. 使用SignalTap II逻辑分析仪捕获实际信号

遇到问题时,可以:

  • 降低时钟频率观察现象
  • 分段隔离问题(先验证计数器,再验证显示)
  • 检查电源稳定性(数码管驱动电流较大)
http://www.jsqmd.com/news/531844/

相关文章:

  • Phi-4-Reasoning-Vision实操手册:JPG/PNG图文输入封装与自动格式对齐
  • 别再傻傻分不清了!5分钟搞懂5G基站里High PHY和Low PHY到底谁在干啥
  • 从零搭建ESP32 BLE吞吐量测试系统:手把手教你搞定GATT通知注册与数据接收
  • 2026年高新技术企业认定公司推荐:科技企业申报难题破解与高口碑服务商深度分析 - 品牌推荐
  • 76. 如何在 RKE CLI 和 Rancher v2.x 配置的 RKE Kubernetes 集群中启用 ingress-nginx 的遗留 TLS 版本
  • 毕设程序java基于区块链的脐橙溯源系统 基于分布式账本技术的赣南脐橙全生命周期追溯平台 基于智能合约的柑橘类农产品可信溯源管理系统
  • 保姆级教程:用Docker Compose一键部署LibreSpeed测速服务(附环境变量详解)
  • Camunda开源协议可否商用
  • PMIC:现代电子设备的能源大脑与智能调度中心
  • SpringBoot与SpringCloud版本搭配避坑指南:从1.x到2.x的实战经验分享
  • 如何用HiFi-GAN在CPU上实现13倍速的语音合成?实战教程来了
  • SEO_解决网站收录问题的SEO诊断与解决办法
  • Axure RP中文界面配置指南:本地化改造提升原型设计效率
  • Comsol多孔疏锂模型:实现锂的均匀沉积与电池性能的优化
  • Enterprise Architect 12实战:如何将已有C++源码快速转换为UML类图
  • 2026年婴幼儿润肤乳产品推荐:秋冬季节宝宝干痒泛红舒缓高性价比产品分析 - 品牌推荐
  • 2026四川旧楼加装电梯高性价比服务商推荐榜:别墅电梯10大品牌/别墅电梯三层大概多少钱/别墅电梯厂家价格/别墅电梯厂家哪家好/选择指南 - 优质品牌商家
  • RAG技术的认知重构:当检索增强遭遇产业落地的冰火两重天
  • Claude vs Gemini 技术拆解对比:2026年两大顶级模型镜像站如何选?
  • Word文档插入代码总乱格式?手把手教你用Code2Word实现完美排版(含常见问题解决方案)
  • VideoAgentTrek Screen Filter在运维监控中的应用:自动过滤服务器仪表盘敏感信息
  • Qwen3.5-35B-A3B-AWQ-4bit图文问答入门必看:上传→提问→多轮对话完整操作流程
  • 2026年婴幼儿润肤乳产品推荐:新生儿日常护理防干痒口碑品牌及成分安全分析 - 品牌推荐
  • 车载毫米波雷达DDMA-MIMO系统优化:Empty-band算法与相位补偿法在发射通道解调及速度解模糊中的协同应用与性能验证
  • RWKV7-1.5B-g1a快速上手:5分钟完成首次prompt交互与结果验证
  • Xinference-v1.17.1数学建模竞赛:优化算法实战案例解析
  • GitHub MCP Server完整指南:AI助手与GitHub的无缝连接
  • 3D高斯光栅化技术:Blender插件的创新应用与实践指南
  • Wan2.2-I2V-A14B开发者案例:封装私有API服务并接入内部内容管理系统
  • 别再全局关Cache了!ZYNQ PS端DDR访问性能优化:细说Cache Flush与Invalidate的正确姿势