我是靠谱客的博主 活泼金鱼,这篇文章主要介绍HEU大二数电时序逻辑电路设计实验Contents1 实验目的2 实验仪器3 子任务4 心得体会,现在分享给大家,希望可以做个参考。

Contents


1 实验目的

2 实验仪器

3 子任务

3.1 消抖电路

  • 实验原理
  • 实验步骤
  • 具体实现
  • 问题解决

3.2 简易篮球比赛计分器

  • 实验原理
  • 实验步骤
  • 具体实现
  • 问题解决

4 结论心得


1 实验目的

  • 掌握时序逻辑电路的一般设计方法。
  • 掌握消抖电路的设计方法。
  • 通过 V e r i l o g Verilog Verilog 语言实现一个简单篮球记分器。

2 实验仪器

  • F P G A FPGA FPGA 开发板 D E 1 − S o C DE1-SoC DE1SoC,如图所示。

在这里插入图片描述

3 子任务

3.1 消抖电路

通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。因而在闭合及断开的瞬间均伴随有一连串的抖动。按键抖动会引起一次按键被误读多次。为确保CPU对键的一次闭合仅作一次处理,必须去除键抖动。在键闭合稳定时读取键的状态,并且必须判别到键释放稳定后再作处理。

实验原理

RcjHKI.jpg

抖动时间的长短由按键的机械特性决定,一般为 5 m s ~ 10 m s 5ms~10ms 5ms10ms 。这是一个很重要的时间参数,在很多场合都要用到。按键稳定闭合时间的长短则是由操作人员的按键动作决定的,一般为零点几秒至数秒。单片机一般采用延迟重采样的方式进行消抖。当检测到信号为低时,延迟一段时间(一般为 20 m s 20ms 20ms ),再次检测信号是否为低,如果为低,则证明按键按下,否则认为按键没有按下,继续下一次检查。
最后,通过实现如下功能的电路来验证消抖是否成功。

  • 消抖脉冲为 500 H z 500Hz 500Hz
  • 用按键作为消抖电路的输入,消抖结果控制一个十进制计数器,用 1 1 1 位数码管显示计数结果。

计数器迭代的流程如图所示:

机械按键触发
消抖电路消抖
计数器迭代一次
数码管显示迭代结果

实验步骤

  1. 根据消抖脉冲要求设计分频计数器。
  2. 设计数码管显示电路。
  3. 编写 V e r i l o g Verilog Verilog 程序并进行调试。
  4. 下载到 F P G A FPGA FPGA 开发板上验证程序相关功能。

具体实现

Q u a r t u s Quartus Quartus 中先编写消抖电路程序并封装成一个模块,程序如下所示:

