2014-2015-2-G02A3050-1
电子电路设计训练(数字EDA部分)
实验报告
( 2015 年5 月 20 日)
教学班
学号 姓名 组长 签名 成绩
自动化科学与电气工程学院
目 录
目 录 .............................................................................................................................................. 1 实验一、简单组合逻辑和简单时序逻辑 ....................................................................................... 1
1.1 实验任务1——简单组合逻辑 ................................................................................. 1
1.1.1 实验要求 ......................................................................................................... 1 1.1.2 模块的核心逻辑设计 ..................................................................................... 1 1.1.3 测试程序的核心逻辑设计 ............................................................................. 1 1.1.4 仿真实验关键结果及其解释 ......................................................................... 2 1.2 实验任务2——简单时序逻辑 ................................................................................. 3
1.2.1 实验要求 ......................................................................................................... 3 1.2.2 模块的核心逻辑设计 ..................................................................................... 3 1.2.3 测试程序的核心逻辑设计 ............................................................................. 3 1.2.4 仿真实验关键结果及其解释 ......................................................................... 4 1.3 实验小结 .................................................................................................................... 4
实验二、条件语句和always过程块 .............................................................................................. 5
2.1 实验任务1——利用条件语句实现计数分频时序电路 ......................................... 5
2.1.1 实验要求 ......................................................................................................... 5 2.1.2 模块的核心逻辑设计 ..................................................................................... 5 2.1.3 测试程序的核心逻辑设计 ............................................................................. 6 2.1.4 仿真实验关键结果及其解释 ......................................................................... 7 2.2 实验任务2——用always块实现较复杂的组合逻辑电路 .................................... 8
2.2.1 实验要求 ......................................................................................................... 8 2.2.2 模块的核心逻辑设计 ..................................................................................... 8 2.2.3 测试程序的核心逻辑设计 ............................................................................. 9 2.2.4 仿真实验关键结果及其解释 ....................................................................... 10 2.3 实验小结 .................................................................................................................. 11
实验三、赋值、函数和任务 ......................................................................................................... 12
3.1 实验任务1——阻塞赋值与非阻塞赋值的区别 ................................................... 12
3.1.1 实验要求 ....................................................................................................... 12 3.1.2 模块的核心逻辑设计 ................................................................................... 12 3.1.3 测试程序的核心逻辑设计 ........................................................................... 13 3.1.4 仿真实验关键结果及其解释 ....................................................................... 14 3.2 实验任务2——在Verilog HDL中使用函数 .......................................................... 16
3.2.1 实验要求 ....................................................................................................... 16 3.2.2 模块的核心逻辑设计 ................................................................................... 16 3.2.3 测试程序的核心逻辑设计 ........................................................................... 18 3.2.4 仿真实验关键结果及其解释 ....................................................................... 19 3.3 实验任务3——在Verilog HDL中使用任务 .......................................................... 20
3.3.1 实验要求 ....................................................................................................... 20 3.3.2 模块的核心逻辑设计 ................................................................................... 20 3.2.3 测试程序的核心逻辑设计 ........................................................................... 21
3.2.4 仿真实验关键结果及其解释 ....................................................................... 22 3.3 实验小结 .................................................................................................................. 22
实验四、有限状态机 ..................................................................................................................... 23
4.1 实验任务1——基于状态机的串行数据检测器 ................................................... 23
4.1.1 实验要求 ....................................................................................................... 23 4.1.2 模块的核心逻辑设计 ................................................................................... 23 4.1.3 测试程序的核心逻辑设计 ........................................................................... 25 4.1.4 仿真实验关键结果及其解释 ....................................................................... 26 4.2 实验任务2——楼梯灯 ........................................................................................... 26
4.2.1 实验要求 ....................................................................................................... 26 4.2.2 模块的核心逻辑设计 ................................................................................... 27 4.2.3 测试程序的核心逻辑设计 ........................................................................... 31 4.2.4 仿真实验关键结果及其解释 ....................................................................... 32 4.3 实验小结 .................................................................................................................. 34
实验一、简单组合逻辑和简单时序逻辑
1.1 实验任务1——简单组合逻辑
1.1.1 实验要求
(1)设计一个两位数据比较器,比较两个数据a和b。若两数据相同,则给出结果1,否则给出结果0。
(2)设计一个字节(8位)的比较器,比较两个字节a[7:0]和b[7:0]的大小。若a大于b,则输出高电平,否则输出低电平。
1.1.2 模块的核心逻辑设计
(1)两位数据比较器
assign equal=(a==b)?1:0; //用连续赋值语句assign对结果equal赋值,a=b时,equal输出为1,否则为0
(2)字节数据比较器
assign res=(a>b)?1:0; //用连续语句assign对结果equal赋值,a>b时equal输出为1,否则输出为0
1.1.3 测试程序的核心逻辑设计
(1)两位数据比较器
always #50 clock=~clock; //产生周期性跳变的时钟,50个时间单位跳变一次 always@(negedge clock) //always后的语句表示时序控制,每次时钟下降沿时刻产生不同的a和b
begin
a={$random}%2;
b={$random}%2; //每次随机产生a和b end
1
initial
begin #100000000 $stop; end //系统任务,暂停仿真以观察波形 (2)字节数据比较器 a={$random}%6;
b={$random}%6; //a和b从0~255共256个数中随机产生,即可生成8位字节数据
1.1.4 仿真实验关键结果及其解释
(1)两位数据比较器
图 1两位数据比较器波形图
如图1所示,a和b相同时equal输出为高电平,否则输出低电平。 (2)字节数据比较器
图 2 字节数据比较器波形图
2
如图2所示,a>b时,res输出高电平,否则res输出低电平。
1.2 实验任务2——简单时序逻辑
1.2.1 实验要求
设计一个分频器,将时钟波形二分频。
1.2.2 模块的核心逻辑设计
always@(posedge clk_in) //always语句后表示时序控制,每次clk_in时钟上升沿时刻进行动作
begin
if(! reset) clk_out=0; //reset信号为低电平时,输出清零
else clk_out=~clk_out; //reset为高电平时,输出时钟clk_out在输入时钟clk_in的上升沿时刻翻转
end
1.2.3 测试程序的核心逻辑设计
always #`clk_cycle clk=~clk; //产生输入时钟 initial begin clk=0; reset=1;
#10 reset=0; //reset给低电平,输出清零 #110 reset=1; //reset复位
#100000 $stop; //系统任务,暂停仿真以便观察波形 end
3
1.2.4 仿真实验关键结果及其解释
图 3 二分频器的波形图
如图3所示,输入时钟clk被二分频输出。
1.3 实验小结
通过实验一,我掌握了如下内容: 1)assign连续赋值语句的使用。 2)always, initial块的使用。 3)reg, wire等数据类型的适用范围 4)调用被测试模块的方法
4
实验二、条件语句和always过程块
2.1 实验任务1——利用条件语句实现计数分频时序电路
2.1.1 实验要求
(1)设计20分频计数器,将10MHz的时钟分频为500kHz的时钟。 (2)利用10MHz的时钟,设计一个给定单周期形状的周期波形。
2.1.2 模块的核心逻辑设计
(1)20分频计数器 begin
if(j==9) //对计数器进行判断,计十个数翻转一次,则一个周期计20个数,即实现20分频 begin
j<=0; //输出时钟翻转的同时计数器置零 F500K<=~F500K; end else
j<=j+1; //若还没计到十个数,继续计数 end
(2)给定单周期形状的波形 begin
if(j<=20)
begin
FDIV<=0;
j<=j+1; //前20个输入时钟周期,计数器计数,但输出不跳变 end
else if((j>20)&&(j<=30))
5
begin
FDIV<=1;
j<=j+1; //中间10个时钟周期输出跳变成高电平,保持计数 end
else if((j>30)&&(j<=50))
begin FDIV<=0;
j<=j+1; //后20个时钟周期输出跳变成低电平,保持计数
end else
j<=0; //计数器清零
end
2.1.3 测试程序的核心逻辑设计
(1)20分频计数器
always #`clk_cycle F10M_clk=~F10M_clk; //产生输入的10MHz时钟
initial
begin end
RESET=1; F10M_clk=0;
#100 RESET=0; //reset给低电平,输出清零 #100 RESET=1; //reset复位
#10000 $stop; //系统任务,暂停仿真以便观察波形
(2)给定单周期形状的波形 begin
RESET=1; F10M_clk=0; #100 RESET=0;
6
#100 RESET=1; #100000 $stop;
end //与(1)一致
2.1.4 仿真实验关键结果及其解释
(1)20分频计数器
图 4 20分频计数器波形图
如图4所示,10MHz的时钟F10M被20分频成500kHz的时钟F500k。 (2)给定单周期形状的波形
图 5 给定单周期形状的波形图
如图5所示,生成了题目要求形状的周期波形图。
7
2.2 实验任务2——用always块实现较复杂的组合逻辑电路
2.2.1 实验要求
(1)设计一个指令译码电路,对输入数据执行相应的操作,包括加、减、与、或和求反。
(2)运用always块设计一个8路数据选择器。要求:每路输入数据与输出数据均为4位2进制数,当选择开关(至少3位)或输入数据发生变化时,输出数据也相应变化。
2.2.2 模块的核心逻辑设计
(1)指令译码电路
always@(opcode or a or b) //电平敏感的always块,当输入数据a,b或控制信号opcode变化时,输出发生变化
begin
case(opcode)
`plus: out=a+b; //控制信号为'plus时,输出等于a+b `minus: out=a-b; //控制信号为'minus时,输出等于a-b `band: out=a&b; //控制信号为'band时,输出等于a&b `bor: out=a|b; //控制信号为'bor时,输出等于a|b `unegate:out=~a; //控制信号为'unegate时,输出等于~a default: out=8'hx; //未收到指令时,输出任意态 endcase
(2)8路数据选择器
always@(ctl or a0 or a1 or a2 or a3 or a4 or a5 or a6 or a7) //电平敏感模块,控制信号ctl或输入a0~a7变化时,输出发生变化
begin case(ctl)
`ctl0: out=a0;
8
`ctl1: out=a1; `ctl2: out=a2; `ctl3: out=a3; `ctl4: out=a4; `ctl5: out=a5; `ctl6: out=a6;
`ctl7: out=a7; //控制端为ctl0~ctl7对应输出a0~a7 default: out=4'dx; //未收到指令时,输出任意态 endcase
2.2.3 测试程序的核心逻辑设计
(1)指令译码电路 begin
a={$random}%6; //从0~255共256个数中随机生成一个数作为输入a b={$random}%6; //从0~255共256个数中随机生成一个数作为输入b opcode=3'h0; //控制信号设为初值0,即'plus,求和 repeat(times) //repeat循环语句使控制及输入信号重复变化
begin
#100 a={$random}%6;
b={$random}%6;
opcode=opcode+1; //每一时钟到来时,输入a,b改变一随机数,
控制信号+1
end
#100 $stop; //系统任务,暂停仿真以观察输出波形 end
(2)8路数据选择器 begin
a0={$random}; a1={$random};
9
a2={$random}; a3={$random}; a4={$random}; a5={$random}; a6={$random};
a7={$random}; //从0~15中随机生成输入a0~a7 ctl=3'd0; //控制端置ctl0
repeat(times) //repeat语句重复改变输入 begin
#100 a0={$random}; a1={$random}; a2={$random}; a3={$random}; a4={$random}; a5={$random}; a6={$random};
a7={$random}; //随机生成a0~a7 ctl=ctl+1; //控制端每次加1 end #100 $stop; end
2.2.4 仿真实验关键结果及其解释
(1)指令译码电路
10
图 6 指令译码电路波形
指令译码电路输出波形如图所示。控制信号opcode为0时,输出为a+b;控制信号opcode为1时,输出为a-b;......以此类推。
(2)8路数据选择器
图 7 8选1数据选择器波形图
8路数据选择器输出波形如图7所示,控制端ctl为0~7时对应输出a0~a7。
2.3 实验小结
通过实验二,我掌握了如下内容: 1)if...else条件语句的使用。 2)case条件语句的使用
11
实验三、赋值、函数和任务
3.1 实验任务1——阻塞赋值与非阻塞赋值的区别
3.1.1 实验要求
本实验中两个模块\和\分别采用阻塞赋值和非阻塞赋值语句,从实验结果比较他们的区别。
3.1.2 模块的核心逻辑设计
(1)阻塞赋值 always@(posedge clk) begin b=a;
c=b; //阻塞赋值,a赋给b,b赋给c
$display(\//在Transcript窗口中显示赋值后a,b,c的值
end
(2)非阻塞赋值 always@(posedge clk) begin b<=a;
c<=b; //非阻塞赋值,a赋给b,b赋给c
$display(\b=%d, c=%d.\ //在Transcript窗口中显示赋值后a,b,c的值
end
(3)改变阻塞赋值程序的写法,再比较二者的区别(测试程序仅改变调用的阻塞赋值模块)
always@(posedge clk)
12
begin c=b;
b=a; //改变阻塞赋值的顺序,b赋给c,a赋给b $display(\ end
(3)再改变阻塞赋值程序的写法,比较二者的区别(测试程序仅改变调用的阻塞赋值模块)
always@(posedge clk) b=a; always@(posedge clk) c=b;
3.1.3 测试程序的核心逻辑设计
将阻塞与非阻塞赋值模块用同一测试程序测试,比较其输出的不同。 begin a=4'h3;
$display(\ #100 a=4'h7;
$display(\ #100 a=4'hf;
$display(\ #100 a=4'ha;
$display(\ #100 a=4'h2;
$display(\
#100 $display(\ //每隔100个时间单位改变一次输入a的值,并显示输出
$stop; end
blocking blocking(clk,a,b1,c1); //阻塞赋值输出用b1,c1表示
non_blocking non_blocking(clk,a,b2,c2); //非阻塞赋值输出用b2,c2表示
13
3.1.4 仿真实验关键结果及其解释
(1)阻塞赋值写法1
图 8 阻塞与非阻塞赋值比较波形图
图 9 阻塞与非阻塞赋值输出结果
如图8所示,b1,c1为阻塞赋值输出,输入a的值改变时,输出b的值随之改变,同时b的值赋给c,即赋值语句执行完后输出b, c值立即改变,然后块才结束。b2,c2为非阻塞赋值输出,赋值语句之后输出b, c的值并不立即改变,而是在块结束后才进行赋值操作,当下一时钟上升沿到来时,上一个a值才赋给b,同时上一b值赋给c。以上即阻塞与非阻塞赋值的区别。
a和b的输出结果如图9所示。 (2)阻塞赋值写法2
14
图 10 阻塞赋值程序变形1波形图
图 11 阻塞赋值程序变形1输出结果
改变阻塞赋值程序后的波形图如图10所示,可见将b=a, c=b的顺序调换之后,阻塞赋值程序先将上一次时钟上升沿时b的值赋给c,再将这一次时钟上升沿时a的值赋给b,即b与a同时变化但c的值是上一个b值。在波形图上看,由于输入a的变化时刻对应的是时钟下降沿,而输出要在下一时钟上升沿才能显示,故阻塞与非阻塞输出c在波形图上看是一致的,实际上在时钟下降沿a发生变化时,阻塞输出c的值已经发生变化。输出结果如图11
(3)阻塞赋值写法3
15
图 12 阻塞赋值程序变形2波形图
图 13 阻塞赋值程序变形2输出结果
阻塞赋值程序变形2的输出波形与结果如图12、图13所示。由于两个阻塞操作用同一个时钟沿触发,执行顺序是不确定的。
3.2 实验任务2——在Verilog HDL中使用函数
3.2.1 实验要求
(1)设计程序实现函数调用
(2)设计一个带控制端的逻辑运算电路,分别完成正整数的平方、立方和最大数为5的阶乘运算。
3.2.2 模块的核心逻辑设计
(1)设计程序实现函数调用
16
always@(posedge clk) //clk上升沿触发同步运算 begin if(!reset)
result<=0; //reset为低时复位 else begin
result<=n*factorial(n)/((n*2)+1); //调用factorial函数,verilog在整数除法运算结果中不考虑余数
end end
function[31:0] factorial; //函数定义,返回一个32位的数 input[3:0] operand; //输入一个4位操作数 reg[3:0] index; //函数内部计数用中间变量 begin
factorial=operand?1:0; //操作数为0时函数输出为0,否则为1 for(index=2;index<=operand;index=index+1) end endfunction
(2)带控制端的逻辑运算电路 always@(posedge clk) begin if(!reset) result<=0; else begin
if(sel==0) result<=n*n; //控制端输入sel=0时,执行平方操作 else if(sel==1) result<=n*n*n; //控制端输入sel=1时,执行立方操作 else if(sel==2&&n<=5) result<=factorial(n); //控制端输入sel=2且
17
factorial=index*factorial; //表示阶乘的迭代运算
输入n小于等于5时,计算n!
else result<=factorial(5); //否则计算5! end end
function[31:0] factorial; //函数定义,返回一个32位的数 input[3:0] operand; //输入一个4位操作数 reg[3:0] index; //函数内部计数用中间变量 begin
factorial=operand?1:0; //操作数为0时函数输出为0,否则为1
for(index=2;index<=operand;index=index+1)
factorial=index*factorial; //表示阶乘的迭代运算 end
3.2.3 测试程序的核心逻辑设计
(1)设计程序实现函数调用 initial begin
clk=0; n=0; reset=1;
#100 reset=0; //产生复位信号的负跳变沿 #100 reset=1; //复位信号恢复高电平后输入n
for(i=0;i<=15;i=i+1) begin
#200 n=i; //用循环结构,每隔200个时钟周期改变一次输入n的值
end
#100 $stop;
end
(2)带控制端的逻辑运算电路
18
begin clk=0; n=0; reset=1;
#100 reset=0; //产生复位信号的负跳变沿 #100 reset=1; //复位信号恢复高电平后输入n for(i=0;i<=15;i=i+1) begin
#200 sel={$random}%3;
n={$random}; //用循环结构,每隔200个时钟周期改变一
次控制端sel和输入n的值,n从0~15中随机生成
end #100 $stop; end
3.2.4 仿真实验关键结果及其解释
(1)设计程序实现函数调用
图 14 函数调用输出结果波形图
调用函数实现的运算输出结果波形如图14所示。通过调用函数实现了
result?n?n!的结果输出。(由于输入n, i为4位二进制数,计算机默认为补码2n?1形式,若以十进制显示,9~15将显示负值,为避免混乱,输入用二进制显示)。
19
(2)带控制端的逻辑运算电路
图 15 带控制端的逻辑运算电路输出结果波形图
逻辑运算电路输出结果波形如图15所示。从图中可见,输入n=4,控制端sel=2,输出result=4!=24;输入n=11,控制端sel=1,输出result?113?1331;输入n=13,控制端sel=2,输出result=5!=120;输入n=4,控制端sel=0,输出
result?42?16。
3.3 实验任务3——在Verilog HDL中使用任务
3.3.1 实验要求
使用任务设计4个4位并行输入数的排序组合逻辑。
3.3.2 模块的核心逻辑设计
always@(a or b or c or d) begin
{va,vb,vc,vd}={a,b,c,d}; rank2(va,vb); rank2(va,vc); rank2(va,vd); rank2(vb,vc);
20
rank2(vb,vd); rank2(vc,vd);
{ra,rb,rc,rd}={va,vb,vc,vd}; //用选择排序法排序 end
task rank2; //执行排序算法的任务 inout[3:0] x,y; reg[3:0] tmp; if(x>y) begin tmp=x; x=y;
y=tmp; //x与y变量内容互换,要求顺序执行,采用阻塞赋值方式 end endtask
(实验指导书上采用快速排序算法,我对快速排序不熟悉,故采用选择排序算法)
3.2.3 测试程序的核心逻辑设计
begin
a=0;b=0;c=0;d=0; repeat(50) begin
#100 a={$random}; b={$random}; c={$random};
d={$random}; //随机生成参与排序的数a,b,c,d end
21
3.2.4 仿真实验关键结果及其解释
图 16 使用任务进行排序输出波形
使用任务进行排序得到的输出波形如图16所示。输出以16进制显示,可见排序功能实现正确。
3.3 实验小结
通过实验三,我掌握了如下内容:
(1)深入理解了阻塞与非阻塞赋值的区别。
(2)掌握了在Verilog HDL中使用函数的方法,进一步熟悉了if...else和case分支结构的使用。
(3)掌握了用repeat语句实现for循环结构的方法。
(4)掌握了在Verilog HDL中使用任务的方法,回顾了排序算法。
22
实验四、有限状态机
4.1 实验任务1——基于状态机的串行数据检测器
4.1.1 实验要求
设计一个串行数据监测器。要求是:连续4个或4个以上为1时输出1,其他情况下输出0。
4.1.2 模块的核心逻辑设计
always@(posedge clk) if(!rst) state<=Q0; else
state<=nextstate; //复位端为0时输出状态置零,复位端为1时输出状态始终向下一状态变化
always@(state or x) case(state) Q0: if(x==1) nextstate=Q1;
else
nextstate=Q0; Q1: if(x==1) nextstate=Q2; else
nextstate=Q0; Q2: if(x==1) nextstate=Q3;
23
else
nextstate=Q0; Q3: if(x==1) nextstate=Q4; else
nextstate=Q0; Q4: if(x==1)
nextstate=Q4; else
nextstate=Q0;
default nextstate=Q0;
endcase //状态转移的条件判断部分,转移逻辑见状态图 always@(state or rst or x) if(!rst) Y=0; else
if(state==Q4&&x==1) Y=1; else
Y=0; //输出的条件判断部分,输出逻辑见状态图 状态图如图17所示:
24
图 17 \状态机状态图
4.1.3 测试程序的核心逻辑设计
always@(posedge clk)
data={data[22:0],data[23]}; initial begin clk=0; rst=1; #5 rst=0; #30 rst=1;
data='b1011_1110_0010_1111_1110; //待检测的数字序列 #500 $stop; end
25
4.1.4 仿真实验关键结果及其解释
图 18 \序列检测输出波形1
图 19 \序列检测输出波形2
图18、图19为“1111”序列检测的输出波形。由输出波形可见,当检测到第一段“1111”后输出Y翻转,输出为1,当再次输入0时输出复位为0;监测到第二段“1111”后输出Y又变为1,且当输入在“1111”后保持为1时,输出也保持为1。
4.2 实验任务2——楼梯灯
4.2.1 实验要求
楼下到楼上依次有3个感应灯:灯1、灯2、灯3。当行人上下楼梯时,各个灯感应到后自动点亮,若在8s内感应信号消失,则点亮8s,若感应信号存在
26
时间超过8s,则感应信号消失4s后灯自动关闭。
基本任务:
(1)做出如上逻辑电路并仿真。
(2)设感应信号是电平信号,考虑去抖情况,对于感应信号到达存在毛刺(小于0.5s),设计合适逻辑并剔除。
扩展任务:
(3)若为节约能源,下一个灯点亮的同时将自动关闭上一个灯,作出如上逻辑设计并仿真(仅考虑一个人的情况)。
(4)考虑存在多个人上下楼梯的情况,比如:
行人1已经从灯1到达灯2,灯2受感应自动点亮,但此时行人2刚上楼梯到达灯1的位置,则灯1和灯2都须点亮。
更加复杂一点,如果行人2是下楼梯刚到达灯3位置,作出如上逻辑设计并仿真。
4.2.2 模块的核心逻辑设计
(1)基本任务 对一盏灯进行建模
always @ ( posedge clock or negedge reset_n) begin if ( ! reset_n ) begin state <= OFF ; end
else begin // reset信号为0时,关灯;reset信号为1时,开始执行 case ( state ) OFF: begin
count <= 0 ; state <= nstate ; end
ON: begin
if ( nstate == LONG ) count <= 0 ;
27
else count <= count + 1 ; state <= nstate ; end
LONG: begin
if ( nstate == LONG ) count <=0 ; state <= nstate ; end
DELAY_LONG: begin
if ( nstate == DELAY_LONG ) count = count + 1 ; state <= nstate ; end
DELAY_SHORT: begin
if ( nstate == DELAY_SHORT ) count <= count + 1 ; else count <= 0 ; state <= nstate ; end
default : state <= OFF ;
endcase //二段式中的第一段,给出各状态跳变到下一状态的条件 end end
always @ ( state or switch or count ) begin case ( state )
OFF:
if ( switch ) nstate = ON ; ON: if ( switch )
if ( count < NUM_WAIT-1 ) nstate = ON ; else nstate = LONG ; else nstate = DELAY_SHORT ;
28
LONG:
if ( switch ) nstate = LONG ;
else nstate = DELAY_LONG ;
DELAY_LONG: if ( switch ) nstate = ON ;
else if ( tolerance < NUM_DELAY-1 ) nstate = DELAY_LONG ; else if ( count < NUM_DELAY-1 ) nstate = DELAY_LONG ; else nstate = OFF ;
DELAY_SHORT:
if ( switch ) nstate = ON ;
else if ( count < NUM_WAIT-1 ) nstate = DELAY_SHORT ; else nstate = OFF ; default: nstate = OFF;
endcase
end //二段式中的第二段,判断各状态时满足条件的下一状态是哪个状态
assign light = ( state == OFF )? 0 : 1 ; //light为输出变量,表示灯的亮灭,OFF为0时灯亮,OFF为1时灯灭
(2)去抖任务
assign filtered = ( state == INACTIVE ) ? 0 : 1 ; assign out = filtered || in ; ACTIVE :
if ( !in ) begin state <= PENDING ; count <= 0 ; end PENDING : begin
if ( in ) state <= ACTIVE ; else if ( count < NUM_JITTER-1) count <= count + 1 ;
else if(count >=NUM_JITTER-1&&(!in)) state=INACTIVE;
29
else state <= INACTIVE ;
end //老师的程序只做了当原输出状态为1(亮灯)时的去抖,方法时当原输出状态为1且有0输入时增加一个PENDING状态,判断输入信号的持续时间是否大于0.5s,若小于0.5s,则认为是ACTIVE状态,即忽略扰动,否则认为是INACTIVE状态,输出变化。而输出是由filtered变量和输入in共同控制的,filtered==ACTIVE,通过assign连续赋值语句,使输出为in||filtered,从而实现原状态为1时的防抖。我尝试了设计原状态为0的防抖,但效果不佳,代码如下:
always @ ( posedge clock ) begin if(state==INACTIVE) out<=0; else if(state==ACTIVE) out<=1; else out<=0; end ...
INACTIVE : if ( in ) begin
state <= PENDING1 ; count<=0; end ...
PENDING1:begin
if(!in) state<=INACTIVE; else if(count < NUM_JITTER-1) count <= count + 1 ;
else if(count >=NUM_JITTER-1&&(in)) state=ACTIVE; else state<=ACTIVE;
end //我尝试在INACTIVE状态下增加一个等待判断状态PENDING1,且输出采用always块给寄存器变量赋值的形式,但效果不佳,见结果分析部分
30
4.2.3 测试程序的核心逻辑设计
(1)基本任务 仅测试一盏灯:
initial begin // 短开关信号测试 switch = 0 ; #100 switch = 1 ;
#20 switch = 0 ; //第一个开关信号持续2s #100 switch = 1 ; //10s后第二个开关信号到来 #30 switch = 0 ; //第二个开关信号持续3s #40 switch = 1 ; // 4s后又一开关信号到来 #60 switch = 0 ;
//长开关信号测试 #50 switch = 1 ;
#99.5 switch = 0 ; // 第一个开关信号持续9.95s #50.5 switch = 1 ; // 5.05s后第二个开关信号到来 #90 switch = 0 ; //第二个开关信号持续9s #30 switch = 1 ; // 3s后第二个开关信号到来 #10 switch = 0 ; //10s后开关信号结束 //SUM = 330 end
三盏灯的测试只需在测试程序中调用3个单盏灯测试程序,且开关信号分为switch[1]~switch[3],表示灯的亮灭的输出变量分为light[1]~light[3]。
(2)防抖任务 initial begin clock = 0 ; in = 0 ; #10 in = 1 ; #50 in = 0 ; #3 in = 1 ;
31
#12 in = 0 ; #20 in = 1 ; #10 in = 0 ; #8 in = 1 ; #2 in = 0 ; #8 in=1; #3 in=0;
#50 $stop ; end
4.2.4 仿真实验关键结果及其解释
(1)基本任务
图 20 开关信号持续时间小于8s的情况
图 21 开关信号持续时间大于8s的情况
32
只对一盏灯进行控制和测试时,开关信号持续时间小于或大于8s的情况分别如图20、图21所示。图20中,红色光标线处开始有一开关信号,持续时间2s,对应亮灯信号则在开关信号到来时跳变成1,持续8s后跳变回0。图21中,红色光标处开始的开关信号持续时间为9.95s,则对应亮灯信号在开关信号消失后再持续4s才跳变回0。
(2)去抖任务
图 22用连续赋值的方法设计的去抖程序
图 23 用always块赋值方法
对老师的程序稍作改变的结果如图22所示,显然,由于输出为filtered||in,故当有in=1抖动输入时输出依然会跳变,只是随抖动结束输出也跳变回0。
增加一个状态并用always块赋值得到的结果如图23。由图中可见,这种方法对原输入状态为0时的防抖功能实现较好,但反而对原状态为1时效果不好,不仅没有实现防抖,在真正输入跳变时输出的跟随也变慢了。
由于时间不足,我没能深入研究产生上述现象的原因并找出解决办法,也没
33
有做任务(3)、(4),望老师见谅。
4.3 实验小结
通过实验4,我学习了有限状态机的使用,尝试用有限状态机解决比较复杂的楼梯灯问题。但由于时间不足,我只是在理解的基础上采用了老师给的程序,想对其作出改进但并不成功。如果日后有时间的话,我会再研究一下这个问题,希望能够找到解决方法。
34