官方论坛
官方淘宝
官方博客
微信公众号
点击联系吴工 点击联系周老师

【案例】定时转换LED交通灯设计

发布时间:2023-04-13   作者:admin 浏览量:

1.1 总体设计


1.1.1 概述

发光二极管简称为LED,是一种常用的发光器件,通过电子与空穴复合释放能量发光,它可以高效的将电能转化为光能,在现代社会具有广泛的用途,如照明、平板显示、医疗器件等。可通过高低电平的变化来控制LED灯的明灭状态,当输出信号为低电平时,LED灯亮,反之,当输出信号为高电平时,LED灯灭。

1.1.2 设计目标

实现开发板上东西南北 4 个方向,每个方向上的 3 个 LED 灯按照“绿灯--黄灯--红灯--绿灯--黄灯......”依次循环变化。变化的速度不同,东面的间隔时间为 1 秒;西面的间隔时间为 2 秒;南面的间隔时间为 3 秒;北面的间隔时间为 4 秒。

具体要求:

1、每个方向的灯分开独立设计。

2、首先设计东向的灯:设计一个计时 1 秒的计数器,用来计算灯的状态变化的时间间隔。

3、如果计时 1 秒到了,把黄灯点亮;再过 1 秒把红灯点亮;再过 1 秒,把绿灯点亮......

依次循环。

4、设计西方向的灯:设计一个计时 2 秒的计数器,其他的类似。

5、其它两个方向的设计类似。


1.1.3 信号列表

「每周FPGA案例」定时转换的LED交通灯1设计


1.1.4 设计思路

根据题目功能要求,东西南北四个方向LED灯颜色变换的速度都不同。因为在数字电路中的延时都是通过计数器实现的,计数器*时钟周期=延时时间。本模块中,由于输入时钟是50MHz,时钟周期为20ns,功能要求每1秒变化一次。我们通过counter来表示延时,当其值为1s/20ns=5000_0000时,表示1秒时间到。

本工程架构由四个计数器组成:

「每周FPGA案例」定时转换的LED交通灯1设计

东方向计数器e_counter:该计数器用于计算东向1s的时钟个数,加一条件为1,表示一直计数;数到5000_0000下,则表示数到1秒了。

西方向计数器w_counter:该计数器用于计算西向2s的时钟个数,加一条件为1,表示一直计数;数到2*5000_0000下,则表示数到2秒了。

南方向计数器s_counter:该计数器用于计算南向3s的时钟个数,加一条件为1,表示一直计数;数到3*5000_0000下,则表示数到3秒了。

北方向计数器n_counter:该计数器用于计算北向4s的时钟个数,加一条件为1,表示一直计数;数到4*5000_0000下,则表示数到4秒了。

下面是东西南北四个方向的秒计数器的代码。


parameter   COUNT_1S        =   26'd5000_0000;

parameter   COUNT_WID       =   28;

reg      [COUNT_WID-1:0] e_counter;       

reg     [COUNT_WID-1:0] s_counter;

reg     [COUNT_WID-1:0] w_counter;

reg     [COUNT_WID-1:0] n_counter;

wire                    add_e_counter;

wire                    end_e_counter;

wire                    add_w_counter;

wire                    end_w_counter;

wire                    add_s_counter;

wire                    end_s_counter;

wire                    add_n_counter;

wire                    end_n_counter;

always @(posedge clk or negedge rst_n) begin

    if (rst_n==0) begin

        e_counter <= 0;

    end

    else if(add_e_counter) begin

        if(end_e_counter)

            e_counter <= 0;

        else

            e_counter <= e_counter+1 ;

   end

end

assign add_e_counter = 1;

assign end_e_counter = add_e_counter  && e_counter == COUNT_1S-1 ;

always @(posedge clk or negedge rst_n) begin

    if (rst_n==0) begin

        w_counter <= 0;

    end

    else if(add_w_counter) begin

        if(end_w_counter)

            w_counter <= 0;

        else

            w_counter <= w_counter+1 ;

   end

end

