-5-16
使用软件为quartusII 9.1,芯片为EPM1270T144C5
一、实验任务要求
设计并实现一个控制16个发光二极管亮灭的电路,仿真验证其功能。实现功能如下:
(1)单点移动模式:从左到右依次循环点亮16个发光二极管,每个发光二极管的点亮时间为0.5s;
(2)幕布式:从中间两个发光二极管开始点亮,向两边每次增加点亮2个发光二极管,直至点亮16个发光二极管;然后再从两边开始每次灭掉2个发光二极管,直至所有发光二极管灭掉,依次往复,每个状态持续时间为0.5s;
(3)两个模式可用按键进行切换。
二、VHDL代码
分频器:
LIBRARY IEEE;USE IEEE.STD_LOGIC_1164.ALL;--div50ENTITY div50 isport(clk1: IN STD_LOGIC;clkout: OUT STD_LOGIC);END div50;ARCHITECTURE div50_arch of div50 issignal count: integer range 0 to 49;beginprocess(clk1)beginif(clk1'event and clk1 = '1') thenif(count = 49) thencount <= 0;elsecount <= count + 1;end if;if count <= 24 thenclkout <= '0';elseclkout <= '1';end if;end if;end process;END div50_arch;
防抖电路:
LIBRARY IEEE;USE IEEE.STD_LOGIC_1164.ALL;--anti-shakeENTITY anti_shake_key isport(clk2: IN STD_LOGIC;reset: IN STD_LOGIC;resetn: OUT STD_LOGIC);END anti_shake_key;ARCHITECTURE key_arch of anti_shake_key issignal resetmp1,resetmp2:STD_LOGIC;beginprocess(clk2)beginif(clk2'event and clk2 = '0') thenresetmp2 <= resetmp1;resetmp1 <= reset;end if;end process;resetn <= clk2 AND resetmp1 AND (NOT resetmp2);END key_arch;
控制器:
LIBRARY IEEE;USE IEEE.STD_LOGIC_1164.ALL;--colorlampENTITY colorlamp isport(clk3: IN STD_LOGIC;key_in: IN STD_LOGIC;reset: IN STD_LOGIC;led: OUT STD_LOGIC_VECTOR(15 downto 0));END colorlamp;ARCHITECTURE colorlamp_arch of colorlamp istype all_state is(s0,s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13,s14,s15);signal cnt: STD_LOGIC :='0';signal state:all_state;beginprocess(key_in,reset)--01count--to change modesbeginif(key_in'event and key_in = '1') thencnt <= cnt XOR '1';end if;if(reset = '1')thencnt <= '0'; --resetend if;end process;process(clk3,reset)beginif(clk3'event and clk3 = '1')thenif(cnt = '0') thencase state iswhen s0=>state<=s1;led <= "1000000000000000";when s1=>state<=s2;led <= "0100000000000000";when s2=>state<=s3;led <= "0010000000000000";when s3=>state<=s4;led <= "0001000000000000";when s4=>state<=s5;led <= "0000100000000000";when s5=>state<=s6;led <= "0000010000000000";when s6=>state<=s7;led <= "0000001000000000";when s7=>state<=s8;led <= "0000000100000000";when s8=>state<=s9;led <= "0000000010000000";when s9=>state<=s10;led <= "0000000001000000";when s10=>state<=s11;led <= "0000000000100000";when s11=>state<=s12;led <= "0000000000010000";when s12=>state<=s13;led <= "0000000000001000";when s13=>state<=s14;led <= "0000000000000100";when s14=>state<=s15;led <= "0000000000000010";when others => state<=s0;led <= "0000000000000001";end case;end if;if(cnt = '1')thencase state iswhen s0=>state<=s1;led <= "0000000110000000";when s1=>state<=s2;led <= "0000001111000000";when s2=>state<=s3;led <= "0000011111100000";when s3=>state<=s4;led <= "0000111111110000";when s4=>state<=s5;led <= "0001111111111000";when s5=>state<=s6;led <= "0011111111111100";when s6=>state<=s7;led <= "0111111111111110";when s7=>state<=s8;led <= "1111111111111111";when s8=>state<=s9;led <= "0111111111111110";when s9=>state<=s10;led <= "0011111111111100";when s10=>state<=s11;led <= "0001111111111000";when s11=>state<=s12;led <= "0000111111110000";when s12=>state<=s13;led <= "0000011111100000";when s13=>state<=s14;led <= "0000001111000000";when s14=>state<=s15;led <= "0000000110000000";when s15=>state<=s0;led <= "0000000000000000";end case;end if;end if;if(reset = '1')thenstate <= s0;--resetend if;end process;END colorlamp_arch;
连接电路:
LIBRARY IEEE;USE IEEE.STD_LOGIC_1164.ALL;--connectionENTITY lamp_player isport(ain:IN STD_LOGIC;reset:IN STD_LOGIC;key:IN STD_LOGIC;bout:OUT STD_LOGIC_VECTOR(15 DOWNTO 0));END lamp_player;ARCHITECTURE player_arch of lamp_player isCOMPONENT div50port(clk1:IN STD_LOGIC;clkout:OUT STD_LOGIC);END COMPONENT;COMPONENT anti_shake_keyport(clk2:IN STD_LOGIC;reset:IN STD_LOGIC;resetn:OUT STD_LOGIC);END COMPONENT;COMPONENT colorlampport(clk3:IN STD_LOGIC;key_in:IN STD_LOGIC;reset:IN STD_LOGIC;led:OUT STD_LOGIC_VECTOR(15 downto 0));END COMPONENT;SIGNAL c0,c1:STD_LOGIC;beginu1:div50 PORT MAP(clk1=>ain,clkout=>c0);u2:anti_shake_key PORT MAP(clk2=>ain,reset=>key,resetn=>c1);u3:colorlamp PORT MAP(clk3=>c0,key_in=>c1,reset=>reset,led(15 downto 0)=>bout(15 downto 0));END;
三、仿真波形及分析:
(1)分频器
由图可见该部分为分频系数为50的分频器,输入信号的频率为100Hz,则分频后的信号的频率为2Hz周期为0.5s。
(2)防抖电路
输出信号resetn = clk and resetmp1 and(not resetmp2),该电路部分采用时钟信号下降沿触发,以reset信号第一次发生“抖动”为例:在第一个时钟(clk2)信号下降沿,resetmp2得到resetmp1的值为低电平“0”,resetmp1得到此时reset的值为高电平“1”,且由于边沿触发,两个信号直至第二个时钟信号下降沿到达前一直保持该值(稳定)。在第二个时钟下降沿时,resetmp2得到resetmp1的值为高电平“1”,resetmp1为时钟下降沿时刻的reset值,保持高电平“1”输出,直至第三个时钟信号下降沿到来,reset信号为低电平,resetmp1变为低电平,resetmp2在第四个时钟下降沿被赋予此刻resetmp1的值变为低电平。resetmp2由resetmp1开始变化前的值赋予,因此总是比resetmp1要“延迟”一个时钟信号,且resetmp1和resetmp2在高电平有效时间内稳定,则resetn经过resetmp1和resetmp2的处理相较于reset初始信号变得更稳定,消除了可能发生的抖动。由于在第一个被检测到的reset信号进来时,resetmp1立刻变为高电平,resetmp2慢一个时钟信号变为高电平,正好“错峰”,在resetn = clk and resetmp1 and(not resetmp2)的逻辑下得到一个稳定的按键信号。
图形可见当输入信号reset在发生“抖动”时,信号resetn稳定输出,实现了按键消抖。
(3)控制器
整体图形:
在按键之前,发光二极管从左(led15)到右(led0)依次闪烁,循环点亮,实现单点移动要求;按键产生一个脉冲信号,切换模式,从中间两个发光二极管开始点亮,向两边每次点亮两个发光二极管直至全部点亮,再从两边开始每次熄灭两个二极管,实现幕布式点亮和熄灭,如下图所示:
再次按按键,则又变回单点移动模式:
reset信号高电平有效,实现信号复位,当reset信号为1时进行复位操作,变回单点移动模式,如下图所示:
(4)完整电路仿真波形
整体图形:
在按下按键之前按照单点移动模式运行,发光二极管自左(bout15)向右(bout0)循环依次点亮,第一次按下按键后产生脉冲信号,转换模式,变为幕布式亮灭灯,第二次按下按键重新切换为单点移动模式,第三次按下按钮变为幕布式亮灭灯,注意到在这之后有一个reset高电平信号,电路复位,变为初始状态,发光二极管重新变为单点移动模式,且从最左端(bout15)开始向右“移动”。
放大仿真波形,可见输入信号ain的频率为100Hz,分频器对其进行分频,得到频率为2Hz周期为0.5s的周期信号,如下图,一个发光二极管的发光时间为0.5s,满足设计要求:
四、故障分析
在设计控制器的时候cnt对按键产生的脉冲信号进行模值为2的计数,以更方便地实现灯亮模式的转换,但是最初用的是电平触发,导致仿真波形发生多次翻转,而后改进为边沿(上升沿)触发解决问题。
五、总结和结论
本次实验进一步提升了VHDL的编程能力和图形的仿真分析能力,学会了一个较为完整的电路设计,同时实践了机械按键的消抖,对按键消抖有了更深刻的认识。
============
更新:发现自己的防抖处理好像把问题复杂化了,还有一种防抖的方式是设定一个计数器,若按键按下的持续时间未达到设定值,则认为按键无效(持续时间太短,认为是按键抖动或者其他原因造成的误差),只有在按下的持续时间超过一定值才认为是有效地按下按钮。
process(clk_1ms)//该部分与上面的报告无关,只是补充一个防抖的写法//时间可自己设置variable num: integer range 0 to 100 := 0;beginif(clk_1ms'event and clk_1ms = '1')thenif(btn = '1')thenif(num = 99)thennum := 99;elsenum := num + 1;end if;if(num > 30)thenbtn_out <= '1';//设置防抖后的有效输出elsebtn_out <= '0';end if;elsenum := 0;btn <= '0';end if;end if;end process;
如果觉得《【学习笔记】数电实验——发光二极管走马灯电路的设计与实现》对你有帮助,请点赞、收藏,并留下你的观点哦!