Repository navigation
Expand file tree
/
Copy pathelevator_ctrl.vhd
More file actions
433 lines (392 loc) · 17.2 KB
/
Copy pathelevator_ctrl.vhd
File metadata and controls
433 lines (392 loc) · 17.2 KB
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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
------------------------------------------------------------------------
-- elevator_ctrl.vhd
-- 三层电梯主控制器状态机
--
-- 功能: SCAN 调度算法,控制电梯上下运行、开关门、楼层计数
-- 标准: VHDL-93, Quartus II 9.1 兼容
-- 风格: 双进程(时序寄存器 + 组合逻辑)
-- 复位: 异步低电平有效 (rst_n)
------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity elevator_ctrl is
port(
clk_1hz : in std_logic; -- 1Hz 节拍时钟
rst_n : in std_logic; -- 异步复位(低电平有效)
-- 来自 request_handler 的请求信号
req_up : in std_logic_vector(2 downto 0); -- 上行请求 [1F, 2F, 未用]
req_dn : in std_logic_vector(2 downto 0); -- 下行请求 [未用, 2F, 3F]
req_go : in std_logic_vector(2 downto 0); -- 轿厢目标 [1F, 2F, 3F]
any_request : in std_logic; -- 任意请求有效标志
-- 来自 door_controller 的状态信号
door_closed : in std_logic; -- 门已完全关闭
door_opened : in std_logic; -- 门已完全打开
-- 报警信号
alarm_active : in std_logic; -- 报警有效
-- 输出到各模块的控制信号
current_floor : out std_logic_vector(1 downto 0); -- 当前楼层 "00"=1F "01"=2F "10"=3F
direction : out std_logic; -- 运动方向 '0'=上 '1'=下
motor_en : out std_logic; -- 电机使能
door_open_cmd : out std_logic; -- 开门命令
door_close_cmd: out std_logic; -- 关门命令
clear_req : out std_logic_vector(2 downto 0); -- 请求清除(到达楼层对应位为1)
state_out : out std_logic_vector(3 downto 0) -- 状态编码(调试用)
);
end entity elevator_ctrl;
architecture rtl of elevator_ctrl is
---------------------------------------------------------------
-- 状态定义
---------------------------------------------------------------
constant S_IDLE : std_logic_vector(3 downto 0) := "0000"; -- 空闲等待
constant S_DOOR_OPENING : std_logic_vector(3 downto 0) := "0001"; -- 开门中
constant S_DOOR_OPEN : std_logic_vector(3 downto 0) := "0010"; -- 门开等待10秒
constant S_DOOR_CLOSING : std_logic_vector(3 downto 0) := "0011"; -- 关门中
constant S_CHECK_REQ : std_logic_vector(3 downto 0) := "0100"; -- 检查请求决定方向
constant S_MOVING_UP : std_logic_vector(3 downto 0) := "0101"; -- 上升中
constant S_MOVING_DOWN : std_logic_vector(3 downto 0) := "0110"; -- 下降中
constant S_ARRIVED : std_logic_vector(3 downto 0) := "0111"; -- 到达目标层
constant S_RETURN_HOME : std_logic_vector(3 downto 0) := "1000"; -- 返回1楼
constant S_ALARM : std_logic_vector(3 downto 0) := "1001"; -- 报警
-- 门开等待时间常量(由 door_controller 自主管理,此处不再使用)
-- constant DOOR_WAIT_MAX : std_logic_vector(3 downto 0) := "1001";
---------------------------------------------------------------
-- 内部寄存器信号
---------------------------------------------------------------
signal current_state : std_logic_vector(3 downto 0); -- 当前状态
signal floor_reg : std_logic_vector(1 downto 0); -- 楼层寄存器
signal dir_reg : std_logic; -- 方向寄存器 '0'=上 '1'=下
---------------------------------------------------------------
-- 组合逻辑到寄存器的中间信号
---------------------------------------------------------------
signal next_state : std_logic_vector(3 downto 0);
signal next_floor : std_logic_vector(1 downto 0);
signal next_dir : std_logic;
---------------------------------------------------------------
-- 请求聚合信号(组合逻辑)
-- req_any(i): 第i层是否有任何类型请求
---------------------------------------------------------------
signal req_any : std_logic_vector(2 downto 0);
-- 当前楼层上方/下方是否有请求
signal req_above : std_logic;
signal req_below : std_logic;
-- 当前楼层是否需要停靠(考虑运行方向)
signal need_stop : std_logic;
begin
---------------------------------------------------------------
-- 请求聚合(组合逻辑)
-- req_any(0) = 1楼所有请求 OR
-- req_any(1) = 2楼所有请求 OR
-- req_any(2) = 3楼所有请求 OR
---------------------------------------------------------------
req_any(0) <= req_up(0) or req_dn(0) or req_go(0);
req_any(1) <= req_up(1) or req_dn(1) or req_go(1);
req_any(2) <= req_up(2) or req_dn(2) or req_go(2);
---------------------------------------------------------------
-- 上方/下方请求检测(基于 floor_reg)
---------------------------------------------------------------
-- 当前楼层上方是否有请求
req_above <= '1' when (floor_reg = "00" and (req_any(1) = '1' or req_any(2) = '1')) else
'1' when (floor_reg = "01" and req_any(2) = '1') else
'0';
-- 当前楼层下方是否有请求
req_below <= '1' when (floor_reg = "10" and (req_any(1) = '1' or req_any(0) = '1')) else
'1' when (floor_reg = "01" and req_any(0) = '1') else
'0';
---------------------------------------------------------------
-- 到达停靠判定(考虑方向)
-- 上行时:内选 + 同方向外呼 + 顶楼下行外呼
-- 下行时:内选 + 同方向外呼 + 底楼上行外呼
---------------------------------------------------------------
process(floor_reg, dir_reg, req_up, req_dn, req_go)
begin
need_stop <= '0'; -- 默认值
case floor_reg is
when "00" => -- 1楼
-- 1楼是底楼,只有上行外呼,任何方向到达都需停靠
if req_go(0) = '1' or req_up(0) = '1' then
need_stop <= '1';
end if;
when "01" => -- 2楼
if req_go(1) = '1' then
need_stop <= '1';
elsif dir_reg = '0' and req_up(1) = '1' then
-- 上行模式停靠上行外呼
need_stop <= '1';
elsif dir_reg = '1' and req_dn(1) = '1' then
-- 下行模式停靠下行外呼
need_stop <= '1';
end if;
when "10" => -- 3楼
-- 3楼是顶楼,只有下行外呼,任何方向到达都需停靠
if req_go(2) = '1' or req_dn(2) = '1' then
need_stop <= '1';
end if;
when others =>
need_stop <= '0';
end case;
end process;
---------------------------------------------------------------
-- 输出连接
---------------------------------------------------------------
current_floor <= floor_reg;
direction <= dir_reg;
state_out <= current_state;
---------------------------------------------------------------
-- 进程1: 时序逻辑(状态寄存器 + 楼层/方向更新)
-- 在 clk_1hz 上升沿将 next_xxx 写入寄存器
---------------------------------------------------------------
process(clk_1hz, rst_n)
begin
if rst_n = '0' then
-- 异步复位:1楼、上行方向、空闲状态
current_state <= S_IDLE;
floor_reg <= "00"; -- 1楼
dir_reg <= '0'; -- 上行
elsif rising_edge(clk_1hz) then
current_state <= next_state;
floor_reg <= next_floor;
dir_reg <= next_dir;
end if;
end process;
---------------------------------------------------------------
-- 进程2: 组合逻辑(计算 next_state 和所有控制输出)
---------------------------------------------------------------
process(current_state, floor_reg, dir_reg,
req_up, req_dn, req_go, any_request,
door_closed, door_opened, alarm_active,
req_any, req_above, req_below, need_stop)
begin
-------------------------------------------------------
-- 所有输出信号默认值(防止产生锁存器)
-------------------------------------------------------
next_state <= current_state;
next_floor <= floor_reg;
next_dir <= dir_reg;
motor_en <= '0';
door_open_cmd <= '0';
door_close_cmd <= '0';
clear_req <= "000";
-------------------------------------------------------
-- 报警最高优先级:任何状态下 alarm 有效立即进入 S_ALARM
-------------------------------------------------------
if alarm_active = '1' and current_state /= S_ALARM then
next_state <= S_ALARM;
else
case current_state is
--=====================================================
-- S_IDLE: 空闲等待
-- 无请求则保持;有请求则判断方向开始运行
--=====================================================
when S_IDLE =>
if any_request = '1' then
-- 当前楼层有请求:直接开门
if (floor_reg = "00" and req_any(0) = '1') or
(floor_reg = "01" and req_any(1) = '1') or
(floor_reg = "10" and req_any(2) = '1') then
next_state <= S_DOOR_OPENING;
-- 仅上方有请求
elsif req_above = '1' and req_below = '0' then
next_dir <= '0'; -- 上行
next_state <= S_MOVING_UP;
-- 仅下方有请求
elsif req_below = '1' and req_above = '0' then
next_dir <= '1'; -- 下行
next_state <= S_MOVING_DOWN;
-- 上下均有请求,默认先上行
elsif req_above = '1' and req_below = '1' then
next_dir <= '0'; -- 上行
next_state <= S_MOVING_UP;
end if;
end if;
--=====================================================
-- S_DOOR_OPENING: 开门中
-- 发出开门命令,等待 door_opened 信号
--=====================================================
when S_DOOR_OPENING =>
door_open_cmd <= '1';
-- 清除当前楼层的请求
case floor_reg is
when "00" => clear_req <= "001"; -- 清1楼
when "01" => clear_req <= "010"; -- 清2楼
when "10" => clear_req <= "100"; -- 清3楼
when others => clear_req <= "000";
end case;
if door_opened = '1' then
next_state <= S_DOOR_OPEN;
end if;
--=====================================================
-- S_DOOR_OPEN: 门开等待
-- 维持开门,等待门控制器自主关门(10秒超时或手动关门)
-- 当门完全关闭后,转入检查请求状态
--=====================================================
when S_DOOR_OPEN =>
door_open_cmd <= '1'; -- 维持开门
if door_closed = '1' then
-- 门已关闭(door_controller 自主完成了关门流程)
next_state <= S_CHECK_REQ;
end if;
--=====================================================
-- S_DOOR_CLOSING: 关门中(预留状态,当前流程中不使用)
-- 门的关闭由 door_controller 自主完成
-- 发出关门命令,等待 door_closed 信号
--=====================================================
when S_DOOR_CLOSING =>
door_close_cmd <= '1';
if door_closed = '1' then
next_state <= S_CHECK_REQ;
end if;
--=====================================================
-- S_CHECK_REQ: 检查请求,决定下一步动作
-- 核心调度逻辑:SCAN 算法方向决策
--=====================================================
when S_CHECK_REQ =>
if any_request = '0' then
-- 无任何请求
if floor_reg /= "00" then
-- 不在1楼,返回1楼
next_state <= S_RETURN_HOME;
next_dir <= '1'; -- 下行返回
else
-- 已在1楼,进入空闲
next_state <= S_IDLE;
end if;
elsif dir_reg = '0' then
-- 当前方向为上
if req_above = '1' then
-- 上方有请求,继续上行
next_state <= S_MOVING_UP;
elsif need_stop = '1' then
-- 上方无请求但当前楼层有反向请求,换向后先开门服务本层
next_dir <= '1';
next_state <= S_DOOR_OPENING;
elsif req_below = '1' then
-- 上方无请求,当前层无请求,下方有请求,切换下行
next_dir <= '1';
next_state <= S_MOVING_DOWN;
else
-- 仅当前楼层有请求(安全兜底)
next_state <= S_DOOR_OPENING;
end if;
else
-- 当前方向为下 (dir_reg = '1')
if req_below = '1' then
-- 下方有请求,继续下行
next_state <= S_MOVING_DOWN;
elsif need_stop = '1' then
-- 下方无请求但当前楼层有反向请求,换向后先开门服务本层
next_dir <= '0';
next_state <= S_DOOR_OPENING;
elsif req_above = '1' then
-- 下方无请求,当前层无请求,上方有请求,切换上行
next_dir <= '0';
next_state <= S_MOVING_UP;
else
-- 仅当前楼层有请求
next_state <= S_DOOR_OPENING;
end if;
end if;
--=====================================================
-- S_MOVING_UP: 上升运动
-- 每拍上升一层,到达后检查是否停靠
--=====================================================
when S_MOVING_UP =>
motor_en <= '1';
-- 楼层 +1(上限保护:最大 "10" = 3楼)
if floor_reg < "10" then
next_floor <= floor_reg + 1;
else
next_floor <= "10";
end if;
-- 移动后的状态判断在 S_ARRIVED 或组合逻辑中完成
-- 先跳转到 S_ARRIVED 做到达检测
next_state <= S_ARRIVED;
--=====================================================
-- S_MOVING_DOWN: 下降运动
-- 每拍下降一层,到达后检查是否停靠
--=====================================================
when S_MOVING_DOWN =>
motor_en <= '1';
-- 楼层 -1(下限保护:最小 "00" = 1楼)
if floor_reg > "00" then
next_floor <= floor_reg - 1;
else
next_floor <= "00";
end if;
next_state <= S_ARRIVED;
--=====================================================
-- S_ARRIVED: 到达检测
-- 检查新楼层是否有匹配请求
-- 注意: 此时 floor_reg 还是旧值,next_floor 是新值
-- 但由于寄存器还未更新,需要用 next_floor 来判断
--=====================================================
when S_ARRIVED =>
-- 此时 floor_reg 已经是移动后的新楼层(上一拍 MOVING 写入)
if need_stop = '1' then
-- 有匹配请求,开门
next_state <= S_DOOR_OPENING;
else
-- 无匹配请求,判断是否到达边界或继续移动
if dir_reg = '0' then
-- 上行方向
if floor_reg = "10" then
-- 到达顶楼,检查请求决定下一步
next_state <= S_CHECK_REQ;
elsif req_above = '1' then
-- 上方仍有请求,继续上行
next_state <= S_MOVING_UP;
else
-- 上方无请求,检查方向
next_state <= S_CHECK_REQ;
end if;
else
-- 下行方向
if floor_reg = "00" then
-- 到达底楼
next_state <= S_CHECK_REQ;
elsif req_below = '1' then
-- 下方仍有请求,继续下行
next_state <= S_MOVING_DOWN;
else
next_state <= S_CHECK_REQ;
end if;
end if;
end if;
--=====================================================
-- S_RETURN_HOME: 返回1楼
-- 无请求时自动回归1楼
--=====================================================
when S_RETURN_HOME =>
motor_en <= '1';
next_dir <= '1'; -- 维持下行
-- 如果中途出现新请求,中断返回
if any_request = '1' then
next_state <= S_CHECK_REQ;
elsif floor_reg = "00" then
-- 已到1楼
next_state <= S_IDLE;
next_dir <= '0'; -- 恢复默认上行方向
else
-- 继续下降
next_floor <= floor_reg - 1;
end if;
--=====================================================
-- S_ALARM: 报警状态
-- 等待报警解除后进入 S_CHECK_REQ,如果无请求则返回1楼
--=====================================================
when S_ALARM =>
-- 报警期间电机停止,门保持当前状态
if alarm_active = '0' then
next_state <= S_CHECK_REQ;
end if;
--=====================================================
-- 默认分支(防止非法状态)
--=====================================================
when others =>
next_state <= S_IDLE;
next_floor <= "00";
next_dir <= '0';
end case;
end if; -- alarm_active 判断结束
end process;
end architecture rtl;