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

FPGA数码管驱动模块

本工程实现了一个完整的 6位动态扫描数码管显示系统。
将任意 30 位二进制整数(最大约10亿)实时显示在数码管上,支持带小数点控制。

模块构成

模块名功能描述
HC_FPGA_Demo_Top工程顶层模块,连接时钟、按键、串口、LED 与数码管等外设
smg数码管显示顶层模块,组合 binary2bcd + digital_tube
binary2bcd使用 Shift-Add-3 算法将二进制转为 6 位 BCD 数字
digital_tube数码管扫描模块,实现段选/位选输出,支持小数点动态控制

顶层模块

module HC_FPGA_Demo_Top
(input CLOCK_XTAL_50MHz,input RESET,input  KEY4,input  SIG_IN,input  RXD,output TXD,output LED0,output LED1,output LED2,output LED3,output  SIG_OUT1,output  SIG_OUT2,output  SIG_OUT3,output  SIG_OUT4,output  SIG_OUT5,output[7:0] DIG,output[5:0] SEL
);parameter CLK_FREQ = 50000000;    //定义系统时钟频率wire [29:0] smg_disp_data;smg u_smg (.i_clk(CLOCK_XTAL_50MHz),.i_rst_n(RESET),.i_data(123456),.i_dp(0),.o_sel(SEL),.o_seg(DIG)
);endmodule

数码管显示模块

/***  数码管显示模块* - 输入:30 位二进制数字* - 输出:6 位数码管段选与位选(带小数点)* - 结构:binary2bcd + digital_tube*/
module smg (input   wire                i_clk       ,   // 时钟input   wire                i_rst_n     ,   // 异步复位,低有效input   wire [29:0]         i_data      ,   // 输入 30bit 二进制数据input   wire [5:0]          i_dp        ,   // 小数点控制(1亮)output  wire [5:0]          o_sel       ,   // 数码管位选(低有效)output  wire [7:0]          o_seg           // 数码管段选(负逻辑)
);// ==================================================// 中间信号定义// ==================================================wire        w_bcd_vld;wire [3:0]  w_bcd_d0, w_bcd_d1, w_bcd_d2, w_bcd_d3, w_bcd_d4, w_bcd_d5;// ==================================================// 二进制转BCD模块(显示6位十进制)// ==================================================binary2bcd u_binary2bcd (.i_clk       (i_clk),.i_rst_n     (i_rst_n),.i_data      (i_data),.o_data      ({w_bcd_d0, w_bcd_d1, w_bcd_d2, w_bcd_d3, w_bcd_d4, w_bcd_d5}),.o_data_vld  (w_bcd_vld));// ==================================================// 数码管扫描显示模块// ==================================================digital_tube #(.P_CLK_FREQ   (50_000_000),.P_SCAN_FREQ  (1_000),.P_DIGIT_NUM  (6)) u_digital_tube (.i_clk     (i_clk),.i_rst_n   (i_rst_n),.i_dig0    (w_bcd_d0),.i_dig1    (w_bcd_d1),.i_dig2    (w_bcd_d2),.i_dig3    (w_bcd_d3),.i_dig4    (w_bcd_d4),.i_dig5    (w_bcd_d5),.i_dp      (i_dp),.o_sel     (o_sel),.o_seg     (o_seg));endmodule

二进制转BCD

