一、 实验目的
实现4个LED灯的亮灭控制
二、 实验原理
LED灯的典型电路如下2-1所示,我们控制led灯的亮灭,实质就是去控制FPGA的IO输给LED负极一个低电平或者高电平。从图中可知,我们给对应的led负极上一个低电平,就会有对应的电流通过 电阻,流过led灯,于是LED灯就会被点亮;当给led负极一个高电平时,led两端电压相等,因此没有电流流过,led则呈熄灭状态。
图2-1 led灯典型电路
三、 硬件设计
本实验的硬件电路即如图2-1所示,读者一看即懂,因此本节内容略。
四、 架构设计
虽然本实验只是一个简单的点亮led灯实验,整个实验代码不过四五行,但是为了遵循小梅哥一直喜欢的那种模块化的设计理念,因此本设计还是将led的驱动做成子模块的形式。
本实验由两个模块组成,分别为led驱动模块和顶层例化模块,可能看过其它开发板资料的同学会觉得这样反而增加了系统的复杂程度,但是,小梅哥如此设计必定有我的道理,图4-1为本实验的模块组织结构
图4-1 led实验模块组织结构图
由图可知本实验仅有n个输出端口,对应了n个led灯(为了代码的可移植性,这里并没有将led的个数限定死,而是采用了参数化的设计,因此,在实际使用过程中,就可根据实际不同的需要,自由的调整led的个数)。在modelsim仿真过程中,所有信号必须要有复位初始值,因此复位信号(Rst_n)必不可少。可能读者这里会发现,与我昨天所写的端口命名规范有出入。如果按照我所出的规范中来命名的话,则应该将复位信号命名为Global_Rst,对于这个问题,暂时小梅哥不做深入解说,其实严格意义上来说,这里的这个Rst_n应该只能算是一个内部信号,该信号在实际工程应用中往往由锁相环产生。这里因为为了配合仿真,因此该信号就暂时被引出来,做了全局复位信号。详细的关于全局复位与内部复位信号的处理,小梅哥在后面涉及到锁相环的使用的实验中会详细解说。
表4-1 led实验端口说明
五、 代码组织方式
本实验中,每个模块也就四五行的代码,因此谈不上代码组织方式,因此本节从略。
六、 关键代码解读
以下是代码片段:
module LED_Driver #(parameter Width = 1)/*定义位宽参数*/
(Rst_n,Sig,Led);/*定义模块端口*/
input Rst_n;
input [Width-1:0] Sig;
output [Width-1:0] Led;
assign Led = (Rst_n)?Sig:{Width{1'b1}};/*复位输出全1,否则按照Sig的值输出*/
endmodule
以上为LED驱动模块的代码,第1行定义了一个参数“Width”,即位宽,因此在例化(调用)此模块时,根据实际需要给Width赋予不同的值,则可实现不同的LED位宽的设置。第4至7行为输入输出端口定义,具体信号含义见表4-1。第9行为LED输出赋值语句,有关该代码的含义,请读者自行阅读夏宇闻老师的《Verilog数字系统设计教程》一书。小梅哥精力和时间实在太有限,没办法一一帮大家补充Verilog的知识,望见谅。总之,该语句实现了当复位信号为低电平时(系统处于复位状态),所有LED全部熄灭;当复位信号为高电平(系统正常工作)时,led输出对应的Sig信号各位的状态。
以下是代码片段:
module LED_TOP(Rst_n,Led);
input Rst_n;
output [3:0] Led;
LED_Driver
#( /*参数例化*/
.Width (4)
)
LED_Driver_inst(/*端口例化*/
.Rst_n(Rst_n),
.Sig(4'b1001),/*OFF ON ON OFF*/
.Led(Led)
);
endmodule
以上为LED实验的顶层模块,其中将位宽参数例化为了4,即4个LED。因为没有其他模块提供Sig信号,因此直接将该信号赋值为4’b1001。则如果下载到实验板上,会看到4个led灯分别处于“灭 亮 亮 灭”的状态。