课程设计目的

  1. 使学生更好地巩固和加深对基础知识的理解,学会设计简单数字系统的方法,独立完成调试过程,增强学生理论联系实际的能力,提高学生电路设计和分析的能力。
  2. 通过实践教学引导学生在理论指导下有所创新,为后继专业课的学习和日后工程实践奠定基础。

开发工具选择

本次课程设计使用软件Quartus 13.0 sp1完成。本次课程设计将采用模块化设计方法,底层的元件使用硬件描述语言VHDL进行描述,顶层采用原理图的方法。依靠计算机,借助Quartus,实现系统功能。

设计方案

需求分析

需求

  1. 十字路口由一条东西方向的主干道和南北方向的支干道构成。东西南北4个方向各装1个车辆传感器。
  2. 通常保持主干道绿灯、支干道红灯。只有支干道有车时,才转为主干道红灯,支干道绿灯。
  3. 绿灯转红灯过程中,先由绿灯转为黄灯,5s后再由黄灯转为红灯;同时对方才由红灯转为绿灯。
  4. 当两个方向同时有车时,红绿灯每隔30s变换一次,应扣除绿灯转红灯过程中有5s黄灯过渡,绿灯实际只亮25s。
  5. 若仅一个方向有车时,处理方法为:
    1. 该方向原来为红灯时,另一个方向立即由绿灯变为黄灯,5s后 再由黄灯变为红灯,同时本方向由红灯变为绿灯。
    2. 该方向原为绿灯时,继续保持绿灯。另一个方向有车来时,作两个方向均有车处理。

分析

逻辑符号:

  1. 定义主干道(东西两侧)的绿灯黄灯红灯分别为MG1、MY1、MR1,MG2、MY2、MR2(其中东侧灯代号末尾为1,西侧灯为2),支干道(南北两侧)的绿灯黄灯红灯分别为SG1、SY1、SR1,SG2、SY2、SR2(其中东侧灯代号末尾为1,西侧灯为2),定义高电平亮,低电平灭。因为道路东西两侧或南北两侧变化相同,因此可以直接由同一个信号进行控制。这里定义控制东西两侧灯的三个信号为MG、MY、MR,控制南北两侧灯的三个信号为SG、SY、SR。信号为0时对应灯灭,信号为1时对应灯亮。
  2. 东西南北4个方向各装1个车辆传感器(这里定义有车时输出高电平,无车时输出低电平),主干道(东西两侧)两个传感器分别用M1,M2表示,支干道(南北两侧)两个传感器分别用S1,S2表示。当M1或M2任意一个为1时,代表主干道有车;当S1或S2任意一个为1时,代表支干道有车。这里定义M=M1+M2,S=S1+S2。
  3. 定义信号MK,表示该时刻是否应该由主干道切换为支干道,为1时应该切换。
  4. 定义信号SK,表示该时刻是否应该由支干道切换为主干道,为1时应该切换。

模块划分

  1. 5秒定时器
  2. 25秒定时器
  3. 控制模块(运行主程序)

主要模块设计

控制模块的几个状态

  1. 开始时,进入状态1:主干道绿灯亮(MG=1,MY=MR=0),支干道红灯亮(SR=1,SY=SG=0),并开启25秒定时器。
  2. 在状态1时判断MK状态,为0时保持状态1,为1时进入状态2:主干道黄灯亮(MY=1,MG=MR=0),支干道红灯亮(SR=1,SY=SG=0),并开启5秒定时器。
  3. 5秒定时器结束后,进入状态3:主干道红灯亮(MR=1,MY=MG=0),支干道绿灯亮(SG=1,SY=SR=0),并开启25秒定时器
  4. 在状态3时判断SK状态,为0时保持状态3,为1时进入状态4:主干道红灯亮(MR=1,MY=MG=0),支干道黄灯亮(SY=1,SG=SR=0),并开启5秒定时器。
  5. 5秒定时器结束后回到状态1。

MK和SK

