目录
前言
上一次写的代码不是很好,这次的我个人感觉更加容易理解和实现,更加的好看。
一、设计要求
使用VHDL语言建模,让开发板上的任意一个 LED实现呼吸灯的效果,即由灭渐亮(过程为2秒),然后再由亮渐灭(过程为2秒),可实现复位和随时暂停。PWM频率为50Hz,灰度级为50。
二、设计思路
第一步:分频系统时钟得到50HZ的pwm时钟,该时钟用于控制占空比的递增递减
第二步:调整占空比,每一pwm周期占空比加 1 或减 1,占空比的灰度级设置为50
第三步:利用占空比和系统时钟来控制LED的亮灭以达到呼吸效果,在这里不使用pwm时钟来控制,即相当于又设置了一个50HZ的时钟。
第四步:在原来基础上加入复位和暂停功能,复位键按下LED熄灭,松手呼吸灯重新开始(从亮到灭,再从灭到亮),占空比跳到最大;暂停键按下LED断气停止“呼吸”,再次按下LED恢复“呼吸”,并保留“断气”前的占空比和呼吸状态。
PWM 占空比示意图:
三、VHDL设计代码
library ieee;
use ieee.std_logic_1164.all;
entity new_breathing is
port(sys_clk:in std_logic;--系统时钟
sys_rst:in std_logic;--复位键,按下状态恢复为由亮到灭
pause:in std_logic;--暂停键,第一次按下呼吸灯暂停,再次按下呼吸灯继续亮灭
led:out std_logic);
end new_breathing;
architecture behav of new_breathing is
signal pwm_clk:std_logic:='0';--pwm时钟
signal duty_cycle:integer range 0 to 51:=0;--占空比,范围0~50,选51是怕后续会溢出报错,但应该也不会,因为2^8>51
signal mode:std_logic:='0';--'0'为由亮到灭,'1'为由灭到亮
signal state:std_logic:='1';--'0'为暂停,'1'为开始
begin
--时钟分频为50hz
process(sys_clk, sys_rst, pause)
variable count:integer range 0 to 500000:=0;--这里说明pwm的周期为50M/(500000*2)=50hz,用于调整呼吸长短(t = (2*x)/1000000)秒
begin
if(rising_edge(sys_clk)) then--这里是时钟分频
if(count<500000) then
count:=count+1;
else pwm_clk<= not pwm_clk;--翻转
count:=0;--重新计数
end if;
end if;
if(sys_rst='1') then--复位键会覆盖暂停键
if(rising_edge(pause)) then--暂停键,只有按下的时候才翻转,符合暂停的定义
state<=not state;
end if;
elsif(sys_rst='0') then
state<= '1';--如果复位了则暂停键失效
end if;
end process;
process(pwm_clk, sys_rst, pause)
begin
if(rising_edge(pwm_clk)) then--pwm每周期占空比会加1或减1以达到连续的效果
if(sys_rst='1') then
if(state='1') then--未复位
if(mode='0') then--由亮到暗
if(duty_cycle>0) then
duty_cycle<=duty_cycle-1;--占空比逐渐减少
elsif(duty_cycle=0) then
mode<='1';--模式跳转
end if;
elsif(mode='1') then--由暗到亮
if(duty_cycle<51) then
duty_cycle<=duty_cycle+1;--占空比逐渐增大
elsif(duty_cycle=51) then
mode<='0';--模式跳转
end if;
end if;
elsif(state='0') then--暂停效果
duty_cycle<=duty_cycle;--占空比保持
mode<=mode;--模式保持,多余的,因为mode只受duty_cycle影响
end if;
elsif(sys_rst='0') then--复位效果
mode<='0';--模式跳转为由亮到暗
duty_cycle<=50;--占空比跳到最大
end if;
end if;
end process;
process(sys_clk, sys_rst)
variable count2:integer range 0 to 1000000:=0;--pwm周期50M/1M=50hz
begin
if(rising_edge(sys_clk)) then
count2:=count2+1;
if(sys_rst='1') then
if(count2<duty_cycle*20000) then--50/1000000=1/20000
led<='1';
elsif(count2>duty_cycle) then
led<='0';
elsif(count2=1000000) then
count2:=0;
led<='0';--如果为'1'则led会闪烁一下
end if;
elsif(sys_rst='0') then--复位效果
count2:=0;--重新开始计数
led<='0';--断气
end if;
end if;
end process;
end behav;
四、引脚分配
我的板子是正点原子的新起点v2,芯片型号:EP4CE10F17C8
引脚分配见下图:
五、试验演示
视频链接:点击这里_哔哩哔哩_bilibili
总结
这次书写比上次更加得心应手,没有卡顿的地方,上次想得太复杂了。
(我是小白,不喜轻喷)