/** 二进制转BCD* Shift-Add-3 Algorithm* 输入:i_data(二进制)* 输出:o_data(BCD),o_data_vld(完成标志)*/
module binary2bcd #(parameter P_DATA_WIDTH = 30,     // 输入数据位宽parameter P_CLK_FREQ   = 50_000_000 // 时钟频率(保留风格一致性)
) (input   wire                i_clk        , // 时钟input   wire                i_rst_n      , // 异步复位,低有效input   wire [P_DATA_WIDTH-1:0] i_data   , // 输入二进制数output  reg  [36:0]     o_data       , // 输出9位BCD码,共36位output  reg                o_data_vld    // 有效标志
);// ==================================================// Local Parameters// ==================================================localparam L_CNT_SHIFT_NUM = P_DATA_WIDTH;localparam L_SHIFT_WIDTH   = P_DATA_WIDTH + 36;  // BCD(9位) + 二进制// ==================================================// Registers// ==================================================reg [6:0]       r_cnt_shift;reg [L_SHIFT_WIDTH-1:0] r_data_shift;reg             r_shift_flag;// ==================================================// 移位控制计数器// ==================================================always @(posedge i_clk or negedge i_rst_n) beginif (!i_rst_n)r_cnt_shift <= 7'd0;else if ((r_cnt_shift == L_CNT_SHIFT_NUM + 1) && r_shift_flag)r_cnt_shift <= 7'd0;else if (r_shift_flag)r_cnt_shift <= r_cnt_shift + 1'b1;end// ==================================================// BCD移位转换逻辑// ==================================================always @(posedge i_clk or negedge i_rst_n) beginif (!i_rst_n)r_data_shift <= {L_SHIFT_WIDTH{1'b0}};else if (r_cnt_shift == 0)r_data_shift <= {{36{1'b0}}, i_data};else if ((r_cnt_shift <= L_CNT_SHIFT_NUM) && !r_shift_flag) beginif (r_data_shift[65:62] > 4) r_data_shift[65:62] <= r_data_shift[65:62] + 3;if (r_data_shift[61:58] > 4) r_data_shift[61:58] <= r_data_shift[61:58] + 3;if (r_data_shift[57:54] > 4) r_data_shift[57:54] <= r_data_shift[57:54] + 3;if (r_data_shift[53:50] > 4) r_data_shift[53:50] <= r_data_shift[53:50] + 3;if (r_data_shift[49:46] > 4) r_data_shift[49:46] <= r_data_shift[49:46] + 3;if (r_data_shift[45:42] > 4) r_data_shift[45:42] <= r_data_shift[45:42] + 3;if (r_data_shift[41:38] > 4) r_data_shift[41:38] <= r_data_shift[41:38] + 3;if (r_data_shift[37:34] > 4) r_data_shift[37:34] <= r_data_shift[37:34] + 3;if (r_data_shift[33:30] > 4) r_data_shift[33:30] <= r_data_shift[33:30] + 3;end else if ((r_cnt_shift <= L_CNT_SHIFT_NUM) && r_shift_flag)r_data_shift <= r_data_shift << 1;end// ==================================================// 交替控制加3/移位// ==================================================always @(posedge i_clk or negedge i_rst_n) beginif (!i_rst_n)r_shift_flag <= 1'b0;elser_shift_flag <= ~r_shift_flag;end// ==================================================// 结果输出// ==================================================always @(posedge i_clk or negedge i_rst_n) beginif (!i_rst_n) begino_data     <= 36'd0;o_data_vld <= 1'b0;end else if (r_cnt_shift == L_CNT_SHIFT_NUM + 1) begino_data     <= r_data_shift[65:30]; // 取出 BCD 码部分o_data_vld <= 1'b1;end else begino_data_vld <= 1'b0;endendendmodule

数码管扫描显示模块

