菜鸟工程师成长之路

基于FPGA的简易数字信号分析仪(眼图)的设计

2017-04-25  本文已影响157人  言丶武

此题曾为全国大学生电子设计竞赛题目,我将其简化,省略了模拟电路部分,用FPGA简单实现眼图效果,重在学习m序列的产生和时钟恢复的VHDL代码实现。

使用示波器观察结果,使用时钟恢复的信号作为触发源

一、模块总览
整个系统设计由顶层文件、m序列产生模块、时钟分频模块、时钟恢复模块、按键消抖模块构成

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序列产生模块

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、时钟恢复模块

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);--曼码暂存相邻连个码元
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);--提取最大的时钟间隔最大不超65536
signal p_temp:std_logic_vector(15 downto 0);  --输出最大时间间隔临时寄存器
signal period:std_logic_vector(15 downto 0);  --锁存最大间隔计数


signal period_4:std_logic_vector(15 downto 0); --period/4
signal period_2:std_logic_vector(15 downto 0);  --period/2,依次来实现2倍频
signal cnt2:std_logic_vector(15 downto 0);      --计数产生同步时钟


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;



------------------------------------计算最大的两个跳变沿(上升或下降)的最大时间间隔
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'则计数清零
    else cnt1<=cnt1+1;    --man_code_edge='0'开始计算跳变沿间隔数,即多少个clk脉冲
    end if;
    
    if (en_100ms='1') then   
        period<=p_temp;
        p_temp<=(others=>'0');         --100ms到则p_temp赋值同时清零
    elsif(cnt1>p_temp) then     --en_100ms='0'时与p_temp比较,取最大cnt1的值
            p_temp<=cnt1;       
    end if; 
end if;
end process;

--------------------------利用最大时间间隔,产生和曼码速率一样的时钟
       period_4<="00" & period(15 downto 2);  --period/4
        period_2<='0' &period(15 downto 1);     --period/2,依次来实现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,以此达到2倍频
end if;
                
end process;

end behave;

4、时钟分频

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;
上一篇下一篇

猜你喜欢

热点阅读