前言:
本文主要介绍了集成电路EDA这门课程的相关实验及代码。使用的软件是Quartus Ⅱ,该实验使用DE2-115,fpga芯片为cyclone IV EP4CE115F29C7。
(一)实验目的
(1)熟悉流水灯的工作原理;
(2)了解设计中的优化方案;
(3)进一步掌握PWM信号的设计;
(二)设计要求
利用FPGA板及4个LED发光二极管,设计一个亮度可调流水灯程序:
其中流水灯亮度使用PWM驱动,并且可以使用按键切换不同亮度。
(三)实验原理
流水灯的实质是FPGA板各引脚在规定的时间逐个上电,使LED灯能逐个亮起来但过了该引脚通电的时间后便灭灯的过程,至于亮度可调则是使用PWM产生一定占空比的方波,实现输出电压变化,并可以通过调节占空比的大小改变输出电压值即LED灯的亮度。
实验中使用了单片机的P1端口和P4端口,对4个LED灯进行控制,要实现逐个亮灯即将各端口逐一置零,中间使用延时函数调用隔开各灯的亮灭。
本次实验先令四个灯全亮,延时500ms后再令四个灯全灭,之后点亮P4.7,P1.7两个灯,延时500ms后熄灭,之后依次点亮P4.7,P4.6,P1.7,P1.6,(一个灯点亮500ms后熄灭,第二个灯再点亮),然后反向,按照P1.6,P1.7,P4.6,P4.7顺序点亮一遍,如此往复循环。
(四)实验设备
(1)DE2-115型号FPGA板
(2)PC电脑
(五)实验结果
仿真图:
PWM波形使用cnt_1ms与tim变量大小来产生,当cnt_1ms<=tim时低电平否则高电平,图中可以看到,初始值tim=0,此时当cnt_1ms>tim时第一个灯亮,按下一次按键后,time自加8,此时当cnt_1ms<=8时,灯灭,否则第一个灯亮。
如上图所示,可以看到当cnt计数达到999时,由第二个灯亮变成第三个灯亮,证明完成了灯的流水操作。
实物图:
初始流水灯:
按下按键调节亮度后:
(六)结果分析
本次实验为了完成可调节亮度的流水灯的设计,首先产生0.5s脉冲使得每0.5s更改亮灯的位置,之后通过按键更改PWM产生波形中的占空比,从而调节灯的亮度。
代码:
1.顶层模块water_led
//4个led_out_reg灯,依次点亮,间隔0.5s 50Mhz-20ns 25000000次-25位
module water_led
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire key1 ,
output reg [3:0] led_out
);
parameter CNT_MAX=25'd24_999_999 ; //0.5s
parameter CNT_1US_MAX=6'd49 ; //1个时钟20ns,50个即1us
parameter CNT_1MS_MAX=10'd999 ; //计满1000个即1ms
wire key1_flag;
reg cnt_flag;
reg [9:0] tim;
reg [24:0] cnt;
reg [5:0] cnt_1us;
reg [9:0] cnt_1ms;
reg [9:0] cnt_1s;
reg [3:0] i;
//0.5s间隔闪烁
always @(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
cnt<=25'd0;
else if(cnt==CNT_MAX)
cnt<=25'd0;
else
cnt<=cnt+25'd1;
//计数满0.5s标志位
always @(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
cnt_flag<=1'd0;
else if(cnt==CNT_MAX-1)
cnt_flag<=1'd1;
else
cnt_flag<=1'd0;
//亮度变量调整
always @(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
tim <= 10'd0;
else if(tim >= 10'd999)
tim <= 10'd0;
else if(key1_flag)
tim <= tim + 10'd80;
else
tim <= tim;
//cnt_1us
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
cnt_1us<=6'd0;
else if(cnt_1us==CNT_1US_MAX)
cnt_1us<=6'd0;
else
cnt_1us<=cnt_1us+6'd1;
//cnt_1ms
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
cnt_1ms<=10'd0;
else if((cnt_1ms==CNT_1MS_MAX)&&(cnt_1us==CNT_1US_MAX))
cnt_1ms<=10'd0;
else if(cnt_1us==CNT_1US_MAX)
cnt_1ms<=cnt_1ms+10'd1;
else
cnt_1ms<=cnt_1ms;
//每0.5s,i自加1,即更改亮灯位置
always @(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
i <= 3'd0;
else if((cnt_flag == 1'd1)&&(i == 3))
i <= 3'd0;
else if(cnt_flag == 1'd1)
i <= i + 1'd1;
else
i <= i;
//输出控制
always @(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
led_out <= 4'b0001;
else
begin
if(cnt_1ms<=tim)
led_out <= 4'b0000;
else
case(i)
3'd0: led_out <= 4'b0001;
3'd1: led_out <= 4'b0010;
3'd2: led_out <= 4'b0100;
3'd3: led_out <= 4'b1000;
default: led_out <= 4'b0000;
endcase
end
//按键滤波模块,按下按键后模块输出一个时钟周期的高脉冲
key_filiter key_filiter_inst
(
.sys_clk (sys_clk ) ,
.sys_rst_n (sys_rst_n) ,
.key_in (key1 ) ,
.key_flag (key1_flag)
);
endmodule
2.按键模块key_filiter
//按键滤波器,按下按钮后即低电平输入,经过该模块输出一个系统时钟周期的高脉冲
module key_filiter
(
input sys_clk ,
input sys_rst_n ,
input key_in ,
output reg key_flag
);
reg [19:0] cnt_20ms;
parameter CNT_MAX=20'd999999;
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
cnt_20ms<=20'd0;
else if(key_in)
cnt_20ms<=20'd0;
else if(cnt_20ms==CNT_MAX) //最大值保持
cnt_20ms<=CNT_MAX;
else
cnt_20ms<=cnt_20ms+1'd1;
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
key_flag<=1'b0;
else if(cnt_20ms==CNT_MAX-20'd1)
key_flag<=1'b1;
else
key_flag<=1'b0;
endmodule