实验四 用状态机实现序列检测器
EDA 实验报告
用状态机实现序列检测器
电信1002班 姓名:谌晴 学号:1404100320
用状态机实现序列检测器
1. 实验目的
掌握利用有限状态机实现一般时序逻辑分析的方法,了解一般状态机的设计与应用。 2. 实验内容
设计一序列检测器并在SmartSOPC 试验箱上进行硬件测试。利用Quartus II软件进行设计方真验
证,最后进行引脚锁定并完成硬件测试。用KEY5控制复位,KEY6控制状态机时钟,KEY1~KEY4控制输入待检预置数和检测预置数(检测密码),并在数码管1\2和4\5上显示。 3. 实验原理
(1) 序列检测器可用于检测有二进制码组成的脉冲序列信号。
当序列检测器连续收到一组串行二进制码后,如果这组序列码与检测器中预先设置的序列码相同,则输出1,否则输出0. 这种检测的关键是必须收到连续的正确码,所以要求序列检测器必须对前一次接收到的序列码做记忆分析,直到在连续检测中所收到的每一位二进码都与预置序列码对应相同。在检测过程中,只要有一位不相等都将回到初始状态重新开始检测。这里不考虑序列重叠的可能。 (2) 为了配合硬件测试,本实验提供了一个测试模块
(schk_test),
对模块的各端口说明如下:
Clock 系统时钟输入(48MHz )
Key[5..0] 按键输入; Disp[3..0] Sda
序列检测器检测结果输入(显示与数码管8);
串行序列码输出;
序列检测器状态机时钟输出; 序列检测器复位信号输出;
Clkout Rstout
Dat[7..0] 序列预置数输出; Led[7..0] LED输出; Seg[7..0] 数码管段输出; Dig[7..0] 数码管位输出;
该模块主要用于产生序列检测器所需的时钟、复位、串行输入序列码及预置数等信号;同时处理按键、显示等操作。
4. 实验步骤
(1) 启动Quartus II 建立一个空白工程,然后命名为
schk_top.qpf。
(2) 新建verilog HDL源程序文件schk.v ,输入程序代码并保
存,进行综合编译。若在编译过程中发现错误,则找出并更正错误,直到编译成功为止。 (3) 将光盘中的文件拷贝到工程目录。
(4) 新建图形设计文件,命名为schk_top.bdf并保存。
(5) 选择目标器件并对相应的引脚进行锁定,在这里所选择的
器件为Altera 公司Cyclone 系列的EP1C12Q240C8芯片,引脚锁定方法如下表。将未使用的引脚设置为三态输入。
(6) 将schk_top.bdf设置为顶层尸体。对该工程文件进行全程
编译处理,若在编译过程中发现错误,则找出并更正错误,直至编译成功为止。
(7) 硬件连接、下载程序。
用实验箱配置的连线将核心板上PACK 区的引脚236、237、238、239分别与数码管显示区的COM3(DIG_COM)的DIG4_DIG7相对应连接。
将跳线短接冒跳接到SmartSOPC 实验箱上的JP6的
LED0~LED7和KEY1~KEY6,使LED0~LED7和KEY1~KEY6分别与FPGA 的引脚相连。通过ByteBlaster II 下载电缆连接实验箱JTAG 口和主计算机,接通实验箱电源,执行下载命令,把程序下载到FPGA 器件中。
按KEY3\KEY4输入检测预置数(在数码管4\5上显示),假设为“11001001”(C9);按KEY1\KEY2输入待检测序列码(在数码管1\2上显示),也是“11001001”(C9)。设置好之后按KEY5复位(平时数码管8显示“0”),然后按KEY6(CLK )8次,待检测序列码串行输入,输入过程显示于LED1~LED8上。若串行输入的序列码(LED1~LED8)与预置序列码相同,数码管显示“F ”;否则仍显示“0”。更改检测预置数重复以上步骤再做验证。
5、实验结果
按KEY6(CLK )8次,LED1~LED8显示的结果分别是(假设灯亮了为1,灯没亮为0):0000-0001,0000-0011,0000-0110,0000-1100,0001-1001,0011-0010,0110-0100,1100-1001。其中在前7次中数码管8一直显示0,直到第8次输入待检测码与检测预置数相同,数码管8显示“F ”。
当预置数更改时,LED1~LED8显示的结果是预置数依次移位的结果,当串行输入的序列码(LED1~LED8)与预置序列码相同,数码管8显示“F ”;否则仍显示“0”。
附录 实验程序为: Schk 模块:
module schk(sda,clk,rst,dat,disp); input input input
sda; clk; rst;
//序列检测模块 //串行序列码输入
//时钟信号输入 //复位信号输入 //输入待检测预置数
//检测结果输出
input[7:0] dat;
output[3:0]disp;
reg[3:0] disp_r; reg[3:0] state;
//检测结果输出寄存器 //状态机寄存器
parameter S0 = 4'd0, S1 = 4'd1,
S2 = 4'd2, S3 = 4'd3, S4 = 4'd4, S5 = 4'd5, S6 = 4'd6, S7 = 4'd7, S8 = 4'd8;
//状态机参数
assign disp = disp_r;
//输出检测结果
always @(posedge clk or negedge rst)
begin if(~rst)
//复位
state
else begin case(state) S0:if(sda == dat[7]) state
default:state
endcase
end end
always @(state) begin
if(state == S8)
//状态S0 //状态S1 //状态S2 //状态S3 //状态S4 //状态S5 //状态S6 //状态S7
disp_r
else
disp_r
//序列码检测错误,输出"0"
end
endmodule
顶层模块:
module schk_test(clock,key,sda,clkout,rstout,dat,disp,led,seg,dig); //外接I/O口 input clock;
//系统时钟 //按键输入 //输出接LED
//输出接数码管段码 //输出接数码管位码
input[5:0]key; output[7:0]led; output[7:0]seg; output[7:0]dig;
//序列码检测模块I/O口 output sda;
//串行序列码输出 //产生时钟信号输出 //产生复位信号输出 //8位预置数输出 //输入检测结果
output clkout; output rstout; output[7:0]dat; input[3:0]disp;
reg[7:0]dat_r; reg[7:0]led_r;
reg[7:0]seg_r; reg[7:0]dig_r;
reg[16:0]count; reg[7:0]data;
reg[8:0]data_shift;
reg[5:0]dout1,dout2,dout3,buff; reg[2:0]cnt3;
reg[3:0]disp_dat; reg div_clk;
wire[5:0]key_edge;
assign dat = dat_r; assign led = ~led_r; assign seg = seg_r; assign dig = dig_r;
//时钟分频部分
always @(posedge clock) begin
//输出寄存器
//时钟分频计数器
//内部寄存器
//消抖寄存器
//数码管扫描计数器
//数码管扫描显存
//分频时钟, 用于消抖和扫描
//按键消抖输出
begin
count
count
//按键消抖部分 always @(posedge clock) begin
if(div_clk) begin
dout1
end
end
//按键边沿检测部分 always @(posedge clock) begin
buff
end
assign key_edge = ~(dout1 | dout2 | dout3) & buff;
//按键控制处理部分
//按键1 序列码高4位
always @(posedge clock) begin
if(key_edge[0])
//下降沿检测
data[7:4]
end
//按键2 序列码低4位
always @(posedge clock) begin
if(key_edge[1])
//下降沿检测
data[3:0]
end
always @(posedge clock) begin if(key_edge[2])
dat_r[7:4]
end
always @(posedge clock) begin if(key_edge[3])
dat_r[3:0]
end
assign rstout = buff[4];
assign clkout = buff[5];
always @(posedge clock) begin if(key_edge[4])
begin data_shift = {1'b0,data};
led_r = 8'd0;
end
//按键3 预置数高4位
//下降沿检测
//按键4 预置数低4位
//下降沿检测
//按键5 复位 //按键6 时钟
//按键5 复位
//重新装载数据
begin
data_shift = data_shift
//LED左移显示
led_r = {data_shift[8],led_r[7:1]};
end
end
assign sda = data_shift[8];
//数码管扫描显示部分 always @(posedge clock)
begin if(div_clk)
cnt3
end
always @(posedge clock) begin if(div_clk) begin
case(cnt3)
//串行序列码输出//定义上升沿触发进程
//选择扫描显示数据
3'd1:disp_dat = data[3:0]; 3'd3:disp_dat = dat[7:4]; 3'd4:disp_dat = dat[3:0]; 3'd7:disp_dat = disp; default:disp_dat = 4'h0;
//第二个数码管 //第四个数码管 //第五个数码管 //第八个数码管
endcase case(cnt3)
//选择数码管显示位 //选择第一个数码管显示 //选择第二个数码管显示 //选择第一个数码管显示 //选择第二个数码管显示 //选择第八个数码管显示
3'd0:dig_r = 8'b01111111; 3'd1:dig_r = 8'b10111111; 3'd3:dig_r = 8'b11101111; 3'd4:dig_r = 8'b11110111; 3'd7:dig_r = 8'b11111110;
default:dig_r = 8'b11111111; endcase
end
end
always @(disp_dat) begin
case(disp_dat)
//七段译码
//显示0
4'h0:seg_r = 8'hc0;
4'h1:seg_r = 8'hf9; 4'h2:seg_r = 8'ha4; 4'h3:seg_r = 8'hb0; 4'h4:seg_r = 8'h99; 4'h5:seg_r = 8'h92; 4'h6:seg_r = 8'h82; 4'h7:seg_r = 8'hf8; 4'h8:seg_r = 8'h80; 4'h9:seg_r = 8'h90; 4'ha:seg_r = 8'h88; 4'hb:seg_r = 8'h83; 4'hc:seg_r = 8'hc6; 4'hd:seg_r = 8'ha1; 4'he:seg_r = 8'h86;
4'hf:seg_r = 8'h8e;
endcase
end
endmodule
//显示1 //显示2 //显示3 //显示4 //显示5
//显示6
//显示7 //显示8 //显示9 //显示a //显示b //显示c //显示d
//显示e
//显示f