根据上述需求分析可知,当仅支干道方向有车($\overline{M}S = 1$)或两个方向同时有车且到达绿灯的25秒限制($MS*T_{25} = 1$)时,MK=1。

当两个方向均无车($\overline{M}*\overline{S} = 1$),仅主干道方向有车($\overline{S}*M = 1$)或两个方向同时有车且到达绿灯的25秒限制($MST_{25} = 1$)时,SK=1。

ASM图

具体实现

计数器

  1. 25秒正计数器

    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
    library IEEE;
    use IEEE.STD_LOGIC_1164.ALL;
    use IEEE.NUMERIC_STD.ALL;

    entity T25 is
    Port (
    enable : in STD_LOGIC;
    clk : in STD_LOGIC;
    reset : in STD_LOGIC;
    timeout : out STD_LOGIC
    );
    end T25;

    architecture Behavioral of T25 is
    constant CLK_FREQUENCY : integer := 1; -- 输入时钟频率
    constant TARGET_TIME : integer := 25 * CLK_FREQUENCY;
    -- 目标时间 = 时间个数 × 时钟频率
    signal count : unsigned(31 downto 0); -- 计数器信号

    begin
    process(clk, reset)
    begin
    if reset = '1' then
    count <= (others => '0'); -- 复位计数器
    timeout <= '0';
    elsif rising_edge(clk) then
    if enable = '1' then
    if count = TARGET_TIME - 1 then -- 达到目标时间
    timeout <= '1';
    count <= (others => '0'); -- 复位计数器
    else
    count <= count + 1; -- 递增计数器
    timeout <= '0';
    end if;
    end if;
    end if;
    end process;
    end Behavioral;
  2. 5秒正计数器

    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
    library IEEE;
    use IEEE.STD_LOGIC_1164.ALL;
    use IEEE.NUMERIC_STD.ALL;

    entity T5 is
    Port (
    enable : in STD_LOGIC;
    clk : in STD_LOGIC;
    reset : in STD_LOGIC;
    timeout : out STD_LOGIC
    );
    end T5;

    architecture Behavioral of T5 is
    constant CLK_FREQUENCY : integer := 1; -- 输入时钟频率
    constant TARGET_TIME : integer := 5 * CLK_FREQUENCY;
    -- 目标时间 = 时间个数 × 时钟频率
    signal count : unsigned(31 downto 0); -- 计数器信号

    begin
    process(clk, reset)
    begin
    if reset = '1' then
    count <= (others => '0'); -- 复位计数器
    timeout <= '0';
    elsif rising_edge(clk) then
    if enable = '1' then
    if count = TARGET_TIME - 1 then -- 达到目标时间
    timeout <= '1';
    count <= (others => '0'); -- 复位计数器
    else
    count <= count + 1; -- 递增计数器
    timeout <= '0';
    end if;
    end if;
    end if;
    end process;
    end Behavioral;

控制部件

这里采用Moore型状态机。

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
library ieee;
use ieee.std_logic_1164.all;

entity crosslight is
port (
clk : in std_logic; -- 时钟信号
reset : in std_logic; -- 复位信号
M : in std_logic; -- 主干道检测器
S : in std_logic; -- 支干道检测器
TT25, TT5 : in std_logic; -- 25s, 5s定时器到时信号
EN25, EN5 : out std_logic; -- 25s, 5s定时器使能
RST25, RST5 : out std_logic; -- 25s, 5s定时器复位
MR, MY, MG : out std_logic; -- 主干道红绿灯
SR, SY, SG : out std_logic -- 支干道红绿灯
);
end entity crosslight;

architecture rtl of crosslight is
-- 内部用到的信号声明
signal MK, SK : std_logic; -- 主干道是否切换支干道,支干道是否切换主干道
type state is (s0, s1, s2, s3); -- 状态机几个状态的声明
signal presentstate : state; -- 当前状态
signal nextstate : state; -- 下一个状态(次态)
begin
-- 定义内部信号的逻辑表达式
MK <= ((not M) and S) or(M and S and TT25);
-- MK:主干道是否切换支干道的逻辑表达式
SK <= ((not M) and (not S)) or ((not S) and M) or (M and S and TT25);
-- SK:支干道是否切换主干道的逻辑表达式

