一. 流水灯
1.1流水灯原理
流水灯是每个学电子的入门“游戏” ,示意图如图1,其原理极其简单,但是可玩性却极强,可以就8个LED写出不同花样的程序。在1.2中我们列出两个不同思路的代码作为VHDL的入门例程。
图1 流水灯电路图
1.2 流水灯例程
这里提供两个不同的代码。
第一个代码的思路是先对系统时钟分频,产生1s信号(即变量count取值到25000000,这样分频时间=20ns*25000000*2=1s),然后使用移位操作符指令进行操作。该指令是在VHDL93中引入的,包括sll,srl,sla,sra,rol,ror6个指令,指令操作如图2一目了然。值得注意的是,使用该指令,左操作数必须是BIT_VECTOR类型,右操作数必须是INTEGER类型(前面可以有负号)。
图2 移位操作符示意图
例如:令x <= “10110”,则
y <= x sll 2 ;--逻辑左移两位,y <= “ 11000”,空余位填充0
y <= x srl 2 ;--逻辑右移两位,y <= “00101”,空余位填充0
y <= x sla 2 ;--算术左移两位,y <= “11000”,空余位复制最右边上的数值
y <= x sra 2 ;--算术右移两位,y <= “11101”,空余位复制最左边上的数值
y <= x rol 2 ;--循环逻辑左移两位,y <= “11010”,左侧移出位填补到右侧
y <= x ror 2 ;--循环逻辑右移两位,y <= “10101”,右侧移出位填补到左侧
例程一:
1 -------------------------------------------------------------------------------------------------- 2 3 library IEEE; 4 5 use IEEE.std_logic_1164.all; 6 7 -------------------------------------------------------------------------------------------------- 8 9 entity VHDL_LEDWATER1 is 10 11 port ( 12 13 Clk : in STD_LOGIC; --创建时钟端口,连接开发板PIN23 14 15 Rst : in STD_LOGIC; --创建复位端口,连接开发板PIN116 16 17 Output : out BIT_VECTOR(7 downto 0) --创建输出端口,对应8个LED。分别 18 19 --为PIN142-PIN133,要使用移位操作符 20 21 ); --其左侧必须为BIT_VECTOR类型 22 23 end VHDL_LEDWATER1; 24 25 -------------------------------------------------------------------------------------------------- 26 27 architecture behave of VHDL_LEDWATER1 is 28 29 signal Clk1 : STD_LOGIC; --建立中间时钟信号 30 31 begin 32 33 P1:process(Clk) 34 35 variable count : INTEGER range 0 to 25 := 0; --变量初始值不可综合,在仿真中使用,并 36 37 variable count1: STD_LOGIC := ‘1‘; --且为便于仿真,这里取到25,当烧写到开 38 39 --发板时候,改写为25000000即可 40 41 begin 42 43 if(Rst = ‘0‘) then 44 45 count := 0; 46 47 elsif(Clk‘event and Clk = ‘1‘) then 48 49 count := count + 1; 50 51 if(count = 25) then --这里使用=,而不是>=,可以防止产生比较器,节省硬件资源 52 53 count := 0; 54 55 count1 := not count1; 56 57 end if; 58 59 end if; 60 61 Clk1 <= count1; 62 63 end process P1; 64 65 P2:process(Clk1) 66 67 variable temp : BIT_VECTOR(7 downto 0) := "11111110";--注意左操作数类型 68 69 begin 70 71 if(Clk1‘event and Clk1 = ‘1‘) then 72 73 temp := (temp rol 1); 74 75 end if; 76 77 Output <= temp; 78 79 end process P2; 80 81 end architecture;
--------------------------------------------------------------------------------------------------
仿真波形:
从仿真波形中,可以验证例程的正确性。
第二个代码的思路是先对系统时钟分频,产生1s信号,然后对该1s信号进行模8计数,再利用case-when语句进行判断,进而控制LED。
例程二:
1 -------------------------------------------------------------------------------------------------- 2 3 library IEEE; 4 5 use IEEE.std_logic_1164.all;--该库定义了std_logic(8值)和std_ulogic(9值)多值逻辑结构 6 7 -------------------------------------------------------------------------------------------------- 8 9 entity LEDWATER is 10 11 port ( 12 13 Clk : in STD_LOGIC; --创建时钟端口,连接开发板PIN23 14 15 Rst : in STD_LOGIC; --创建复位端口,连接开发板PIN116 16 17 Output : out STD_LOGIC_VECTOR(7 downto 0) --创建输出端口,连接开发板PIN142-PIN133 18 19 ); 20 21 end LEDWATER; 22 23 -------------------------------------------------------------------------------------------------- 24 25 architecture BEHAVIOR_LEDWATER of LEDWATER is 26 27 signal Clk1 : STD_LOGIC; --建立中间时钟信号 28 29 begin 30 31 P1: process(Clk) --进程1,对时钟信号进行N分频 32 33 variable count : INTEGER range 0 to 25 := 0;--变量初始值不可综合,在仿真中使用 34 35 variable count1: STD_LOGIC := ‘1‘; 36 37 begin 38 39 if(Rst = ‘0‘) then 40 41 count := 0; 42 43 elsif(Clk‘event and Clk = ‘1‘) then 44 45 count := count + 1; 46 47 if(count = 25) then 48 49 count := 0; 50 51 count1:= not count1; 52 53 end if; 54 55 Clk1 <= count1; 56 57 end if; 58 59 end process; 60 61 P2: process(Clk1) --进程2,对分频信号进行计数,进而控制LED亮灭 62 63 variable count2 : INTEGER range 0 to 8 := 0;--变量初始值不可综合,在仿真中使用 64 65 begin 66 67 if(Clk1‘event and Clk1 = ‘1‘) then 68 69 count2 := count2 + 1; 70 71 if(count2 = 8) then 72 73 count2 := 0; 74 75 end if; 76 77 end if; 78 79 case count2 is 80 81 when 0 => Output <= "11111110"; 82 83 when 1 => Output <= "11111101"; 84 85 when 2 => Output <= "11111011"; 86 87 when 3 => Output <= "11110111"; 88 89 when 4 => Output <= "11101111"; 90 91 when 5 => Output <= "11011111"; 92 93 when 6 => Output <= "10111111"; 94 95 when 7 => Output <= "01111111"; 96 97 when others => Output <= (others => ‘Z‘); 98 99 end case; 100 101 end process; 102 103 end BEHAVIOR_LEDWATER;
仿真波形:
从仿真波形中,可以验证例程的正确性。
1.3 总结
其实,肯定还有其他精妙的想法,这里只列举了两种代码作为学习的开头。不过通过两个代码的学习,也熟悉了移位操作符和case-when语句的使用。下一节将开始数码管的学习。
参考文献:
[1] Volnei A.Pedroni.VHDL 数字电路设计教程[M].北京:电子工业出版社,2009:39-40;
[2] http://leonmoon.blog.hexun.com/4609284_d.html