目录
简介:
实验任务:
硬件设计:
程序设计:
下载验证:
简介:
LED,又名发光二极管。LED 灯工作电流很小(有的仅零点几毫安即可发光),抗冲击和抗震性能好, 可靠性高,寿命长。由于这些优点,LED 灯被广泛用在仪器仪表中作指示灯、液晶屏背光源等诸多领域。
发光二极管与普通二极管一样具有单向导电性。给它加上阳极正向电压后,通过 5mA 左右的电流就可 以使二极管发光。通过二极管的电流越大,发出的光亮度越强。不过我们一般将电流限定在 3~20mA 之间, 否则电流过大就会烧坏二极管。
实验任务:
本节实验任务是使新起点开发板上的 4 个 LED 灯顺序点亮并熄灭,循环往复产生流水的现象。
硬件设计:
发光二极管的原理图如图:
本实验中,系统时钟、按键复位以及 LED 端口的管脚分配如下表:
对应的 TCL 约束语句如下:
set_location_assignment PIN_M2 -to sys_clk
set_location_assignment PIN_M1 -to sys_rst_n
set_location_assignment PIN_D11 -to led[0]
set_location_assignment PIN_C11 -to led[1]
set_location_assignment PIN_E10 -to led[2]
set_location_assignment PIN_F9 -to led[3]
程序设计 :
由于发光二极管的阳极与 FPGA 的管脚相连,只需要改变与 LED 灯相连的 FPGA 管脚的电平,LED 灯 的亮灭状态就会发生变化。当 FPGA 管脚为高电平时,LED 灯点亮;为低电平时,LED 灯熄灭。本次设计的模块端口及信号连接如下图所示:
由于人眼的视觉暂留效应,流水灯状态变换间隔时间最好不要低于 0.1s,否则就不能清晰地观察到流水 效果。这里我们让流水灯每间隔 0.2s 变化一次。在程序中需要用一个计数器累加计数来计时,计时达 0.2s 后计数器清零并重新开始计数,这样就得到了固定的时间间隔。每当计数器计数满 0.2s 就让 led 灯发光状态变化一次。
代码如下:
1 module flow_led(
2 input sys_clk , //系统时钟
3 input sys_rst_n, //系统复位,低电平有效
4
5 output reg [3:0] led //4 个 LED 灯
6 );
7
8 //reg define
9 reg [23:0] counter;
10
11 //*****************************************************
12 //** main code
13 //*****************************************************
14
15 //计数器对系统时钟计数,计时 0.2 秒
16 always @(posedge sys_clk or negedge sys_rst_n) begin
17 if (!sys_rst_n)
18 counter <= 24'd0;
19 else if (counter < 24'd1000_0000)
20 counter <= counter + 1'b1;
21 else
22 counter <= 24'd0;
23 end
24
25 //通过移位寄存器控制 IO 口的高低电平,从而改变 LED 的显示状态
26 always @(posedge sys_clk or negedge sys_rst_n) begin
27 if (!sys_rst_n)
28 led <= 4'b0001;
29 else if(counter == 24'd1000_0000)
30 led[3:0] <= {led[2:0],led[3]};
31 else
32 led <= led;
33 end
34
35 endmodule
本程序中输入时钟为 50MHz,所以一个时钟周期为 20ns(1/50MHz)。因此计数器 counter 通过对 50MHz 系统时钟计数,计时到 0.2s,需要累加 0.2s/20ns=10000000 次。在代码第 22 行,每当计时到 0.2s 计数器清零一次。
同时,每当计数器计数到 10000000 时,将各个 LED 灯的状态左移一位,并将最高位的值移动到最低 位,循环往复。其他时间,LED 灯的状态不变。如代码中第 29 至 32 行所示。
需要说明的是,led 的初始值必须是一位为 1,其它位为 0,在循环左移的过程中才会呈现流水灯的效 果;而如果 led 的初始值为 0,则左移后 led 的状态仍然为 0。代码中 led 的初始值是由复位信号(sys_rst_n) 控制的,如代码中第 27 行和第 28 行所示。这里的复位信号对应的就是板载的复位按键,尽管在上电后没 有按下复位按键,由于 FPGA 芯片内部有一个上电检测模块,一旦检测到电源电压超过检测门限后,就产 生一个上电复位脉冲(Power On Reset)送给所有的寄存器,led 的初始值就是在这个时候复位成 4‘b0001 的。
我们在 Modelsim 中对流水灯程序进行仿真,为了减少仿真过程所需要的时间,将流水灯状态变化的间 隔时间修改为 0.1ms。仿真得到的波形图如图 8.4.2 所示,led 端口寄存器的值按照 0001→0010→0100→1000 →0001 的顺序变化,对应的各个 LED 灯的接口电平依次改变。
仿真过程用到的测试程序如下所示:
1 `timescale 1ns/1ns // 定义仿真时间单位 1ns 和仿真时间精度为 1ns
2
3 module flow_led_tb; // 测试模块
4
5 //parameter define
6 parameter T = 20; // 时钟周期为 20ns
7
8 //reg define
9 reg sys_clk; // 时钟信号
10 reg sys_rst_n; // 复位信号
11
12 //wire define
13 wire [3:0] led;
14
15 //*****************************************************
16 //** main code
//*****************************************************
18
19 //给输入信号初始值
20 initial begin
21 sys_clk = 1'b0;
22 sys_rst_n = 1'b0; // 复位
23 #(T+1) sys_rst_n = 1'b1; // 在第 21ns 的时候复位信号信号拉高
24 end
25
26 //50Mhz 的时钟,周期则为 1/50Mhz=20ns,所以每 10ns,电平取反一次
27 always #(T/2) sys_clk = ~sys_clk;
28
29 //例化 led 模块
30 flow_led u0_flow_led (
31 .sys_clk (sys_clk ),
32 .sys_rst_n (sys_rst_n),
33 .led (led )
34 );
35
36 endmodule
下载验证:
可以看到功能正常