-- 定义过程: 时钟信号上升沿检测,状态机状态切换
switchtonextstate : process (clk,reset)
begin
-- 复位,状态机状态切换到s0
if reset = '1' then
presentstate <= s0;
-- 时钟信号上升沿检测,状态机状态切换到下一个状态
elsif clk'event and clk = '1' then
presentstate <= nextstate;
end if;
end process switchtonextstate;

-- 定义过程: 状态机状态切换的逻辑和输入输出信号处理
-- 这里process的几个敏感信号: 25s, 5s定时器到时信号, 主干道检测器, 支干道检测器, 当前状态
changestatemode : process (TT25, TT5, M, S, MK, SK, presentstate)
begin
case presentstate is
when s0 =>
-- 主干道绿灯,支干道红灯
if MK = '1' then
nextstate <= s1;
else
nextstate <= s0;
end if;
-- 切灯
MR <= '0';
MY <= '0';
MG <= '1';
SR <= '1';
SY <= '0';
SG <= '0';
-- 开25s定时器,复位5s定时器
RST25 <= '0';
RST5 <= '1';
EN25 <= '1';
when s1 =>
-- 主干道黄灯,支干道红灯
if TT5 = '1' then
nextstate <= s2;
else
nextstate <= s1;
end if;
-- 切灯
MR <= '0';
MY <= '1';
MG <= '0';
SR <= '1';
SY <= '0';
SG <= '0';
-- 开5s定时器,复位25s定时器
RST25 <= '1';
RST5 <= '0';
EN5 <= '1';
when s2 =>
-- 主干道红灯,支干道绿灯
if SK = '1' then
nextstate <= s3;
else
nextstate <= s2;
end if;
-- 切灯
MR <= '1';
MY <= '0';
MG <= '0';
SR <= '0';
SY <= '0';
SG <= '1';
-- 开25s定时器,复位5s定时器
RST25 <= '0';
RST5 <= '1';
EN25 <= '1';
when s3 =>
if TT5 = '1' then
nextstate <= s0;
else
nextstate <= s3;
end if;
-- 切灯
MR <= '1';
MY <= '0';
MG <= '0';
SR <= '0';
SY <= '1';
SG <= '0';
-- 开5s定时器,复位25s定时器
RST25 <= '1';
RST5 <= '0';
EN5 <= '1';
when others =>
-- 其他情况,状态机状态切换到s0
nextstate <= s0;
end case;
end process changestatemode;
end rtl;

系统构成

调试仿真

上图是一种仿真模拟情况:模拟两端均有车时交通灯的切换效果,可以看到上文设计成功完成主绿支红-主黄支红-主红支绿-主红支黄的循环。

课程设计回顾总结

经过一星期的努力,我最终完成了十字路口交通灯控制系统的设计与仿真,较好地完成了需求。

本次设计采用层次结构,模块化设计 。经历了完整的需求分析-模块划分-绘制ASM图-代码设计-代码实现-测试仿真的开发流程,是我接触数字逻辑以来的最大项目。

本次设计充满了挑战:无论是需求分析时对于主支干道切换的逻辑分析,还是具体实现时对于状态机语句顺序的写法,还是绘制电路图并用其编译,都是困难和新鲜的。但同时它们也是机遇:正因我坚持解决了这些问题,我才能够更好地理解数字逻辑和VHDL语言,以及Quartus软件的使用方式方法。

总的来说这是一次难忘的、宝贵的经历。这次设计不仅提升了我的专业知识和技能理解,还培养我的创新精神和解决生活中的实际问题的能力,同时也让我明白:只要目标清晰、坚持不懈,没有什么解决不了的问题。

参考文献

[1]盛建伦编著. 数字逻辑与VHDL逻辑设计(第2版)[M]. 北京:清华大学出版社, 2016.01.