明德扬吴老师 发表于 2020-7-4 13:04:24

【每周FPGA案例】定时转换的LED交通灯1编号:000800000235


本案例的编号为:000800000235,如果有疑问,请按编号在下面贴子查找答案:MDY案例交流【汇总贴】_FPGA-明德扬科教 (mdy-edu.com)

【上板现象】

定时转换的LED交通灯1在MP801的上板现象
https://www.bilibili.com/video/BV1h4411175c?p=79

定时转换的LED交通灯1在点拨开发板的上板现象

https://www.bilibili.com/video/BV1h4411175c?p=80

定时转换的LED交通灯1在实验箱的上板现象

https://www.bilibili.com/video/BV1h4411175c?p=81
【设计教程】

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 信号列表
信号名I/O位宽定义
clkI1系统工作时钟 50M
rst_nI1系统复位信号,低电平有效
led_eastO33 比特信号,表示东面三个 led 灯,最高位为红灯,最低位为绿灯,低电平时灯亮。
led_southO33 比特信号,表示南面三个 led 灯,最高位为红灯,最低位为绿灯,低电平时灯亮。
led_westO33 比特信号,表示西面三个 led 灯,最高位为红灯,最低位为绿灯,低电平时灯亮。
led_northO33 比特信号,表示北面三个 led 灯,最高位为红灯,最低位为绿灯,低电平时灯亮。





1.1.4 设计思路

根据题目功能要求,东西南北四个方向LED灯颜色变换的速度都不同。因为在数字电路中的延时都是通过计数器实现的,计数器*时钟周期=延时时间。本模块中,由于输入时钟是50MHz,时钟周期为20ns,功能要求每1秒变化一次。我们通过counter来表示延时,当其值为1s/20ns=5000_0000时,表示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          e_counter;      
reg    s_counter;
reg    w_counter;
reg    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=3’b110;然后每隔1秒,依次循环变化:101,011,110。即end_e_counter(每隔1秒)时,led_east数值循环左移,其他时候不变。
led_west、led_south、led_north也是同理,即:
上电后,led_west=3’b110;然后每隔2秒,依次循环变化:101,011,110。即end_w_counter(每隔2秒)时,led_west数值循环左移,其他时候不变。
上电后,led_south=3’b110;然后每隔3秒,依次循环变化:101,011,110。即end_s_counter(每隔3秒)时,led_south数值循环左移,其他时候不变。
上电后,led_north=3’b110;然后每隔4秒,依次循环变化:101,011,110。即end_n_counter(每隔4秒)时,led_north数值循环左移,其他时候不变。


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

parameter   LED_LEN         =   3;

output   led_east;
output   led_south;
output   led_west;
output   led_north;

reg      led_east;
reg      led_south;
reg      led_west;
reg      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_east};
    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_west};
    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_south};
    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_north};
    end
    else begin
      led_north<=led_north;
    end
end



1.1.5 参考设计代码
moduletraf_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_east ;
output   led_south;
output   led_west ;
output   led_north;

reg      led_east ;
reg      led_south;
reg      led_west ;
reg      led_north;

reg             e_counter;      
reg    s_counter;
reg    w_counter;
reg    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_east};
    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_west};
    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_south};
    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_north};
    end
    else begin
      led_north<=led_north;
    end
end

endmodule


1.2 效果和总结


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


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



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


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


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



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


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


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


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


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


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


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


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


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


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


观看上面的现象,可以发现,工程各项功能正常:开发板上东西南北 4 个方向,每个方向上的 3 个 LED 灯按照“绿灯--黄灯--红灯--绿灯--黄灯......”依次循环变化,并且东西南北 4 个方向LED灯变化的速度不同,东面的间隔时间为 1 秒;西面的间隔时间为 2 秒;南面的间隔时间为 3 秒;北面的间隔时间为 4 秒,成功完成设计目标。
感兴趣的朋友也可以访问明德扬论坛(http://www.fpgabbs.cn/)进行FPGA相关工程设计学习,也欢迎大家在评论进行讨论!
【设计教程下载】


【设计视频教程】
https://www.bilibili.com/video/BV1Af4y117H4?p=2

【工程源码】







014 发表于 2021-3-28 17:13:45

有这个工程的测试文件吗?

明德扬吴老师 发表于 2021-3-29 10:38:42

014 发表于 2021-3-28 17:13
有这个工程的测试文件吗?

还没有的,需要自己编写。 请看此教程03 测试文件的编写教程
http://www.fpgabbs.cn/forum.php?mod=viewthread&tid=459&fromuid=9396
(出处: 明德扬论坛)
页: [1]
查看完整版本: 【每周FPGA案例】定时转换的LED交通灯1编号:000800000235