计数器FPGA电路实验作业
实验内容1
内容1视频:计数器单数码管显示
人工RTL图
顶层设计
时间基准模块的OV产生以1s为周期的脉冲信号;带使能的多周期计数器进行循环计数,并以时间基准模块的OV作为使能端;4-7译码器用于译码使在数码管上显示对应字符。
时间基准模块
在CLK的上升沿,判断计数值CNTVAL是否小于计数循环最大值MAX_VAL,若是,则输出CNTVAL+1,否则输出循环初值0。当计数到最大值时,OV溢出为1,代表一个周期。
带使能的多周期计数器
同步高电平复位,在CLK上升沿,且RST高电平复位,给输出CNT、循环最大值CNT_VAL分别赋初值0、6。RST低电平且使能有效时,判断输出CNT是否小于循环最大值CNT_VAL,若是,则输出CNT+1,否则输出CNT为0,并判断循环最大值CNT_VAL是否小于9,若是,则CNT_VAL++,否则CNT_VAL赋6。使能为0时,保持输出值CNT。
数码管4-8译码器_无小数点
数码管为共阳极,即输出为低电压时,相应字码段点亮,反之熄灭。根据下图可得到译码字段即可,RTL根据译码字段通过或门可以画出来,略过。
Quartus生成的RTL图
顶层设计 时间基准模块 带使能的多周期计数器 数码管4-8译码器_无小数点
SignalTap分析
计数器的计数值的SignalTap截图,使用Segment 模式,捕获一个完整的计数循环过程中所有的计数值。以时间基准模块的OV为触发信号,2k的采样深度,设置segmented为64段32点进行采样,结果如下:
代码片
时间基准模块
module cnt_sync(
CLK ,
CNTVAL,
OV );
parameter CNTVAL_WL =
32;
parameter MAX_VAL =
50_000_000;
input CLK;
output [CNTVAL_WL-
1:
0] CNTVAL;
output OV;
reg [CNTVAL_WL-
1:
0] CNTVAL;
reg OV;
always @ (posedge CLK)
begin
if(CNTVAL < MAX_VAL)
CNTVAL <= CNTVAL +
1'b1;
else
CNTVAL <=
0;
end
always @ (CNTVAL)
begin
if(CNTVAL == MAX_VAL)
OV =
1'b1;
else
OV =
1'b0;
end
endmodule
带使能的多周期计数模块
module cnt_en_circle_0tomax6_9(
CLK ,
EN ,
RST ,
CNT ,
OV );
input CLK , RST , EN ;
output OV ;
output [
4-
1:
0] CNT;
parameter CNT_VAL_MIN=
6;
parameter CNT_VAL_MAX=
9;
reg [
4-
1:
0] CNT;
reg [
4-
1:
0] CNT_VAL=CNT_VAL_MIN;
reg OV;
always @ (posedge CLK)
begin
if(RST)
begin
CNT <=
0;
CNT_VAL <= CNT_VAL_MIN;
end
else begin
if(EN)
begin
if(CNT < CNT_VAL)
CNT <= CNT +
1'b1;
else begin
CNT <=
0;
if(CNT_VAL < CNT_VAL_MAX)
CNT_VAL <= CNT_VAL +
1'b1;
else
CNT_VAL <= CNT_VAL_MIN;
end
end
else CNT <= CNT ;
end
end
always @ (CNT)
begin
if( CNT == CNT_VAL)
OV =
1'b1 ;
else
OV =
1'b0 ;
end
endmodule
数码管4-8译码器_无小数点
module dec_4to8(
IN ,
OUT);
input [
4-
1:
0]
IN ;
output [
8-
1:
0]
OUT ;
reg [
8-
1:
0]
OUT ;
always @ (
IN)
begin
case(
IN) //判断输入值是几就相应编码使在数码管上显示对应字符
4'b0000:
OUT =
8'b11000000;//
0
4'b0001:
OUT =
8'b11111001;//
1
4'b0010:
OUT =
8'b10100100;//
2
4'b0011:
OUT =
8'b10110000;//
3
4'b0100:
OUT =
8'b10011001;//
4
4'b0101:
OUT =
8'b10010010;//
5
4'b0110:
OUT =
8'b10000010;//
6
4'b0111:
OUT =
8'b11111000;//
7
4'b1000:
OUT =
8'b10000000;//
8
4'b1001:
OUT =
8'b10011000;//
9
4'b1010:
OUT =
8'b10001000;//A
4'b1011:
OUT =
8'b10000011;//b
4'b1100:
OUT =
8'b11000110;//C
4'b1101:
OUT =
8'b10100001;//d
4'b1110:
OUT =
8'b10000110;//E
4'b1111:
OUT =
8'b10001110;//F
default:
OUT =
8'bx;
endcase
end
endmodule // module dec_4to8
实验内容2
内容2视频:计数器四数码管显示
人工RTL图
顶层设计
时间基准模块的OV产生以1s为周期的脉冲信号;带使能的多周期计数器进行循环计数,并以时间基准模块的OV作为使能端;to_dec模块用来将计数值选择在哪个数码管上显示;4-8译码器用于译码使在数码管上显示对应字符。
时间基准模块
在CLK的上升沿,判断计数值CNTVAL是否小于计数循环最大值MAX_VAL,若是,则输出CNTVAL+1,否则输出循环初值0。当计数到最大值时,OV溢出为1,代表一个周期。
带使能的多周期计数器
异步高电平复位,RST高电平时,给输出CNT、循环最大值CNT_VAL分别赋初值0、6。RST低电平且使能有效时,判断输出CNT是否小于循环最大值CNT_VAL,若是,则输出CNT+1,否则输出CNT为0,并判断循环最大值CNT_VAL是否小于9,若是,则CNT_VAL++,否则CNT_VAL赋6。使能为0时,保持输出值CNT。
to_dec模块
16位的输出送给四个4-8译码管,来控制数码管亮灭和显示数字复位时,16位的输出全置1,则数码管就全灭掉在EN的下降沿,计EN的数。由case语句判断计数0,1,2,3,则相应的数码管就会显示数字。
数码管4-8译码器_无小数点
数码管为共阳极,即输出为低电压时,相应字码段点亮,反之熄灭。当四个数码管的所有字段都为高时,4个数码管都熄灭。
Quartus生成的RTL图
顶层设计 时间基准模块 带使能的多周期计数器 to_dec模块
SignalTap分析
计数器的计数值的SignalTap截图,使用Segment 模式,捕获一个完整的计数循环过程中所有的计数值。以时间基准模块的OV为触发信号,256点的采样深度,设置segmented为64段4点进行采样,结果如下: 在数码管上显示情况:左1-FFFx;左2-FFxF;左3-FxFF;右1-xFFF。其中x表示在数码管上显示的相应数字。以数码管左1和左2的显示情况为例,SignalTap见下图: 复位时所有数码管熄灭: 本设计仍存在的问题:复位之后,0显示的时间不足1s,这是由于采用上升沿触发、高电平复位。
代码片
时间基准模块
module cnt_sync(
CLK ,
CNTVAL,
OV );
parameter CNTVAL_WL =
32;
parameter MAX_VAL =
50_000_000;
input CLK;
output [CNTVAL_WL-
1:
0] CNTVAL;
output OV;
reg [CNTVAL_WL-
1:
0] CNTVAL;
reg OV;
always @ (posedge CLK)
begin
if(CNTVAL < MAX_VAL)
CNTVAL <= CNTVAL +
1'b1;
else
CNTVAL <=
0;
end
always @ (CNTVAL)
begin
if(CNTVAL == MAX_VAL)
OV =
1'b1;
else
OV =
1'b0;
end
endmodule
带使能的多周期计数器
module cnt_en_circle_0tomax6_9(
CLK ,
EN ,
RST ,
CNT ,
OV );
input CLK , RST , EN ;
output OV ;
output [
4-
1:
0] CNT;
parameter CNT_VAL_MIN=
6;
parameter CNT_VAL_MAX=
9;
reg [
4-
1:
0] CNT;
reg [
4-
1:
0] CNT_VAL=CNT_VAL_MIN;
reg OV;
always @ (posedge CLK
or posedge RST)
begin
if(RST)
begin
CNT <=
0;
CNT_VAL <= CNT_VAL_MIN;
end
else begin
if(EN)
begin
if(CNT < CNT_VAL)
CNT <= CNT +
1'b1;
else begin
CNT <=
0;
if(CNT_VAL < CNT_VAL_MAX)
CNT_VAL <= CNT_VAL +
1'b1;
else
CNT_VAL <= CNT_VAL_MIN;
end
end
else CNT <= CNT ;
end
end
always @ (CNT)
begin
if( CNT == CNT_VAL)
OV =
1'b1 ;
else
OV =
1'b0 ;
end
endmodule
to_dec模块
module to_dec(
// CLK ,//本模块不需要用到
IN ,
EN ,//enable counter
RST ,//asynchronous reset, active high
OUT);
input EN,RST;
input [
3:
0]
IN;
output [
3:
0]
OUT;
reg [
15:
0]
OUT;
reg [
3:
0]CNT;
always @ (negedge EN
or posedge RST)
begin
//这里EN要采用下降沿,因为在EN高电平期间,对应的输入
IN是最大值,这个值应算在前一个周期里,故用下降沿触发
//如果采用上升沿触发,则EN高电平时的
IN算在下一个周期,实际现象是:每个数码管的最大值圆周右移一位显示。
if(RST)
begin
CNT <=
0;
//
OUT[
15:
0] <=
16'hffff;
//注意:上面被注释掉的语句错误,否则编译出现错误如下
//Error (
10028): Can
't resolve multiple
constant drivers
for net
"OUT[15]" at rtl_module.v(
60)
//原因:
OUT信号在两个always并行块里。两个进程里都有同一个条件判断的话,会产生并行信号冲突的问题。
//同一个信号不允许在多个进程中赋值,否则则为多驱动。
//进程的并行性决定了多进程不同能对同一个对象进行赋值。
end
else begin
if(CNT <
3)
CNT <= CNT +
1'b1;
else
CNT <=
0;
end
end
always @ (CNT)
begin
if(RST)
OUT[
15:
0] <=
16'hffff; //
all HEX LED turn off
else begin
case(CNT)
2'b00://the left-first HEX LED display
begin
OUT[
3:
0] <=
IN[
3:
0];
OUT[
7:
4] <=
4'b1111;
OUT[
11:
8] <=
4'b1111;
OUT[
15:
12] <=
4'b1111;
end
2'b01://the left-second HEX LED display
begin
OUT[
3:
0] <=
4'b1111;
OUT[
7:
4] <=
IN[
3:
0];
OUT[
11:
8] <=
4'b1111;
OUT[
15:
12] <=
4'b1111;
end
2'b10://the left-third HEX LED display
begin
OUT[
3:
0] <=
4'b1111;
OUT[
7:
4] <=
4'b1111;
OUT[
11:
8] <=
IN[
3:
0];
OUT[
15:
12] <=
4'b1111;
end
2'b11://the right-first HEX LED display
begin
OUT[
3:
0] <=
4'b1111;
OUT[
7:
4] <=
4'b1111;
OUT[
11:
8] <=
4'b1111;
OUT[
15:
12] <=
IN[
3:
0];
end
endcase
end
end
endmodule //module to_dec
数码管4-8译码器_无小数点
module dec_4to8(
IN ,
OUT);
input [
4-
1:
0]
IN ;
output [
8-
1:
0]
OUT ;
reg [
8-
1:
0]
OUT ;
always @ (
IN)
begin
case(
IN) //判断输入值是几就相应编码使在数码管上显示对应字符
4'b0000:
OUT =
8'b11000000;//
0
4'b0001:
OUT =
8'b11111001;//
1
4'b0010:
OUT =
8'b10100100;//
2
4'b0011:
OUT =
8'b10110000;//
3
4'b0100:
OUT =
8'b10011001;//
4
4'b0101:
OUT =
8'b10010010;//
5
4'b0110:
OUT =
8'b10000010;//
6
4'b0111:
OUT =
8'b11111000;//
7
4'b1000:
OUT =
8'b10000000;//
8
4'b1001:
OUT =
8'b10011000;//
9
4'b1010:
OUT =
8'b10001000;//A
4'b1011:
OUT =
8'b10000011;//b
4'b1100:
OUT =
8'b11000110;//C
4'b1101:
OUT =
8'b10100001;//d
4'b1110:
OUT =
8'b10000110;//E
4'b1111:
OUT =
8'b11111111;//不显示
default:
OUT =
8'bx;
endcase
end
endmodule // module dec_4to8