assign add_w_counter = 1;

assign end_w_counter = add_w_counter  && w_counter == 2*COUNT_1S-1 ;

always @(posedge clk or negedge rst_n) begin

    if (rst_n==0) begin

        s_counter <= 0;

    end

    else if(add_s_counter) begin

        if(end_s_counter)

            s_counter <= 0;

        else

            s_counter <= s_counter+1 ;

   end

end

assign add_s_counter = 1;

assign end_s_counter = add_s_counter  && s_counter == 3*COUNT_1S-1 ;

always @(posedge clk or negedge rst_n) begin

    if (rst_n==0) begin

        n_counter <= 0;

    end

    else if(add_n_counter) begin

        if(end_n_counter)

            n_counter <= 0;

        else

            n_counter <= n_counter+1 ;

   end

end

assign add_n_counter = 1;

assign end_n_counter = add_n_counter  && n_counter == 4*COUNT_1S-1 ;


LED灯信号的变化,根据功能要求,东面的间隔时间为 1 秒;西面的间隔时间为 2 秒;南面2的间隔时间为 3 秒;北面的间隔时间为 4 秒。计数时间到时变化;时间没到,则不变化。每一时刻每个方向只有一个灯亮,并且亮灯的颜色顺序按照“绿灯--黄灯--红灯--绿灯--黄灯.....”依次循环变化。

东西南北四个方向的各有三盏不同颜色的LED灯,每个方向的三个LED灯都由3 比特信号控制,最高位为红灯,最低位为绿灯,并且低电平时LED灯亮。led_east表示东面三个LED灯,led_west表示西面三个LED灯,led_south表示南面三个LED灯,led_north表示北面三个LED灯。

三色LED灯的循环变换控制可以通过拼接的方法使数据循环左移来实现。

以led_east的变化为例,上电后,led_east[2:0]=3’b110;然后每隔1秒,依次循环变化:101,011,110。即end_e_counter(每隔1秒)时,led_east[2:0]数值循环左移,其他时候不变。

led_west、led_south、led_north也是同理,即:

上电后,led_west[2:0]=3’b110;然后每隔2秒,依次循环变化:101,011,110。即end_w_counter(每隔2秒)时,led_west[2:0]数值循环左移,其他时候不变。

上电后,led_south[2:0]=3’b110;然后每隔3秒,依次循环变化:101,011,110。即end_s_counter(每隔3秒)时,led_south[2:0]数值循环左移,其他时候不变。

上电后,led_north[2:0]=3’b110;然后每隔4秒,依次循环变化:101,011,110。即end_n_counter(每隔4秒)时,led_north[2:0]数值循环左移,其他时候不变。

下面是个东西南北四个方向的LED灯亮灯控制代码。


parameter   LED_LEN         =   3;

output  [LED_LEN-1:0]   led_east;

output  [LED_LEN-1:0]   led_south;

output  [LED_LEN-1:0]   led_west;

output  [LED_LEN-1:0]   led_north;

reg     [LED_LEN-1:0]   led_east;

reg     [LED_LEN-1:0]   led_south;

reg     [LED_LEN-1:0]   led_west;

reg     [LED_LEN-1:0]   led_north;

