quartus——基于FPGA的LED呼吸灯设计(VHDL语言)

题目

针对ETP-MB-1开发板,采用VHDL语言,设计合适的数字逻辑系统,实现4路LED灯控制,LED亮度从0~100%变化,各 LED灯组合产生呼吸灯效果,每位灯按照1s周期线性亮起,按照2s周期线性熄灭,4位灯之间相位相差90度。

分析

此实验要做的是4路呼吸灯,在此基础上增加的条件有亮起与熄灭时间比例为1:2以及4路灯之间相位差为90度。考虑到仿真时间的问题,实验时LED灯熄灭的时间为20ms,亮起的时间为10ms。
首先通过锁相环对输入的50MHz晶振信号进行分频,由于不能无限小得分频,所以只能输出10MHz的时钟信号。再通过十分频计数器再次分频得到合适的1MHz信号。1MHz的脉冲信号通过脉冲宽度调制模块后,从引脚输出接LED灯,实现对LED灯亮度的控制。而对于相位差问题,可通过延时实现。

流程图

这流程图我自己看着都头大,不过好不容易做出来了,就放这吧。
在这里插入图片描述

各模块基本原理

一、PLL模块
由于老师没要求我们自己写代码,这里只简述一下利用quartus自动生成PLL的步骤。

1.建好工程后,点击tools中的“魔法棒”
2. 点击next
在这里插入图片描述
3. 注意下图中红框圈出来的地方,然后点击next
在这里插入图片描述

  1. 芯片晶振为50MHz,所以将Input改成50(笔记本显示不全,可用快捷键进行操作:next,alt+n或者enter;back,alt+b;finish,alt+f)
    在这里插入图片描述

  2. 不需要复位和锁存,所以将对钩取消。
    在这里插入图片描述

  3. 直接next
    在这里插入图片描述

  4. 按图操作,注意不能无限小得分频,只需一路信号则不需设置c1、c2
    在这里插入图片描述

  5. 直接next
    在这里插入图片描述

  6. 只选最后一个
    在这里插入图片描述

二、十分频计数模块
对输入信号的上升沿进行计数,计满10个数,将输出电平拉高,否则保持低电平,这样输出信号的频率就会降低到原来的十分之一。

LIBRARY ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity count10 is
port
  (
   clk1:in std_logic;
   outclk1:out std_logic
   );
end;

architecture one of count10 is
begin
process(clk1)
variable count:integer:=0;
begin
if clk1'event and clk1='1' then
     count:=count+1;
     if count=10 then
        outclk1<='1';
        count:=0;
     else 
        outclk1<='0';
     end if;
end if;
end process;
end;

三、PWM模块
脉冲宽度调制模块思路为,将时间进行等分,每份则是一个周期,通过线性改变每个周期内高低电平的占空比使得LED灯亮度改变。50MHz晶振经过PLL锁相环和十分频计数器后得到1MHz时钟信号,脉冲调制模块所有的计数操作都是以1MHz时钟信号为基础。对上升沿进行计数,计满100个上升沿,即经过0.1ms时,拉低输出电平,同时计数值归0。每次计数后将计数值与与阈值进行比较,若两者相等,拉高输出电平。在LED灯熄灭的过程中,每次拉高输出电平后使阈值加1;在LED灯亮起过程中,每次拉高输出电平后使阈值减1。阈值的上限和下限分别是99和1,需要注意的是,由于熄灭时间要求是20ms,那么需要的时钟信号是2MHz,这样需要再加一个变量,将1MHz的信号变换成2MHz。
而对于4路灯之间的相位差为90度这个要求,进行延迟即可达到。一次完整的呼吸周期为30ms,那么第一路LED灯不延迟,第2路灯延迟7500us,第三路灯延迟15000us,第四路灯延迟22500us。

第一路LED灯(无延迟)代码如下。

LIBRARY ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity pwm1 is
port
  (
   clkus1:in std_logic;
   pwmout1:out std_logic
   );
end;

architecture one of pwm1 is
begin
process(clkus1)
variable pwmgate:integer:=1;
variable pwmcount:integer:=0;
variable pwmcount_1:integer:=0;
variable count:integer:=0;
variable light:integer:=0;
begin
if clkus1'event and clkus1='1' then
        
     if light=0 then
        if count=0 then
           count:=1;
           pwmcount_1:=pwmcount_1+1;
        else count:=0;
        end if;
        
        if pwmcount_1=pwmgate then
           pwmout1<='1';
        end if;
        
        if pwmcount_1=99 then
           pwmgate:=pwmgate+1;
           pwmcount_1:=0;
           pwmout1<='0';
        end if;
        
        if pwmgate=99 then  --yu zhi zeng jia dao 99,ze
           light:=1; 
        end if;
     end if;
     
     if light=1 then        --liang qi guo cheng zhong
        pwmcount:=pwmcount+1; 
        if pwmcount=pwmgate then
           pwmout1<='1';
        end if;
        
        if pwmcount=99 then
           pwmgate:=pwmgate-1;
           pwmcount:=0;
           pwmout1<='0';
        end if;
        
        if pwmgate=1 then  --yu zhi jian xiao dao 1
           light:=0; 
        end if;
     end if;
     
end if;
end process;
end;

各模块构建好后在顶层文件中用元件例化语句进行连接。

RTL视图

如图所示,PLL是锁相环模块,inclk0是输入引脚,c0是输出引脚。Count10是十分频计数器模块,clk1是输入引脚,outclk1是输出引脚。Pwm1、pwm2、pwm3、pwm4是脉冲宽度调制模块,clkus1、clkus2、clkus3、clkus4分别是其输入引脚,pwmout1、pwmou2、pwmout3、pwmout4分别是其输出引脚。
在这里插入图片描述

仿真分析

仿真时间正好为一个完整的呼吸周期30ms,以没有延迟的第一路LED为例,从仿真可以看出在前20ms,高电平占空比一直在降低,而在20ms后,高电平的占空比开始增加,这就模拟了LED灯由熄灭到亮起的过程。第二路LED灯延迟7.5ms,第三路LED灯延迟了15ms,第四路LED灯延迟了22.5ms。
在这里插入图片描述
就整理这些吧,作业中的另一个暂时不整理了,因为借鉴了网上别人的方法,有的地方还是没有搞太懂。

方法总比困难多,加油加油!


7.10 ——昨天出成绩了,没达到预期,有些难受,实验我真的认真做了,也许是报告写的不好吧…

  • 8
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值