1、LED的基本原理

LED,又名发光二极管。LED灯工作电流很小(有的仅零点几毫安即可发光),抗冲击和抗震性能好,可靠性高,寿命长。由于这些优点,LED灯被广泛用在仪器仪表中作指示灯、液晶屏背光源等诸多领域。不同材料的发光二极管可以发出红、橙、黄、绿、青、蓝、紫、白这八种颜色的光。下图是可以发出黄、红、蓝三种颜色的直插型二极管实物图,这种二极管长的一端是阳极,短的那端是阴极。

下图是开发板上用的贴片发光二极管实物图。贴片二极管的正面一般都有颜色标记,有标记的那端就是阴极。

发光二极管与普通二极管一样具有单向导电性。给它加上阳极正向电压后,通过5mA左右的电流就可以使二极管发光。通过二极管的电流越大,发出的光亮度越强。不过我们一般将电 流限定在3~20mA之间,否则电流过大就会烧坏二极管。

2、串行与并行实现的区别

大多数开发板的LED都是设计成阴极接地,而阳极接到FPGA(或者单片机)的IO管脚上,所以我们只需要对IO口赋值即可实现LED的亮灭(赋值高电平==LED亮;赋值低电平==LED灭)。相信大多数同学都有C语言和单片机的基础(什么?你没有?那你还不去学),所以我们先来看一下单片机完成流水灯是怎么做的:

