module seg_7(
input clk,
input rst_n,
input [23:0]data_in,
output reg [2:0]sel,
output reg [7:0]seg
);
parameter CNT_1K = 15'd24999;//分频计数
reg [3:0]data_tmp;//译码数据缓存
reg [14:0]cnt_1k;
reg flag_1K;
always@(posedge clk or negedge rst_n)
if(!rst_n)
cnt_1k <= 15'd0;
else if(cnt_1k == CNT_1K)
cnt_1k <= 15'd0;
else
cnt_1k <= cnt_1k + 1'b1;
//1K扫描时钟生成模块
always@(posedge clk or negedge rst_n)
if(!rst_n)
flag_1K <= 1'b0;
else if(cnt_1k == CNT_1K)
flag_1K <= 1'b1; //产生1K扫描时钟的脉冲信号
else
flag_1K <= 1'b0;
//6位循环移位寄存器
always@(posedge clk or negedge rst_n)
if(!rst_n)
sel <= 3'd0;
else if(sel == 3'd5&&flag_1K==1'b1)//
sel <= 3'd0;
else if(flag_1K==1'b1)
sel <= sel + 1'b1;
always@(posedge clk or negedge rst_n)
if(!rst_n)
data_tmp <= 4'd0;
else begin
case(sel)//数码管位选选择
3'd0:data_tmp <= data_in[23:20];
3'd1:data_tmp <= data_in[19:16];
3'd2:data_tmp <= data_in[15:12];
3'd3:data_tmp <= data_in[11:8];
3'd4:data_tmp <= data_in[7:4];
3'd5:data_tmp <= data_in[3:0];
default:data_tmp <= 4'd0;
endcase
end
always@(posedge clk or negedge rst_n)
if(!rst_n)
seg <= 8'b01000000;
else begin
case(data_tmp)//译码显示值
4'h0 : seg <= 8'b11000000; //0
4'h1 : seg <= 8'b11111001; //1
4'h2 : seg <= 8'b10100100; //2
4'h3 : seg <= 8'b10110000; //3
4'h4 : seg <= 8'b10011001; //4
4'h5 : seg <= 8'b10010010; //5
4'h6 : seg <= 8'b10000010; //6
4'h7 : seg <= 8'b11111000; //7
4'h8 : seg <= 8'b10000000; //8
4'h9 : seg <= 8'b10010000; //9
4'ha : seg <= 8'b10001000; //a
4'hb : seg <= 8'b10000011; //b
4'hc : seg <= 8'b10000110; //c
4'hd : seg <= 8'b10100001; //d
4'he : seg <= 8'b10000110; //e
4'hf : seg <= 8'b10001110; //f
endcase
end
endmodule
//代码解释
产生Flag_1K扫描时钟脉冲,在高速电路中,需要分频时钟可以使用PLL,或者产生分频脉冲作为触发信号
建议当代码中多次使用变量的时候使用parameter CNT_1K = 15’d24999;这样修改代码时,不需要到代码中一个个修改了,直接修改参数中的数值即可
切记:所有的always(posedge clk or negedge rst_n)要基于系统时钟
避免时序分析的时候报错
附:8位数码管译码
原理同6位数码管
注意:
此代码使用的经过修改直接分频时钟clk_1K作为触发信号作为对比
因为数码管电路不要求高速,直接使用分频信号影响不大,但建议养成良好的习惯
比如使用 `define Char_0 7’b1000000 //字符 ‘0’
`define Char_0 7'b1000000 //字符 ‘0’
`define Char_1 7'b1111001 //字符 ‘1’
`define Char_2 7'b0100100 //字符 ‘2’
`define Char_3 7'b0110000 //字符 ‘3’
`define Char_4 7'b0011001 //字符 ‘4’
`define Char_5 7'b0010010 //字符 ‘5’
`define Char_6 7'b0000010 //字符 ‘6’
`define Char_7 7'b1111000 //字符 ‘7’
`define Char_8 7'b0000000 //字符 ‘8’
`define Char_9 7'b0010000 //字符 ‘9’
`define Char_a 7'b0001000 //字符 ‘A’
`define Char_b 7'b0000011 //字符 ‘b’
`define Char_c 7'b1000110 //字符 ‘C’
`define Char_d 7'b0100001 //字符 ‘d’
`define Char_e 7'b0000110 //字符 ‘E’
`define Char_f 7'b0001110 //字符 ‘F’
`define Char__ 7'b0111111 //字符 ‘-’
`define Char_H 7'b0001001 //字符 ‘H’
`define Char_OFF 7'b1111111 //消影
reg [14:0]divider_cnt;//25000-1
reg clk_1K;
reg [7:0]sel_r;
reg [3:0]data_tmp;//数据缓存
// 分频计数器计数模块
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
divider_cnt <= 15'd0;
else if(!En)
divider_cnt <= 15'd0;
else if(divider_cnt == 24999)
divider_cnt <= 15'd0;
else
divider_cnt <= divider_cnt + 1'b1;
//1K扫描时钟生成模块
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
clk_1K <= 1'b0;
else if(divider_cnt == 24999)
clk_1K <= ~clk_1K;
else
clk_1K <= clk_1K;
//8位循环移位寄存器
//此处clk_1K 正确方式应该使用脉冲触发
always@(posedge clk_1K or negedge Rst_n)
if(!Rst_n)
sel_r <= 8'b0000_0001;
else if(sel_r == 8'b1000_0000 || 8'b0000_0000)
sel_r <= 8'b0000_0001;
else
sel_r <= sel_r << 1;
//数据多路器,根据当前扫描的数码管位,将对于数据传给显示暂存
always@(*)
case(sel_r)
8'b0000_0001:data_tmp = disp_data[3:0];
8'b0000_0010:data_tmp = disp_data[7:4];
8'b0000_0100:data_tmp = disp_data[11:8];
8'b0000_1000:data_tmp = disp_data[15:12];
8'b0001_0000:data_tmp = disp_data[19:16];
8'b0010_0000:data_tmp = disp_data[23:20];
8'b0100_0000:data_tmp = disp_data[27:24];
8'b1000_0000:data_tmp = disp_data[31:28];
default:data_tmp = 4'b0000;
endcase
//对显示暂存内容进行译码,并输出该数据对应的段码
always@(*)
case(data_tmp)
4'h0:seg = `Char_0; //字符 ‘0’
4'h1:seg = `Char_1; //字符 ‘1’
4'h2:seg = `Char_2; //字符 ‘2’
4'h3:seg = `Char_3; //字符 ‘3’
4'h4:seg = `Char_4; //字符 ‘4’
4'h5:seg = `Char_5; //字符 ‘5’
4'h6:seg = `Char_6; //字符 ‘6’
4'h7:seg = `Char_7; //字符 ‘7’
4'h8:seg = `Char_8; //字符 ‘8’
4'h9:seg = `Char_9; //字符 ‘9’
4'ha:seg = `Char_a; //字符 ‘A’
4'hb:seg = `Char__; //字符 ‘-’
4'hc:seg = `Char_c; //字符 ‘C’
4'hd:seg = `Char_OFF; //消影
4'he:seg = `Char_H; //字符 ‘H’
4'hf:seg = `Char_f; //字符 ‘F’
endcase
//根据是否使能数码管显示,控制位选值
assign sel = (En)?sel_r:8'b0000_0000;