今天我分享自己写的数码管显示模块。
本模块使用的外部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