[原创].七段数码管驱动,Verilog版本

时间:2022-11-08 20:30:16

我以前在艾米电子写的驱动。贴在博客之目的:一、时常记记,以防忘记;二、分享给大家。也许是工作比较忙之缘故吧,新近的博文啰嗦的话语少了许多,直接贴上代码,大家有什么不明白的,留言即可。

版本1

[原创].七段数码管驱动,Verilog版本

顶层例化文件

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

[原创].七段数码管驱动,Verilog版本

顶层例化文件

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