counter-mod60

60进制计数器

郭高旭 ggx21@mails.tsinghua.edu.cn 2021010803

实验目的

  • 掌握组合逻辑电路的基本分析方法与设计方法;

  • 理解触发器的分析与设计方法;

  • 学会元件例化;

  • 学会利用软件仿真实现对数字电路的验证与分析

实验内容

  • 设计D触发器

  • 利用半加器构建60进制计数器

实验原理

D触发器:

输入:D, CP, Rd, Sd: in std_logic ;

输出:Q,nQ: out std_logic ;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
architecture arch of DFF is
begin
process(Rd, Sd, CP)
begin
if (Rd = '0') then
Q <= '0';
nQ <= '1';
elsif (Sd = '0') then
Q <= '1';
nQ <= '0';
elsif (CP'event and CP = '1') then
Q <= D;
nQ <= not D;
end if ;
end process ;
end arch;

过程中的三个 if 语句用于控制 D 触发器的行为。当 Rd 信号为 ‘0’ 时,Q 和 nQ 都被强制为 ‘0’ 和 ‘1’。当 Sd 信号为 ‘0’ 时,Q 和 nQ 都被强制为 ‘1’ 和 ‘0’。当 CP 信号上升沿(在事件发生条件 CP’event and CP = ‘1’ 下)发生时,D 触发器接收 D 信号,Q 和 nQ 的值被更新。

计数器:

基于上面构建的D触发器,可以构建六进制与十进制计数器,下面以六进制为例。

输入:clk, Rd, c0: in std_logic ;

输出:out_6: out std_logic_vector(3 downto 0)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
architecture click_6_bhv of click_6 is
component ourDFF is
port(
D, CP, Rd, Sd: in std_logic ;
Q: out std_logic := '0';
nQ: out std_logic := '1'
);
end component;
signal D, Q, nQ: std_logic_vector(2 downto 0);
begin
lb0: for i in 0 to 2 generate
Di: ourDFF port map(D(i), clk , Rd, '1', Q(i), nQ(i));
end generate lb0;
D(0) <= c0 xor Q(0);
D(1) <= ((not c0) and Q(1)) or (c0 and (nQ(2) and (Q(1) xor Q(0))));
D(2) <= ((not c0) and Q(2)) or (c0 and ((Q(2) and nQ(0)) or (Q(1) and Q(0))));
out_6(2 downto 0) <= Q;
out_6(3) <= '0';
end click_6_bhv;

首先generate三个 D 触发器的实例,其端口分别是 D、CP、Rd、Sd、Q 和 nQ。其中,D、CP、Rd 和 Sd 分别表示 D 触发器的输入端口 D、时钟、异步清零和异步置位,分别连接的是计数器输入端口 c0、clk、Rd 和常量’1’。Q 和 nQ 分别表示 D 触发器的输出端口 Q 和 nQ,这两个端口被访问和修改的是一个 std_logic_vector 类型的信号 D,由该信号内的三个元素 D(2 downto 0) 分别连接这三个 D 触发器的输入端口 D。注意到 D 触发器的输出信号 Q(0) 、Q(1) 和 Q(2) 作为后续逻辑的信号。

在 process 外部,当 c0 在时钟信号时一次产生一个计数脉冲时,D 触发器的输入信号 D(0)、D(1) 和 D(2) 会被根据 c0、Q(0)、Q(1)、Q(2)、nQ(0)、nQ(1)、nQ(2) 计算得到对应的取值,分别站三个位置的权位。

最后,计数器的值被送到输出端口 out_6 上,其中低三位连接 Q(2)、Q(1)、Q(0),因为这三个信号是计数器的低三位,最高位是输出默认设置为 0。

因此,每当输入端口 c0 产生一个计数脉冲时,计数器的值增加 1,计数器的最小值是 0,最大值是 5(即 101b)。

注意:六进制计数器作为高位,应该考虑一个低位进位输入c0,而10位计数器不考虑输入。

组合6进制计数器与10进制计数器:basic

输入:clk , rst : in std_logic ;

输出:low, high: out std_logic_vector(3 downto 0)

大致思路:引入一个6进制计数器与10进制计数器,再额外引进一个触发器用于判断是否进位。

1
2
3
4
5
6
7
8
9
10
begin
count_low: click_10 port map(clk, Rd, QL);
count_high: click_6 port map(clk, Rd, c0, QH);
trigger: ourDFF port map(D, clk, Rd, '1', c0);
-- Rd <= not (rst or(QH(0)and(((not QL(3))and(QL(2)and QL(1)))and (not QL(0))))); 16进制
Rd<=not (rst)--60进制
D <= (QL(3) and (not QL(2))) and ((not QL(1)) and (not QL(0)));
low <= QL;
high <= QH;
end basic_bhv;

在六十进制情况下,只有rst被触发,才激活异步清零;

而十六进制,rst被触发或判断到达十六,就异步清零

D:trigger的输入,在Low位到达8的时候为1,激活trigger.这样下一刻low位到达9,trigger修改低位进位输出c0,再下一刻使得高位加1.

low,high输出.

七位译码管.

为了让输出在不带译码器的数码管显示,需要一个七位译码管.实现不作分析,参见代码.

点击触发:

基本要求,用开关实现clk,rst.

时钟触发:

基于点击触发:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
begin
main_count: click port map(clk2, rst , lout , hout);
process(pause, clk , rst )
begin
if ( rst = '1') then
t <= 0;
clk2 <= '0';
elsif (clk 'event and clk = '1' and pause = '0') then
if (t = 1000000) then
t <= 0;
clk2 <= '1';
elsif (t = 500000) then
t <= t + 1;
clk2 <= '0';
else
t <= t + 1;
end if ;
end if ;
end process ;
end counter_bhv;

逢1M模拟一次clk,一半低电平一半高电平.

实验现象

16进制触发器与60进制触发器均正常工作.

实验后优化了代码,转到了使用译码管的实现.

发现取消clk的低电平也即

1
2
3
elsif (t = 500000) then
t <= t + 1;
clk2 <= '0';

一样work




本文总阅读量