基于FPGA的简易数字信号分析仪(眼图)的设计
2017-04-25 本文已影响157人
言丶武
此题曾为全国大学生电子设计竞赛题目,我将其简化,省略了模拟电路部分,用FPGA简单实现眼图效果,重在学习m序列的产生和时钟恢复的VHDL代码实现。
使用示波器观察结果,使用时钟恢复的信号作为触发源一、模块总览
整个系统设计由顶层文件、m序列产生模块、时钟分频模块、时钟恢复模块、按键消抖模块构成
二、各模块代码
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;