15356|42

5979

帖子

8

TA的资源

版主

楼主
 

EE_FPGA基础教程系列 --NO.3-- 玩转LED [复制链接]



Table of Contents
1.        剧情回放        4
2.        玩转LED        4
  2.1        硬件连接        4
  2.2        程序编写        4
  2.3        程序简介        5
  2.4        换个玩法        7
  2.5        点灯进阶        7
  2.6        答疑解惑        9
3.        总结        10
详细内容:
1.        剧情回放
  话说上次在建立的第一个EE_FPGA工程的时候,我们使用了一个点亮LED的范例,这里我们继续点亮LED这个话题。
2.        玩转LED
  2.1        硬件连接
  首先,我们得打开EE_FPGA的硬件手册,找到LED部分的原理图。如下图所示,我们看到,LED的右端是连着上拉电阻的VDD3.3V高电平,左端则连着FPGA的管脚pin_31-35。那我们想,假若我们的FPGA管脚输出的是高电平即3.3V,那么左右两端的电压相当,就不会有电流流过LED,也就不会发光了。如果FPGA管脚输出的是低电平,那就有电流从LED流过,LED就点亮了。原理就是这么简单。
  

  2.2        程序编写
  一般FPGA的核心电平是1.2V,管脚电平是3.3V,所以,要想点亮哪个LED,只要给连接的那个管脚赋0,不点亮赋1就可以了。
上次点亮四个LED的程序我们是这样写的:
  1. module led (
  2. clk,rst_n,
  3. led
  4. );

  5. input clk;
  6. input rst_n;
  7. output[3:0] led;

  8. reg[3:0] led_r;
  9. always @(posedge clk or negedge rst_n)
  10. begin
  11.   if(!rst_n)
  12. led_r <= 4'b1111;
  13.   else
  14.     led_r <= 4'b0;   // led是一端接上拉电阻,输入低电平点亮
  15. end

  16. assign led = led_r;

  17. endmodule
复制代码

  2.3        程序简介
  这里我就讲点Verilog的经验之谈,有不妥的地方还请大家多指正。关于Verilog语法,还请大家找本书系统地学习下,这里无法一点一点细讲,要细讲的话书上是最合适的。推荐两本书,一本是夏宇闻老师的《Verilog 数字系统设计教程》 ,另外一本《设计与验证Verilog HDL》也很不错。
Verilog的一个程序模块,是以module 和 endmodule 开头和结尾的。跟在module后面的是这个模块的模块名。模块名后面的括号里列出了这个模块的输入输出管脚列表。再接下来我们要对这些管脚是输入input 还是输出 output 以及是多少位进行描述。再接下来差不多就是程序的正文了。
我们知道,数字电路就分为两种:组合逻辑电路和时序逻辑电路。其实我们写的FPGA程序它不叫程序,它一般叫做硬件描述语言,(这里我也是图方便混着叫了,嘿嘿)。说这个呢,想表达这么个意思:我们写了FPGA程序,然后Quartus帮我们综合到FPGA芯片中,在FPGA内部就是生成两种数字电路,组合逻辑电路和时序逻辑电路。
  所以,我们写程序,也就两种逻辑电路的描述。凡是clock信号有关系的就是时序逻辑,跟clock没什么关系的就是组合逻辑(这是我妄自断言,还没有出处,有问题的话请拍砖)。这就引出了wire数据型和reg数据型的问题,还有阻塞赋值和非阻塞赋值。这些概念大家一定要在书里仔细阅读。
学习Verilog并不难,花个一天时间看下书,弄个程序写一下基本就会了。对于以前一直从事c语言,c++软件开发的同学,首先得理解这样的问题。我们所写的Verilog程序,并非软件程序,它是用来描述硬件电路的!
  1. module led (
  2.   clk,rst_n,
  3.   led
  4. );

  5. input clk;
  6. input rst_n;
  7. output[3:0] led;

  8. reg[3:0] led_r;
  9. always @(posedge clk or negedge rst_n)
  10. begin
  11.   if(!rst_n)
  12.     led_r <= 4'b1111;
  13.   else
  14.     led_r <= 4'b0;   // led是一端接上拉电阻,输入低电平点亮
  15. end

  16. wire[3:0] led;
  17. assign led = led_r;

  18. endmodule
复制代码
2.4        换个玩法
  四个LED亮着是不是没什么好玩的呢?我们可不可以这样的,让四个灯轮流亮起来,就是第一个灯亮了之后熄灭,然后第二个亮再熄灭,接着第三个,第四个。这个流水灯,或者叫跑马灯,大家在做单片机实验的时候估计都做过吧。这里我们只要做一个移位寄存器就可以了。我们修改下面这段程序
  1. reg[3:0] led_r;
  2. always @(posedge clk or negedge rst_n)
  3. begin
  4.   if(!rst_n)
  5.     led_r <= 4'b0111;
  6.   else
  7.     led_r <= {led_r[0],led_r[3:1]};
  8. end
