FPGA开发——呼吸灯的设计

一、原理

呼吸灯的原理主要基于‌PWM(脉冲宽度调制)技术,通过控制LED灯的占空比来实现亮度的逐渐变化。这种技术通过调整PWM信号的占空比,即高电平在一个周期内所占的比例,来控制LED灯的亮度。当占空比从0%逐渐变化到100%,再从100%变化回0%,就实现了灯光亮度由暗到亮,再由亮到暗的循环变化,模拟了人的呼吸效果。‌

具体来说,PWM信号的周期是固定的,通过改变高电平的时间长度(即占空比),可以控制LED灯的亮度。例如,当占空比为0%时,LED灯不亮;当占空比为100%时,LED灯最亮。通过编程或微电脑控制,可以实时调整这些参数,从而实现灯光亮度的动态变化。‌

此外,还有一些非PWM的实现方式,例如通过编程控制亮和灭的时间比例,虽然这种方法较为复杂且可能不如PWM技术普及,但它提供了一种不同的实现思路。总的来说,PWM技术因其简单有效和广泛的应用支持,是实现呼吸灯的主要技术手段。‌

二、实现思路

这里我们在设计的时候采用三个周期计数器,分别是us级,ms级以及s级计数器,通过对开发板系统时钟的20ns进行分频,接着实现us计数器的设计,最后利用us计数器实现毫秒计数器,利用ms计数器实现s计数器的方法逐一完成三个计数器,最后的占空比的调整是在ms计数器进行里面设置。在计数器设计好之后利用s级计数器对于状态标志进行一个设定,用于实现呼吸灯状态的改变标志。最后实现呼吸灯的相关功能。(这里实现的是2s的呼吸灯)

三、代码编写

设计文件

cpp 复制代码
module led(
    input clk,
    input rst_n,
    output  reg [3:0] led_out
);

//参数定义
parameter TIME_2us=1_000_000;
parameter TIME_2ms=1000-1;
parameter TIME_2s=1000-1;

//内部信号定义
reg  [6:0]  cnt_us;
reg  [9:0]  cnt_ms;
reg  [26:0]  cnt_s;
reg          flag;//呼吸灯亮灭标志位
wire        add_cnt_us;
wire        end_cnt_us;
wire        add_cnt_ms;
wire        end_cnt_ms;
wire        add_cnt_s;
wire        end_cnt_s;


//2us计数器
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)
        cnt_us<= 0;
    else if(add_cnt_us)begin
        if(end_cnt_us)
            cnt_us<=0;
        else
            cnt_us<= cnt_us+1'b1;
    end 
end 
assign add_cnt_us = 1'b1;
assign end_cnt_us = (cnt_us==7'd99) && add_cnt_us;

//ms计数器
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)
        cnt_ms<= 0;
    else if(add_cnt_ms)begin
        if(end_cnt_ms)
            cnt_ms<=0;
        else
            cnt_ms<= cnt_ms+1'b1;
    end 
end 
assign add_cnt_ms = end_cnt_us;
assign end_cnt_ms = add_cnt_ms && (cnt_ms==TIME_2ms);

//s计数器
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)
        cnt_s<= 0;
    else if(add_cnt_s)begin
        if(end_cnt_s)
            cnt_s<=0;
        else
            cnt_s<= cnt_s+1'b1;
    end 
end 
assign add_cnt_s = end_cnt_ms;
assign end_cnt_s = add_cnt_s && (cnt_s==TIME_2s);

//flag亮灭状态描述
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        flag<= 0;
    else if(end_cnt_s)
        flag<=~flag;
    else
        flag<= flag;
end

//功能实现
always @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)
		led_out <= 4'b0000;
	// 由灭到亮
	else if((flag == 1'b0)&&(cnt_s <= cnt_ms))
		led_out <= 4'b0000;
	else if((flag == 1'b0)&&(cnt_s > cnt_ms))
		led_out <= 4'b1111;
	
	// 由亮到灭
	else if((flag == 1'b1)&&(cnt_s < cnt_ms))
		led_out <= 4'b1111;	
	else if((flag == 1'b1)&&(cnt_s >= cnt_ms))
		led_out <= 4'b0000;
	else
		led_out <= led_out;
end 

endmodule

测试文件的编写

cpp 复制代码
//定义时间尺度
`timescale 1ns/1ps
module led_tb();

//重定义
defparam  led_inst.TIME_2us=10;
defparam  led_inst.TIME_2ms=10;
defparam  led_inst.TIME_2s=10;

//内部变量定义
reg clk;
reg rst_n;
wire  led_out;

//模块实例化
led led_inst(
    /*input              */ .rst_n    (rst_n     ),
    /*input            */ .clk      (clk       ),
    /*output reg [3:0] */ .led_out  (led_out   )
);

//时钟
parameter CLK_CLY =20;
initial clk=0;
always  #(CLK_CLY/2) clk=~clk;

//复位
initial begin
    rst_n =1'b0;
    #(CLK_CLY*2);
    #3;
    rst_n =1'b1;
end 
//激励

endmodule

四、仿真波形图

由于我们设置的计数器技术周期和系统的周期相差过大,所以在测试文件中进行重定义来更好在波形途中观察ms周期中高低占空比的改变。

通过波形图我们可以观察到低电平从最开始的100%慢慢变成0%,最后又会从0%变为100%,高电平从最开始的0%慢慢变成100%,最后又会从100%变为0%(这里,0000和1111的频率占空比),这里的波形图位置有限,没有拍完。

受格式的影响,这里就不放下板之后的效果,最终实现的效果就是4个LED会由暗变为亮,在由亮变暗的呼吸灯效果。

相关推荐
ShiMetaPi3 小时前
操作【GM3568JHF】FPGA+ARM异构开发板 使用指南:蓝牙
arm开发·嵌入式硬件·fpga开发·rk3568
知识充实人生10 小时前
静态时序分析详解之时序路径类型
fpga开发·时序路径·关键路径
zhong liu bin11 小时前
Vue框架技术详解——项目驱动概念理解【前端】【Vue】
前端·javascript·vue.js·vscode·vue
Blue桃之夭夭1 天前
Visual Studio Code设置个性化背景教程
ide·vscode·编辑器
9527华安1 天前
Xilinx系列FPGA实现DP1.4视频收发,支持4K60帧分辨率,提供2套工程源码和技术支持
fpga开发·音视频·dp1.4·4k60帧
cycf1 天前
高速接口基础
fpga开发
forgeda2 天前
从Vivado集成Lint功能,看FPGA设计的日益ASIC化趋势
fpga开发·vivado·lint·eco·静态检查功能
hexiaoyan8272 天前
国产化FPGA开发板:2050-基于JFMK50T4(XC7A50T)的核心板
fpga开发·工业图像输出·vc709e板卡·zynq 通用计算平台·模拟型号处理
m0_575046342 天前
FPGA数据流分析
数据分析·fpga·数据流分析
雨洛lhw2 天前
The Xilinx 7 series FPGAs 设计PCB 该选择绑定哪个bank引脚,约束引脚时如何定义引脚电平标准?
fpga开发·bank·电平标准