分频器的设计有两种思路,一种只适用于偶数次,另外一个是通用。
1.首先,需要知道分频的次数。
通过晶振算出时钟周期,然后你需要定时多少时间,用这个时间除周期,就可以得到计数次数。如:500ms的led翻转,50mhz的晶振,由50Mhz晶振得到20ns的时钟周期,用500ms/20ns=25000000次,这就是计数的次数。
2.通用方法:
主要思路,计数待分频的整个周期,也就是说,如:想要得到clkout,已知clkin,且10次clkin周期是一个clkout周期,那么我只要计10次clkin的周期,输出一个cnt,然后对cnt做二进制变化,取其最高位。因为它的最高位只是变化了1次 从0到1。
这是由48mhz时钟得到10hz时钟,那么10hz的周期是0.1s,48mhz的周期是1/48m。那么0.1s*48m得4800000次,其中2400000高电平,2400000是低电平。
代码:
process
begin
if clkin'event and clkin='1' then
if cnt=10 then cnt<=1;
else cnt<=cnt+1;
end if;
end if;
end process;
cnt_vec<=conv_std_logic(cnt,4);
clkout<=cnt_vec(3);
3.偶次分频
代码:
process(clk48mhz)
begin
if clk48mhz'event and clk48mhz='1' then
if cnt=2400000 then
cnt<=1;
clk_temp<=not clk_temp;--这就构成一个负脉冲或者正脉冲,一半周期就形成,
else
cnt<=cnt+1;--构成连续的周期
end if;
end if;
end process;
4.用分频器做流水灯
移位寄存器的思路,低位向前进,最高位移到最低位。
代码:
process(clk_10hz)
begin
if rising_edge(clk_10hz) then
data(8 downto 2)<=data(7 downto 1);--把原来的低7位给现在的高7位
data(1)<=data(8);--把原先的最高位给现在的最低位。
end if;
end process;
5.综合实现:
代码:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity fenpinqi is
Port ( clkin : in STD_LOGIC;
led : out STD_LOGIC_VECTOR (8 downto 1));
end fenpinqi;
architecture Behavioral of fenpinqi is
signal cnt:integer range 1 to 2400000 :=1;
signal clkout:std_logic:='0';
signal data:std_logic_vector(8 downto 1):="11111110";
begin
p1:process(clkin)--第一个进程做分频器,产生10hz时钟
begin
if clkin'event and clkin='1' then
if cnt=2400000 then
cnt<=1;
clkout<= not clkout;
else
cnt<=cnt+1;
end if;
end if;
end process p1;
p2:process(clkout)--第二个进程,在10hz时钟得上升沿移位。
begin
if rising_edge(clkout) then
data(8 downto 2)<=data(7 downto 1);--把原来的低7位给现在的高7位
data(1)<=data(8);--把原先的最高位给现在的最低位。
end if;
end process p2;
led<=data;
end Behavioral;
直接仿真:
可以清晰得看到,每个clkout时,led状态变化一次。
6.小结
1)process忘记加begin了
2)定义了两个信号,可以全局使用,如果是进程中得变量的话就不能全局调用。
3)如果是00001111这种一定是双引号。
4)用ise直接定义端口的话可以不写实体。