always  @(posedge clk or negedge rst_n)begin

    if(rst_n==1'b0)begin

        led_east<={{(LED_LEN-1){1'b1}},1'b0};

    end

    else if(end_e_counter)begin

        led_east<={led_east[LED_LEN-2:0],led_east[LED_LEN-1]};

    end

    else begin

        led_east<=led_east;

    end

end

always  @(posedge clk or negedge rst_n)begin

    if(rst_n==1'b0)begin

        led_west<={{(LED_LEN-1){1'b1}},1'b0};

    end

    else if(end_w_counter)begin

        led_west<={led_west[LED_LEN-2:0],led_west[LED_LEN-1]};

    end

    else begin

        led_west<=led_west;

    end

end

always  @(posedge clk or negedge rst_n)begin

    if(rst_n==1'b0)begin

        led_south<={{(LED_LEN-1){1'b1}},1'b0};

    end

    else if(end_s_counter)begin

        led_south<={led_south[LED_LEN-2:0],led_south[LED_LEN-1]};

    end

    else begin

        led_south<=led_south;

    end

end

always  @(posedge clk or negedge rst_n)begin

    if(rst_n==1'b0)begin

        led_north<={{(LED_LEN-1){1'b1}},1'b0};

    end

    else if(end_n_counter)begin

        led_north<={led_north[LED_LEN-2:0],led_north[LED_LEN-1]};

    end

    else begin

        led_north<=led_north;

    end

end



1.1.5 参考设计代码

module  traf_light1(

    clk             ,

    rst_n           ,

    led_east        ,

    led_south       ,

    led_west        ,

    led_north      

    );

parameter   LED_LEN         =   3;

parameter   COUNT_1S        =   26'd5000_0000;

parameter   COUNT_WID       =   28;

input                   clk      ;

input                   rst_n    ;

output  [LED_LEN-1:0]   led_east ;

output  [LED_LEN-1:0]   led_south;

output  [LED_LEN-1:0]   led_west ;

output  [LED_LEN-1:0]   led_north;

reg     [LED_LEN-1:0]   led_east ;

reg     [LED_LEN-1:0]   led_south;

reg     [LED_LEN-1:0]   led_west ;

reg     [LED_LEN-1:0]   led_north;

reg       [COUNT_WID-1:0] e_counter;       

reg     [COUNT_WID-1:0] s_counter;

reg     [COUNT_WID-1:0] w_counter;

reg     [COUNT_WID-1:0] n_counter;

wire                    add_e_counter;

wire                    end_e_counter;

wire                    add_w_counter;

wire                    end_w_counter;

wire                    add_s_counter;

wire                    end_s_counter;

wire                    add_n_counter;

wire                    end_n_counter;

always @(posedge clk or negedge rst_n) begin

    if (rst_n==0) begin

        e_counter <= 0;

    end

    else if(add_e_counter) begin

        if(end_e_counter)

            e_counter <= 0;

        else

            e_counter <= e_counter+1 ;

   end

end

assign add_e_counter = 1;

assign end_e_counter = add_e_counter  && e_counter == COUNT_1S-1 ;

always @(posedge clk or negedge rst_n) begin

    if (rst_n==0) begin

        w_counter <= 0;

    end

    else if(add_w_counter) begin

        if(end_w_counter)

            w_counter <= 0;

        else

            w_counter <= w_counter+1 ;

   end

end

assign add_w_counter = 1;

assign end_w_counter = add_w_counter  && w_counter == 2*COUNT_1S-1 ;

always @(posedge clk or negedge rst_n) begin

    if (rst_n==0) begin

        s_counter <= 0;

    end

    else if(add_s_counter) begin

        if(end_s_counter)

            s_counter <= 0;

        else

            s_counter <= s_counter+1 ;

   end

end

assign add_s_counter = 1;

assign end_s_counter = add_s_counter  && s_counter == 3*COUNT_1S-1 ;

always @(posedge clk or negedge rst_n) begin

    if (rst_n==0) begin

        n_counter <= 0;

    end

    else if(add_n_counter) begin

        if(end_n_counter)

            n_counter <= 0;

        else

            n_counter <= n_counter+1 ;

   end

end

assign add_n_counter = 1;

assign end_n_counter = add_n_counter  && n_counter == 4*COUNT_1S-1 ;

always  @(posedge clk or negedge rst_n)begin

    if(rst_n==1'b0)begin

        led_east<={{(LED_LEN-1){1'b1}},1'b0};

    end

    else if(end_e_counter)begin

        led_east<={led_east[LED_LEN-2:0],led_east[LED_LEN-1]};

    end

    else begin

        led_east<=led_east;

    end

end

always  @(posedge clk or negedge rst_n)begin

    if(rst_n==1'b0)begin

        led_west<={{(LED_LEN-1){1'b1}},1'b0};

    end

    else if(end_w_counter)begin

        led_west<={led_west[LED_LEN-2:0],led_west[LED_LEN-1]};

    end

    else begin

        led_west<=led_west;

    end

end

always  @(posedge clk or negedge rst_n)begin

    if(rst_n==1'b0)begin

        led_south<={{(LED_LEN-1){1'b1}},1'b0};

    end

    else if(end_s_counter)begin

        led_south<={led_south[LED_LEN-2:0],led_south[LED_LEN-1]};

    end

    else begin

        led_south<=led_south;

    end

end

always  @(posedge clk or negedge rst_n)begin

    if(rst_n==1'b0)begin

        led_north<={{(LED_LEN-1){1'b1}},1'b0};

    end

    else if(end_n_counter)begin

        led_north<={led_north[LED_LEN-2:0],led_north[LED_LEN-1]};

    end

    else begin

        led_north<=led_north;

    end

end

endmodule



1.2 效果和总结


点拨板

1. 复位,东西南北四面都是绿灯

「每周FPGA案例」定时转换的LED交通灯1设计


2. 时间经过1秒后,东面变为黄灯,其余三面还是绿灯

「每周FPGA案例」定时转换的LED交通灯1设计


3. 时间经过2秒后,东面变为红灯,西面变为黄灯,其余两面不变

「每周FPGA案例」定时转换的LED交通灯1设计


4. 时间经过3秒后,东面又变回绿灯,南面变为黄灯,西面还是黄灯,北面还是绿灯不变

「每周FPGA案例」定时转换的LED交通灯1设计


5. 时间经过4秒后,东面循环变为黄灯,南面还是黄灯,西面变为红灯,北面变为黄灯

「每周FPGA案例」定时转换的LED交通灯1设计


Mp801

1. 复位,东西南北四面都是绿灯

「每周FPGA案例」定时转换的LED交通灯1设计


2. 时间经过1秒后,东面变为黄灯,其余三面还是绿灯

「每周FPGA案例」定时转换的LED交通灯1设计


3. 时间经过2秒后,东面变为红灯,西面变为黄灯,其余两面不变

「每周FPGA案例」定时转换的LED交通灯1设计


4. 时间经过3秒后,东面又变回绿灯,南面变为黄灯,西面还是黄灯,北面还是绿灯不变

「每周FPGA案例」定时转换的LED交通灯1设计


5. 时间经过4秒后,东面循环变为黄灯,南面还是黄灯,西面变为红灯,北面变为黄灯

「每周FPGA案例」定时转换的LED交通灯1设计


实验箱

1. 复位,东西南北四面都是绿灯

「每周FPGA案例」定时转换的LED交通灯1设计


2. 时间经过1秒后,东面变为黄灯,其余三面还是绿灯

「每周FPGA案例」定时转换的LED交通灯1设计


3. 时间经过2秒后,东面变为红灯,西面变为黄灯,其余两面不变

「每周FPGA案例」定时转换的LED交通灯1设计


4. 时间经过3秒后,东面又变回绿灯,南面变为黄灯,西面还是黄灯,北面还是绿灯不变

「每周FPGA案例」定时转换的LED交通灯1设计


5. 时间经过4秒后,东面循环变为黄灯,南面还是黄灯,西面变为红灯,北面变为黄灯

「每周FPGA案例」定时转换的LED交通灯1设计

观看上面的现象,可以发现,工程各项功能正常:开发板上东西南北 4 个方向,每个方向上的 3 个 LED 灯按照“绿灯--黄灯--红灯--绿灯--黄灯......”依次循环变化,并且东西南北 4 个方向LED灯变化的速度不同,东面的间隔时间为 1 秒;西面的间隔时间为 2 秒;南面的间隔时间为 3 秒;北面的间隔时间为 4 秒,成功完成设计目标。

设计视频教程、工程源代码请移步明德扬论坛观看下载。

感兴趣的朋友也可以访问明德扬论坛(http://www.FPGAbbs.cn/)进行FPGA相关工程设计学习,也欢迎大家在评论进行讨论!

   拓展阅读