前言
最近在北邮沉迷学习数电,第一个验收的实验是实现循环自动计数的计数器。就这次实验写一个小结回顾,也希望能给后来人启发。
实验要求
完成一个计数值为00~19的计数器的设计和仿真,并下载到实验板上验证。要求如下:
- 计数值每秒加1,加到19后回0
BTN0
为暂停键,按一下计时停止,再按一下计时继续,要求为BTN0
设计防抖电路- 在数码管
DISP1
和DISP0
上显示计数结果 BTN7
为复位键,无论何时按下计数值都回到00
- 实验板上时钟选择
100Hz
系统分析
输入输出端口设计
首先,我们先设计系统的输入和输出。
输入显然有两个:暂停按钮 btn0
和复位按钮 reset
。
输出是数码管,但是我们发现数码管共用一个输入端口,所以为了实现多位数字显示,我们需要用 扫描 的方式显示。于是我们定义输出为 seg
,位选为 cat
。
我们可以定义整个顶层模块如下:
module segCounter (
input wire clk,
input wire btn0,
reset,
output reg [6:0] seg,
output reg [7:0] cat
);
系统模块设计
按键消抖模块
由于按键动作的时刻和按下时间长短随机,并且存在开关簧片反弹导致电平抖动,我们需要设计一个按键消抖模块。一般抖动时间小于 20ms
,所以我们只需要检测高电平持续的长度大于20ms(实验里取30ms为检测时间)时再置高电平即可。
可见,btn0
是原始的按键输入波形, cnt_3
的作用是基于 clk
实现计数,每当 clk
到上升沿时,若高电平则+1,计数到3后则 stable_flag
置高电平,同时 press
产生一个周期的高电平。
cnt_3
为什么要计数到3呢?因为 clk
频率是 100Hz ,频率是周期的倒数,所以简单换算如下:$$ f=\frac{1}{T} \Rightarrow T=\frac{1}{f}=\frac{1}{100}s=10ms $$每隔10ms clk
来一个上升沿, cnt_3
+1,则当 cnt_3
为3时显然时间就过去了30ms。
消抖模块对应代码如下:
// 消抖
always @(posedge clk or posedge reset) begin
if (reset == 1'b1) begin
cnt_3 <= 3'b000;
end else if (cnt_3 == 3'b011) begin
cnt_3 <= 3'b000;
end else if (btn0 == 1'b1) begin
cnt_3 <= cnt_3 + 3'b001;
end else begin
cnt_3 <= 3'b000;
end
end
always @(posedge clk or posedge reset) begin
if (reset == 1'b1) begin
stable_flag <= 1'b0;
end else if (btn0 == 1'b1 && cnt_3 == 'd3) begin
stable_flag <= 1'b1;
end else if (btn0 == 1'b0) begin
stable_flag <= 1'b0;
end
end
always @(posedge clk or posedge reset) begin
if (reset == 1'b1) begin
press <= 1'b0;
end else if (stable_flag == 1'b0 && cnt_3 == 'd3) begin
press <= 1'b1;
end else begin
press <= 1'b0;
end
end
复位功能设计
我们采用异步复位( posedge clk or posedge reset
里面用 or
),当reset按下时就立刻执行复位操作。因为复位功能显然优先级最高,所以所有 always
块内我们都先验证 reset
的状态。
数码管的显示
如图,要使得共阴极数码管点亮,需要改变的是阳极的状态。而阳极是多个数码管共用的,所以我们借助人 视觉暂留 的特点,用扫描的方式显示所有数字(类似显示屏的原理)。
可见,我们使用 select
区分当前显示的是十位还是个位。译码器负责转换数字到数码管阳极状态的映射关系,扫描控制电路负责控制不同位数数码管的点亮与否。
代码实现
最后,整个代码如下:
module segCounter (
input wire clk,
input wire btn0,
reset,
output reg [6:0] seg,
output reg [7:0] cat
);
reg [2:0] cnt_3;
reg [6:0] cnt_100;
reg stable_flag, press, ctr, select;
reg [3:0] cnt1;
reg [3:0] cnt2;
reg [3:0] bin;
// 消抖
always @(posedge clk or posedge reset) begin
if (reset == 1'b1) begin
cnt_3 <= 3'b000;
end else if (cnt_3 == 3'b011) begin
cnt_3 <= 3'b000;
end else if (btn0 == 1'b1) begin
cnt_3 <= cnt_3 + 3'b001;
end else begin
cnt_3 <= 3'b000;
end
end
always @(posedge clk or posedge reset) begin
if (reset == 1'b1) begin
stable_flag <= 1'b0;
end else if (btn0 == 1'b1 && cnt_3 == 'd3) begin
stable_flag <= 1'b1;
end else if (btn0 == 1'b0) begin
stable_flag <= 1'b0;
end
end
always @(posedge clk or posedge reset) begin
if (reset == 1'b1) begin
press <= 1'b0;
end else if (stable_flag == 1'b0 && cnt_3 == 'd3) begin
press <= 1'b1;
end else begin
press <= 1'b0;
end
end
// 暂停标志
always @(posedge press or posedge reset) begin
if (reset == 1'b1) begin
ctr <= 1'b0;
end else begin
ctr <= ~ctr;
end
end
// 时钟倍频(cnt_100 clk计数)
always @(posedge clk or posedge reset) begin
if (reset == 1'b1) begin
cnt_100 <= 7'b000_0000;
end else if (cnt_100 == 7'b110_0100 && ctr == 1'b0) begin
cnt_100 <= 7'b000_0000;
end else if (ctr == 1'b0) begin
cnt_100 <= cnt_100 + 7'b000_0001;
end
end
// 显示(cnt1 个位,cnt2 十位)
always @(posedge clk, posedge reset) begin
if (reset == 1'b1) begin
cnt1 <= 0;
cnt2 <= 0;
end else if (cnt_100 == 7'b110_0100 && ctr == 1'b0) begin
if (cnt1 == 4'b1001) begin
cnt1 <= 0;
if (cnt2 == 0) cnt2 <= cnt2 + 1;
else cnt2 <= 0;
end else begin
cnt1 <= cnt1 + 1;
end
end
end
// 扫描
always @(posedge clk, posedge reset) begin
if (reset == 1'b1) begin
cat <= 8'b1111_1111;
bin <= 0;
end else begin
select <= ~select;
if (select == 1'b0) begin
cat <= 8'b1111_1110;
bin <= cnt1;
end else begin
cat <= 8'b1111_1101;
bin <= cnt2;
end
end
end
// 译码
always @(bin) begin
case (bin)
4'd0: seg = 7'b1111110;
4'd1: seg = 7'b0110000;
4'd2: seg = 7'b1101101;
4'd3: seg = 7'b1111001;
4'd4: seg = 7'b0110011;
4'd5: seg = 7'b1011011;
4'd6: seg = 7'b1011111;
4'd7: seg = 7'b1110000;
4'd8: seg = 7'b1111111;
4'd9: seg = 7'b1111011;
default: seg = 7'b0000000;
endcase
end
endmodule
实验用板如图,引脚对应如下。
大佬!能不能请教一下你的博客搭建使用的是什么工具呀!你的博客很丝滑欸!!!
用的Typecho哦,比wordpress轻量些
大部分丝滑动画是前端做的
赞(。^▽^)