今天我分享自己写的数码管显示模块。
本模块使用的外部1000/3 hz的频率,其主要原因是有8个数码管,每扫完一轮要24毫秒, 可以避开人眼的间隙空间,3ms的周期不必讲究.
模块使用一个时序电路,是为地址扫描设计的, 多数使用过的组合电路,主要是能让数据实时处理.不用考虑数据的延迟.
module reg8x8_driver(
input clk,rst_n, // 时钟: 1000/3 hz 复位信号,低电平有效
input [7:0] i_turn_off, // 熄灭位
input [7:0] i_dp_off, // 小数点
input [31:0] i_data, // 需要显示的8个数
output reg [2:0] o_sel, // 位选 外部3-8译码器
output reg [7:0] o_seg // 段选
);
//------------------------------------------------------------------------------------------------
parameter _0_seg = 8'b1100_0000,_1_seg = 8'b1111_1001,_2_seg = 8'b1010_0100,_3_seg = 8'b1011_0000,
_4_seg = 8'b1001_1001,_5_seg = 8'b1001_0010,_6_seg = 8'b1000_0010,_7_seg = 8'b1111_1000,
_8_seg = 8'b1000_0000,_9_seg = 8'b1001_0000,_a_seg = 8'b1010_0000,_b_seg = 8'b1000_0011,
_c_seg = 8'b1010_0111,_d_seg = 8'b1010_0001,_e_seg = 8'b1000_0100,_f_seg = 8'b1000_1110,
_dark_seg = 8'b1111_1111; //全暗
//------------------------------------------------------------------------------------------------
//扫描地址生成
always @(posedge clk,negedge rst_n)begin
if(!rst_n)
o_sel <= 3'b111;
else
o_sel <= o_sel - 1'b1;
end
//根据扫描地址取相应显示的数据,这里是组合电路,具有实时性.
reg[3:0] numb;
always @(*)
case(o_sel)
3'b111 : numb = i_data[3:0];
3'b011 : numb = i_data[7:4];
3'b101 : numb = i_data[11:8];
3'b001 : numb = i_data[15:12];
3'b110 : numb = i_data[19:16];
3'b010 : numb = i_data[23:20];
3'b100 : numb = i_data[27:24];
3'b000 : numb = i_data[31:28];
default : numb = 4'b0000;
endcase
//给数据进行编码,这里是组合电路,具有实时性.
reg[7:0] o_seg_r;
always @(*)
case(numb)
4'h0 : o_seg_r = _0_seg;
4'h1 : o_seg_r = _1_seg;
4'h2 : o_seg_r = _2_seg;
4'h3 : o_seg_r = _3_seg;
4'h4 : o_seg_r = _4_seg;
4'h5 : o_seg_r = _5_seg;
4'h6 : o_seg_r = _6_seg;
4'h7 : o_seg_r = _7_seg;
4'h8 : o_seg_r = _8_seg;
4'h9 : o_seg_r = _9_seg;
4'ha : o_seg_r = _a_seg;
4'hb : o_seg_r = _b_seg;
4'hc : o_seg_r = _c_seg;
4'hd : o_seg_r = _d_seg;
4'he : o_seg_r = _e_seg;
4'hf : o_seg_r = _f_seg;
default: o_seg_r = _dark_seg;
endcase
// 对位的小数点、熄灭与否,进行进一步的处理,该模块也是组合逻辑,数据处理具有实时性.
always @(*)
case(o_sel)
3'b000 : if(!(i_turn_off & 8'h80)) //最高位的运算,往下递减.
o_seg = {(!i_dp_off[7]),o_seg_r[6:0]}; //最高位的小数点运算,往下递减.
else
o_seg = _dark_seg;
3'b001 : if(!(i_turn_off & 8'h40))
o_seg = {(!i_dp_off[6]),o_seg_r[6:0]};
else
o_seg = _dark_seg;
3'b010 : if(!(i_turn_off & 8'h20))
o_seg = {(!i_dp_off[5]),o_seg_r[6:0]};
else
o_seg = _dark_seg;
3'b011 : if(!(i_turn_off & 8'h10))
o_seg = {(!i_dp_off[4]),o_seg_r[6:0]};
else
o_seg = _dark_seg;
3'b100 : if(!(i_turn_off & 8'h08))
o_seg = {(!i_dp_off[3]),o_seg_r[6:0]};
else
o_seg = _dark_seg;
3'b101 : if(!(i_turn_off & 8'h04))
o_seg = {(!i_dp_off[2]),o_seg_r[6:0]};
else
o_seg = _dark_seg;
3'b110 : if(!(i_turn_off & 8'h02))
o_seg = {(!i_dp_off[1]),o_seg_r[6:0]};
else
o_seg = _dark_seg;
3'b111 : if(!(i_turn_off & 8'h01))
o_seg = {(!i_dp_off[0]),o_seg_r[6:0]};
else
o_seg = _dark_seg;
default : o_seg = _dark_seg;
endcase
endmodule