任务:使用开发板上的LED实现呼吸灯
硬件设计:与实验1的LED原理图相同
程序设计
学习单片机中用过PWM的应该都知道,我们一般生成PWM都是用两个计数器,一个是一直不停的周期性地加,从0加到某一最大值,另外一个计数器,存放一个比较值,当第一个计数器的值比第二个计时器值大时输出高电平,反之低电平。而不断改变第二个计数器的值(且计数器的频率一定要低于第一个计数器),就可以实现占空比调节。
本节,我们就是用两个计数器。CNT1用来周期计数。从1加到50000,每次CNT1加完一个周期,CNT2就加25(这个值随意,是5的倍数就好),最大值也是50000,CNT1>CNT2时输出高电平,反之低电平。定义一个加减标志位,用来判断CNT2是应该加还是减。(因为CNT2要从0->50000,然后再从50000->0)
rtl文件
module breath_led(
input sys_clk,
input sys_rst_n,
output led
);
reg [15:0] period_cnt; // 计数值0-50000,周期为1ms,频率1k
reg [15:0] duty_cycle; //占空比计数,每次+/- 25 ,最大50000
//所以PWM的半周期是 50000/25 *1ms = 2000ms,全周期是4
reg inc_dec_flag; //duty_cycle加减计数的标志位
assign led = (period_cnt >= duty_cycle) ? 1'b1 : 1'b0; //输出PWM
//周期计时器
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
period_cnt <= 16'd0;
else if(period_cnt == 50000)
period_cnt <= 16'd0;
else
period_cnt <= period_cnt + 1'b1;
end
//调节占空比duty_cycle的值
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)begin
duty_cycle <= 16'd0;
inc_dec_flag <= 1'b0;//默认为加
end
else begin
if(period_cnt == 16'd50000)begin
if(inc_dec_flag == 1'b0)begin
if(duty_cycle == 16'd50000) //如果已经加到5000了
inc_dec_flag <= 1'b1; //标志位置成 减
else
duty_cycle <= duty_cycle + 16'd25;
end
else begin
if(duty_cycle == 16'd0) //如果已经减到0了
inc_dec_flag <= 1'b0; //标志位置成 加
else
duty_cycle <= duty_cycle - 16'd25;
end
end
end
end
endmodule
ucf文件
NET sys_clk TNM_NET = sys_clk_pin;
TIMESPEC TS_sys_clk_pin = PERIOD sys_clk_pin 20ns HIGH 50%;
NET sys_clk LOC = T8 | IOSTANDARD = LVCMOS33;
NET sys_rst_n LOC = L3 | IOSTANDARD = LVCMOS33;
################## LED ############################
NET led LOC = M6 | IOSTANDARD = LVCMOS33;
这一节难度不大,也没有什么可以过多需要说明的。tb文件更简单。只需要一个时钟即可。