欢迎光临
我们一直在努力

关于Quartus的简易交通灯仿真

该工程有两种模式:

模式0下,强制行人模式(强制红灯500ns)

模式1下,正常绿黄红循环(300ns-100ns-300ns)

模式切换利用按键进行,当按键未被按下时,且当复位结束后,模式1正常运行,当按键被按下,长达3个时钟周期的时长,此时进行模式0,强制行人模式。

这里利用了消抖的原理,如果有不正常的抖动,模式0的切换会不正常,本工程里面设计了持续长达3个时钟周期(60ns)才是真正的按键被按下,否则,依旧为模式1的运行模式。

但是消抖的原理讲来讲去,都是对按键按下的时长进行计数,然后利用边沿检测来确定,图像如下:

a_dly为a的延迟信号,当确保a被按下后,以a_dly为准,对信号进行赋值,产生一个高电平脉冲,而这个高电平脉冲需要(a信号取反)与(a_dly)的一个(与门)来产生。

代码如下:

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;

ENTITY traffic_lights IS
PORT(
    clk            : IN  STD_LOGIC;
    rst_n          : IN  STD_LOGIC;
    key_pedestrian : IN  STD_LOGIC;
    led_r          : OUT STD_LOGIC;
    led_y          : OUT STD_LOGIC;
    led_g          : OUT STD_LOGIC
);
END traffic_lights;

ARCHITECTURE bh OF traffic_lights IS
–仿真缩小时钟计数:20ns时钟                                            –15是时钟数,27是这个信号的位宽
CONSTANT GREEN_TIME    : UNSIGNED(26 DOWNTO 0) := TO_UNSIGNED(15,27);  –绿 300ns
CONSTANT YELLOW_TIME   : UNSIGNED(26 DOWNTO 0) := TO_UNSIGNED(5,27);   –黄 100ns
CONSTANT RED_TIME      : UNSIGNED(26 DOWNTO 0) := TO_UNSIGNED(15,27);   –红 300ns
CONSTANT RED_PED_TIME  : UNSIGNED(26 DOWNTO 0) := TO_UNSIGNED(25,27);  –行人红灯 500ns
CONSTANT C_DEBOUNCE_CNT: UNSIGNED(19 DOWNTO 0) := TO_UNSIGNED(2,20);    –消抖2个周期

–内部信号定义
SIGNAL mode             : STD_LOGIC;
SIGNAL light_state      : STD_LOGIC_VECTOR(1 DOWNTO 0);–3个状态的位宽占据
SIGNAL cnt              : UNSIGNED(26 DOWNTO 0);–计数模式0的时间
SIGNAL key0,key1,key2   : STD_LOGIC;
SIGNAL count_debounce_cnt: UNSIGNED(19 DOWNTO 0);–计数消抖所需要的时长,满时为真正消抖,即为真实按键按下
SIGNAL key_trig         : STD_LOGIC;                –检测按键按下的脉冲
SIGNAL ped_cnt          : UNSIGNED(26 DOWNTO 0);–计数模式1的时间
SIGNAL exit_ped         : STD_LOGIC;  — 退出行人模式标志
BEGIN

–1.按键同步+消抖
PROCESS(clk,rst_n)
BEGIN
    IF rst_n='0' THEN
        key0 <= '1';
        key1 <= '1';
        key2 <= '1';
        count_debounce_cnt <= (OTHERS=>'0');
    ELSIF clk'EVENT AND clk='1' THEN
        key0 <= key_pedestrian;
        key1 <= key0;
        
        IF(key1 /= key0) THEN
            count_debounce_cnt <= C_DEBOUNCE_CNT;–参数传递
        ELSIF(count_debounce_cnt > 0) THEN
            count_debounce_cnt <= count_debounce_cnt – 1;
            IF(count_debounce_cnt = 1) THEN
                key2 <= key1;
            END IF;
        END IF;
    END IF;
END PROCESS;

— 边沿检测:检测key2的下降沿
key_trig <= '1' WHEN (key2 = '0' AND key1 = '1') ELSE '0';

–2.行人模式控制
PROCESS(clk,rst_n)
BEGIN
    IF rst_n='0' THEN  –功能初始化
        mode <= '0';
        ped_cnt <= (OTHERS=>'0');
        exit_ped <= '0';
    ELSIF clk'EVENT AND clk='1' THEN
     exit_ped <= '0';  — 默认清零  为循环计数做准备,此时模式0下不断循环
        
        IF key_trig='1' AND mode='0' THEN   –检测到按键的按下,立刻切换模式1
            mode <= '1';
            ped_cnt <= (OTHERS=>'0');            –模式1下的计数清零准备计数
        ELSIF mode='1' THEN
            IF ped_cnt >= RED_PED_TIME – 1 THEN  –模式1下红灯的时长,这里是结束了模式1后的清零状态
                mode <= '0';                        –模式1结束了,进入模式0
                ped_cnt <= (OTHERS=>'0');        –模式1的计数清零,为下次做准备
                exit_ped <= '1';  — 产生退出脉冲  为进入模式0的循环做准备
            ELSE
                ped_cnt <= ped_cnt + 1;  –如果模式1没有计数结束,就持续加加
            END IF;
        END IF;
    END IF;
