用PWM波的方式实现呼吸灯。
LED高点灯,使用64bit移位寄存器作为PWM的发生器,因此PWM的细分颗粒度为1/64。
10MHz的时钟为主频,移位64bit,耗时6.4us。
每个PWM数据移位2048次,然后PWM的脉宽改变一次,即6.4us*2048=13ms,led的亮度就会改变一次。
从暗到亮,耗时 13ms*64=838.9ms,在1.7s内,完成一次呼吸。
顶层代码如下:
//仿真单位/精度
`timescale 1ns/1ps
//-------------------------------------------------------------------------------------------------
module top_breath_led (
inputsys_clk,
//inputreset,
output[3:0]ov_fpga_led
);
wiresys_clk_ibufg;
wiredcm_reset;
wiredcm_lock;
wireclk_10m_reset;
wireclk_10m;
wireclk_40m;
reg[7:0]pwr_up_cnt= 8'b0;
reg[1:0]shift_reset = 2'b11;
reg[5:0]count_64= 6'h0;
reg[11:0]count_2k= 12'h0;
reg[63:0]shifter= 64'h0;
//ref signals
//ref ARCHITECTURE
// ===============================================================================================
//时钟复位
// ===============================================================================================
// -------------------------------------------------------------------------------------
//ibufg
// -------------------------------------------------------------------------------------
IBUFG IBUFG_inst (
.O(sys_clk_ibufg),// Clock buffer output
.I(sys_clk)// Clock buffer input (connect directly to top-level port)
);
// -------------------------------------------------------------------------------------
//上电复位dcm,时钟采用ibufg输出的时钟
// -------------------------------------------------------------------------------------
always @ (posedge sys_clk_ibufg) begin
if(pwr_up_cnt[7] == 1'b0) begin
pwr_up_cnt<= pwr_up_cnt + 1'b1;
end
end
assigndcm_reset = !pwr_up_cnt[7];
// -------------------------------------------------------------------------------------
//DCM
// -------------------------------------------------------------------------------------
dcm dcm_inst (
.CLK_IN1(sys_clk_ibufg),
.CLK_OUT1(clk_10m),
.CLK_OUT2(clk_40m),
.RESET(dcm_reset),
.LOCKED(dcm_lock)
);
// -------------------------------------------------------------------------------------
//10M时钟域的复位信号
// -------------------------------------------------------------------------------------
always @ (posedge clk_10m or negedge dcm_lock) begin
if(!dcm_lock) begin
shift_reset<= 2'b11;
end
else begin
shift_reset<= {shift_reset[0],1'b0};
end
end
assignclk_10m_reset= shift_reset[1];
// ===============================================================================================
//产生PWM波形
//1. 64bit shifter 10MHz clk driver
//2. 6.4us shift all 64bit
//3. Shifter init value is 64'h0
//3. every shifter shift 2048 times,Tall = 6.4us * 2048 = 13ms.Then high bit add once.
//4. from 64bit0 to 64bit1,T = 13ms * 64 = 839ms
// ===============================================================================================
// -------------------------------------------------------------------------------------
//0-63 cnt
// -------------------------------------------------------------------------------------
always @ (posedge clk_10m) begin
if(clk_10m_reset) begin
count_64<= 'b0;
end
else begin
if(count_64 == 6'b111111) begin
count_64<= 'b0;
end
else begin
count_64<= count_64 + 1'b1;
end
end
end
// -------------------------------------------------------------------------------------
//2048 cnt
//当移位器的64bit都移走之后,计数器++
// -------------------------------------------------------------------------------------
always @ (posedge clk_10m) begin
if(clk_10m_reset) begin
count_2k<= 'b0;
end
else begin
if(count_64 == 6'b111111) begin
if(count_2k[11]) begin
count_2k<= 'b0;
end
else begin
count_2k<= count_2k + 1'b1;
end
end
end
end
// -------------------------------------------------------------------------------------
//64bit shifter
//已经移位了2048次,需要改变数据了
// -------------------------------------------------------------------------------------
always @ (posedge clk_10m) begin
if(clk_10m_reset) begin
shifter<= 'b0;
end
else begin
if((count_64 == 6'b111111)&&(count_2k[11] == 1'b1)) begin
shifter<= {shifter[61:0],shifter[63],!shifter[62]};
end
else begin
shifter<= {shifter[62:0],shifter[63]};
end
end
end
// ===============================================================================================
//输出
// ===============================================================================================
//assignov_fpga_led[0]= shifter[63];
//assignov_fpga_led[2:1]= 3'b000;
//assignov_fpga_led[3]= 1'b1;
assignov_fpga_led[3:0]= {4{shifter[63]}};
endmodule
UCF约束如下:
##===============================================================================================
##breath_led
##===============================================================================================
# ref 1 pin location ------------------------------------------------------------------------------
#----ref clk reset --------------------------------------------------------------------------------
NET "sys_clk"LOC = "V10" | IOSTANDARD = "LVCMOS33"; #Bank = 2, pin name = IO_L30N_GCLK0_USERCCLK, Sch name = GCLK
#NET "sys_rst"LOC = "F26" | IOSTANDARD = LVCMOS33;
#----ref FPGA test --------------------------------------------------------------------------------
NET "ov_fpga_led[0]"LOC = "U16" | IOSTANDARD = "LVCMOS33"; #Bank = 2, Pin name = IO_L2P_CMPCLK, Sch name = LD0
NET "ov_fpga_led[1]"LOC = "V16" | IOSTANDARD = "LVCMOS33"; #Bank = 2, Pin name = IO_L2N_CMPMOSI, Sch name = LD1
NET "ov_fpga_led[2]"LOC = "U15" | IOSTANDARD = "LVCMOS33"; #Bank = 2, Pin name = IO_L5P, Sch name = LD2
NET "ov_fpga_led[3]"LOC = "V15" | IOSTANDARD = "LVCMOS33"; #Bank = 2, Pin name = IO_L5N, Sch name = LD3
# ref 2 timing constraints ------------------------------------------------------------------------
#----ref clk constraint ---------------------------------------------------------------------------
NET "sys_clk" TNM_NET = "TNM_sys_clk";
TIMESPEC "TS_sys_clk" = PERIOD "TNM_sys_clk" 40 MHz HIGH 50 %;
#----ref MultiPath constraint ---------------------------------------------------------------------
#NET "clk_rst_top_inst/w_reset_loc_pll"TIG;
#NET "CLKA" TNM_NET = FFS "GRP_A";
#NET "CLKB" TNM_NET = FFS "GRP_B";
#TIMESPEC TS_Example = FROM "GRP_A" TO "GRP_B" 5 ns DATAPATHONLY;