前言
我认为在FPGA的设计中,理论联系实际是十分重要的。下面转载的PWM呼吸灯就是一个很好的例子——作者用Verilog实现了一个变化pwm占空比的电路,应用在呼吸灯上。设计并不复杂,作者的代码风格也好,是相当优秀的Project。
设计文件
//======================================================================
// --- 名称 : breathing_led
// --- 作者 : xianyu_FPGA
// --- 日期 : 2018-12-15
// --- 描述 : PWM频率调制实现真呼吸灯的效果,4秒1次循环,
// 每2ms秒变化1次,前2秒亮度增大,后2秒亮度减小
//======================================================================
module breathing_led
//---------------------<端口声明>---------------------------------------
(
input wire clk , //时钟,50Mhz
input wire rst_n , //复位,低电平有效
output wire led //led灯
);
//---------------------<参数定义>---------------------------------------
parameter TIME_2MS = 100_000 ; //2ms时间
parameter TIME_2MS_W = 17 ; //2ms时间位宽
parameter NUM = 1000 ; //2ms到2s为1000份
parameter NUM_W = 10 ; //份数位宽
parameter STEP = 100 ; //2ms也分成1000份,每份为步长100
//---------------------<信号定义>---------------------------------------
reg [TIME_2MS_W-1:0] cnt0 ;
wire add_cnt0 ;
wire end_cnt0 ;
reg [NUM_W:0] cnt1 ;
wire add_cnt1 ;
wire end_cnt1 ;
reg [1:0] cnt2 ;
wire add_cnt2 ;
wire end_cnt2 ;
reg [TIME_2MS_W-1:0] pwm_high ;
//----------------------------------------------------------------------
//-- 2ms时间计时
//----------------------------------------------------------------------
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt0 <= 0;
else if(add_cnt0)begin
if(end_cnt0)
cnt0 <= 0;
else
cnt0 <= cnt0 + 1;
end
else
cnt0 <= cnt0;
end
assign add_cnt0 = 1;
assign end_cnt0 = add_cnt0 && cnt0==TIME_2MS-1 ;
//----------------------------------------------------------------------
//-- 每2ms计1次,计到2秒共需计NUM次
//----------------------------------------------------------------------
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt1 <= 0;
else if(add_cnt1)begin
if(end_cnt1)
cnt1 <= 0;
else
cnt1 <= cnt1 + 1;
end
else
cnt1 <= cnt1;
end
assign add_cnt1 = end_cnt0;
assign end_cnt1 = add_cnt1 && cnt1==NUM-1 ;
//----------------------------------------------------------------------
//-- 每2秒计1次,计到4秒共需计2次
//----------------------------------------------------------------------
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt2 <= 0;
end
else if(add_cnt2)begin
if(end_cnt2)
cnt2 <= 0;
else
cnt2 <= cnt2 + 1;
end
else
cnt2 <= cnt2;
end
assign add_cnt2 = end_cnt1;
assign end_cnt2 = add_cnt2 && cnt2==2-1 ;
//----------------------------------------------------------------------
//-- 设置pwm的占空比时间
//----------------------------------------------------------------------
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
pwm_high <= 0;
else if(cnt2==0 && end_cnt0)
pwm_high <= pwm_high + STEP;
else if(cnt2==1 && end_cnt0)
pwm_high <= pwm_high - STEP;
else
pwm_high <= pwm_high;
end
//----------------------------------------------------------------------
//-- 输出led灯
//----------------------------------------------------------------------
assign led = (cnt0 < pwm_high) ? 1'b1 : 1'b0;
endmodule
仿真文件
`timescale 1ns/1ps //时间精度
`define Clock 20 //时钟周期
module breathing_led_tb;
//---------------------<端口定义>---------------------------------------
reg clk ; //时钟,50Mhz
reg rst_n ; //复位,低电平有效
wire led ;
//----------------------------------------------------------------------
//-- 模块例化
//----------------------------------------------------------------------
breathing_led
#(
.TIME_2MS (1000 ), //2ms时间 100_000
.NUM (100 ), //2ms到2s为1000份
.STEP (10 ) //2ms也分成1000份,每份为步长100
)
u_breathing_led
(
.clk (clk ),
.rst_n (rst_n ),
.led (led )
);
//----------------------------------------------------------------------
//-- 时钟信号和复位信号
//----------------------------------------------------------------------
initial begin
clk = 1;
forever
#(`Clock/2) clk = ~clk;
end
initial begin
rst_n = 0; #(`Clock*20+1);
rst_n = 1;
end
endmodule
仿真波形
可以看到led信号的占空比先不断增加后不断减少,循环反复。
本文转载自:
https://www.cnblogs.com/xianyufpga/p/11026878.html