复制代码
{}是Verilog里的拼接运算符,这句{led_r[0],led_r[3:1]}的意思就是把上次led_r的第0位移到最高位,然后高3位往右移。也就是说,最初,我们给四个led的赋值是0111,那只有最高位的那个led灯是点亮的。第一次移位后变成1011,那就只有第二个是亮的;接着1101,第三个;1110,第四个;然后又变成第一个0111。
  2.5        点灯进阶
  按原理分析,我们应该是实现了流水灯这个功能了。下载到板子上看看效果吧。结果估计另大家都失望了,怎么回事?四个LED灯都还亮着。聪明的同学估计找到原因了,但我还想买个关子,我们先做下面的实验。
  1. module led (
  2.   clk,rst_n,
  3.   led
  4. );

  5. input clk;
  6. input rst_n;
  7. output[3:0] led;

  8. reg[19:0] cnt;
  9. always @(posedge clk or negedge rst_n)
  10. begin
  11.   if(!rst_n)
  12.     cnt <= 20'b0;
  13.   else
  14.     cnt <= cnt + 1'b1;
  15. end

  16. reg enable_r;
  17. always @(posedge clk or negedge rst_n)
  18. begin
  19.   if(!rst_n)
  20.     enable_r <= 1'b0;
  21.   else if (cnt == 20'hfffff)
  22.     enable_r <= 1'b1;
  23.   else
  24.     enable_r <= 1'b0;
  25. end

  26. wire enable;
  27. assign enable = enable_r;

  28. reg[3:0] led_r;
  29. always @(posedge clk or negedge rst_n)
  30. begin
  31.   if(!rst_n)
  32.     led_r <= 4'b1;
  33.   else if(enable)
  34.     led_r <= {led_r[0],led_r[3:1]};
  35.   else ;
  36. end

  37. wire[3:0] led;
  38. assign led = led_r;

  39. endmodule
复制代码
我又写了上面这段程序,程序中我增加了一个计数器cnt。开始,计数器是20位的,每个系统时钟的上升沿 posedge clk 执行一次计数器 +1 操作 cnt <= cnt + 1'b1 。 在计数器计数到满的时候,我定义了一个enable信号 else if (cnt == 20'hfffff) enable_r <= 1'b1;而其他时候,我都让这个 enable 信号维持低电平。(这里加一句,计数器到满的时候 cnt = 20'hfffff再 + 1 它就溢出了,回到20’h0)。
  1. reg[3:0] led_r;
  2. always @(posedge clk or negedge rst_n)
  3. begin
  4.   if(!rst_n)
  5.     led_r <= 4'b1;
  6.   else if(enable)
  7.     led_r <= {led_r[0],led_r[3:1]};
  8.   else ;
  9. end
复制代码
然后我们再看这段程序,我让它只有在 enable == 1’b1 的时候进行移位。大家把这段程序下载到板子上,有什么现象?四个led在闪动。

  2.6        答疑解惑
  好了,这个关子就卖到这里了。问题出在我们的眼睛骗了我们。百度一下,知道一个数据:人眼分辨事物的最高频率为24HZ,即反应一次要0.042s 。我们最初的移位是用的系统时钟clk,它是50MHZ,也就是说灯的每盏灯的亮灭是按50M的速度在移动,眼睛当然是完全看不出来啦,所以效果跟四个灯全亮是一样的。
后面我们用了一个计数器,使移位变成了2的20次方个CLK时间,即频率变成了50M/1048576 ,约等于50 HZ,这时我们的眼睛还是分辨不了,所以我们看到四个灯都在闪烁。
  接下来,我们再把计数增大一点,把移位的频率降下来,就能看到流水灯的现象了。
这是个有趣的现象,相同原理的实验我在本科的时候做过,那时候也没太在意。最近发现安装在山地车轮胎上的“风火轮”也是用的这个原理哦!

  3.        总结
  这一篇我们讲了LED点亮的原理,以及计数器的设计,还有流水灯的设计。好玩吧!有兴趣的欢迎加入一起学习!

附:pdf文档: EE_FPGA基础教程系列 -- 玩转LED.pdf (750.21 KB, 下载次数: 2193)

[ 本帖最后由 xieqiang 于 2011-5-12 11:27 编辑 ]

最新回复

很好  详情 回复 发表于 2013-7-31 20:27
点赞 关注
个人签名生活就是油盐酱醋再加一点糖,快活就是一天到晚乐呵呵的忙
===================================
做一个简单的人,踏实而务实,不沉溺幻想,不庸人自扰
 

