一,设计原理
因Verilog HDL编写的源程序是并行执行的,故分析原理时,分别分析各个层次模块之间的接口关系。
(1)顶层模块与计数器计数模块:外部50Mhz时钟和复位信号传递给顶层模块,顶层模块通过模块例化将50Mhz的时钟、复位信号及3位的key_value变量值分别传递给计数器计数模块中的clk、rst_n和key_control,在计数器计数模块中经分频后产生周期为0.01秒的方波并在rst_n1和key_control3’b011时开始计数;在key_control3’b101时计数值清零;在key_control3’b110时暂停,在并将计数值存于24位的rNum变量,然后将24位的rNum变量里的值传递给24位的Number_Sig变量,最后通过Number_Sig变量将计数值返回至顶层模块中的24位的Number_Sig变量中暂存。
(2)顶层模块与按键检测模块:外部三个独立按键、50Mhz的时钟及复位信号传递给顶层模块,通过模块例化的方式将三个独立按键值、时钟和复位信号分别传递给按键检测模块中的三位的key_in变量、clk和rst_n变量。在按键检测模块中将时钟信号分频至周期为20毫秒的方波,利用按键在20毫秒里电平的变化检测是否有按键按下,即:wire [2:0]flag_key = key_scan_r[2:0] & (~key_scan[2:0]);此语句检测按键是否按下。再通过flag_key里的值判断哪个按键按下,再将对应的按键值赋值给三位的temp变量,最后将temp里的值赋给三位的key_out变量返回至顶层模块中的三位的key_value变量。
(3)顶层模块与数码管接口模块:顶层模块利用模块例化的方式将50Mhz时钟、复位信号、Number_Sig变量值分别传递给数码管接口模块中的一位CLK、RSTn和24位的Number_Sig变量。数码管接口模块最终将八位的SMG_Data和六位的Scan_Sig变量返回给顶层模块中八位的SMG_Data和六位的Scan_Sig变量,顶层最后将八位的SMG_Data和六位的Scan_Sig变量里的值经译码电路输送至六位共阳数码管显示。
(4)数码管接口模块与计数值分配模块:数码管接口模块将从顶层模块传递过来的Number_Sig变量值、50Mhz时钟和复位信号分别传给计数值分配模块里的24位的Number_Sig变量、一位的CLK、RSTn变量。在计数值分配模块中,将时钟信号经分频后产生周期为1毫秒的方波,将24位的Number_Sig变量里的值在分频后的时序下从高到低四位四位的取出赋值给四位rNumber,最后将rNumber里的值赋值给Number_Data返回至数码管接口模块里的四位的Number_Data变量。
(5)数码管接口模块与段选模块:将50Mhz、复位信号以及Number_Data变量值传递给段选模块中的一位的CLK、RSTn和四位Number_Data变量。在段选模块里,利用parameter语句定义数码管显示0-9时对应的八位段选值,例如:parameter _0 = 8’b1100_0000;在50Mhz时钟产生的时序下,利用case语句将Number_Data变量值进行比较,若为零则八位的rSMG变量被赋值为数码管显示零的八位段选值。最后将rSMG赋值给八位的SMG_Data变量返回至上层模块里的SMG_Data变量。
(6)数码管接口模块与位选模块:将50Mhz、复位信号传递给位选模块中的一位的CLK、RSTn,在位选模块中,将时钟信号分频至周期为1毫秒的方波,在此时序下,从低到高依次选通一位数码管,即将一个低电平和五个高电平赋值给六位的rScan变量。最后将rScan变量赋值给六位Scan_Sig变量返回至上层模块里的Scan_Sig 变量。
二,程序源码
module key_test
(
clk,
rst_n,
key_in,
key_out
);
//端口信号
input clk,rst_n;
input [2:0] key_in;
output [2:0] key_out;
//定义寄存器
reg [19:0] count;
reg [2:0] key_scan;
//每次40ms判断一次
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
count <= 20'd0;
else
begin
if(count ==20'd999_999)
begin
count <= 20'b0;
key_scan <= key_in;
end
else
count <= count + 20'b1;
end
end
reg [2:0] key_scan_r;
always @(posedge clk)
begin
key_scan_r <= key_scan; //将输入信号打一拍,用于捕获下降沿
end
wire [2:0] flag_key = key_scan_r[2:0] & (~key_scan[2:0]); //捕获下降沿
reg [2:0] temp; //每个按键按下所得到的值
always @ (posedge clk or negedge rst_n) //判断哪个按键按下
begin
if (!rst_n)
begin temp<= 3'b111;end
else
begin
if(flag_key[0])
temp <= 3'b110;
else if(flag_key[1])
temp<= 3'b101;
else if(flag_key[2])
temp<= 3'b011;
else ;
end
end
assign key_out = temp;
endmodule
module smg_control_module
(
input CLK,
input RSTn,
input [23:0]Number_Sig,
output [3:0]Number_Data
);
parameter T1MS = 16'd49999; //1ms计数
reg [15:0]C1;
always @ ( posedge CLK or negedge RSTn )
begin
if( !RSTn )
C1 <= 16'd0;
else if( C1 == T1MS )
C1 <= 16'd0;
else
C1 <= C1 + 1'b1;
end
reg [3:0]i;reg [3:0]rNumber;
always @ ( posedge CLK or negedge RSTn )
begin
if( !RSTn )
begin
i <= 4'd0;
rNumber <= 4'd0;
end
else
case( i )
0:
if( C1 == T1MS ) i <= i + 1'b1;
else rNumber <= Number_Sig[23:20];//十万位数码管显示
1:
if( C1 == T1MS ) i <= i + 1'b1;
else rNumber <= Number_Sig[19:16];//万位数码管显示
2:
if( C1 == T1MS ) i <= i + 1'b1;
else rNumber <= Number_Sig[15:12]; //千位数码管显示
3:
if( C1 == T1MS ) i <= i + 1'b1;
else rNumber <= Number_Sig[11:8]; //百位数码管显示
4:
if( C1 == T1MS ) i <= i + 1'b1;
else rNumber <= Number_Sig[7:4]; //十位数码管显示
5:
if( C1 == T1MS ) i <= 4'd0;
else rNumber <= Number_Sig[3:0]; //低位数码管显示
endcase end
assign Number_Data = rNumber;
endmodule
module seg_led_key
(
input CLK,
input RSTn,
output [7:0]SMG_Data,
output [5:0]Scan_Sig,
input [2:0]button
);
wire [23:0]Number_Sig;
wire [2:0]key_value;
key_test u1
(
.clk(CLK),
.rst_n(RSTn),
.key_in(button),
.key_out(key_value)
);
demo_control_module U1
(
.CLK( CLK ),
.RSTn( RSTn ),
.Number_Sig( Number_Sig ),
.key_control(key_value)
);
smg_interface U2
(
.CLK( CLK ),
.RSTn( RSTn ),
.Number_Sig( Number_Sig ),
.SMG_Data( SMG_Data ), //
.Scan_Sig( Scan_Sig ) //
);
endmodule
// 编码模块: 十进制数 -> 7段数码管
module smg_encode_module
(
input CLK,
input RSTn,
input [3:0]Number_Data,
output [7:0]SMG_Data,
input flag
);
//数字码
parameter _0 = 8'b1100_0000, _1 = 8'b1111_1001, _2 = 8'b1010_0100,
_3 = 8'b1011_0000, _4 = 8'b1001_1001, _5 = 8'b1001_0010,
_6 = 8'b1000_0010, _7 = 8'b1111_1000, _8 = 8'b1000_0000,
_9 = 8'b1001_0000;
//
reg [7:0]rSMG;
always @ ( posedge CLK or negedge RSTn )
begin
if(!RSTn)
rSMG <= 8'b1111_1111;
else
case( Number_Data )
4'd0 : rSMG <= _0;
4'd1 : rSMG <= _1;
4'd2 : rSMG <= _2;
4'd3 : rSMG <= _3;
4'd4 : rSMG <= _4;
4'd5 : rSMG <= _5;
4'd6 : rSMG <= _6;
4'd7 : rSMG <= _7;
4'd8 : rSMG <= _8;
4'd9 : rSMG <= _9;
endcase
end
assign SMG_Data = flag ? rSMG & 8'b0111_1111 : rSMG;
endmodule
module smg_interface
(
input CLK,
input RSTn,
input [23:0]Number_Sig,
output [7:0]SMG_Data,
output [5:0]Scan_Sig
);
wire [3:0]Number_Data;
wire flag;
smg_control_module U1
(
.CLK( CLK ),
.RSTn( RSTn ),
.Number_Sig( Number_Sig ),
.Number_Data( Number_Data )
);
smg_encode_module U2
(
.CLK( CLK ),
.RSTn( RSTn ),
.Number_Data(Number_Data),
.SMG_Data( SMG_Data ),
.flag (flag)
);
smg_scan_module U3
(
.CLK( CLK ),
.RSTn( RSTn ),
.Scan_Sig( Scan_Sig ),
.flag (flag)
);
endmodule
// 数码管扫描模块 //
module smg_scan_module
(
input CLK,
input RSTn,
output [5:0]Scan_Sig,
output reg flag
);
parameter T1MS = 16'd49999;
reg [15:0]C1;
reg [3:0]i;
reg [5:0]rScan;
always @ ( posedge CLK or negedge RSTn )
begin
if( !RSTn )
C1 <= 16'd0;
else if( C1 == T1MS )
C1 <= 16'd0;
else
C1 <= C1 + 1'b1;
end
always @ ( posedge CLK or negedge RSTn )
begin
if( !RSTn )begin
flag <= 1'b0;
i <= 4'd0;
rScan <= 6'b100_000;
end
else
begin
flag <= 1'b0;
case( i )
0:
if( C1 == T1MS ) i <= i + 1'b1;
else rScan <= 6'b011_111;
//第一个数码选通
1:
if( C1 == T1MS ) i <= i + 1'b1;
else rScan <= 6'b101_111;
//第二个数码选通
2:
if( C1 == T1MS ) i <= i + 1'b1;
else rScan <= 6'b110_111;
//第三个数码选通
3:
if( C1 == T1MS ) i <= i + 1'b1;
else
begin
rScan <= 6'b111_011;
flag <= 1'b1;
end
//第四个数码选通
4:
if( C1 == T1MS ) i <= i + 1'b1;
else
rScan <= 6'b111_101;
//第五个数码选通
5:
if( C1 == T1MS ) i <= 4'd0;
else rScan <= 6'b111_110;
//第六个数码选通
endcase
end
end
assign Scan_Sig = rScan;
endmodule