FPGA初级课程第五讲 呼吸灯
本帖最后由 lcytms 于 2016-11-3 20:40 编辑FPGA初级课程
第五讲 呼吸灯
Hi,大家好!我是至芯科技的李老师。
今天讲课的题目是:呼吸灯。
本节课我先简要地介绍一下呼吸灯的物理原理,然后实际演示一下呼吸灯驱动逻辑电路的建模与仿真,最后下板查看效果。
本帖最后由 lcytms 于 2016-11-3 21:08 编辑
什么是呼吸灯呢?
没有听说过的同学,可能觉得比较新鲜。
顾名思义,就是像人的呼吸一样,逐渐变强,然后逐渐变弱,依次循环。
耳听为虚,眼见为实。
看看我做好的至芯ZX_1开发板上的led呼吸灯吧。
这有两个灯亮着,一个灯是逐渐变亮,5s之后突然熄灭,依次循环,这是靠开发板右侧的led。这显然不是渐强渐弱的呼吸灯。
而靠开发板左侧另一个灯则是逐渐变亮,5s之后逐渐变弱,10s一个循环。
没错,这就是我们要讲的呼吸灯。
看到这两个灯,我们是不是会联想起这样两个波形,锯齿波和三角波呢?
请看guagle软件上面的波形。请看锯齿波和三角波。
是不是强弱变化的节奏很类似呢?
没错,正是如此。
大家有没有发现,三角波的右半边波形实质上就是左半边的镜像呢?
实质上,如果我们得到了更基础的锯齿波,我们如果将偶数周期的波形取补值,就可以得到三角波。
那我们就先讨论锯齿波吧。
锯齿波又如何用FPGA实现呢?
当然也可以用DA器件。但是更普遍的是使用PWM技术。
也就是用不同占空比的波形来表达驱动的强弱。
还是结合实例,好理解一点。来看做好的仿真波形。
为了方便观察,我们输出了对应的脉冲波形。
本帖最后由 lcytms 于 2016-11-3 20:52 编辑
占空比变化从0一直变化到100%。
比如说是分成100份,我们通常是从1到100循环变化。
仿真波形中为了方便观察,分辨率只有5,也就是说从1到5地变化。
我们的演示做得分辨率更高,是分成了1000份,也就是说从1到1000进行变化。
第1个周期占空比为1‰,第2个周期占空比为2‰,第3个周期占空比为3‰,依次递进,第1000个周期占空比为1000‰,然后回到第一个周期,如此循环。
当然了,实现1‰的占空比,至少要1000个脉冲,对不对?
第1个脉冲为高电平,其余999个脉冲为低电平,这就是1‰的占空比。
因此,要实现以上需求,需要1000*1000个脉冲来完成一个逐渐变强的爬坡波形。
比如说这个波形持续5s,那么每个脉冲的周期就是5us,相当250个时钟,因为50MHz时钟对应时钟周期为20ns。
因此,我们要生成一个间隔为5us的基础脉冲。
在此基础上,依次生成间隔为1000倍和1000*1000倍的脉冲,对应为间隔5ms的脉冲和间隔5s的脉冲。
本帖最后由 lcytms 于 2016-11-3 21:02 编辑
好了锯齿波的物理原理既然清楚了,就来建模仿真吧。
建立新工程文件夹pulse。
编写pulse.v文件。
module pulse(clk, rst_n, led);
input clk, rst_n;
output led;
reg count5us, count5ms, count5s; //, count_duty
reg flag5us, flag5us_r, flag5ms, flag5s;
reg dutysawtooth;
reg switch5s;
parameter T5us = 250; // 5us/20ns = 250
parameter CNT1k = 1000; // 1000
always @ (posedge clk or negedge rst_n)
begin
if (!rst_n)
begin
count5us <= 0;
flag5us <= 0;
end
else
begin
if (count5us < T5us - 1)
begin
count5us <= count5us + 1;
flag5us <= 0;
end
else
begin
count5us <= 0;
flag5us <= 1;
end
end
end
always @ (posedge clk or negedge rst_n)
begin
if (!rst_n)
flag5us_r <= 0;
else
flag5us_r <= flag5us;
end
always @ (posedge clk or negedge rst_n)
begin
if (!rst_n)
begin
count5ms <= 0;
flag5ms <= 0;
end
else
begin
if (!flag5us)
flag5ms <= 0;
else
begin
if (count5ms < CNT1k - 1)
begin
count5ms <= count5ms + 1;
flag5ms <= 0;
end
else
begin
count5ms <= 0;
flag5ms <= 1;
end
end
end
end
always @ (posedge clk or negedge rst_n)
begin
if (!rst_n)
begin
count5s <= 0;
flag5s <= 0;
end
else
begin
if (!flag5ms)
flag5s <= 0;
else
begin
if (count5s < CNT1k - 1)
begin
count5s <= count5s + 1;
flag5s <= 0;
end
else
begin
count5s <= 0;
flag5s <= 1;
end
end
end
end
always @ (posedge clk or negedge rst_n)
begin
if (!rst_n)
dutysawtooth <= 0;
else if (flag5us)
begin
if (count5ms <= count5s) //需要重点理解的地方,对应第n个周期占空比为n‰
dutysawtooth <= 1;
else
dutysawtooth <= 0;
end
end
always @ (posedge clk or negedge rst_n)
begin
if (!rst_n)
switch5s <= 0;
else
begin
if (flag5s)
switch5s <= ~switch5s;
else
switch5s <= switch5s;
end
end
wire dutysawtooth_o;
assign dutysawtooth_o = dutysawtooth & flag5us_r;
////////////////////////////////////////////////////////////
wire dutytriangle;
assign dutytriangle = switch5s ? ~dutysawtooth : dutysawtooth;
wire dutytriangle_o;
assign dutytriangle_o = dutytriangle & flag5us_r;
////////////////////////////////////////////////////////////
// assign led = {3'b111, ~dutysawtooth_o};
assign led = {~dutytriangle, 2'b11, ~dutysawtooth};
// assign led = {4{~dutytriangle}};
// assign led = {4{~dutysawtooth}};
endmodule
本帖最后由 lcytms 于 2016-11-3 21:02 编辑
对编好的pulse.v模块进行分析综合检查。
再编写Testbench。新建pulse_tb.v文件。
`timescale 1ns/1ps
module pulse_tb;
reg clk, rst_n;
wire led;
pulse #(.T5us(5), .CNT1k(5)) dut(.clk(clk), .rst_n(rst_n), .led(led));
initial begin
clk = 1;
rst_n = 0;
#200.1
rst_n = 1;
#10_000 $stop;
end
always #10 clk = ~clk;
endmodule
设置仿真,查看锯齿波的led灯输出的仿真结果。
在锯齿波的基础上,改写pulse.v文件,增加三角波的led灯输出。
设置仿真,查看锯齿波 + 三角波的led灯输出的仿真结果。
本帖最后由 lcytms 于 2016-11-3 20:36 编辑
参照.tcl文件设置好FPGA管脚
参照EP4CE10F17C8Nzx_1.tcl文件内容,对FPGA芯片管脚进行设置。
EP4CE10F17C8Nzx_1.tcl文件相关内容如下所示。FPGA芯片配置结果如图所示。
#set_global_assignment -name FAMILY "Cyclone IV"
#set_global_assignment -name DEVICE ep4ce10f17c8n
set_location_assignment PIN_E1 -to clk
# LED
set_location_assignment PIN_T12 -to LED
set_location_assignment PIN_P8 -to LED
set_location_assignment PIN_M8 -to LED
set_location_assignment PIN_M10 -to LED
# KEY 轻触按键
set_location_assignment PIN_L3 -to key
.sof文件下载到FPGA
全编译FPGA工程,生成.sof文件,连接至芯ZX-1开发板并上电。
打开Programmer通过Jtag口,将.sof文件下载到FPGA进行在线仿真。
.sof文件下载界面如下图所示。