verilog计数器实验报告.docx
《verilog计数器实验报告.docx》由会员分享,可在线阅读,更多相关《verilog计数器实验报告.docx(19页珍藏版)》请在冰点文库上搜索。
verilog计数器实验报告
计数器
1、实现目标及介绍
实验实现了一个简易的计数器,计数范围可达899(0~899),通过key4按键计数,每按下一次,计数加一,百位数显示在led上,个位与十位显示在数码管上。
为十进制计数,数码管1计数到九后置零。
数码管2获得进位加一,数码管2到9后当再次获得个位进位时再次向百位进一,点亮led1,每百位点亮一个led。
此外key4为清零键,可随时按键清零。
2、效果展示
计数99
清零
计数100
视频展示(双击观看)
3、代码实现与模块分析
1.顶层模块
modulejishuqi
(
inputwireclk,rst,//时钟和复位输入
inputwirekey1,//拨码计
outputwire[7:
0]led,
outputwire[8:
0]segment_led_1,segment_led_2//数码管输出
);
wirekey_pulse;
reg[7:
0]cnt;//计时计数器
reg[7:
0]hud;//百位计数
initialhud[7:
0]<=8'b11111111;
always@(posedgeclkornegedgerst)
begin//数码管显示要按照十进制的方式显示
if(!
rst)
begincnt<=8'h00;
hud[7:
0]<=8'b11111111;
end
elseif(key_pulse)
begin
if(cnt[3:
0]==4'd9)//个位进位判断
begin
cnt[3:
0]<=4'd0;
if(cnt[7:
4]==4'd9)//十位进位判断
begin
cnt[7:
4]<=4'd0;
hud[7:
0]<=hud[7:
0]-1'b1;
end
else
cnt[7:
4]<=cnt[7:
4]+1'b1;
end
elsecnt[3:
0]<=cnt[3:
0]+1'b1;
end
else
cnt<=cnt;
end
assignled=hud;
//例化调用数码管显示模块
segmentu2
(
.seg_data_1(cnt[7:
4]),//g_datainput
.seg_data_2(cnt[3:
0]),//g_datainput
.seg_led_1(segment_led_1),//MSB~LSB=SEG,DP,G,F,E,D,C,B,A
.seg_led_2(segment_led_2)//MSB~LSB=SEG,DP,G,F,E,D,C,B,A
);
//例化调用消抖模块
debounceu1(
.clk(clk),
.rst(rst),
.key(key1),
.key_pulse(key_pulse)
);
endmodule
2.数码管显示模块
modulesegment(seg_data_1,seg_data_2,seg_led_1,seg_led_2);
input[3:
0]seg_data_1;//数码管需要显示0~9十个数字,所以最少需要4位输入做译码
input[3:
0]seg_data_2;//小脚丫上第二个数码管
output[8:
0]seg_led_1;//在小脚丫上控制一个数码管需要9个信号MSB~LSB=DIG、DP、G、F、E、D、C、B、A
output[8:
0]seg_led_2;//在小脚丫上第二个数码管的控制信号MSB~LSB=DIG、DP、G、F、E、D、C、B、A
reg[8:
0]seg[9:
0];
//定义了一个reg型的数组变量,相当于一个10*9的存储器,存储器一共有10个数,每个数有9位宽
initial
//在过程块中只能给reg型变量赋值,Verilog中有两种过程块always和initial
//initial和always不同,其中语句只执行一次
begin
seg[0]=9'h3f;//对存储器中第一个数赋值9'b00_0011_1111,相当于共阴极接地,DP点变低不亮,7段显示数字0
seg[1]=9'h06;//7段显示数字1
seg[2]=9'h5b;//7段显示数字2
seg[3]=9'h4f;//7段显示数字3
seg[4]=9'h66;//7段显示数字4
seg[5]=9'h6d;//7段显示数字5
seg[6]=9'h7d;//7段显示数字6
seg[7]=9'h07;//7段显示数字7
seg[8]=9'h7f;//7段显示数字8
seg[9]=9'h6f;//7段显示数字9
end
assignseg_led_1=seg[seg_data_1];//连续赋值,这样输入不同四位数,就能输出对于译码的9位输出
assignseg_led_2=seg[seg_data_2];
endmodule
3.按键消抖模块
//按键消抖
moduledebounce(clk,rst,key,key_pulse);
parameterN=2;//要消除的按键的数量
inputclk;
inputrst;
input[N-1:
0]key;//输入的按键
output[N-1:
0]key_pulse;//按键动作产生的脉冲
reg[N-1:
0]key_rst_pre;//定义一个寄存器型变量存储上一个触发时的按键值
reg[N-1:
0]key_rst;//定义一个寄存器变量储存储当前时刻触发的按键值
wire[N-1:
0]key_edge;//检测到按键由高到低变化是产生一个高脉冲
//利用非阻塞赋值特点,将两个时钟触发时按键状态存储在两个寄存器变量中
always@(posedgeclkornegedgerst)
begin
if(!
rst)
begin
key_rst<={N{1'b1}};//初始化时给key_rst赋值全为1,{}中表示N个1
key_rst_pre<={N{1'b1}};
end
else
begin
key_rst<=key;//第一个时钟上升沿触发之后key的值赋给key_rst,同时key_rst的值赋给key_rst_pre
key_rst_pre<=key_rst;//非阻塞赋值。
相当于经过两个时钟触发,key_rst存储的是当前时刻key的值,key_rst_pre存储的是前一个时钟的key的值
end
end
assignkey_edge=key_rst_pre&(~key_rst);//脉冲边沿检测。
当key检测到下降沿时,key_edge产生一个时钟周期的高电平
reg[17:
0]cnt;//产生延时所用的计数器,系统时钟12MHz,要延时20ms左右时间,至少需要18位计数器
//产生20ms延时,当检测到key_edge有效是计数器清零开始计数
always@(posedgeclkornegedgerst)
begin
if(!
rst)
cnt<=18'h0;
elseif(key_edge)
cnt<=18'h0;
else
cnt<=cnt+1'h1;
end
reg[N-1:
0]key_sec_pre;//延时后检测电平寄存器变量
reg[N-1:
0]key_sec;
//延时后检测key,如果按键状态变低产生一个时钟的高脉冲。
如果按键状态是高的话说明按键无效
always@(posedgeclkornegedgerst)
begin
if(!
rst)
key_sec<={N{1'b1}};
elseif(cnt==18'h3ffff)
key_sec<=key;
end
always@(posedgeclkornegedgerst)
begin
if(!
rst)
key_sec_pre<={N{1'b1}};
else
key_sec_pre<=key_sec;
end
assignkey_pulse=key_sec_pre&(~key_sec);
endmodule
4、源码与源码图片
modulejishuqi
(
inputwireclk,rst,//时钟和复位输入
inputwirekey1,//拨码计
outputwire[7:
0]led,
outputwire[8:
0]segment_led_1,segment_led_2//数码管输出
);
wirekey_pulse;
reg[7:
0]cnt;//计时计数器
reg[7:
0]hud;//百位计数
initialhud[7:
0]<=8'b11111111;
always@(posedgeclkornegedgerst)
begin//数码管显示要按照十进制的方式显示
if(!
rst)
begincnt<=8'h00;
hud[7:
0]<=8'b11111111;
end
elseif(key_pulse)
begin
if(cnt[3:
0]==4'd9)
begin
cnt[3:
0]<=4'd0;
if(cnt[7:
4]==4'd9)
begin
cnt[7:
4]<=4'd0;
hud[7:
0]<=hud[7:
0]-1'b1;
end
else
cnt[7:
4]<=cnt[7:
4]+1'b1;
end
elsecnt[3:
0]<=cnt[3:
0]+1'b1;
end
else
cnt<=cnt;
end
assignled=hud;
segmentu2
(
.seg_data_1(cnt[7:
4]),//g_datainput
.seg_data_2(cnt[3:
0]),//g_datainput
.seg_led_1(segment_led_1),//MSB~LSB=SEG,DP,G,F,E,D,C,B,A
.seg_led_2(segment_led_2)//MSB~LSB=SEG,DP,G,F,E,D,C,B,A
);
debounceu1(
.clk(clk),
.rst(rst),
.key(key1),
.key_pulse(key_pulse)
);
endmodule
//按键消抖
moduledebounce(clk,rst,key,key_pulse);
parameterN=2;//要消除的按键的数量
inputclk;
inputrst;
input[N-1:
0]key;//输入的按键
output[N-1:
0]key_pulse;//按键动作产生的脉冲
reg[N-1:
0]key_rst_pre;//定义一个寄存器型变量存储上一个触发时的按键值
reg[N-1:
0]key_rst;//定义一个寄存器变量储存储当前时刻触发的按键值
wire[N-1:
0]key_edge;//检测到按键由高到低变化是产生一个高脉冲
//利用非阻塞赋值特点,将两个时钟触发时按键状态存储在两个寄存器变量中
always@(posedgeclkornegedgerst)
begin
if(!
rst)
begin
key_rst<={N{1'b1}};//初始化时给key_rst赋值全为1,{}中表示N个1
key_rst_pre<={N{1'b1}};
end
else
begin
key_rst<=key;//第一个时钟上升沿触发之后key的值赋给key_rst,同时key_rst的值赋给key_rst_pre
key_rst_pre<=key_rst;//非阻塞赋值。
相当于经过两个时钟触发,key_rst存储的是当前时刻key的值,key_rst_pre存储的是前一个时钟的key的值
end
end
assignkey_edge=key_rst_pre&(~key_rst);//脉冲边沿检测。
当key检测到下降沿时,key_edge产生一个时钟周期的高电平
reg[17:
0]cnt;//产生延时所用的计数器,系统时钟12MHz,要延时20ms左右时间,至少需要18位计数器
//产生20ms延时,当检测到key_edge有效是计数器清零开始计数
always@(posedgeclkornegedgerst)
begin
if(!
rst)
cnt<=18'h0;
elseif(key_edge)
cnt<=18'h0;
else
cnt<=cnt+1'h1;
end
reg[N-1:
0]key_sec_pre;//延时后检测电平寄存器变量
reg[N-1:
0]key_sec;
//延时后检测key,如果按键状态变低产生一个时钟的高脉冲。
如果按键状态是高的话说明按键无效
always@(posedgeclkornegedgerst)
begin
if(!
rst)
key_sec<={N{1'b1}};
elseif(cnt==18'h3ffff)
key_sec<=key;
end
always@(posedgeclkornegedgerst)
begin
if(!
rst)
key_sec_pre<={N{1'b1}};
else
key_sec_pre<=key_sec;
end
assignkey_pulse=key_sec_pre&(~key_sec);
endmodule
modulesegment(seg_data_1,seg_data_2,seg_led_1,seg_led_2);
input[3:
0]seg_data_1;//数码管需要显示0~9十个数字,所以最少需要4位输入做译码
input[3:
0]seg_data_2;//小脚丫上第二个数码管
output[8:
0]seg_led_1;//在小脚丫上控制一个数码管需要9个信号MSB~LSB=DIG、DP、G、F、E、D、C、B、A
output[8:
0]seg_led_2;//在小脚丫上第二个数码管的控制信号MSB~LSB=DIG、DP、G、F、E、D、C、B、A
reg[8:
0]seg[9:
0];
//定义了一个reg型的数组变量,相当于一个10*9的存储器,存储器一共有10个数,每个数有9位宽
initial
//在过程块中只能给reg型变量赋值,Verilog中有两种过程块always和initial
//initial和always不同,其中语句只执行一次
begin
seg[0]=9'h3f;//对存储器中第一个数赋值9'b00_0011_1111,相当于共阴极接地,DP点变低不亮,7段显示数字0
seg[1]=9'h06;//7段显示数字1
seg[2]=9'h5b;//7段显示数字2
seg[3]=9'h4f;//7段显示数字3
seg[4]=9'h66;//7段显示数字4
seg[5]=9'h6d;//7段显示数字5
seg[6]=9'h7d;//7段显示数字6
seg[7]=9'h07;//7段显示数字7
seg[8]=9'h7f;//7段显示数字8
seg[9]=9'h6f;//7段显示数字9
end
assignseg_led_1=seg[seg_data_1];//连续赋值,这样输入不同四位数,就能输出对于译码的9位输出
assignseg_led_2=seg[seg_data_2];
endmodule