END PROCESS;

–3.全局计时计数器
PROCESS(clk,rst_n)
BEGIN
    IF rst_n='0' THEN
        cnt <= (OTHERS=>'0');
    ELSIF clk'EVENT AND clk='1' THEN
        IF mode='1' THEN
            cnt <= (OTHERS=>'0');
        ELSIF key_trig='1' THEN
            cnt <= (OTHERS=>'0');
        ELSIF exit_ped='1' THEN
            cnt <= (OTHERS=>'0');  — 退出时清零,让绿灯从0开始
        ELSE
            IF (light_state="00" AND cnt >= GREEN_TIME-1) OR
               (light_state="01" AND cnt >= YELLOW_TIME-1) OR
               (light_state="10" AND cnt >= RED_TIME-1) THEN
                cnt <= (OTHERS=>'0');
            ELSE
                cnt <= cnt + 1; –在红绿黄3个状态下,计数未满,则一直计数加加,直到满了清0
            END IF;
        END IF;
    END IF;
END PROCESS;

–4.红绿灯状态跳转(关键:退出时强制切换到绿灯)
PROCESS(clk,rst_n)
BEGIN
    IF rst_n='0' THEN
        light_state <= "00";          –初始化绿灯
    ELSIF clk'EVENT AND clk='1' THEN
        IF mode='1' THEN             –模式一状态下为红灯
            light_state <= "10";     
        ELSIF exit_ped='1' THEN   –收到模式1结束时候的脉冲,表示要切换到模式0
            light_state <= "00";  — 退出行人模式时强制切换到绿灯
        ELSE
            CASE light_state IS
                WHEN "00" =>
                    IF cnt >= GREEN_TIME-1 THEN –绿灯下计数结束后进入黄灯
                        light_state <= "01";
                    END IF;
                WHEN "01" =>
                    IF cnt >= YELLOW_TIME-1 THEN –黄灯下计数结束后进入红灯
                        light_state <= "10";
                    END IF;
                WHEN "10" =>
                    IF cnt >= RED_TIME-1 THEN      –红灯下计数结束后进入绿灯,达到循环
                        light_state <= "00";
                    END IF;
                WHEN OTHERS =>
                    light_state <= "00";             –初始化绿灯状态
            END CASE;
        END IF;
    END IF;
END PROCESS;

–5.组合逻辑输出(0点亮、1熄灭) – 行人模式用 ped_cnt 直接判断
PROCESS(mode, light_state, rst_n, ped_cnt)
BEGIN
    IF rst_n='0' THEN
        led_r <= '1';
        led_y <= '1';
        led_g <= '1';
    ELSE
        — 行人模式:用 ped_cnt 判断,精确控制500ns
        IF mode='1' OR (ped_cnt > 0 AND ped_cnt < RED_PED_TIME) THEN –模式1下且计数未满时红灯亮
            led_r <= '0';
            led_y <= '1';
            led_g <= '1';
        ELSE
            CASE light_state IS
                WHEN "00" =>
                    led_r <= '1';
                    led_y <= '1';
                    led_g <= '0';
                WHEN "01" =>
                    led_r <= '1';
                    led_y <= '0';
                    led_g <= '1';
                WHEN "10" =>
                    led_r <= '0';
                    led_y <= '1';
                    led_g <= '1';
                WHEN OTHERS =>
                    led_r <= '1';
                    led_y <= '1';
                    led_g <= '1';
            END CASE;
        END IF;
    END IF;
END PROCESS;

END bh;

此时需要额外编写仿真代码,操作与设计代码一样,请自行编写!!!

这里我用的是modelsim仿真的,需要在Quartus上进行仿真路径配置,如无法配置,请卸载该版本Quartus软件,重新安装,注意勾选并安装必备工具!!!

仿真波形如下所示:

从第一张图片可以看出key按下长达3个时钟周期,此时切换到模式0,由于时序延迟,这里产生key_trig脉冲后,仍需从第二个时钟周期开始计数,才是正常的模式0下的500ns计数时长。

从第二张图片可以明显看出key的按下时长不足3个时钟周期,模式不切换,模式1正常循环运行。

赞(0)
未经允许不得转载:171主机测评 » 关于Quartus的简易交通灯仿真
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址