此題曾為全國大學(xué)生電子設(shè)計(jì)競賽題目,我將其簡化,省略了模擬電路部分,用FPGA簡單實(shí)現(xiàn)眼圖效果,重在學(xué)習(xí)m序列的產(chǎn)生和時(shí)鐘恢復(fù)的VHDL代碼實(shí)現(xiàn)。

使用示波器觀察結(jié)果,使用時(shí)鐘恢復(fù)的信號作為觸發(fā)源
一、模塊總覽
整個(gè)系統(tǒng)設(shè)計(jì)由頂層文件、m序列產(chǎn)生模塊、時(shí)鐘分頻模塊、時(shí)鐘恢復(fù)模塊、按鍵消抖模塊構(gòu)成

Paste_Image.png
二、各模塊代碼
1、頂層文件
LIBRARY ieee;
USE ieee.std_logic_1164.all;
LIBRARY work;
ENTITY m_sys IS
PORT
(
reset : IN STD_LOGIC;
clk : IN STD_LOGIC;
keyup : IN STD_LOGIC;
keydown : IN STD_LOGIC;
m_s : OUT STD_LOGIC;
oSyn : OUT STD_LOGIC;
syn_real : OUT STD_LOGIC
);
END m_sys;
ARCHITECTURE bdf_type OF m_sys IS
COMPONENT re_clk
PORT(man_code : IN STD_LOGIC;
clk : IN STD_LOGIC;
oSyn : OUT STD_LOGIC
);
END COMPONENT;
COMPONENT fre_div
PORT(clk : IN STD_LOGIC;
address : IN STD_LOGIC_VECTOR(3 DOWNTO 0);
clkadj : OUT STD_LOGIC
);
END COMPONENT;
COMPONENT m_series
PORT(clk : IN STD_LOGIC;
reset : IN STD_LOGIC;
dataout : OUT STD_LOGIC
);
END COMPONENT;
COMPONENT key
PORT(clk : IN STD_LOGIC;
keyup : IN STD_LOGIC;
keydown : IN STD_LOGIC;
Oaddress : OUT STD_LOGIC_VECTOR(3 DOWNTO 0)
);
END COMPONENT;
SIGNAL SYNTHESIZED_WIRE_0 : STD_LOGIC;
SIGNAL SYNTHESIZED_WIRE_1 : STD_LOGIC_VECTOR(3 DOWNTO 0);
SIGNAL SYNTHESIZED_WIRE_2 : STD_LOGIC;
SIGNAL SYNTHESIZED_WIRE_3 : STD_LOGIC;
BEGIN
m_s <= SYNTHESIZED_WIRE_0;
syn_real <= SYNTHESIZED_WIRE_3;
l1 : re_clk
PORT MAP(man_code => SYNTHESIZED_WIRE_0,
clk => clk,
oSyn => oSyn);
--
l2 : fre_div
PORT MAP(clk => clk,
address => SYNTHESIZED_WIRE_1,
clkadj => SYNTHESIZED_WIRE_3);
l3 : m_series
PORT MAP(clk => SYNTHESIZED_WIRE_3,
reset => reset,
dataout => SYNTHESIZED_WIRE_0);
l4 : key
PORT MAP(clk => clk,
keyup => keyup,
keydown => keydown,
Oaddress => SYNTHESIZED_WIRE_1);
END bdf_type;
2、m序列產(chǎn)生模塊
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity m_series is
port (clk: in std_logic;
reset:in std_logic;
dataout:out std_logic);
end m_series;
architecture behave of m_series is
signal shifter:std_logic_vector(7 downto 0);
signal cnt:std_logic:='0';
signal clk2:std_logic;
signal sout:std_logic;
signal con: std_logic_vector(1 downto 0):="10";
signal flag:std_logic:='0';
begin
clk_2_p:process(clk)
begin
if rising_edge(clk)
then cnt<=not cnt;
clk2<=cnt;
end if;
end process;
m_p:process(clk2,reset)
begin
sout<=shifter(7);
if (reset='0') then shifter<="00001111";
elsif rising_edge(clk2) then
shifter(7 downto 1)<=shifter(6 downto 0);
shifter(0)<=shifter(3) xor shifter(4) xor shifter(5) xor shifter(7);
end if;
end process;
process(clk2)
begin
if clk2 'event and clk2='0' then
if sout='1' then con<="10";
else con <="01";
end if;
end if;
end process;
process(clk)
begin
if clk 'event and clk='1' then
if flag='1' then
dataout<=con(0);
flag<=not flag;
else dataout<=con(1);
flag<=not flag;
end if;
end if ;
end process;
end behave;
3、時(shí)鐘恢復(fù)模塊
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity re_clk is
port( man_code:in std_logic;
clk:in std_logic;
oSyn:out std_logic);
end re_clk;
architecture behave of re_clk is
signal man_code_2temp: std_logic_vector(1 downto 0);--曼碼暫存相鄰連個(gè)碼元
signal man_code_edge: std_logic; --延遲異或后的信號
signal en_100ms:std_logic; --100ms使能信號
signal cnt_for_100ms:integer range 0 to 3999999; --40M晶振,可分頻到100ms
signal cnt1:std_logic_vector(15 downto 0);--提取最大的時(shí)鐘間隔最大不超65536
signal p_temp:std_logic_vector(15 downto 0); --輸出最大時(shí)間間隔臨時(shí)寄存器
signal period:std_logic_vector(15 downto 0); --鎖存最大間隔計(jì)數(shù)
signal period_4:std_logic_vector(15 downto 0); --period/4
signal period_2:std_logic_vector(15 downto 0); --period/2,依次來實(shí)現(xiàn)2倍頻
signal cnt2:std_logic_vector(15 downto 0); --計(jì)數(shù)產(chǎn)生同步時(shí)鐘
begin
-------------------------------延遲異或
p_man_code_2temp:process(clk)
begin
if rising_edge(clk) then
man_code_edge<=man_code_2temp(0) xor man_code_2temp(1); --取相鄰曼碼的異或
man_code_2temp<=man_code_2temp(0) & man_code; --接著存入輸入的曼碼
end if;
end process;
------------------------------------計(jì)算最大的兩個(gè)跳變沿(上升或下降)的最大時(shí)間間隔
p_100ms:process(clk)
begin
if rising_edge(clk) then
if cnt_for_100ms=3999999 then
cnt_for_100ms<=0;
en_100ms<='1'; --到100ms,en_100ms使能
else cnt_for_100ms<=cnt_for_100ms+1;
en_100ms<='0';
end if;
end if;
end process;
p_cnt1:process(clk)
begin
if rising_edge(clk) then
if(man_code_edge='1') then
cnt1<=(others=>'0'); --man_code_edge='1'則計(jì)數(shù)清零
else cnt1<=cnt1+1; --man_code_edge='0'開始計(jì)算跳變沿間隔數(shù),即多少個(gè)clk脈沖
end if;
if (en_100ms='1') then
period<=p_temp;
p_temp<=(others=>'0'); --100ms到則p_temp賦值同時(shí)清零
elsif(cnt1>p_temp) then --en_100ms='0'時(shí)與p_temp比較,取最大cnt1的值
p_temp<=cnt1;
end if;
end if;
end process;
--------------------------利用最大時(shí)間間隔,產(chǎn)生和曼碼速率一樣的時(shí)鐘
period_4<="00" & period(15 downto 2); --period/4
period_2<='0' &period(15 downto 1); --period/2,依次來實(shí)現(xiàn)2倍頻
p_syn:process(clk)
begin
if rising_edge(clk) then
if man_code_edge='1' then
if (cnt2>(period-(period_4)) or cnt2<period_4) then
cnt2<=(others=>'0');
end if;
else
if (cnt2<(period-1)) then
cnt2<=cnt2+1;
else cnt2<=(others=>'0');
end if;
end if;
end if;
if cnt2<period_2 and cnt2>period_4 then --1/4至2/4處為1
oSyn<='0';
elsif cnt2>(period-period_4) and cnt2<(period-1) then --3/4至4/4處為1
oSyn<='0';
else oSyn<='1'; --其余處為0,以此達(dá)到2倍頻
end if;
end process;
end behave;
4、時(shí)鐘分頻
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity fre_div is
port (clk:in std_logic; --40M?????????
address:in std_logic_vector(3 downto 0); --?????????????????
clkadj:out std_logic); --????????????
end fre_div;
architecture behave of fre_div is
signal cnt1:integer range 0 to 1999999;
signal cnt2:integer range 0 to 3;
signal factor: integer range 0 to 2000000;
begin
cnt1_p:process(clk)
begin
if rising_edge(clk) then
if cnt1=factor then cnt1<=0;
else cnt1<=cnt1+1;
if cnt1<(factor/2)then clkadj<='1';
else clkadj<='0';
end if;
end if;
end if;
end process;
process(address)
begin
case address is
when "0000" => factor<=1999; --20k???????,10k????????
when "0001" => factor<=999; --40k???????
when "0010" => factor<=666; --60k???????
when "0011" => factor<=499; --80k???????
when "0100" => factor<=399; --100k???????
when "0101" => factor<=332; --120k???????
when "0110" => factor<=285; --140k???????
when "0111" => factor<=249; --160k???????
when "1000" => factor<=221; --180k???????
when "1001" => factor<=199; --200k???????
when others => factor<=399; --???????????100k???????
end case;
end process;
end behave;
5、按鍵防抖
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity key is
port( clk:in std_logic;
keyup:in std_logic;
keydown:in std_logic;
Oaddress:buffer std_logic_vector(3 downto 0):="0100");
end key;
architecture behave of key is
type ST is (state0, state1, state2, state3,state4);
signal pre_state,next_state:ST:=state0;
signal key_link:std_logic;
begin
key_link<=keyup and keydown;
-----------------------------------------
course_p:process(clk)
BEGIN
if(clk 'EVENT and clk='1') then
pre_state<=next_state;
end if;
end process;
st_P:process(pre_state,next_state,key_link)
BEGIN
CASE pre_state is
when state0 =>
if(key_link='0') then
next_state<=state1;
else next_state<=state0;
end if;
when state1 =>
if(key_link='0') then
next_state<=state2;
else
next_state<=state0;
end if;
when state2 =>
if(key_link='0') then
next_state<=state3;
else
next_state<=state0;
end if;
when state3 =>
if(key_link='0') then
next_state<=state4;
else
next_state<=state0;
end if;
when state4 =>
if keyup='0' then
if Oaddress="1001" then
Oaddress<="1001";
else Oaddress<=Oaddress+1;
end if;
end if;
if keydown='0' then
if Oaddress="0000" then
Oaddress<="0000";
else
Oaddress<=Oaddress+1;
end if;
end if;
if(key_link='0') then
next_state<=state4;
else
next_state<=state0;
end if;
end case;
end process;
end behave;