实验三序列发生器与序列检测器实验报告
发布时间:2024-11-17
发布时间:2024-11-17
南昌大学实验报告
姓名: 学号: 6100210173 专业班级: 中兴通信101 实验类型:验证 □综合 ■设计 □创新 □实验日期:2012、11、16
实验四 序列信号发生器与检测器设计
一、实验目的
1、.学习VHDL文本输入法 2、学习有限状态机的设计 3、设计序列信号发生器和检测器 二.实验内容与要求
1. 设计序列发生器,完成序列为0111010011011010的序列生成器 2.用有限状态机设计序列检测器,实现串行序列11010的检测器 3. 若检测到符合要求的序列,则输出显示位为“1”,否则为“0”
4. 对检测到的次数计数 三. 设计思路
1. 设计分频器 因为最终要把待检测序列的检测次数在数码管上显示出,所以必须设计一个分频器,将起始频率作为数码管的扫描频率,而将分频后的频率作为序列发生器的移位频率,所以在程序中设置10KHZ进行分频分成1HZ脉冲(10KHZ的扫描频率是为了让数码管的动态显示更加清晰)
2. 设计序列发生器
在这次的设计序列发生器时没有用状态转移的方法来来形成一个16位的序列,而是通过直接设计一串16位的序列,通过对最高位的输出与并置来形成一串循环的16位序列,这样设计简单方便,易于操作与控制,也减少了在状态转移产生的误差,其主要的核心程序为:
architecture bhv of p2 is
signal bs: std_logic_vector(15 downto 0):="0111010011011010"; begin
xlout<=bs(15); process (clk1hz) begin
if (clk1hz'event and clk1hz='1') then bs<= bs(14 downto 0)&bs(15);
先将序列最高位输出至序列检测器中,然后在一个脉冲作用下,将此时最高位变成最低位,其余14位不变,使序列循环移动,最终形成一个16位循环序列。
3. 设计序列检测器
基本思想是采用有限状态机设计,通过状态的转移来实现被检测序列的的检测,首先设定6个状态S0 S1 S2 S3 S4 S5 通过这6个状态的转移情况来检测出11010这个序列。
但因为序列发生器发生的序列不断循环过程中也会出现一些类似11010的特殊序列,则在状态转移中则需要通过一些状态的变换来检测出里面包含的11010序列,如下文所讲的两种特殊情形便是我们序列发生器产生序列中出现的特殊序列:
(1)在序列发生器产生序列不断循环过程中出现该序列1110100,此序列中也有一个要检测到的序列但在状态转移过程需要注意:
1 1 1 0 1 0 0 S0 S1 S2 S2 S3 S4 S5 S0
即当S2状态转移到S3状态时,如果此时序列值为1,则只需转移到状态本身S2而不需要转移至S0,这样即可节约转移时间也可提高检测效率,之后的状态按正常转移并且最后从状态S5回到S0。
(2)在序列发生器产生序列不断循环过程中出现该序列110110100,此序列中也有一个要检测到的序列但是在状态团转移时同样需要注意:
1 1 0 1 1 0 1 0 0 S0 S1 S2 S3 S4 S2 S3 S4 S5 S0 即当状态S4转移到S5状态时,如果此时序列值为1,则需要将状态转移至S2状态,从S2状态重新开始检测,而不需要转移至S0,之后其它状态正常转移并且最后由S5状态转移至S0状态。
从上面的流程图可以看出所有的回路在检测完一次序列后在下一次没有该序列时会流向初始状态S0,而当两个或多个被检测序列连续在一起时,状态S5会跳过状态S0直接转移至状态S1完成序列的的检测,直到检测完后再次回到初始状态S0,并且为了避免上面所讲的两种特殊序列在状态转移都进行了改进,在状态S2至状态S3时若序列值为1则返回自身,消除第一种特殊情况下序列的检测问题,在状态S4至状态S5时若序列值为1返回到状态S2,消除第二种特殊情况对1101016序列的检测。
3、此外在设计序列检测器时,为了使实验现象更明显,更好的观测序列的的移动与检测情况我使用了5个LED分别来显示最新产生的五个序列位,分别输出到端口ledag(4),ledag(3),ledag(2),ledag(1),ledag(0)实现程序语句如下
if(clk1hz'event and clk1hz='1') then
ledag(4)<=ledag(3);---移位输出显示在led上以便观看
ledag(3)<=ledag(2); ledag(2)<=ledag(1); ledag(1)<=ledag(0);
ledag(0)<=xlout;--将最近生产的序列赋给最前端的ledge(0)位 end if; 4、设计计数器模块
因为序列发生器产生的序列不断地循环,待检测序列11010的个数很多,则在程序中设计计数模块,当序列检测器模块检测完一次待检测序列11010时产生一次下降沿,而计数器模块通过该下降沿进行计数自动加一,因为用两个数码管来表示待检测序列的个数,所以计数模块取上限为99即用数码管译码模块将计数值在数码管表示出来时最多能计99检测序列之后清零重新计数,这样设计之后比通过LED
四、实验程序(程序来源于自己编写) --
--分频器模块
library ieee;
use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; entity p1 is
rt(clk:in std_logic;
clk1hz:out std_logic --分频的频率1HZ的输出端口 ); end p1;
architecture behave of p1 is
Signal Clk_Count1 : std_logic_vector(13 downto 0); begin
process(clk) --将10KHZ的频率分频成1HZ begin
if(Clk'event and Clk='1') then if(Clk_Count1<10000) then
Clk_Count1<=Clk_Count1+1; --在小于10000时,自动加1 else
Clk_Count1<="00000000000001"; --超过10000后返回1
end if; end if;
end process;
Clk1Hz<=Clk_Count1(13); --将Clk_Count1的第14位赋给Clk1Hz end behave;
--序列发生器模块 library ieee;
use ieee.std_logic_1164.all; entity p2 is port
(clk1hz : in std_logic; --定义输入端口此时频率为1HZ xlout : out std_logic --输出序列发生器产生的序列端口 );
end entity;
architecture bhv of p2 is
signal bs: std_logic_vector(15 downto 0):="0111010011011010"; begin
xlout<=bs(15); --将bs的第16位值赋给xlout process (clk1hz) begin
if (clk1hz'event and clk1hz='1') then
bs<= bs(14 downto 0)&bs(15); --前15位保持不变,将bs的第16位并到最前来形 成序列的循环 end if;
end process; end bhv;
--序列检测器模块 library ieee;
use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; entity p3 is port
( clr :in std_logic; --清零端口
clk1hz:in std_logic; --输入信号频率 xlout : in std_logic; --输入序列 result: out std_logic ); end entity;
architecture bhv of p3 is
type state_value is(s0,s1,s2,s3,s4,s5); --定义6个状态
signal state: state_value; signal dclk: std_logic; begin
result<=dclk;
process (clr,clk1hz) begin
if (clr='0') then state<=s0; dclk<='0'; --检测输入序列“11010”由左开始 elsif(clk1hz'event and clk1hz='0') then case state is
when s0=> if xlout='1' then --序列值为1S0转态S1,若序列值为0,返回自身 state<=s1; else state<=s0; end if;
when s1=> if xlout='1' then state<=s2; else state<=s0; end if;
when s2=> if xlout='0' then --序列值为1,S2转向自身,序列值为0,转向S3 state<=s3; else state<=s2;
end if; when s3=> if xlout='1' then state<=s4;
else state<=s0; end if;
when s4=> if xlout='0' then --序列值为0,S4转向S5,输出端为1 state<=s5; dclk<='1';
else state<=s2; --若此时序列值为1,S4转向S2 end if;
when s5=> if xlout='0' then --序列值1,S5转移至S1,若为0,转向S0 state<=s0;
else state<=s1; end if; dclk<='0';
when others => state<=s0; --其它状态都将返回初始状态 end case; end if;
end process; end bhv;
--100计数模块 library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity p5 is port
( result:in std_logic; --前面序列检测模块中检测到序列后产生的跳变信号 d6,d7: out std_logic_vector(3 downto 0) --定义十位个位数值 ); end entity;
architecture behave of p5 is
signal cnt0,cnt1:std_logic_vector(3 downto 0):="0000"; --初始化 begin
process (result) begin
if (result'event and result='0') then
if (cnt0="1001" and cnt1="1001") then --设置计数上限为99 cnt0<="0000"; cnt1<="0000";
elsif (cnt0="1001") then --BCD码的调整 cnt0<="0000";
cnt1<=cnt1+1; --接受跳变信号后自动加1计数 else cnt0<=cnt0+1; end if; end if;
end process;
d6<=cnt1;d7<=cnt0; end behave;
--数码管译码模块 library ieee;
use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; entity p6 is
port(clk:in std_logic; --扫描频率10KHZ的输入端口 sel0,sel1,sel2:buffer std_logic; --数码管的位选信号 sg:out std_logic_vector(6 downto 0); --数码管的段选 sel:out std_logic_vector(7 downto 0);
d6,d7:in std_logic_vector(3 downto 0) --计数模块中个位十位的数值 ); end p6;
architecture behave of p6 is
signal cnt:std_logic_vector(1 downto 0); signal A:std_logic_vector(3 downto 0); begin
process(clk) begin
if clk'event and clk='1' then if cnt<"01" then cnt<=cnt+1;
else cnt<=(others=>'0'); end if; end if;
sel(0)<=sel0; sel(1)<=sel1; sel(2)<=sel2; case cnt is
when "00"=>sel2<='1';sel1<='1';sel0<='1';A<=d7; --选择数码管的位置 when "01"=>sel2<='1';sel1<='1';sel0<='0';A<=d6; when others=>null; end case; end process; process(A) begin case A is
when "0000" =>sg<="0111111"; --数码管显示值为0时的译码值 when "0001" =>sg<="0000110"; when "0010"=>sg<="1011011"; when "0011"=>sg<="1001111"; when "0100"=>sg<="1100110"; when "0101"=>sg<="1101101"; when "0110"=>sg<="1111101"; when "0111"=>sg<="0000111"; when "1000"=>sg<="1111111"; when "1001"=>sg<="1101111"; when others=>null; end case; end process; end behave;
--显示序列移动模块 library ieee;
use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; entity p4 is
port(clk1hz:in std_logic; --分频后的频率输入端口 xlout:in std_logic; --序列发生器产生的序列
ledag :buffer std_logic_vector(4 downto 0) --5位序列值的输出口 ); end p4;
architecture behave of p4 is begin
process(clk1hz)
begin
if(clk1hz'event and clk1hz='1') then
ledag(4)<=ledag(3);
--序列值向左移动 ledag(3)<=ledag(2);
ledag(2)<=ledag(1); ledag(1)<=ledag(0);
ledag(0)<=xlout; --将最近生产的序列赋给最前端的ledge(0)位 end if;
end process; end behave;
四. 实验步骤 1. 建立工程项目
2. 在VHDL编辑窗口下写好程序,并保存
3、进行全编译,没有错误。显示出状态机如图所示:
完全符合前面的设计思想,说明了程序的正确性。 4再新建波形仿真文件,引入端口,设置输入 5、接下来就是波形仿真了,点击
,时序仿真,结果如下图所示
五、仿真波形分析
结合仿真图和图上的注释对设计的模块进行功能的检测。由于序列产生的是0111010011011010,而要检测的序列是11010,因此,当检测到一个序列时,须经7或9的移位脉冲才能检测到下一个序列,根据第一个仿真图,可看出仿真是正确的。
由于总体的仿真正确了,所以对细节的仿真,例如:序列是如何在移位脉冲的输入下输出的:每检测到一个11010序列,数码管的具体输出是多少等,就不一一作分析了。
六、硬件测试
1.Assignments-.>device->
引脚锁定,参照下载实验板引脚号说明书,选择适当的引脚
2.引脚锁定后,保存,必须重新进行一次全程编译,编译通过后才能编程下载。 3.编程下载,用下载线将计算机并口和试验箱上的JTAG口接起来,接通电源。 选择Tools—>Programmer菜单,打开programmer窗口。 在mode中选中JTAG,将
Program/Configure下的方框选中
4在开始编程之前,必须正确设置编程硬件。点击“Hardware Setup”按钮,打开硬件设置口。
点击“Add Hardware”打开硬件添加窗口,在“Hardware type”下拉框中选择“USB”,点击OK按钮确认,关闭Hardware Setup窗口,完成硬件设置。 5、点击“Start”按钮,开始编程下载
然后就可以根据实验要就进行检测,看是否能产生正确的序列,是不是在正确的状态计数等等功能。 七、硬件测试结果
(1)序列发生器测试结果,实验中产生了序列0111010011011010
而且产生的原理即为通过预先设计的一个序列0111010011011010,然后通过把最高位移至最低位后与其余不变的15位相并接形成一个新的序列,然后循环往复,便可循环的产生该序列例如: 第一步为0111010011011010 第二次为1110100110110100 第三次为1101001101101001 第四次为1010011011010011 第五次为0100110110100111等等
然后继续循环相并即产生了序列0111010011011010
每一次的最高位都会输出到LED中显示,然后通过循环次数,不断地向右推进,例如上面所写的:LED显示的是01110即灭、亮、亮、亮、灭 ,第五次的最高位0就是最近新产生的,而该LED就显示在锁定的ledag(4),ledag(3), ledag(2),ledag(1), ledag(0)五个LED管中并且一一对应产生的序列值。
(2)序列检测器测试结果
当ledag(4),ledag(3), ledag(2),ledag(1),ledag(0)连接的二极管为亮、亮、灭、亮、灭时,数码管显示的数值会自动加一,说明检测到了一次待检测的序列11010。原理上在一组序列中,在检测的序列0111010011011010中有两个11010,数码管应计数到2,但因为序列是循环的产生的,所以待检测的序列便可不断的产生,在每检测到一次待检测序列后数码管上会自动的加一直至到计数器设置的上限99后自动清零,而在实际操作中正如分析结果一样,每当五个二极管为亮、亮、灭、亮、灭时,数码管便自动加一,最终加到99然后清零。理论与结果相匹配,所以实验成功。
八、实验心得体会
1、序列发生器模块:开始使用状态机的方法去设计的,经老师提点发现用状态机做的话会增加FPGA的布线,所以改进了方法,利用循环移位的思想进行设计。对应的程序是: bs<= bs(14 downto 0)&bs(15);从而妥善的解决了该问
题,说明了设计思想是有优劣之分的,同一个问题,可以有许多解决方法,但一定会有一个相对比较好的办法,因此需多思多实践。然后将最高位不断地输出到设定的五个LED二极管中,通过移动位置,便可清楚的看到序列产生的过程。当五个LED二极管出现亮、亮、灭、亮、灭时,数码管计数值加一,完成一次对待检测序列的检测。
2、序列显示移动模块:正是因为增加了该模块,所以在上面所讲的序列发生器模块产生的序列便可以通过移动位置在LED二极管中显示出来,其原理就是通过将次高位的值赋给高位的值来实现位置的移动显示的。但需要注意的是最后一位即ledag(0)是最新产生的序列值。
在序列发生器产生序列不断循环过程中出现该序列1110100,此序列中也有
一个要检测到的序列但在状态转移过程需要注意:
即当S2状态转移到S3状态时,如果此时序列值为1,则只需转移到状态本身S2而不需要转移至S0,这样即可节约转移时间也可提高检测效率,之后的状态按正常转移并且最后从状态S5回到S0。这在设计的过程中要非常注意,一旦设计出错了,设计结果将得不到意想的。由于软件中可看到状态图,所以最好相比对一下,确保设计的的正确性。
九、参考资料
《EDA技术实用教程》 潘松 黄继业 《EDA实验指导书》 丁杰 朱启标