001:FPGA入门——呼吸灯

  在一家做嵌入式公司实习已经两个月了,需要学习整理的东西很多。决定坚持写一些总结,留下一些记忆更有意义。呼吸灯这个题目刚拿到没有思路,网上的参考示例也没有找到合适的,不过最后找到一个YHXT机构(不是广告,很简单的实现了这个功能,放到博客一起学习。控制LED的亮度变化,就是要控制电压,让电压高低变化,是一个电压从低到高再到低的一个线性变换过程。这里用PWM控制电压最合适。产生PWM需要分别产生载波信号和调制信号,最后对两者的大小进行比较产生pwm

  载波用cnt1计数器生成一个锯齿波就是载波。这里计数器cnt1从0开始计数到N,计数到最大值再次从0开始计数,不断的循环计数。cnt1的最大值是N-1。根据你的时钟(系统时钟,FPGA的工作时钟,大多情况是50mhz,我这里用的是40mhz,25ns)来计数,每来一次时钟上升沿计数器加一。那么从0到N-1,所需的时间就是N*T。这个就是一个锯齿波的周期。

  调制信号呼吸灯是一个亮度又低到高再到低的过程,这里再用一个计数器cnt2生成一个三角波,这个三角波的周期就是呼吸灯工作一次的周期。三角波计数器从0到最大值N ,相当于对调制信号N等份,每一个等份是一个载波周期。这里有一个公式   N^2 * T = 呼吸灯周期/2 。知道呼吸灯周期和时钟的情况下容易得到计数器最大值N。(这里为了方便,我设置整个led周期5s,T = 25ns,则N = 10000。)这里相当于cnt1计数到最大值,cnt2加一。当cnt2从0计数到N-1的过程就是一个上升的斜线,由N-1递减到0就是下降的斜线。在cnt2计数到最大值时设置一个标志位信号flag,flag为1,代表开始递减。

  大小比较通过载波和调制信号的大小比较,就可以生成一个pwm波。载波大于调制信号时,pwm = 0,载波小于调制信号时,pwm =1。

 

 

verilog逻辑代码:

module hxled(clk,led1,led2);

input clk;//系统时钟40mhz

output led1;
output led2;//这里两个led交替呼吸

reg [13:0]cnt1;
reg [13:0]cnt2;
reg flag;//标志位
parameter N = 10000;// 计数值最大值,一次暗亮暗的时间是5s
//cnt1
always@(posedge clk) begin
if(cnt1 == N - 1)
cnt1 <= 1'b0;
else
cnt1 <= cnt1 + 1'b1;
end

//cnt2
always@(posedge clk)
begin
if(cnt1 == N - 1) //cnt1计满一次 cnt2才递增或递减
begin
if(!flag)//标志位为0时 cnt2加状态
begin
if(cnt2 == N - 1)
flag <= 1'b1;//cnt2计满时 标志位拉高
else
cnt2 <= cnt2 + 1'b1;
end
else
begin
if(cnt2 == 0)
flag <= 1'b0;
else
cnt2 <= cnt2 - 1'b1;
end
end
else
cnt2 <= cnt2;
end

assign led1 = (cnt1 < cnt2)?1'b1:1'b0;//大小比较
assign led2 = ~led1;//两个灯交替呼吸

endmodule

testbench文件:

`timescale 1ns/1ps
`define clock_period 25
module hxled_tb;

reg clk;
wire led1;
wire led2;

hxled u1(
.clk(clk),
.led1(led1),
.led2(led2)
);

initial clk = 1;
always# (`clock_period/2) clk = ~clk;

endmodule

  这次波形比较简单就不分析仿真波形了,板级验证通过,要注意quartus软件的操作。不同的工作时钟可以更改一下计数器值,也可以加入复位信号。如果实验现象不明显可能是计数器值设置的问题。

  再次感谢YH学堂 这次学习 了解如何用计数器产生载波信号 调制信号 如何产生PWM 以及控制呼吸灯的原理。

 

posted @ 2020-10-13 22:15  河西到美西  阅读(795)  评论(0)    收藏  举报