Codes

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
module xiaodou ( input clk , //输入时钟信号,开发板上是50MHz input rst_n , //复位键(低电平触发) input key_in, //对应的机械按键 output reg clk_500hz, //分频出的500Hz时钟脉冲信号 output key_done //按键按下动作完成标志 ); reg [25:0]div_cnt; //分频计数器 always@(posedge clk or negedge rst_n) //获得500Hz时钟脉冲信号 begin if(!rst_n) begin div_cnt <= 0; clk_500hz <= 0; end else if(div_cnt == 99999) //计数十万次反转状态 begin div_cnt <= 0; clk_500hz <= ~clk_500hz; end else begin div_cnt <= div_cnt + 1; clk_500hz <= clk_500hz; end end reg qout; reg key_tmp1,key_tmp2; parameter n = 10; reg [25:0] cnt; always@(posedge clk_500hz or negedge rst_n) begin if(!rst_n) begin cnt <= 0; qout <= 0; end else if(key_in == 0) //按键按下 begin if(cnt == n-1) //持续2ms的话判定按下 begin cnt <= cnt; qout <= 1; end else begin cnt <= cnt+1; qout <= 0; end end else begin qout <= 0; cnt <= 0; end end /*提取前后按键信号*/ always@(posedge clk_500hz or negedge rst_n) begin if(!rst_n) begin key_tmp1 <= 0; key_tmp2 <= 0; end else begin key_tmp1 <= qout; key_tmp2 <= key_tmp1; end end assign key_done = key_tmp1 & (~ key_tmp2); endmodule

消抖模块电路逻辑图

在这里插入图片描述

然后编写十进制计数器程序,代码如下:

Codes

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
module count ( input clk, input rst_n, input key, output reg[6:0] seg ); reg[3:0]cnt; wire key_done; xiaodou u1 ( .clk (clk ), //需要分频的信号为50Mhz时钟脉冲信号 .rst_n (rst_n ), //复位键 .key_in (key ), //机械按键 .clk_500hz (clk_500hz), //分频得到的500Hz时钟脉冲信号 .key_done (key_done) //按键动作完成标志 ); always@(posedge clk_500hz or negedge rst_n) begin if(!rst_n) cnt <= 0; else if(key_done) //按下动作完成 begin if(cnt == 9) //计数到9后需要清零 cnt <= 0; else cnt <= cnt + 1; end end always@(cnt) //数码管显示模块 begin case(cnt) 0:seg = 7'b0000001; 1:seg = 7'b1001111; 2:seg = 7'b0010010; 3:seg = 7'b0000110; 4:seg = 7'b1001100; 5:seg = 7'b0100100; 6:seg = 7'b0100000; 7:seg = 7'b0001111; 8:seg = 7'b0000000; 9:seg = 7'b0000100; endcase end endmodule

十进制计数器电路逻辑图

在这里插入图片描述

十进制计数器引脚分配方案

在这里插入图片描述

下载验证

在这里插入图片描述

问题解决

个人认为,这个实验的主要难点在于如何分频出 500 H z 500Hz 500Hz 的时钟脉冲信号。由于临近期末时间紧迫,我没法系统地深入学习 V e r i l o g Verilog Verilog 语言,因此消抖模块的程序也是找的现成的程序进行学习理解。在最初编写的程序里,我的代码是没有以下这段的。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
always@(posedge clk_500hz or negedge rst_n) begin if(!rst_n) begin key_tmp1 <= 0; key_tmp2 <= 0; end else begin key_tmp1 <= qout; key_tmp2 <= key_tmp1; end end

我以为,只要计数够 2 m s 2ms 2ms (就是稳定状态)还是低电平就可以了,这段代码没啥存在的必要,但实际验证貌似还是会有不成功的情况。后来才发现,从原理上来说,机械按键按下存在前沿抖动和后沿抖动,因此需要取前后按键信号的按下状态来进行强判定是否按下。

3.2 简易篮球比赛计分器

利用开发板上现有的按键、开关和数码管资源实现一个简易篮球比赛计分器。

实验原理

简易篮球比赛计分器的基本功能要求如下:

  • 甲乙两队的得分分别用两个数码管显示
  • 每次可以给甲队或乙队加上 1 1 1 分, 2 2 2 分或 3 3 3 分,比分显示范围 00 00 00 99 99 99

篮球计分器主要由以下模块构成

带消抖电路的加分按键模块
计数器模块
计分对象控制模块
数码管显示电路

实验步骤

  1. 根据功能要求设计各模块电路。
  2. 对各模块进行逻辑和算法分析。
  3. 编写 V e r i l o g Verilog Verilog 程序并进行调试。
  4. 下载到 F P G A FPGA FPGA 开发板上验证程序相关功能。

具体实现

下面以甲队计分的过程为例描述计分器的设计过程:

加分按键模块三个按钮有一个按下
判断甲队加分控制端开关是否拉为高电平
若甲队加分开关为高电平则加对应分数
数码管显示甲队分数

Q u a r t u s Quartus Quartus 中编写程序,总代码如下:

Codes

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
module ball ( input [2:0] o, //表示对应加1,2,3分按键的状态 input m, //甲队加分控制端 input m1, //乙队加分控制端 input clk, //50MHz时钟脉冲信号 input rst_n, //复位键 input key, output reg [6:0] ans1, output reg [6:0] ans2, output reg [6:0] ans3, output reg [6:0] ans4 ); integer i; reg [3:0] l; //甲队分数的十位 reg [3:0] r; //甲队分数的个位 reg [3:0] l1; //乙队分数的十位 reg [3:0] r1; //乙队分数的个位 //reg [3:0] key1; //reg [3:0] key2; //reg [3:0] key3; wire key_done; //有按键按下 xiaodou u1 //消抖模块,代码与子任务3.1中略有不同 ( .clk (clk ), .rst_n (rst_n ), .key_in1 (o[0] ), .key_in2 (o[1] ), .key_in3 (o[2] ), .clk_500hz (clk_500hz), .key_done (key_done) ); always@(posedge clk_500hz or negedge rst_n) begin if (!rst_n) begin //复位 l=0; r=0; l1=0; r1=0; end else begin if (key_done) begin //当有加分按键按下时 for (i=0; i<=2; i=i+1) begin if (!o[i]) begin //判断是哪个按键按下 case (i) 0:begin if (m) begin //给甲队加分 r=r+1; if (r==10) begin r=0; l=l+1; end end if (m1) begin //给乙队加分 r1=r1+1; if (r1==10) begin r1=0; l1=l1+1; end end end 1:begin if (m) begin r=r+2; if (r>=10) begin r=r-10; l=l+1; end end if (m1) begin r1=r1+2; if (r1>=10) begin r1=r1-10; l1=l1+1; end end end 2:begin if (m) begin r=r+3; if (r>=10) begin r=r-10; l=l+1; end end if (m1) begin r1=r1+3; if (r1>=10) begin r1=r1-10; l1=l1+1; end end end endcase end end end end end always @ (l) begin case(l) 0:ans1 = 7'b0000001; 1:ans1 = 7'b1001111; 2:ans1 = 7'b0010010; 3:ans1 = 7'b0000110; 4:ans1 = 7'b1001100; 5:ans1 = 7'b0100100; 6:ans1 = 7'b0100000; 7:ans1 = 7'b0001111; 8:ans1 = 7'b0000000; 9:ans1 = 7'b0000100; endcase end always @ (r) begin case(r) 0:ans2 = 7'b0000001; 1:ans2 = 7'b1001111; 2:ans2 = 7'b0010010; 3:ans2 = 7'b0000110; 4:ans2 = 7'b1001100; 5:ans2 = 7'b0100100; 6:ans2 = 7'b0100000; 7:ans2 = 7'b0001111; 8:ans2 = 7'b0000000; 9:ans2 = 7'b0000100; endcase end always @ (l1) begin case(l1) 0:ans3 = 7'b0000001; 1:ans3 = 7'b1001111; 2:ans3 = 7'b0010010; 3:ans3 = 7'b0000110; 4:ans3 = 7'b1001100; 5:ans3 = 7'b0100100; 6:ans3 = 7'b0100000; 7:ans3 = 7'b0001111; 8:ans3 = 7'b0000000; 9:ans3 = 7'b0000100; endcase end always @ (r1) begin case(r1) 0:ans4 = 7'b0000001; 1:ans4 = 7'b1001111; 2:ans4 = 7'b0010010; 3:ans4 = 7'b0000110; 4:ans4 = 7'b1001100; 5:ans4 = 7'b0100100; 6:ans4 = 7'b0100000; 7:ans4 = 7'b0001111; 8:ans4 = 7'b0000000; 9:ans4 = 7'b0000100; endcase end endmodule

其中,消抖电路模块代码如下:

Codes

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
module xiaodou ( input clk , input rst_n , input key_in1, input key_in2, input key_in3, output reg clk_500hz, output key_done ); reg [25:0]div_cnt; always@(posedge clk or negedge rst_n) begin if(!rst_n) begin div_cnt <= 0; clk_500hz <= 0; end else if(div_cnt == 99999) begin div_cnt <= 0; clk_500hz <= ~clk_500hz; end else begin div_cnt <= div_cnt + 1; clk_500hz <= clk_500hz; end end reg qout; reg key_tmp1,key_tmp2; parameter n = 10; reg [25:0] cnt; always@(posedge clk_500hz or negedge rst_n) begin if(!rst_n) begin cnt <= 0; qout <= 0; end else if(key_in1==0 || key_in2==0 || key_in3==0) //此处与子任务3.1中的条件不同 begin if(cnt == n-1) begin cnt <= cnt; qout <= 1; end else begin cnt <= cnt+1; qout <= 0; end end else begin qout <= 0; cnt <= 0; end end always@(posedge clk_500hz or negedge rst_n) begin if(!rst_n) begin key_tmp1 <= 0; key_tmp2 <= 0; end else begin key_tmp1 <= qout; key_tmp2 <= key_tmp1; end end assign key_done = key_tmp1 & (~ key_tmp2); endmodule

简易篮球计分器电路逻辑图

在这里插入图片描述

简易篮球计分器引脚分配方案

在这里插入图片描述

下载验证

在这里插入图片描述

问题解决

这个实验是一个综合度较高的基础实验,我个人也是遇到了不少的问题,经过不断修改调试,总结了以下几个主要的问题:

  • V e r i l o g Verilog Verilog 语言中一个寄存器变量不能在两个 a l w a y s always always 语句(有限状态机)中赋值。
  • V e r i l o g Verilog Verilog 语言虽然为硬件程序设计语言,但是不同于 C C C 语言等传统软件编程语言,有些复杂逻辑(比如多重 i f if if 语句嵌套,或者是上面那个程序中 if (!rst_n) 改成 if (rst_n)),虽然语法正确,但是系统综合分析就是会失败,报错提示顶层的模块名要跟工程文件名一致。
  • 在主程序向消抖模块传递参数时,不能只把按键存储的寄存器变量 o o o 直接传递,这样它会默认只判断寄存器最低位的状态,不管高位的状态了。

主要的解决方法就是:

  • 从硬件原理上来说,如果一个变量能在两个有限状态机中赋值,那么这个逻辑其实不是那么牢靠的,可能存在冲突现象,因此要避免。
  • 降低算法复杂度,尽量避免多重 i f if if 嵌套。
  • 将某一按键动作判断归一化为只要所有按键中有一个按下就判定按下成立(或逻辑),然后通过循环扫描哪一个按键的电平是低电平(低电平触发)选择具体的按键。

4 心得体会

最后

以上就是活泼金鱼最近收集整理的关于HEU大二数电时序逻辑电路设计实验Contents1 实验目的2 实验仪器3 子任务4 心得体会的全部内容,更多相关HEU大二数电时序逻辑电路设计实验Contents1内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(78)

评论列表共有 0 条评论

立即
投稿
返回
顶部