#include<reg52.h>#define uchar  unsigned char
#define uint   unsigned int sbit LED1 = P2^0;
sbit LED2 = P2^1;
sbit LED3 = P2^2;
sbit LED4 = P2^3;
sbit LED5 = P2^4;
sbit LED6 = P2^5;
sbit LED7 = P2^6;
sbit LED8 = P2^7;void delay(uint z)
{uint x,y;for(x = 0; x < z; x++)for(y = 0; y < 113; y++);
}void main(void)
{while(1){LED1 = 0;           //灯亮delay(1000);        //持续亮1sLED1 = 1;           //灯灭delay(1000);        //持续灭1sLED2 = 0;delay(1000);LED2 = 1;delay(1000);LED3 = 0;delay(1000);LED3 = 1;delay(1000);LED4 = 0;           //灯亮delay(1000);        //持续亮1sLED4 = 1;           //灯灭delay(1000);        //持续灭1s}
}

直接看main函数:串行设计的流水灯是怎么实现的呢?

  • 1、首先点亮第1个LED----延时1s----熄灭第1个LED;

    • 2、然后点亮第2个LED----延时1s----熄灭第2个LED;

      • 3、然后点亮第3个LED----延时1s----熄灭第3个LED;

        • 4、最后点亮第4个LED----延时1s----熄灭第4个LED;

可以看到整个结构都是顺序执行下来的,即符合单片的顺序结构,也非常契合人类的思维方式。那么FPGA不是顺序结构的,而是并行结构,无法直接一条一条指令地执行,那么该如何实现流水灯?

FPGA的工作是无法离开时钟的(组合逻辑除外)。我们可以设计一个always块,实现计数(或者说是计时)功能:每来一个时钟,让寄存器cnt的值累加1,直到加到预先设计的阈值再从0开始循环。假设FPGA的工作频率是50M,那么周期就是20ns。要实现计数到1s,则需要计数1s/20ns = 50_000_000次。所以我们的计时模块,就从0计数到50_000_000 – 1,即可实现计数1s。

同时我们再设计一个always块(LED显示),每当计数模块计数到了1s,就让LED的输出变化一次。比如初始显示最右边的LED,第1s到来时切换显示右边数第2个LED;第2s到来时切换显示右边数第3个LED;第3s到来时切换显示最左边的LED。这样就可以实现LED的流水显示了。

从上面的分析,可以通过流程图来直观感受串行设计与并行设计的不同:

3、流水灯的具体实现

第二章实际上已经把流水灯的实现方法阐明了:

  • 构造一个计时器,循环计时1s
  • 构造显示的always块,每当计数器计时到1s,则切换LED显示状态

1s计时器

上面算了在50M的时钟频率下,计数到1s需要计数50000000次,这个数转换成二进制需要26位才能表示,所以寄存器cnt的位宽是26位,如下:

reg  [25:0]  cnt;                                    //1s计时器always@(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)cnt <= 26'd0;                              //复位为0else if(cnt == 50_000_000 - 1)                  //计数到1scnt <= 26'd0;                               //清零计数器else                                         //计数不到1scnt <= cnt + 1'd1;                        //计数器每个周期累加1
end

LED显示

每当计数器计时到1s,则切换LED显示状态:第一次只显示最右边的LED1,下一次显示LED2,再下一次显示LED3,下一次显示LED4,然后重复显示LED1,如此循环,如下图所示:

该部分代码如下:

always@(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)led <= 4'b0001;                                //复位为最右边的点亮else if(cnt == 50_000_000 - 1)                 //计数到1s//拼接运算。把最高位(最左边的LED)移动到最低位,第2、1、0位作为整体向左移动一位led <= {led[2:0],led[3]};       else                                            //计数不到1s    led <= led;                                 //保持LED状态不变
end

需要注意的是:我们是使用移位运算符来实现LED的循环移位:把右边三位【2:0】变成高3位【3:1】,而最高位【3】变成最低位【0】,即可显示LED显示的整体左移。

完整代码如下;

//**************************************************************************
// *** 名称 : led_flow
// *** 作者 : 孤独的单刀
// *** 博客 : https://blog.csdn.net/wuzhikaidetb
// *** 日期 : 2021.12
// *** 描述 : 1s流水灯,循环左移
//**************************************************************************module led_flow
//============================< 信号 >======================================
(
//时钟和复位 --------------------------------------------
input                   sys_clk                 ,   //系统时钟50M
input                   sys_rst_n               ,   //低电平有效的异步复位
//DDR3写 ------------------------------------------------
output  reg [3:0]       led                         //LED的赋值电平
);reg   [25:0]  cnt;                                    //1s计时器always@(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)cnt <= 26'd0;                              //复位为0else if(cnt == 50_000_000 - 1)                  //计数到1scnt <= 26'd0;                               //清零计数器else                                         //计数不到1scnt <= cnt + 1'd1;                        //计数器每个周期累加1
endalways@(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)led <= 4'b0001;                                //复位为最右边的点亮else if(cnt == 50_000_000 - 1)                 //计数到1s//拼接运算。把最高位(最左边的LED)移动到最低位,第2、1、0位作为整体向左移动一位led <= {led[2:0],led[3]};       else                                            //计数不到1s    led <= led;                                 //保持LED状态不变
endendmodule

4、仿真测试

进行仿真测试的时候,我们把代码稍微改下:1s计时模块改成1ms计时模块,即50_000_000改为50_000。原因是若计时1s则仿真需要的时间太长。仿真的testbench比较简单,只需要提供时钟和复位激励即可,如下:

//**************************************************************************
// *** 名称 : tb_led_flow
// *** 作者 : 孤独的单刀
// *** 博客 : https://blog.csdn.net/wuzhikaidetb
// *** 日期 : 2021.12
// *** 描述 : 1s流水灯,循环左移的测试模块
//**************************************************************************`timescale 1ns/1ns     //时间单位/精度//------------<模块及端口声明>----------------------------------------
module  tb_led_flow();reg           sys_clk;
reg             sys_rst_n;wire  [3:0]   led;//------------<例化被测试模块>----------------------------------------
led_flow    led_flow_inst(.sys_clk  (sys_clk    ),.sys_rst_n    (sys_rst_n  ),.led          (led        )
);//------------<设置初始测试条件>----------------------------------------
initial beginsys_clk = 1'b0;                  //初始时钟为0sys_rst_n <= 1'b0;             //初始复位#5                                //5个时钟周期后sys_rst_n <= 1'b1;                //拉高复位,系统进入工作状态end
//------------<设置时钟>----------------------------------------------
always #10 sys_clk = ~sys_clk;     //系统时钟周期20nsendmodule

使用modelsim执行仿真,仿真结果如下:

可以看到:

  • 4个led的初始结果是0001(1代表LED亮,0代表灭),所以此时最右边的LED1亮,其他LED熄灭
  • 1ms(仿真为节省时间改为1ms,实际上板验证是1s)后led的值变成了0010,代表此时仅LED2亮,其他LED熄灭
  • 再1ms后led的值变成了0100,代表此时仅LED3亮,其他LED熄灭
  • 再1ms后led的值变成了1000,代表此时仅LED4亮,其他LED熄灭
  • 再1ms后led的值变成了0001,代表此时仅LED1亮,其他LED熄灭
  • 一直循环上面的状态,以此来实现LED的流水显示

5、上板测试

绑定对应管脚,全编译整个文件,将sof文件通过JTAG接口下载进FPGA开发板,观察其实验现象。结果如下:

可以看到LED以1S的速度向左循环移位,实现了预期的流水灯效果。

6、其他

  • 创作不易,如果本文对您有帮助,还请多多点赞、评论和收藏。您的支持是我持续更新的最大动力!
  • 关于本文,您有什么想法均可在评论区留言。如果需要整个工程,请在评论留下邮箱或者私信我邮箱(注意保护隐私)。
  • 自身能力不足,如有错误还请多多指出!

版本信息

文件:V1.0

编号:0002

Quartus II:Quartus II 13.1 (64-bit)

Modelsim:Modelsim SE-64 2020.4

FPGA极易入门教程----LED篇(1)跑马灯(流水灯)跑起来相关推荐

  1. FPGA极易入门教程----汇总篇(直达链接)

    为什么要写这个系列? 根据费曼学习法,最好的学习方法就是教会一个外行人(初学者).知识分享,独乐乐不如众乐乐.现在FPGA市场巨大,人才缺口很大.我本着能拉一个上贼船就拉一个上贼船的想法来写这个系列文 ...

  2. FPGA极易入门教程----工具篇(2)Quartus II 的在线调试工具 In-System Sources and Probes(ISSP)

    1.什么是ISSP?ISSP有什么用? Quartus II提供了In-System Sources and Probes Editor调试工具,通过JTAG接口使用该工具可以驱动和采样内部节点的逻辑 ...

  3. FPGA极易入门教程----工具篇(1)建立你的第一个FPGA工程(点亮LED)

    1.规范的文件夹 规范的文件夹划分管理也是十分重要的,若是把所有文件,例如设计文件.设计表格.图片.Quartus工程相关文件.仿真文件等不同类型的文件都统一放在一个目录下,将会使得整个文件夹臃肿不堪 ...

  4. FPGA极易入门教程----数码管篇(1)静态显示

    1.数码管简介 数码管是一种半导体发光器件,其基本单元是发光二极管.数码管按段数一般分为七段数码管和八段数码管,八段数码管比七段数码管多一个发光二极管(多一个小数点显 示).当然也还有一些其他类型的数 ...

  5. C51教程 第二个51程序: 跑马灯 流水灯

    keil+proteus 第二个51程序 : 跑马灯 流水灯 这是一个AT89c51单片机教程,我们每次都会提供博文教程以及附带资料下载. 单片机就是一个小型CPU,在电子领域应用广泛,电视.冰箱.洗 ...

  6. 泰凌微8258入门教程 进阶篇③——LIGHT HSL+CT 彩色灯+色温灯调光

    文章目录 一.前言 二.刷新Light函数 light_dim_refresh() 三.Light硬件引脚 light_res_hw 一.前言 HSL彩色灯调光和CT色温灯调光 ,前面两篇博文都有讲述 ...

  7. 【STM32】标准库 菜鸟入门教程(3)闪烁及流水灯

    目录 GPIO GPIO基本结构 GPIO位结构 GPIO模式 器件原理解析 LED 面包板: 蜂鸣器: 小文件分享 LED闪烁 源代码百度云地址: 第一步:使用RCC开启GPIO时钟 第二步:使用G ...

  8. ESP32-C3入门教程 IoT篇⑥——阿里云 物联网平台 EspAliYun RGB LED 实战之设备批量生产工具

    阿里云物联网平台ESP32设备批量工具 文章目录 一.前言 二.软件框架 三.阿里云物联网平台API 3.1 查询设备 3.2 添加设备 四.二维码生成 五.csv生成 六.csv转bin 七.bin ...

  9. Python极简入门教程

    前言 为了方便各位小白能轻松入门Python,同时加深自己对Python的理解,所以创造了"Python极简入门教程",希望能帮到大家,若有错误请多指正,谢谢.极简入门教程代表着不 ...

最新文章

  1. 谁能搞定中国的文艺复兴,我就能搞定中国的政治改革
  2. 如何查找历史版本的SAP UI5 API文档
  3. Python笔记(4) 关键字
  4. 使用正则表达式从字符串中提取email
  5. Cookie与系统安全
  6. 如何让自己的email地址永久有效
  7. 1月15日云栖精选夜读 | 重磅公开!阿里语音识别模型端核心技术,让你“听”见未来...
  8. Linux下获取外网IP地址的方法
  9. 【DPDK】网卡绑定和解绑步骤
  10. windows远程命令执行
  11. (root用户)bash: ./xx: Permission denied解决方法
  12. 请你设计一个用于填充n阶方阵的上三角区域的程序。
  13. 三篇文章彻底搞懂Java面向对象之一
  14. 化工企业安全生产管理监控预警系统软件
  15. mysql-front 下载安装
  16. NMQ消息队列—中间件
  17. 视源股份(CVTE)亮相世界顶级计算机视觉盛会CVPR 2017
  18. 高防BGP服务器速度怎么样?选用高防BGP服务器需要考虑什么
  19. 四年级下册计算机教学目录,最新版人教版小学数学四年级下册目录
  20. 移动端车牌识别哪家好

热门文章

  1. 每次开机Edge浏览器自动启动怎么办
  2. 嵌入式Linux开发环境部署
  3. 一些自己面试unity3D 程序员的面经
  4. 注册kaggle人机验证没有验证码
  5. 山东建筑大学java模拟考试选择总结
  6. 一周信创舆情观察(6.28~7.4)
  7. git 切换分支相互影响的问题
  8. 安卓手机H5页面判断wifi还是数据
  9. 直流电源滤波电容选择
  10. 什么是 C/C++?