明德扬论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

微信扫一扫,快捷登录!

查看: 258|回复: 0

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

[复制链接]
发表于 2020-7-4 13:04:24 | 显示全部楼层 |阅读模式

马上注册,看完整文章,学更多FPGA知识。

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
【上板现象】

定时转换的LED交通灯1在MP801的上板现象


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



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


【设计教程】

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
位宽
定义
clk
I
1
系统工作时钟 50M
rst_n
I
1
系统复位信号,低电平有效
led_east
O
3
3 比特信号,表示东面三个 led 灯,最高位为红灯,最低位为绿灯,低电平时灯亮。
led_south
O
3
3 比特信号,表示南面三个 led 灯,最高位为红灯,最低位为绿灯,低电平时灯亮。
led_west
O
3
3 比特信号,表示西面三个 led 灯,最高位为红灯,最低位为绿灯,低电平时灯亮。
led_north
O
3
3 比特信号,表示北面三个 led 灯,最高位为红灯,最低位为绿灯,低电平时灯亮。





1.1.4 设计思路

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

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

图片1.png

东方向计数器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秒了。


下面是东西南北四个方向的秒计数器的代码。
  1. parameter   COUNT_1S        =   26'd5000_0000;
  2. parameter   COUNT_WID       =   28;

  3. reg           [COUNT_WID-1:0] e_counter;        
  4. reg     [COUNT_WID-1:0] s_counter;
  5. reg     [COUNT_WID-1:0] w_counter;
  6. reg     [COUNT_WID-1:0] n_counter;

  7. wire                    add_e_counter;
  8. wire                    end_e_counter;
  9. wire                    add_w_counter;
  10. wire                    end_w_counter;
  11. wire                    add_s_counter;
  12. wire                    end_s_counter;
  13. wire                    add_n_counter;
  14. wire                    end_n_counter;
复制代码



  1. always @(posedge clk or negedge rst_n) begin
  2.     if (rst_n==0) begin
  3.         e_counter <= 0;
  4.     end
  5.     else if(add_e_counter) begin
  6.         if(end_e_counter)
  7.             e_counter <= 0;
  8.         else
  9.             e_counter <= e_counter+1 ;
  10.    end
  11. end
  12. assign add_e_counter = 1;
  13. assign end_e_counter = add_e_counter  && e_counter == COUNT_1S-1 ;
  14. always @(posedge clk or negedge rst_n) begin
  15.     if (rst_n==0) begin
  16.         w_counter <= 0;
  17.     end
  18.     else if(add_w_counter) begin
  19.         if(end_w_counter)
  20.             w_counter <= 0;
  21.         else
  22.             w_counter <= w_counter+1 ;
  23.    end
  24. end
  25. assign add_w_counter = 1;
  26. assign end_w_counter = add_w_counter  && w_counter == 2*COUNT_1S-1 ;
  27. always @(posedge clk or negedge rst_n) begin
  28.     if (rst_n==0) begin
  29.         s_counter <= 0;
  30.     end
  31.     else if(add_s_counter) begin
  32.         if(end_s_counter)
  33.             s_counter <= 0;
  34.         else
  35.             s_counter <= s_counter+1 ;
  36.    end
  37. end
  38. assign add_s_counter = 1;
  39. assign end_s_counter = add_s_counter  && s_counter == 3*COUNT_1S-1 ;
  40. always @(posedge clk or negedge rst_n) begin
  41.     if (rst_n==0) begin
  42.         n_counter <= 0;
  43.     end
  44.     else if(add_n_counter) begin
  45.         if(end_n_counter)
  46.             n_counter <= 0;
  47.         else
  48.             n_counter <= n_counter+1 ;
  49.    end
  50. end
  51. assign add_n_counter = 1;
  52. 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灯亮灯控制代码。


  1. parameter   LED_LEN         =   3;

  2. output  [LED_LEN-1:0]   led_east;
  3. output  [LED_LEN-1:0]   led_south;
  4. output  [LED_LEN-1:0]   led_west;
  5. output  [LED_LEN-1:0]   led_north;

  6. reg     [LED_LEN-1:0]   led_east;
  7. reg     [LED_LEN-1:0]   led_south;
  8. reg     [LED_LEN-1:0]   led_west;
  9. reg     [LED_LEN-1:0]   led_north;