回复
举报

1万

帖子

16

TA的资源

版主

沙发
 

不错,顶

个人签名http://shop34182318.taobao.com/
https://shop436095304.taobao.com/?spm=a230r.7195193.1997079397.37.69fe60dfT705yr
 
 

回复

255

帖子

0

TA的资源

一粒金砂(中级)

板凳
 
Mark!
 
 
 

回复

6892

帖子

0

TA的资源

五彩晶圆(高级)

4
 

支持! 不错!

个人签名一个为理想不懈前进的人,一个永不言败人!
http://shop57496282.taobao.com/
欢迎光临网上店铺!
 
 
 

回复

670

帖子

0

TA的资源

一粒金砂(中级)

5
 

不错啊

支持
 
 
 

回复

45

帖子

0

TA的资源

一粒金砂(中级)

6
 
thanks!!!!
 
 
 

回复

113

帖子

0

TA的资源

一粒金砂(中级)

7
 
等到有空的时候好好学习这个东西
 
 
 

回复

108

帖子

0

TA的资源

一粒金砂(中级)

8
 
支持一下
 
 
 

回复

6892

帖子

0

TA的资源

五彩晶圆(高级)

9
 

  好东西,我顶我顶我顶!

个人签名一个为理想不懈前进的人,一个永不言败人!
http://shop57496282.taobao.com/
欢迎光临网上店铺!
 
 
 

回复

12

帖子

0

TA的资源

一粒金砂(中级)

10
 
为什么要加个使能信号enable_r,而不直接用计数cnt?有技巧在里面?这样综合出来的电路是否相同?
 
 
 

回复

5979

帖子

8

TA的资源

版主

11
 
把你想的写法用verilog写出来 大家讨论
个人签名生活就是油盐酱醋再加一点糖,快活就是一天到晚乐呵呵的忙
===================================
做一个简单的人,踏实而务实,不沉溺幻想,不庸人自扰
 
 
 

回复

14

帖子

0

TA的资源

一粒金砂(中级)

12
 
led_r <= {led_r[0],led_r[3:1]};
用拼接实现移位,学习了。
 
 
 

回复

12

帖子

0

TA的资源

一粒金砂(中级)

13
 
我的想法如下,据综合出来的结果,会少用一个寄存器(enable_r),其他倒没什么不同
module Test(
        input clk,
        input rst_n,
        output[3:0] led
        );
        reg[3:0] led_r;
        reg [23:0] cnt;
        always @(posedge clk or negedge rst_n)
        begin
                if(!rst_n)
                begin
                        cnt<=24'b0;
                end
                else
                        cnt<=cnt+1'b1;
        end
       
//        reg enable_r;
//        always @(posedge clk or negedge rst_n)
//        begin
//                if(!rst_n)
//                        enable_r<=0;
//                else if(cnt==24'hffffff)
//                        enable_r<=1;
//                else
//                        enable_r<=0;
//        end
//       
//        wire enable;
//        assign enable=enable_r;
       
        always @(posedge clk or negedge rst_n)
        begin
                if(!rst_n)
                begin
                        led_r<=4'b0001;
                end
                else if(cnt==24'hffffff)
                begin
                        led_r<={led_r[0],led_r[3:1]};
                end
        end
        assign led=led_r;
endmodule
 
 
 

回复

6892

帖子

0

TA的资源

五彩晶圆(高级)

14
 

最少资源的代码不一定是好代码。适合的才是最好的。

个人签名一个为理想不懈前进的人,一个永不言败人!
http://shop57496282.taobao.com/
欢迎光临网上店铺!
 
 
 

回复

7183

帖子

195

TA的资源

五彩晶圆(高级)

15
 
kankan 看看来学习
 
 
 

回复

11

帖子

0

TA的资源

一粒金砂(初级)

16
 
来学习的
 
 
 

回复

20

帖子

0

TA的资源

一粒金砂(初级)

17
 
下来学习,谢谢LZ
 
 
 

回复

97

帖子

0

TA的资源

一粒金砂(中级)

18
 
大有深入浅出之势
 
 
 

回复

25

帖子

0

TA的资源

一粒金砂(中级)

19
 

为什么rst_n没有分配IO

按照这个流程下来,流水灯根本留不下来,后来我分配IO给 rst_n,才动起来了。
 
 
 

回复

5979

帖子

8

TA的资源

版主

20
 
哈哈 切图的时候估计切错了 赞仔细
个人签名生活就是油盐酱醋再加一点糖,快活就是一天到晚乐呵呵的忙
===================================
做一个简单的人,踏实而务实,不沉溺幻想,不庸人自扰
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表