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

此题曾为全国大学生电子设计竞赛题目,我将其简化,省略了模拟电路部分,用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;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,951评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,606评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,601评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,478评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,565评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,587评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,590评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,337评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,785评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,096评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,273评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,935评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,578评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,199评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,440评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,163评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,133评论 2 352

推荐阅读更多精彩内容

  • 姓名:徐娇 学号:17011210547 转自 http://mp.weixin.qq.com/s/WNigJh...
    徐Jiao阅读 2,351评论 0 3
  • fpga规范 工作过的朋友肯定知道,公司里是很强调规范的,特别是对于大的设计(无论软件还是硬件),不按照规范走几乎...
    Michael_Johnson阅读 1,885评论 1 4
  • 一个计数器通常是由一组触发器构成,该组触发器按照预先给定的顺序改变其状态,如果所有触发器的状态改变是在同一时钟脉冲...
    锦穗阅读 13,285评论 0 6
  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,945评论 6 13
  • 校区:科学创想乐高机器人和平校区 时间:周日1:00-2:00 学员:孙一鸣,李倬熠 任教老师:杨玲 教学目标: ...
    Happy00阅读 286评论 0 0