要求:
(1)输入信号floor1,floor2,floor3分布表示目的楼层为第1,2,3层,该信号通过触发器保存后输出至状态机,状态机根据目的楼层为第1,2,3层,该信号通过触发器保存后输出至状态机,状态机根据目的楼层及当前楼层控制控制楼层变化,目标楼层到达后由状态机输出清除信号清除该楼层对应触发器;(2)输出信号led[2:0]显示当前楼层,高电平有效,例如:3’b100表示当前楼层为第三层;(3)画出状态机的状态图(Moore状态图,复位后为第一层);(4)以Verilog设计图,其中状态机采用3段式过程语句实现。
这里题目要求的楼层很少,因此可以不用考虑顺序的算法问题。只是一些细节需要注意。
思路:
- 首先画出状态图:
2.有了主干之后需要加入一些细节:
①首先要求输入不能直接输入,而是保存在触发器之中去,设置3个reg变量tmpx表示输入,因为触发器是时钟触发的,因此一定要放在时序逻辑电路表示的那个always中。
②这里做了一个小处理就是因为电梯真实情况下电梯如果在某一楼层而又要去那一楼层是不会被触发的,因此做了一个判断语句,当前楼层是否是目标楼层,不是才输入信号。
③***这里还需要注意因为Quartus中不支持一个变量在两个always语句同时被赋值。***因此tmpx只能写在时序逻辑电路表示的always之中。
④这里做了一个特殊处理加入了一个表示顺路的信号,就是针对在二楼时,同时有1楼和2楼的输入先去哪里,这里是根据上一次运行的方向判断的,如果是从3楼到的2楼,这次就去1楼,否则如果是从1楼到的2楼,这次就是2楼。
因此这里需要稍微修改一下状态图。
3.写成3段式式的代码,第一个always为时序逻辑电路,第二个always为组合逻辑电路,第三个always为时序逻辑电路输出消除毛刺:
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
93module elevator2(CLK, RESET ,floor1, floor2, floor3, led); //建成顶层模块 input CLK;//时钟信号,每过一个时钟周期转化一次楼层 input RESET;//清零信号 input floor1;//按下1楼输入信号 input floor2;//按下2楼输入信号 input floor3;//按下3楼输入信号 output reg[2:0]led;//表示当前所对应楼层,[2:0] reg tmp1;//floor1的触发器 reg tmp2;//floor2的触发器 reg tmp3;//floor3的触发器 reg dir;//代表方向,1为向上,0为向下,默认为1(上行) reg [2:0]next_floor;//下一楼层 reg [2:0]current_floor;//当前楼层,因为要写成三段式,不直接使用led parameter first_floor=3'b001, second_floor=3'b010, third_floor=3'b100; always @(posedge CLK or negedge RESET)//第一段,时序逻辑状态存储 begin if(~RESET)//清零信号 begin current_floor<=first_floor; {tmp3,tmp2,tmp1}<=3'b0; end else begin current_floor=next_floor; tmp1=current_floor==first_floor?0:floor1;//真实情况下电梯按下按键之后如果没有到达目的楼层是不能取消的,如果到达当前楼层再继续按下按键是无效的 tmp2=current_floor==second_floor?0:floor2; tmp3=current_floor==third_floor?0:floor3; end end always @ (current_floor or tmp1 or tmp2 or tmp3) //信号经触发器保存后输出至状态机 //状态机根据目的楼层及当前楼层控制楼层变化 //目标楼层到达后由状态机清除该楼层对应触发器 //如果按键是本楼层,直接清除信号 //存在一个问题,如果当前在3楼,按下1楼和2楼,下到2楼时,有人按下三楼又往3楼,而此时应该是去2楼才正确 //因此应该加上一个当前方向优先级最高,表示顺路 begin case(current_floor) first_floor: begin dir=1;//方向设为上行 if(tmp2||tmp3) next_floor=second_floor; else next_floor=first_floor; //否则不改变,不用写出 end second_floor: begin if(~tmp3&tmp1)//因为只有方向的楼层此时楼层优先 begin next_floor=first_floor; dir=0;//此时为下行,其实设置方向是多余的因为这里楼层太少,到达3或是1都会被重置 end else if(tmp3&~tmp1) begin next_floor=third_floor; dir=1;//此时为上行 end else if(tmp3&tmp1&dir)//因为两个方向的楼层都被按下因此此时方向优先 next_floor=third_floor; else if(tmp3&tmp1&~dir) next_floor=first_floor; else next_floor=second_floor; end third_floor: begin dir=0;//方向设为下行 if(tmp2||tmp1) next_floor=second_floor; else next_floor=third_floor; end endcase end always @(posedge CLK or negedge RESET)//第三段,经过一个寄存器再送出,消除输出信号的毛刺 begin if(~RESET) begin led=3'b001; end else led=current_floor; end endmodule
4.测试结果:
5.Quartus的电路图和状态图:
改进:
①可以看出这个电路存在最大的问题就是不会停留,从1楼到2楼再到3楼和直接到3楼停留的时间一样长,因此从这里着手改进加入一个变量open作为开门信号,open为1表示在此楼层开门,为0表示直接离开。
②还有一个按键输入在实际生活中的电梯按下按键之后输入寄存器一般是不能取消的,只能是到达该楼层后才能取消,因此这里重新处理了一下。
③这里的时序逻辑电路部分写得比较复杂,主要是有多种情况需要讨论。
④这里还要注意第一个时序逻辑电路的always电路最外面的那一层if-else一定要和敏感变量有关否则会报错。
⑤还要特别注意组合逻辑电路的电平值会产生毛刺,因此在时序逻辑电路中一定要注意使用<=和=赋值区别很大。
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
133module elevator5(CLK, RESET ,floor1, floor2, floor3, led, open); //建成顶层模块 input CLK;//时钟信号,每过一个时钟周期转化一次楼层 input RESET;//清零信号 input floor1;//按下1楼输入信号 input floor2;//按下2楼输入信号 input floor3;//按下3楼输入信号 output reg[2:0]led;//表示当前所对应楼层,[2:0] output reg open;//开门信号,1到达某楼层开门,0相反 reg tmp1;//floor1的触发器 reg tmp2;//floor2的触发器 reg tmp3;//floor3的触发器 reg arrive;//作为一个到达信号,因为一个信号不能在两个always语句中被赋值 reg dir;//代表方向,1为向上,0为向下,默认为1(上行) reg [2:0]next_floor;//下一楼层 reg [2:0]current_floor;//当前楼层,因为要写成三段式,不直接使用led integer running_time;//这是到达之后开门时间倒计时 parameter first_floor=3'b001, second_floor=3'b010, third_floor=3'b100, //up_time=3'd1,//楼层转化所需的时间 total_time=3'd3;//这是设置默认开门时间 always @(posedge CLK or negedge RESET)//第一段,时序逻辑状态存储 begin if(~RESET)//清零信号 begin current_floor<=first_floor; {tmp3,tmp2,tmp1}<=3'b000; open<=0; running_time<=0;//默认开始时有个上升 end else begin if(next_floor!=current_floor&running_time==0&open==0)//这里应该是刚刚到达时的情况到达时刻 begin current_floor=next_floor; if(next_floor==first_floor&tmp1) begin tmp1=0; running_time=total_time; open=1; end else if(next_floor==second_floor&tmp2) begin tmp2=0; running_time=total_time; open=1; //current_floor=next_floor; end else if(next_floor==third_floor&tmp3) begin tmp3=0; running_time=total_time; open=1; //current_floor=next_floor; end end if(running_time==0)//倒计时完成后才进行状态转化 begin open=0;//清零开门信号 tmp1=(current_floor==first_floor||tmp1==1)?tmp1:floor1;//真实情况下电梯按下按键之后如果没有到达目的楼层是不能取消的,如果到达当前楼层再继续按下按键是无效的 tmp2=(current_floor==second_floor||tmp2==1)?tmp2:floor2; tmp3=(current_floor==third_floor||tmp3==1)?tmp3:floor3; end else begin current_floor=current_floor; running_time=running_time-1; end end end always @ (current_floor or tmp1 or tmp2 or tmp3) //信号经触发器保存后输出至状态机 //状态机根据目的楼层及当前楼层控制楼层变化 //目标楼层到达后由状态机清除该楼层对应触发器 //如果按键是本楼层,直接清除信号 //存在一个问题,如果当前在3楼,按下1楼和2楼,下到2楼时,有人按下三楼又往3楼,而此时应该是去2楼才正确 //因此应该加上一个当前方向优先级最高,表示顺路 begin case(current_floor) first_floor: begin dir=1;//方向设为上行 if(tmp2||tmp3) next_floor=second_floor; else next_floor=first_floor; //否则不改变,不用写出 end second_floor: begin if(~tmp3&tmp1)//因为只有方向的楼层此时楼层优先 begin next_floor=first_floor; dir=0;//此时为下行,其实设置方向是多余的因为这里楼层太少,到达3或是1都会被重置 end else if(tmp3&~tmp1) begin next_floor=third_floor; dir=1;//此时为上行 end else if(tmp3&tmp1&dir)//因为两个方向的楼层都被按下因此此时方向优先 next_floor=third_floor; else if(tmp3&tmp1&~dir) next_floor=first_floor; else next_floor=second_floor; end third_floor: begin dir=0;//方向设为下行 if(tmp2||tmp1) next_floor=second_floor; else next_floor=third_floor; end endcase end always @(posedge CLK or negedge RESET)//第三段,经过一个寄存器再送出,消除输出信号的毛刺 begin if(~RESET) begin led=3'b001; end else led=current_floor; end endmodule
2.测试图片:
3.Quartus电路图和状态图:
不足之处:
①不能动态设置转化时间即open=0的那段时间,因为这里是用的open区分的刚刚到达状态切换和倒计时结束状态切换两种状态。
②其实可以更改一下tmpx被赋值的位置,不然成了开门的时候不能按下按键。
③只能处理三层楼的情况,拓展性不足。
④逻辑有一些混乱,不够简洁。
如果还有什么不足,请指正。
最后
以上就是无奈纸飞机最近收集整理的关于Verilog HDL3层电梯设计的全部内容,更多相关Verilog内容请搜索靠谱客的其他文章。
发表评论 取消回复