/*** ===============================================* 数码管扫描显示模块(Digital Tube Driver)* ===============================================*/module digital_tube #(parameter P_CLK_FREQ     = 50_000_000,     // 输入时钟频率(Hz)parameter P_SCAN_FREQ    = 1_000,          // 数码管刷新频率(Hz)parameter P_DIGIT_NUM    = 6               // 数码管位数
) (input   wire                i_clk       ,   // 时钟信号input   wire                i_rst_n     ,   // 异步复位,低有效input   wire    [3:0]       i_dig0      ,   // 各位数字输入(0~F)input   wire    [3:0]       i_dig1      ,input   wire    [3:0]       i_dig2      ,input   wire    [3:0]       i_dig3      ,input   wire    [3:0]       i_dig4      ,input   wire    [3:0]       i_dig5      ,input   wire    [P_DIGIT_NUM-1:0] i_dp  ,   // 小数点控制(1亮)output  reg     [P_DIGIT_NUM-1:0] o_sel ,   // 数码管位选(低有效)output  reg     [7:0]       o_seg           // 数码管段选(低有效)
);// ==================================================// 扫描频率计数器// ==================================================localparam integer L_SCAN_CNT_MAX = P_CLK_FREQ / P_SCAN_FREQ;reg [15:0] r_scan_cnt;wire       w_scan_cnt_end = (r_scan_cnt == L_SCAN_CNT_MAX - 1);always @(posedge i_clk or negedge i_rst_n) beginif (!i_rst_n)r_scan_cnt <= 0;else if (w_scan_cnt_end)r_scan_cnt <= 0;elser_scan_cnt <= r_scan_cnt + 1'b1;end// ==================================================//  位索引计数器// ==================================================reg [2:0] r_digit_idx;always @(posedge i_clk or negedge i_rst_n) beginif (!i_rst_n)r_digit_idx <= 0;else if (w_scan_cnt_end)r_digit_idx <= (r_digit_idx == P_DIGIT_NUM - 1) ? 0 : r_digit_idx + 1'b1;end// ==================================================// 数码管片选与数据选择// ==================================================reg  [3:0] r_hex;reg        r_dp;always @(*) begincase (r_digit_idx)3'd0: begin o_sel = 6'b111110; r_hex = i_dig0; r_dp = i_dp[0]; end3'd1: begin o_sel = 6'b111101; r_hex = i_dig1; r_dp = i_dp[1]; end3'd2: begin o_sel = 6'b111011; r_hex = i_dig2; r_dp = i_dp[2]; end3'd3: begin o_sel = 6'b110111; r_hex = i_dig3; r_dp = i_dp[3]; end3'd4: begin o_sel = 6'b101111; r_hex = i_dig4; r_dp = i_dp[4]; enddefault: begin o_sel = 6'b011111; r_hex = i_dig5; r_dp = i_dp[5]; endendcaseend// ==================================================// 数码管段码定义(负逻辑)// ==================================================localparam [7:0] L_NUM0 = ~8'h3f;localparam [7:0] L_NUM1 = ~8'h06;localparam [7:0] L_NUM2 = ~8'h5b;localparam [7:0] L_NUM3 = ~8'h4f;localparam [7:0] L_NUM4 = ~8'h66;localparam [7:0] L_NUM5 = ~8'h6d;localparam [7:0] L_NUM6 = ~8'h7d;localparam [7:0] L_NUM7 = ~8'h07;localparam [7:0] L_NUM8 = ~8'h7f;localparam [7:0] L_NUM9 = ~8'h6f;localparam [7:0] L_NUMA = ~8'h77;localparam [7:0] L_NUMB = ~8'h7c;localparam [7:0] L_NUMC = ~8'h39;localparam [7:0] L_NUMD = ~8'h5e;localparam [7:0] L_NUME = ~8'h79;localparam [7:0] L_NUMF = ~8'h71;// ==================================================// 段选译码输出// ==================================================always @(posedge i_clk or negedge i_rst_n) beginif (!i_rst_n)o_seg <= 8'hff;else begincase (r_hex)4'h0: o_seg[6:0] <= L_NUM0[6:0];4'h1: o_seg[6:0] <= L_NUM1[6:0];4'h2: o_seg[6:0] <= L_NUM2[6:0];4'h3: o_seg[6:0] <= L_NUM3[6:0];4'h4: o_seg[6:0] <= L_NUM4[6:0];4'h5: o_seg[6:0] <= L_NUM5[6:0];4'h6: o_seg[6:0] <= L_NUM6[6:0];4'h7: o_seg[6:0] <= L_NUM7[6:0];4'h8: o_seg[6:0] <= L_NUM8[6:0];4'h9: o_seg[6:0] <= L_NUM9[6:0];4'ha: o_seg[6:0] <= L_NUMA[6:0];4'hb: o_seg[6:0] <= L_NUMB[6:0];4'hc: o_seg[6:0] <= L_NUMC[6:0];4'hd: o_seg[6:0] <= L_NUMD[6:0];4'he: o_seg[6:0] <= L_NUME[6:0];4'hf: o_seg[6:0] <= L_NUMF[6:0];default: o_seg[6:0] <= 7'b0000000;endcaseo_seg[7] <= ~r_dp;  // 小数点控制:高亮 = 段信号为低endendendmodule
http://www.dtcms.com/a/305287.html

相关文章:

  • Netty中FastThreadLocal解读
  • C++多态:面向对象编程的灵魂之
  • Linux_库制作与原理浅理解
  • 青木川古镇
  • Flex布局面试常考的场景题目
  • 墨者:SQL过滤字符后手工注入漏洞测试(第3题)
  • MC0244多重堡垒
  • kotlin使用mybatis plus lambdaQuery报错
  • Java中什么是类加载?类加载的过程?
  • TGD第八篇:二维应用——图像边缘检测
  • FastAPI入门:Cookie参数、Header参数、Cookie参数模型、Header参数模型
  • 移动端 WebView 调试实战,多平台行为差异排查与统一调试流程
  • Gartner发布CTEM指南:使用持续威胁暴露管理来减少网络攻击
  • 应急前端“黄金3分钟”设计:极端场景下的操作界面极速搭建技术
  • COPRAS(Complex Proportional Assessment)简介与简单示例
  • 汇总10个高质量免费AI生成论文网站,支持GPT4.0和DeepSeek-R1
  • [学习记录]URP流程解析(2)--初始化阶段
  • 最新优茗导航系统源码/全开源版本/精美UI/带后台/附教程
  • Effective_C++09: 绝不在构造和析构过程中调用virtual函数
  • 【解决办法】pip install albumentations安装下载遇19kB/s超级慢细水管
  • 无代码测试平台ATECLOUD全场景测试方案
  • Java中Boolean.getBoolean方法误用与修复
  • 【监控】非IP监控系统改造IP监控系统
  • 中科米堆CASAIM空调扇叶自动蓝光三维测量解决方案
  • <RT1176系列12>DMAMUX入门级应用和DMAMUX MAP表
  • Linux定时器和时间管理源码相关总结
  • 【Unity编辑器扩展】Unity场景选择工具 - ScenesChooseTool 使用指南
  • 项目历程—生命数组游戏(两版本)
  • 智源研究院发布数据魔方,以智能化自定义方式重构模型训练数据供给范式
  • 两数之和(每天刷力扣hot100系列)