复制代码

  1. always  @(posedge clk or negedge rst_n)begin
  2.     if(rst_n==1'b0)begin
  3.         led_east<={{(LED_LEN-1){1'b1}},1'b0};
  4.     end
  5.     else if(end_e_counter)begin
  6.         led_east<={led_east[LED_LEN-2:0],led_east[LED_LEN-1]};
  7.     end
  8.     else begin
  9.         led_east<=led_east;
  10.     end
  11. end

  12. always  @(posedge clk or negedge rst_n)begin
  13.     if(rst_n==1'b0)begin
  14.         led_west<={{(LED_LEN-1){1'b1}},1'b0};
  15.     end
  16.     else if(end_w_counter)begin
  17.         led_west<={led_west[LED_LEN-2:0],led_west[LED_LEN-1]};
  18.     end
  19.     else begin
  20.         led_west<=led_west;
  21.     end
  22. end

  23. always  @(posedge clk or negedge rst_n)begin
  24.     if(rst_n==1'b0)begin
  25.         led_south<={{(LED_LEN-1){1'b1}},1'b0};
  26.     end
  27.     else if(end_s_counter)begin
  28.         led_south<={led_south[LED_LEN-2:0],led_south[LED_LEN-1]};
  29.     end
  30.     else begin
  31.         led_south<=led_south;
  32.     end
  33. end

  34. always  @(posedge clk or negedge rst_n)begin
  35.     if(rst_n==1'b0)begin
  36.         led_north<={{(LED_LEN-1){1'b1}},1'b0};
  37.     end
  38.     else if(end_n_counter)begin
  39.         led_north<={led_north[LED_LEN-2:0],led_north[LED_LEN-1]};
  40.     end
  41.     else begin
  42.         led_north<=led_north;
  43.     end
  44. end
复制代码




1.1.5 参考设计代码
  1. module  traf_light1(
  2.     clk             ,
  3.     rst_n           ,
  4.     led_east        ,
  5.     led_south       ,
  6.     led_west        ,
  7.     led_north      
  8.     );


  9. parameter   LED_LEN         =   3;
  10. parameter   COUNT_1S        =   26'd5000_0000;
  11. parameter   COUNT_WID       =   28;

  12. input                   clk      ;
  13. input                   rst_n    ;
  14. output  [LED_LEN-1:0]   led_east ;
  15. output  [LED_LEN-1:0]   led_south;
  16. output  [LED_LEN-1:0]   led_west ;
  17. output  [LED_LEN-1:0]   led_north;

  18. reg     [LED_LEN-1:0]   led_east ;
  19. reg     [LED_LEN-1:0]   led_south;
  20. reg     [LED_LEN-1:0]   led_west ;
  21. reg     [LED_LEN-1:0]   led_north;

  22. reg            [COUNT_WID-1:0] e_counter;        
  23. reg     [COUNT_WID-1:0] s_counter;
  24. reg     [COUNT_WID-1:0] w_counter;
  25. reg     [COUNT_WID-1:0] n_counter;

  26. wire                    add_e_counter;
  27. wire                    end_e_counter;
  28. wire                    add_w_counter;
  29. wire                    end_w_counter;
  30. wire                    add_s_counter;
  31. wire                    end_s_counter;
  32. wire                    add_n_counter;
  33. wire                    end_n_counter;

  34. always @(posedge clk or negedge rst_n) begin
  35.     if (rst_n==0) begin
  36.         e_counter <= 0;
  37.     end
  38.     else if(add_e_counter) begin
  39.         if(end_e_counter)
  40.             e_counter <= 0;
  41.         else
  42.             e_counter <= e_counter+1 ;
  43.    end
  44. end
  45. assign add_e_counter = 1;
  46. assign end_e_counter = add_e_counter  && e_counter == COUNT_1S-1 ;


  47. always @(posedge clk or negedge rst_n) begin
  48.     if (rst_n==0) begin
  49.         w_counter <= 0;
  50.     end
  51.     else if(add_w_counter) begin
  52.         if(end_w_counter)
  53.             w_counter <= 0;
  54.         else
  55.             w_counter <= w_counter+1 ;
  56.    end
  57. end
  58. assign add_w_counter = 1;
  59. assign end_w_counter = add_w_counter  && w_counter == 2*COUNT_1S-1 ;


  60. always @(posedge clk or negedge rst_n) begin
  61.     if (rst_n==0) begin
  62.         s_counter <= 0;
  63.     end
  64.     else if(add_s_counter) begin
  65.         if(end_s_counter)
  66.             s_counter <= 0;
  67.         else
  68.             s_counter <= s_counter+1 ;
  69.    end
  70. end
  71. assign add_s_counter = 1;
  72. assign end_s_counter = add_s_counter  && s_counter == 3*COUNT_1S-1 ;


  73. always @(posedge clk or negedge rst_n) begin
  74.     if (rst_n==0) begin
  75.         n_counter <= 0;
  76.     end
  77.     else if(add_n_counter) begin
  78.         if(end_n_counter)
  79.             n_counter <= 0;
  80.         else
  81.             n_counter <= n_counter+1 ;
  82.    end
  83. end
  84. assign add_n_counter = 1;
  85. assign end_n_counter = add_n_counter  && n_counter == 4*COUNT_1S-1 ;

  86. always  @(posedge clk or negedge rst_n)begin
  87.     if(rst_n==1'b0)begin
  88.         led_east<={{(LED_LEN-1){1'b1}},1'b0};
  89.     end
  90.     else if(end_e_counter)begin
  91.         led_east<={led_east[LED_LEN-2:0],led_east[LED_LEN-1]};
  92.     end
  93.     else begin
  94.         led_east<=led_east;
  95.     end
  96. end

  97. always  @(posedge clk or negedge rst_n)begin
  98.     if(rst_n==1'b0)begin
  99.         led_west<={{(LED_LEN-1){1'b1}},1'b0};
  100.     end
  101.     else if(end_w_counter)begin
  102.         led_west<={led_west[LED_LEN-2:0],led_west[LED_LEN-1]};
  103.     end
  104.     else begin
  105.         led_west<=led_west;
  106.     end
  107. end

  108. always  @(posedge clk or negedge rst_n)begin
  109.     if(rst_n==1'b0)begin
  110.         led_south<={{(LED_LEN-1){1'b1}},1'b0};
  111.     end
  112.     else if(end_s_counter)begin
  113.         led_south<={led_south[LED_LEN-2:0],led_south[LED_LEN-1]};
  114.     end
  115.     else begin
  116.         led_south<=led_south;
  117.     end
  118. end

  119. always  @(posedge clk or negedge rst_n)begin
  120.     if(rst_n==1'b0)begin
  121.         led_north<={{(LED_LEN-1){1'b1}},1'b0};
  122.     end
  123.     else if(end_n_counter)begin
  124.         led_north<={led_north[LED_LEN-2:0],led_north[LED_LEN-1]};
  125.     end
  126.     else begin
  127.         led_north<=led_north;
  128.     end
  129. end

  130. endmodule
复制代码



1.2 效果和总结


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


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

图片3.png



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


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

图片5.png


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

图片6.png



Mp8011. 复位,东西南北四面都是绿灯
图片7.png


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

图片8.png


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

图片9.png


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

图片10.png


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

图片11.png


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


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

图片13.png


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

图片14.png


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

图片15.png


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

图片16.png


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

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

【设计教程下载】
定时转换的LED交通灯.pdf (3.52 MB, 下载次数: 14)
1 喜欢他/她就送朵鲜花吧,赠人玫瑰,手有余香! 鲜花榜单
FPGA视频课程  培训班 FPGA学习资料
吴老师 18022857217(微信同号) Q1241003385
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|MDYBBS ( 粤ICP备16061416号-1

GMT+8, 2020-8-6 05:35 , Processed in 0.569294 second(s), 13 queries , File On.

Powered by Discuz! X3.4

本论坛由广州健飞通信有限公司所有

© 2001-2019 Comsenz Inc.

快速回复 返回顶部 返回列表