[原创].七段数码管驱动,Verilog版本
我以前在艾米电子写的驱动。贴在博客之目的:一、时常记记,以防忘记;二、分享给大家。也许是工作比较忙之缘故吧,新近的博文啰嗦的话语少了许多,直接贴上代码,大家有什么不明白的,留言即可。
版本1
顶层例化文件
module seg7x8( input CLOCK_50, // 板载50MHz时钟 input Q_KEY, // 板载按键RST output [7:0] SEG7_SEG, // 七段数码管 段脚 output [2:0] SEG7_SEL // 七段数码管 待译位脚 ); // 显示效果: // ------------------------- // |1 |2.|3 |4 | |B |C |D | // ------------------------- seg7x8_drive u0( .i_clk (CLOCK_50), .i_rst_n (Q_KEY), .i_turn_off (8'b0000_1000), // 熄灭位[2进制][此处取第3位 .i_dp (8'b0100_0000), // 小数点位[2进制][此处取第6位 .i_data (32'h1234_ABCD), // 欲显数据[16进制] .o_seg(SEG7_SEG), .o_sel(SEG7_SEL) ); endmodule
驱动文件
module seg7x8_drive( input i_clk, input i_rst_n, input [7:0] i_turn_off, // 熄灭位[2进制 input [7:0] i_dp, // 小数点位[2进制 input [31:0] i_data, // 欲显数据[16进制 output [7:0] o_seg, // 段脚 output [2:0] o_sel // 使用74HC138译出位脚 ); //++++++++++++++++++++++++++++++++++++++ // 分频部分 开始 //++++++++++++++++++++++++++++++++++++++ reg [16:0] cnt; // 计数子 always @ (posedge i_clk, negedge i_rst_n) if (!i_rst_n) cnt <= 0; else cnt <= cnt + 1'b1; wire seg7_clk = cnt[16]; // (2^17/50M = 2.6114)ms //-------------------------------------- // 分频部分 结束 //-------------------------------------- //++++++++++++++++++++++++++++++++++++++ // 动态扫描, 生成seg7_addr 开始 //++++++++++++++++++++++++++++++++++++++ reg [2:0] seg7_addr; // 第几个seg7 always @ (posedge seg7_clk, negedge i_rst_n) if (!i_rst_n) seg7_addr <= 0; else seg7_addr <= seg7_addr + 1'b1; //-------------------------------------- // 动态扫描, 生成seg7_addr 结束 //-------------------------------------- //++++++++++++++++++++++++++++++++++++++ // 根据seg7_addr, 译出位码 开始 //++++++++++++++++++++++++++++++++++++++ reg [2:0] o_sel_r; // 位选码寄存器 // 开发板上SEG7的方向是低位在左,高位在右 // 但是实际上我们看数的方向是高位在左,低位在右 // 故此处将第0位对应DIG[7],第7位对应DIG[0] always case (seg7_addr) 0 : o_sel_r = 3'b111; // SEG7[7] 1 : o_sel_r = 3'b110; // SEG7[6] 2 : o_sel_r = 3'b101; // SEG7[5] 3 : o_sel_r = 3'b100; // SEG7[4] 4 : o_sel_r = 3'b011; // SEG7[3] 5 : o_sel_r = 3'b010; // SEG7[2] 6 : o_sel_r = 3'b001; // SEG7[1] 7 : o_sel_r = 3'b000; // SEG7[0] endcase //-------------------------------------- // 根据seg7_addr, 译出位码 结束 //-------------------------------------- //++++++++++++++++++++++++++++++++++++++ // 根据seg7_addr, 选择熄灭码 开始 //++++++++++++++++++++++++++++++++++++++ reg turn_off_r; // 熄灭码 always case (seg7_addr) 0 : turn_off_r = i_turn_off[0]; 1 : turn_off_r = i_turn_off[1]; 2 : turn_off_r = i_turn_off[2]; 3 : turn_off_r = i_turn_off[3]; 4 : turn_off_r = i_turn_off[4]; 5 : turn_off_r = i_turn_off[5]; 6 : turn_off_r = i_turn_off[6]; 7 : turn_off_r = i_turn_off[7]; endcase //-------------------------------------- // 根据seg7_addr, 选择熄灭码 结束 //-------------------------------------- //++++++++++++++++++++++++++++++++++++++ // 根据seg7_addr, 选择小数点码 开始 //++++++++++++++++++++++++++++++++++++++ reg dp_r; // 小数点码 always case (seg7_addr) 0 : dp_r = i_dp[0]; 1 : dp_r = i_dp[1]; 2 : dp_r = i_dp[2]; 3 : dp_r = i_dp[3]; 4 : dp_r = i_dp[4]; 5 : dp_r = i_dp[5]; 6 : dp_r = i_dp[6]; 7 : dp_r = i_dp[7]; endcase //-------------------------------------- // 根据seg7_addr, 选择小数点码 结束 //-------------------------------------- //++++++++++++++++++++++++++++++++++++++ // 根据seg7_addr, 选择待译段码 开始 //++++++++++++++++++++++++++++++++++++++ reg [3:0] seg_data_r; // 待译段码 always case (seg7_addr) 0 : seg_data_r = i_data[3:0]; 1 : seg_data_r = i_data[7:4]; 2 : seg_data_r = i_data[11:8]; 3 : seg_data_r = i_data[15:12]; 4 : seg_data_r = i_data[19:16]; 5 : seg_data_r = i_data[23:20]; 6 : seg_data_r = i_data[27:24]; 7 : seg_data_r = i_data[31:28]; endcase //-------------------------------------- // 根据seg7_addr, 选择待译段码 结束 //-------------------------------------- //++++++++++++++++++++++++++++++++++++++ // 根据熄灭码/小数点码/待译段码 // 译出段码,开始 //++++++++++++++++++++++++++++++++++++++ reg [7:0] o_seg_r; // 段码寄存器 /* * 0 * ------- * | | * 5| 6 |1 * ------- * | | * 4| |2 * ------- . 7 * 3 */ // 共阳 always @ (posedge i_clk, negedge i_rst_n) if (!i_rst_n) o_seg_r <= 8'hFF; // 送熄灭码 else if(turn_off_r) // 送熄灭码 o_seg_r <= 8'hFF; else if(!dp_r) case(seg_data_r) // 无小数点 4'h0 : o_seg_r <= 8'hC0; 4'h1 : o_seg_r <= 8'hF9; 4'h2 : o_seg_r <= 8'hA4; 4'h3 : o_seg_r <= 8'hB0; 4'h4 : o_seg_r <= 8'h99; 4'h5 : o_seg_r <= 8'h92; 4'h6 : o_seg_r <= 8'h82; 4'h7 : o_seg_r <= 8'hF8; 4'h8 : o_seg_r <= 8'h80; 4'h9 : o_seg_r <= 8'h90; 4'hA : o_seg_r <= 8'h88; 4'hB : o_seg_r <= 8'h83; 4'hC : o_seg_r <= 8'hC6; 4'hD : o_seg_r <= 8'hA1; 4'hE : o_seg_r <= 8'h86; 4'hF : o_seg_r <= 8'h8E; endcase else case(seg_data_r) // 加小数点 4'h0 : o_seg_r <= 8'hC0 ^ 8'h80; 4'h1 : o_seg_r <= 8'hF9 ^ 8'h80; 4'h2 : o_seg_r <= 8'hA4 ^ 8'h80; 4'h3 : o_seg_r <= 8'hB0 ^ 8'h80; 4'h4 : o_seg_r <= 8'h99 ^ 8'h80; 4'h5 : o_seg_r <= 8'h92 ^ 8'h80; 4'h6 : o_seg_r <= 8'h82 ^ 8'h80; 4'h7 : o_seg_r <= 8'hF8 ^ 8'h80; 4'h8 : o_seg_r <= 8'h80 ^ 8'h80; 4'h9 : o_seg_r <= 8'h90 ^ 8'h80; 4'hA : o_seg_r <= 8'h88 ^ 8'h80; 4'hB : o_seg_r <= 8'h83 ^ 8'h80; 4'hC : o_seg_r <= 8'hC6 ^ 8'h80; 4'hD : o_seg_r <= 8'hA1 ^ 8'h80; 4'hE : o_seg_r <= 8'h86 ^ 8'h80; 4'hF : o_seg_r <= 8'h8E ^ 8'h80; endcase //-------------------------------------- // 根据熄灭码/小数点码/待译段码 // 译出段码,结束 //-------------------------------------- assign o_sel = o_sel_r; // 寄存器输出位选码 assign o_seg = o_seg_r; // 寄存器输出段码 endmodule
版本2
顶层例化文件
module seg7x8( input CLOCK_50, // 板载50MHz时钟 input [1:1] KEY, // KEY[1] output [7:0] SEG7_SEG, // 七段数码管 段脚 output [7:0] SEG7_DIG // 七段数码管 位脚 ); // 显示效果: // ------------------------- // |1 |2.|3 |4 | |B |C |D | // ------------------------- seg7x8_drive u0( .i_clk (CLOCK_50), .i_rst_n (KEY), .i_turn_off (8'b0000_1000), // 熄灭位[2进制][此处取第3位 .i_dp (8'b0100_0000), // 小数点位[2进制][此处取第6位 .i_data (32'h1234_ABCD), // 欲显数据[16进制] .o_seg (SEG7_SEG), .o_dig (SEG7_DIG) ); endmodule
驱动文件
module seg7x8_drive( input i_clk, input i_rst_n, input [7:0] i_turn_off, // 熄灭位[2进制 input [7:0] i_dp, // 小数点位[2进制 input [31:0] i_data, // 欲显数据[16进制 output [7:0] o_seg, // 段脚 output [7:0] o_dig // 位脚 ); //++++++++++++++++++++++++++++++++++++++ // 分频部分 开始 //++++++++++++++++++++++++++++++++++++++ reg [16:0] cnt; // 计数子 always @ (posedge i_clk, negedge i_rst_n) if (!i_rst_n) cnt <= 0; else cnt <= cnt + 1'b1; wire seg7_clk = cnt[16]; // (2^17/50M = 2.6114)ms //-------------------------------------- // 分频部分 结束 //-------------------------------------- //++++++++++++++++++++++++++++++++++++++ // 动态扫描, 生成seg7_addr 开始 //++++++++++++++++++++++++++++++++++++++ reg [2:0] seg7_addr; // 第几个seg7 always @ (posedge seg7_clk, negedge i_rst_n) if (!i_rst_n) seg7_addr <= 0; else seg7_addr <= seg7_addr + 1'b1; //-------------------------------------- // 动态扫描, 生成seg7_addr 结束 //-------------------------------------- //++++++++++++++++++++++++++++++++++++++ // 根据seg7_addr, 译出位码 开始 //++++++++++++++++++++++++++++++++++++++ reg [7:0] o_dig_r; // 位码寄存器 // 开发板上SEG7的方向是低位在左,高位在右 // 但是实际上我们看数的方向是高位在左,低位在右 // 故此处将第0位对应DIG[7],第7位对应DIG[0] always case (seg7_addr) 0 : o_dig_r = 8'b0000_0001; 1 : o_dig_r = 8'b0000_0010; 2 : o_dig_r = 8'b0000_0100; 3 : o_dig_r = 8'b0000_1000; 4 : o_dig_r = 8'b0001_0000; 5 : o_dig_r = 8'b0010_0000; 6 : o_dig_r = 8'b0100_0000; 7 : o_dig_r = 8'b1000_0000; endcase //-------------------------------------- // 根据seg7_addr, 译出位码 结束 //-------------------------------------- //++++++++++++++++++++++++++++++++++++++ // 根据seg7_addr, 选择熄灭码 开始 //++++++++++++++++++++++++++++++++++++++ reg turn_off_r; // 熄灭码 always case (seg7_addr) 0 : turn_off_r = i_turn_off[0]; 1 : turn_off_r = i_turn_off[1]; 2 : turn_off_r = i_turn_off[2]; 3 : turn_off_r = i_turn_off[3]; 4 : turn_off_r = i_turn_off[4]; 5 : turn_off_r = i_turn_off[5]; 6 : turn_off_r = i_turn_off[6]; 7 : turn_off_r = i_turn_off[7]; endcase //-------------------------------------- // 根据seg7_addr, 选择熄灭码 结束 //-------------------------------------- //++++++++++++++++++++++++++++++++++++++ // 根据seg7_addr, 选择小数点码 开始 //++++++++++++++++++++++++++++++++++++++ reg dp_r; // 小数点码 always case (seg7_addr) 0 : dp_r = i_dp[0]; 1 : dp_r = i_dp[1]; 2 : dp_r = i_dp[2]; 3 : dp_r = i_dp[3]; 4 : dp_r = i_dp[4]; 5 : dp_r = i_dp[5]; 6 : dp_r = i_dp[6]; 7 : dp_r = i_dp[7]; endcase //-------------------------------------- // 根据seg7_addr, 选择小数点码 结束 //-------------------------------------- //++++++++++++++++++++++++++++++++++++++ // 根据seg7_addr, 选择待译段码 开始 //++++++++++++++++++++++++++++++++++++++ reg [3:0] seg_data_r; // 待译段码 always case (seg7_addr) 0 : seg_data_r = i_data[3:0]; 1 : seg_data_r = i_data[7:4]; 2 : seg_data_r = i_data[11:8]; 3 : seg_data_r = i_data[15:12]; 4 : seg_data_r = i_data[19:16]; 5 : seg_data_r = i_data[23:20]; 6 : seg_data_r = i_data[27:24]; 7 : seg_data_r = i_data[31:28]; endcase //-------------------------------------- // 根据seg7_addr, 选择待译段码 结束 //-------------------------------------- //++++++++++++++++++++++++++++++++++++++ // 根据熄灭码/小数点码/待译段码 // 译出段码,开始 //++++++++++++++++++++++++++++++++++++++ reg [7:0] o_seg_r; // 段码寄存器 /* * 0 * ------- * | | * 5| 6 |1 * ------- * | | * 4| |2 * ------- . 7 * 3 */ // 共阳 always @ (posedge i_clk, negedge i_rst_n) if (!i_rst_n) o_seg_r <= 8'hFF; // 送熄灭码 else if(turn_off_r) // 送熄灭码 o_seg_r <= 8'hFF; else if(!dp_r) case(seg_data_r) // 无小数点 4'h0 : o_seg_r <= 8'hC0; 4'h1 : o_seg_r <= 8'hF9; 4'h2 : o_seg_r <= 8'hA4; 4'h3 : o_seg_r <= 8'hB0; 4'h4 : o_seg_r <= 8'h99; 4'h5 : o_seg_r <= 8'h92; 4'h6 : o_seg_r <= 8'h82; 4'h7 : o_seg_r <= 8'hF8; 4'h8 : o_seg_r <= 8'h80; 4'h9 : o_seg_r <= 8'h90; 4'hA : o_seg_r <= 8'h88; 4'hB : o_seg_r <= 8'h83; 4'hC : o_seg_r <= 8'hC6; 4'hD : o_seg_r <= 8'hA1; 4'hE : o_seg_r <= 8'h86; 4'hF : o_seg_r <= 8'h8E; endcase else case(seg_data_r) // 加小数点 4'h0 : o_seg_r <= 8'hC0 ^ 8'h80; 4'h1 : o_seg_r <= 8'hF9 ^ 8'h80; 4'h2 : o_seg_r <= 8'hA4 ^ 8'h80; 4'h3 : o_seg_r <= 8'hB0 ^ 8'h80; 4'h4 : o_seg_r <= 8'h99 ^ 8'h80; 4'h5 : o_seg_r <= 8'h92 ^ 8'h80; 4'h6 : o_seg_r <= 8'h82 ^ 8'h80; 4'h7 : o_seg_r <= 8'hF8 ^ 8'h80; 4'h8 : o_seg_r <= 8'h80 ^ 8'h80; 4'h9 : o_seg_r <= 8'h90 ^ 8'h80; 4'hA : o_seg_r <= 8'h88 ^ 8'h80; 4'hB : o_seg_r <= 8'h83 ^ 8'h80; 4'hC : o_seg_r <= 8'hC6 ^ 8'h80; 4'hD : o_seg_r <= 8'hA1 ^ 8'h80; 4'hE : o_seg_r <= 8'h86 ^ 8'h80; 4'hF : o_seg_r <= 8'h8E ^ 8'h80; endcase //-------------------------------------- // 根据熄灭码/小数点码/待译段码 // 译出段码,结束 //-------------------------------------- /* * | c[1] * b[in] -| * | e[out] */ assign o_dig = ~o_dig_r; // 寄存器输出位码 assign o_seg = o_seg_r; // 寄存器输出段码 endmodule