全国大学生电子设计竞赛训练教程55 常见错误及其原因分析Word格式.docx
- 文档编号:8265124
- 上传时间:2023-05-10
- 格式:DOCX
- 页数:16
- 大小:318.72KB
全国大学生电子设计竞赛训练教程55 常见错误及其原因分析Word格式.docx
《全国大学生电子设计竞赛训练教程55 常见错误及其原因分析Word格式.docx》由会员分享,可在线阅读,更多相关《全国大学生电子设计竞赛训练教程55 常见错误及其原因分析Word格式.docx(16页珍藏版)》请在冰点文库上搜索。
integer;
variabled:
integerrange0to256;
variablecnt:
std_logic_vector(3downto0);
3.CASE语句
casesegis
when"
0000"
=>
q<
="
0000001"
;
0001"
1001111"
1001"
0000100"
whenothers=>
1111111"
endcase;
初学者要紧记这些语法结构,特别注意标点符号的用法,从而避免编程时可能出现的大量小错误。
5.5.2信号与变量
信号与变量都可以用于描述器件内部结构,两者的区别如表5.5.1所示。
表5.5.1信号与变量的区别
信号
变量
基本用法
电路中的信号连线
进程中局部数据存储单元
适用范围
在整个结构体内的任何地方都能使用
只能在所定义的进程中使用
定义位置
进程外部
进程内部
赋值符号
<
=
:
多次赋值
在进程的最后才对信号赋值
立即赋值
初学编程时经常出现的错误是信号或变量的定义位置混淆,如果在进程外部定义变量,或在进程内部定义信号,综合时就会出现Unexpectedsymbolread的错误。
对信号赋值的符号是“<
=”,对变量的赋值符号是“:
=”,如例5.5.1所示。
编程时应正确使用。
【例5.5.1】
entitymulticlockis
Port(clk:
instd_logic;
ps:
outstd_logic);
endmulticlock;
architectureBehavioralofmulticlockis
signalps0:
--定义信号
begin
process(clk)
variableclk1:
integerrange0to32;
--定义变量
ifclk'
eventandclk='
1'
then
clk1:
=clk1+1;
--变量赋值
ifclk1=16then
ps0<
='
--信号赋值
elsifclk1=32then
0'
=0;
endif;
ps<
=ps0;
endprocess;
下面举例说明信号与变量用法的区别:
【例5.5.2】
entitydffis
Port(clk,d:
instd_logic;
q:
enddff;
architectureBehavioralofdffis
signala,b:
a<
=d;
b<
=a;
q<
=b;
endprocess;
endBehavioral
【例5.5.3】
entitydff1is
enddff1;
architectureBehavioralofdff1is
variablea,b:
a:
b:
例5.5.2中的三个赋值语句是并行执行的,在同一时刻中,d的值并不能立即传送到q,实际电路中,a的赋值是上一时钟周期的d,b的值是上一时钟周期的a,q的值是上一时钟周期的b,如图5.5.1所示的仿真图,q比d延时了两个时钟周期。
图5.5.1例5.5.2程序仿真图
例5.5.3由于使用了变量,它的值是立即变化的,三条赋值语句顺序执行,完成了数据的传递,得到的仿真结果如图5.5.2所示。
图5.5.2例5.3程序仿真图
5.5.3IF—ELSE语句
if—else构成的条件语句必须有严格的描述,首先要做到逻辑清晰,层次合理分明,特别注意条件的完整性,也就是说,要为所有可能发生的条件给出对应的处理方式。
例5.5.4给出两种描述一个比较器的程序:
【例5.5.4】
程序1:
entitycomp_1is
程序2:
entitycomp_2is
Port(a,b:
outstd_logic);
endcomp_1;
architectureBehavioralofcomp_1is
process(a,b)
ifa>
bthenq<
elsifa<
--遗漏条件“a=b”对应的操作
endBehavioral;
Port(a,b:
outstd_logic);
endcomp_2;
architectureBehavioralofcomp_2is
elseq<
易见,程序1忽略了当“a=b”的情况,应为else语句囊括了与if语句所描述的情形相反的全部可能。
程序2则描述了所有的情况。
从两个程序的仿真结果图5.5.3和图5.5.4也可看出,图中,当a=b时,q有两种可能取值,而图中,q只有一种取值0。
这两个程序虽然很简单,错误也很明显,但类似的逻辑上的错误往往很容易犯,因此必须特别注意。
图5.5.3例5.5程序1仿真图
图5.5.4例5.5程序2仿真图
IF-ELSE语句的嵌套也是必须十分注意的,如果嵌套的层次没有分清,逻辑混乱,就得不到预期的功能,下面看例5.5.5例和5.5.6两个程序的对比:
例5.5.5取自于一个4位数码管动态显示的驱动器,该进程完成的是一个多位的计数器功能,从最低位起开始计数,满三进一(为方便观察仿真结果,实际应用多为十进制或六进制),计数的同时输出显示。
注意该IF-ElSE的嵌套最里一层位数最高,最低位在嵌套的最外层,循环次数最多。
【例5.5.5】
entitydt1is
Port(clk:
reset:
cnta0,cntb0,cntc0,cntd0:
outstd_logic_vector(3downto0));
enddt1;
architectureBehavioralofdt1is
counter10:
process(reset,clk)
variablecnta,cntb,cntc,cntd:
std_logic_vector(3downto0);
ifreset='
then
cnta:
cntb:
cntc:
cntd:
elsifrising_edge(clk)then
ifcnta="
0011"
thencnta:
cnta0<
=cnta;
--最低位
ifcntb="
thencntb:
cntb0<
=cntb;
ifcntc="
thencntc:
cntc0<
=cntc;
ifcntd="
thencntd:
cntd0<
=cntd;
--最高位
elsecntd:
=cntd+1;
endif;
elsecntc:
=cntc+1;
endif;
elsecntb:
=cntb+1;
elsecnta:
=cnta+1;
图5.5.5例5.5.5程序仿真图
但是,如果将程序中的IF-ELSE结构改成例5.5.6所示:
【例5.5.6】
entitydt2is
enddt2;
architectureBehavioralofdt2is
endif;
ifcntb="
elsecntb:
ifcntc="
elsecntc:
ifcntd="
elsecntd:
图5.5.6例5.6.6程序仿真图
得到图5.5.6所示的仿真结果。
可见,结果不正确,因为IF语句在进程中结构是并行执行而不是顺序执行的。
5.5.4CASE语句
CASE语句与IF-ELSE语句的功能类似,在一些应用中,如编码器、译码器等,使用CASE语句更加方便。
CASE语句的使用要注意其在程序中的位置以及其起作用的时刻。
例如,为了得到一个分频系数可预置的分频器,例5.5.7和例5.5.8两个程序虽然都能通过综合,但得到的波形仿真却不同,如图5.5.7和图5.5.8。
前者的CASE语句受“clk”信号控制,实现了功能,而后者受“en”控制,得不到所需功能。
可见,CASE语句的位置不同,也会影响功能的实现。
【例5.5.7】
entitypulseis
Port(clk,en:
k:
instd_logic_vector(3downto0);
clock:
endpulse;
architectureBehavioralofpulseis
counter:
process(clk,en,k)
variablecnt0,cnt1,count:
integer:
variableclk0:
ifen='
count:
clk0:
casekis
when"
=>
cnt0:
=1;
cnt1:
=2;
when"
=3;
0010"
=6;
=3;
=4;
whenothers=>
endcase;
elsifclk'
=count+1;
ifcount=cnt0then
elsifcount=cnt1then
clk0:
clock<
=clk0;
endprocesscounter;
【例5.5.8】
entitypulsepis
endpulsep;
architectureBehavioralofpulsepis
ifen='
elsifclk'
casekis
when"
endcase;
endprocesscounter;
图5.5.7例5.5.7仿真图
图5.5.8例5.5.8仿真图
5.5.5多时钟源的解决方案
有时,在同一个实体中往往使用多个进程,而每个进程使用不同的时钟源驱动时,就会发生错误。
例如,由分频器产生多个不同频率的时钟脉冲去控制不同的部件时,如果每个进程都采用“ifclk’eventandclk=’1’then”这样的格式来描述时钟上升沿,综合将无法进行。
此时,可以用rising_edge来描述分频后得到的时钟的上升沿,就不会出错。
libraryIEEE;
useIEEE.STD_LOGIC_1164.ALL;
useIEEE.STD_LOGIC_ARITH.ALL;
useIEEE.STD_LOGIC_UNSIGNED.ALL;
d0,d1:
q0,q1:
signalclka,clke:
main:
process(clk)
variablecount0,count1:
variableclk0,clk1:
begin
ifclk'
count0:
=count0+1;
count1:
=count1+1;
ifcount1=16then
clk1:
elsifcount1=32then
count1:
clk1:
ifcount0=8then
elsifcount0=16then
clka<
clke<
=clk1;
endprocessmain;
second:
process(clka)
ifclka'
eventandclka='
q0<
=d0;
endprocesssecond;
third:
process(clke)
ifclke'
eventandclke='
q1<
=d1;
5.5.6仿真无波形
综合成功后进行波形仿真时常常会看不到波形,一般有两种可能:
第一种是仿真周期太长而无法看到,一般见于分频器或计数器中。
对一个32MHz的晶振进行分频,要求得到1Hz的信号。
这时要等32兆个CLK波形才能看到输出有跳变,在仿真图上当然是无法看到的,如果将分频系数减小,例如8分频,就可以看到仿真波形了。
一般分频系数大于几百时就会出现这种现象。
第二种是出现不定态(UNKNOWN),设计分频器时有这种情况,一般是由于没有对变量或信号进行初始化引起的,例如STD_LOGIC有七种逻辑状态,如果不指定其初始值是“0”还是“1”,系统就无法确定。
如例5.5.9及其仿真结果(图5.5.9)所示。
【例5.5.9】
Port(clk:
instd_logic;
c:
process(clk)
variabledd:
integer;
dd:
=dd+1;
ifdd=4thenc<
elsifdd=8thenc<
图5.5.9例5.5.9仿真图(无输出波形)
为解决该问题,可以在定义变量或信号时指定其初始状态。
将例中的“variabledd:
”改为“variabledd:
integer:
”,就能得到如图5.5.10所示的波形了。
图5.5.10例5.9改正后的仿真图(正确的波形)
另一种办法是增加一个清零或置位信号,通过一个清零或置位信号对信号或变量进行初始化,如例5.5.10所示。
得到的结果如图5.5.10所示。
【例5.5.10】
entitypppis
Port(clk,en:
endppp;
architectureBehavioralofpppis
process(clk,en)
ifen='
thendd:
--增加了清零信号
elsifclk'
dd:
图5.5.11例5.50程序仿真图
5.5.7执行时端口丢失
当综合与仿真完成后,就要进行引脚锁定(EditImplementationConstraite),执行引脚锁定时,有时会发现Port表找不到某些定义过的端口。
例如下面一段程序:
【例5.5.11】
entityloseportis
endloseport;
architectureBehavioralofloseportis
integerrange0to256;
--变量范围
ifdd=612then--分频系数
c<
elsifdd=1024then
综合后出现这样的警告:
WARNING:
Xst:
646-Signal<
dd>
isassignedbutneverused.
Foun
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 全国大学生电子设计竞赛训练教程55 常见错误及其原因分析 全国大学生 电子设计 竞赛 训练 教程 55 常见 错误 及其 原因 分析