目录
需要配备:
1.博宸电子ZYNQ7020DEV开发板
2.较熟悉Vivado 2018.3
3.一定的verilog语言基础
一. 任务剖析
1.1 实验目的
实现呼吸灯的效果,从亮起到最亮再到逐渐变暗。以此循环。
1.2原理图
图1 led电路图
本次实验以开发板LED3端口为例,实现LED3灯的呼吸效果。,其引脚定义为Y14。
1.3 呼吸效果分析
led灯的亮度受电流,电压,发光时间等因素影响。在本次实验中,博主通过控制led固定单位时间下的发光时间来控制led灯的明暗程度。也就是占空比不同,发光程度不同
举个例子。设LED最大发光亮度为100.
在占空比为0%时,LED不发光,亮度为0;
在占空比为25%时,LED发光,亮度为25,较微弱;
在占空比为50%时,LED发光,亮度为50,光强一般;
在占空比为100%时,LED发出全部光亮,此时达到最亮;
下图为固定单位时间下不同占空比的LED发光时间图:
图2 占空比为0%
图3 占空比为25%
图4 占空比为50%
图5 占空比为100%
二. 总代码
2.1 敲写代码
2.1.1 代码内容
module led_breath(
input clk,
input rst_n,
output breath_led
);
reg [15:0] cnt; //定义计数器,用来控制周期
reg [15:0] duty_cycle; //定义占空比
reg up_low_flag; //定义变亮或者变暗的过程,1表示亮,0表示暗
// 利用占空比控制灯的明亮程度;
assign breath_led = (duty_cycle >= cnt) ? 1'b1 : 1'b0 ;
//定义always模块,让cnt开始计数,计时1ms;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
cnt <= 1'b0;
end
else if(cnt >= 16'd50000) begin
cnt <= 1'b0;
end
else begin
cnt <= cnt + 1'b1;
end
end
//定义占空比变化的模块
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
duty_cycle <= 1'b0;
up_low_flag <= 1'b1; //先变亮;
end
else if(cnt == 16'd50000) begin
if(duty_cycle == 1'b0)
up_low_flag <= 1'b1; //变亮,启动!
if(duty_cycle == 16'd50000)
up_low_flag <= 1'b0; //变暗,启动!
if(up_low_flag == 1'b1)
duty_cycle <= duty_cycle + 16'd25; //提高占空比
if(up_low_flag == 1'b0)
duty_cycle <= duty_cycle - 16'd25; //减小占空比
end
end
endmodule
2.1.2 代码分析
- cnt计数器:
根据01节的知识,敲写出cnt计时1毫秒。因为这样人的肉眼容易观测出led呼吸灯的效果。当然你也可以根据自己的喜好去调节计时时间,只需要更改cnt>=xxx中的xxx即可;
- 占空比模块
2.1 up-low-flag参数:
根据实验目的,应该先变亮再变暗。为了明确代码的变亮还是变暗过程。首先定义了寄存器类型的up-low-flag参数,当它等于1时,代表正在变亮,反之变暗。
2.2 duty-cycle参数:
定义占空比特征参数为duty-cycle。根据1.3的分析,当duty-cycle>=cnt时令led发光,反之不发光。以此间接反映占空比。
2.3 16‘d25数值意义:
在变亮过程中,占空比应不断增大。但增大的幅值应该是多少呢。如果幅值过大,那么发光的连续性就较差,肉眼难以观测出呼吸的效果。幅值过小,又非常耗时。通过测试,博主将本实验的增大幅值定义为0.5%,即每毫秒duty-cycle增加16’d50000*0.5%=16’d25。这样是比较合适的。当然大家也可以定义为1%,2%等等。
2.4 assign赋值语句:
这条语句控制着led灯的明暗程度,直接控制着呼吸效果!
原理可见下图解释:(以75%占空比为例)
duty_cycle = 16’d50000*75% = 16’d37500
在1ms内,cnt从0开始累加,当cnt<duty_cycle时,即黑色阴影部分,根据assign语句可知,led发光。其余部分led不发光。从1ms的时间整体来看,led的发光程度就是75%.
切记!!!
在1毫秒的周期内,duty_cycle相当于一个定值,而cnt是一直累加的,因此duty_cycle与cnt的大小关系才具有反映占空比含义的这一效果。
2.2 引脚与电压分配
本实验采取方式一的引脚分配。
如下图:
三.仿真
老样子,为了方便没有开发板的同学,咱们看仿真效果也是没有问题哒。
3.1 建立仿真
建立方法同01节,忘记的小伙伴可以去博主01节找一找,这里就不多赘述啦。
3.2 仿真代码
`timescale 1ns / 1ps
module tb_led_breath();
reg sys_clk;
reg sys_rst_n;
wire breath_led;
initial begin //初始化
sys_clk = 1'b0;
sys_rst_n = 1'b0;
#1 sys_rst_n = 1'b1;
end
always #10 sys_clk = ~sys_clk; //定义一个50M赫兹的时钟
led_breath u_led_breath( //例化
.clk (sys_clk),
.rst_n (sys_rst_n),
.breath_led (breath_led)
);
endmodule
3.3 仿真波形
图6 开始变亮
图7 逐渐变亮
图8 全亮状态
图9 开始变暗
图10 几乎无光
从仿真图来看,本次实验成功,实现了呼吸灯的效果。
四.课后小问题
在本次实验代码中,主要逻辑部分(即占空比的时序模块定义中)采用了四个if语句进行判断,能不能减少if语句的使用来让代码更加美丽呢。有答案的小伙伴可以在评论区进行交流喔。
(提示:从逻辑角度上考虑,占空比duty_cycle的增减代码块可以通过某个变量合一,在一个语句内即可完成增和减)