pld运动计时器实验报告|555计时器实验报告
时间:2020-08-20 12:44:57 来源:天一资源网 本文已影响 人
PLD与数字系统设计实验报告
--设计性实验报告(运动计时器
1、实验说明:
作为Verilog语言的初学者,此次报告全面的展示了计时器实验设计的过程,总结了自己学习的一些内容。计时器设计的实现方法比较多,本设计的创新点主要有以下方面:
= 1 \* GB3 ①使用了硬件描述语言和原理图混合输入的方式,进行模块化设计,生成电路元件符号,设计方法比较直观,方便其他实验进行模块调用。
= 2 \* GB3 ②计时器的暂停\开始功能的控制,使用StateCAD图像化的设计方式,利用状态机实现该模块的设计。
1.1 实验要求
使用Xilinx公司的Spartan3S 400AN开发板上的相关模块,利用ISE开发软件完成运动计时器的设计,要求实现如下功能:
(1)在LED数码管上显示分钟和秒,最长的计时时间为59:59。
(2)自定义清零按键,按下该按键,在数码管上显示的时间为00:00。
(3)自定义启动/暂停按键,按下该按键,则启动或暂停计时器计时。其功能与实际的计时器的开始/停止按钮功能相同。
1.2 实验工具
XUP(FPGA:Spartan3S400AN)实验开发板
Xilinx软件ISE13.4开发软件
二、实验分析设计过程
实验设计理念主要为自顶向下的设计方法,这也是数字系统设计中最常用的设计方法,也是基于芯片的系统设计的主要方法。它的基本原理框图如下:
图 1 设计方法框图
自顶向下的设计方法利用功能分割手段将设计由上到下进行层次化和模块化,即分层次、分模块进行设计和仿真。功能分割时,将系统功能分解为功能块,功能块再分解为逻辑块,逻辑块再分解为更少的逻辑块和电路。如此分割,逐步的将系统细化,将功能逐步具体化,模块化。高层次设计进行功能和接口描述,说明模块的功能和接口,模块功能的更详细描述在下一设计层次说明,最底层的设计才涉及具体寄存器和逻辑门电路等实现方式的描述。
2.1 各模块描述语言的实现
本实验采用硬件描述语言和电路原理图混合输入的方式实现,用Verilog描述语言分别产生计数、显示和控制模块,然后将这些模块生成电路符号并构成一个顶层电路原理图,这种方法使用方便,设计也比较直观,并且生成的功能模块方便其他设计的调用。下面是每个模块设计的思路:
2.1.1 计时模块的设计
本模块的设计类似于数字时钟的方法,秒、分都是60 进制计数,采用了 6 进制计数器与10 进制计数器的组合实现;控制逻辑主要是用来实现计数和清零。
首先,要由系统时钟(50Mhz)分频得到秒信号,秒时钟累加即可得到分钟信号,分频方案主要有以下两种:
占空比1:1方波信号
分频效果如下图所示,(这里为了仿真的方便改变计数器的数值)
图 2 秒信号(方波形式)
非方波形式
从50Mhz的时钟信号分频,得到秒信号高电平的脉冲宽度为分频时钟的一个周期,控制秒钟加1。
图 3 秒信号(非方波形式)
本实验采用第二种分频方式,主要是为了防止在进行综合的时候出现分频信号向系统时钟偏移(clock skew)的警告,一般遵循使用一个时钟域几个使能域优于多个全局时钟域的规则。
图4 时钟偏移的考虑
其次,用分频出的秒信号,作为计数模块秒低位计数器的触发信号,依此完成秒高位、分低位、分高位的计数功能。其实现方法是使用四个always进程模块,分别对计时器的四位计数,由于always进程是并行的,因此可以提高程序运行的效率。对其仿真结果如下所示:
图 5 计数器仿真
上图是计数器仿真部分截图,从图中数据看到,计数器功能正常。此模块所对应的程序如下所示:
module timer(clken,rst,clk_50M,sec1,sec2,min1,min2);
input clk_50M;//系统时钟
input clken,rst;//其中clken是控制计数信号,rst是清零信号,都由控制模块产生
output [3:0]sec1;
output [3:0]sec2;
output [3:0]min1;
output [3:0]min2;
reg [3:0] sec1; //秒低位信号
reg [3:0] sec2; //秒高位信号
reg [3:0] min1; //分钟低位信号
reg [3:0] min2; //分钟高位信号
reg [27:0] count;
reg clk_1H;
//分频得到1s的信号
always @(posedge clk_50M or posedge rst )
begin
if(rst)
begin
count <= 28'd0;
end
else
begin
//if(count==28'd2499_9999)
if(count==28'd4)
begin
count <= 28'd0;
clk_1H <= 1'd1;
end
else
begin
count <= count+1;
clk_1H <= 1'd0;
end
end
end
//秒个位计数器
always @(posedge clk_50M or negedge rst)
begin
if(rst)
begin
sec1 <= 4'b0;
end
else
if(clken)//计数使能信号
begin
if(clk_1H)
begin
if(sec1 == 4'b1001)
sec1 <= 4'b0000;
else
sec1 <= sec1+4'b0001;
end
end
end
//秒十位计数器
always @(posedge clk_50M or negedge rst)
begin
if(!rst)
begin
sec2 <= 4'b0;
end
else
if(clken)//计数使能信号
begin
if(clk_1H&&(sec1 == 4'b1001))//秒信号和秒低位信号控制秒高位计数
begin
if(sec2 == 4'b0101)
sec2 <= 4'b0;
else
sec2 <= sec2+4'b0001;
end
end
end
//分个位计数器
always @(posedge clk_50M or negedge rst)
begin
if(rst)
begin
min1 <= 4'b0;
end
else
if(clken)
begin
if(clk_1H&&(sec1 == 4'b1001)&&(sec2 ==4'b0101))
begin
if(min1 == 4'b1001)
min1 <= 4'b0;
else
min1 <= min1 +4'b0001;
end
end
end
//分十位计数器
always @(posedge clk_50M or negedge rst)
begin
if(rst)
begin
min2 <= 4'b0;
end
else
if(clken)
begin
if(clk_1H&&(sec1 == 4'b1001)&&(sec2 == 4'b0101)&&(min1 == 4'b1001))
begin
if(min2 == 4'b0101)
min2 <= 4'b0;
else
min2 <= min2 +4'b0001;
end
end
end
endmodule
2.1.2 数码管显示模块设计
本模块主要是对数码管显示进行动态扫描及译码输出。动态扫描显示的原理很简单,由于在实验中片选信号和笔画码都是不经过数据锁存而直接由IO口送数码管的,并且四位数码管共用并行的笔画码数据线,因此必须轮流选中某一位数码管,才能使各位数码管能显示不同的数字或符号。再利用人眼睛对50Hz以上的光的闪烁不敏感的特性。因此,只要轮流选中某一位的时间间隔不超过20ms(对四位数码管来说,相邻位选中间隔不超过5ms),就感觉数码管是在持续发光显示一样。其次是要根据实验板上数码管共阳的特性进行译码输出。
图 6 数码管编码段选
设计源程序如下:使用了计数器cnt实现了对数码管的逐位点亮,并在把相应的显示数据送到该位显示。
module player(clk_50M,reset,sec1,sec2,min1,min2,dula,weil);
input clk_50M;
input reset;
input [3:0]sec1;
input [3:0]sec2;
input [3:0]min1;
input [3:0]min2;
output [7:0] dula; //数码管段选控制
output [3:0] weil;//数码管位选控制
reg [7:0] dula;
reg [3:0] weil;
reg [3:0] num;
reg [27:0] count;
reg [1:0] cnt;
reg clks;//数码管扫描的频率
//分频得到500hz的扫描频率
always @(posedge clk_50M or negedge reset)
begin
if(!reset)
begin
count <= 28'd0;
clks <= 0;
end
else
begin
if(count==28'd49_999)
begin
count <= 28'd0;
clks <= 1'b1;
end
else
begin
count <= count+1;//默认为十进制
clks <= 1'b0;
end
end
end
always @(posedge clk_50M)
begin
if(clks)//////////
begin
cnt <= cnt+2'b01;
end
case(cnt)
2'b00 :begin
weil <= 4'b1110;//最右边的数码管亮
num <= sec1;
end
2'b01 :begin
weil <= 4'b1101;
num <= sec2;
end
2'b10 :begin
weil <= 4'b1011;//左二位
num <= min1;
end
2'b11 :begin
weil <= 4'b0111;//最左边的数目管亮
num <= min2;
end
endcase
end
//译码模块
always @(num)
begin
case(num)
4'b0000 :dula[7:1] <= ~(7'b1111_110);//显示0
4'b0001 :dula[7:1] <= ~(7'b0110_000);//1
4'b0010 :dula[7:1] <= ~(7'b1101_101);//2
4'b0011 :dula[7:1] <= ~(7'b1111_001);//3
4'b0100 :dula[7:1] <= ~(7'b0110_011);//4
4'b0101 :dula[7:1] <= ~(7'b1011_011);
4'b0110 :dula[7:1] <= ~(7'b1011_111);
4'b0111 :dula[7:1] <= ~(7'b1110_000);
4'b1000 :dula[7:1] <= ~(7'b1111_111);
4'b1001 :dula[7:1] <= ~(7'b1111_011);
default :;
endcase
end
endmodule
2.1.3 控制模块的设计
根据实验的要求,用一个按键实现计时器的暂停和开始的功能。这个功能的实现有以下两个方案:
= 1 \* GB3 ①通过检测按键的电平变化,改变控制计数的变量的值,可以通过取反来实现0、1状态的反转,从而完成暂停和开始的控制。
= 2 \* GB3 ②利用有限状态机。ISE中的StateCAD支持以状态转移图作为逻辑设计输入,可以实现将状态转移图生成HDL语言,在此基础上进行一些必要性的修改,可以获得控制模块的代码。根据清零按键和暂停\开始按键输出控制信号clken和rst,控制计数模块timer的计数和清零。在ISE中的timer工程新建状态机文件,有限状态机的变化过程如下:
图7 控制模块状态机转换
本设计使用了第二种控制方法,相比第一种方法逻辑控制较严密,并取得了较好的效果。其描述语言如下所示:
module control(clk_50M,reset,pause,clken,rst);
input clk_50M;
input reset,pause;//低电平有效
output clken;
output rst;
reg clken;
reg rst;
//定义状态机的六个状态
parameter clear = 6'b000_001,
parameter zero = 6'b000_010,
parameter start = 6'b000_100,
parameter counting = 6'b001_000,
parameter stop1 = 6'b010_000,
parameter stopped = 6'b100_000;
reg [5:0] current_state;//当前状态
reg [5:0] next_state; //下一状态
always @(current_state or pause)
begin
case(current_state)
clear:begin
next_state <= zero;
clken <= 1'b0;
rst <= 1'b1;
end
zero:begin
next_state <= (pause)?zero:start;
clken <= 1'b0;
rst <= 1'b0;
end
start:begin
next_state <= (pause)?counting:start;
clken <= 1'b0;
rst <= 1'b0;
end
counting:begin
next_state <= (pause)?counting:stop1;
clken <= 1'b1;
rst <= 1'b0;
end
stop1:begin
next_state <= (pause)?stopped:stop1;
clken <= 1'b0;
rst <= 1'b0;
end
stopped:begin
next_state <= (pause)?stopped:start;
clken <= 1'b0;
rst <= 1'b0;
end
endcase
end
always @(posedge clk_50M or negedge reset)
begin
if(!reset)
current_state = clear;
else
current_state = next_state;
end
endmodule
2.2 综合及设计实现
在完成各模块的HDL描述后,进行语法的检查,生成电路模块设计顶层原理图。加入用户约束文件,确定对应的管脚编号,最后对原理图进行综合和设计实现及生成下载文件。
2.2.1 各模块原理图的生成
在当前工程窗口中的Design Utilites项目中,双击Creat Schmatic Symbol命令,得到三个模块control、timer、display原理图,如下所示:
图8 控制模块原理图
图9 计数模块原理图
图10 显示模块原理图
2.2.2 顶层原理图的设计和综合
在工程中新建Schematic文件,命名为time_sch,并设置为顶层文件(选择Set as top module),然后选择放置上面生成的原理图符号,添加连线和I\O管脚,如下图所示:
图11 顶层原理图设计
顶层原理图生成后可以看到,3个模块在其下方表示底层文件。新建UCF文件进行管脚约束,这里使用直接输入的方式实现。
图12 约束文件
三 实验结果及总结
经过多次的调整修改后,将生产的程序文件下载到开发板的芯片,实验现象完全符合要求,最终得到了预期的要求。下图是实验结果:
图13 计时清零
图14 计时暂停
在完成Verilog的实验的过程中,也遇到过一些问题,比如在程序中直接使用分频的方波周期信号做为另一个进程的时钟信号在综合的时候提示“skew”时钟偏移;再比如软件给出一些error“Cannot mix blocking and non blocking assignments on signal”,是因为使用了同时阻塞和非阻塞方式对同一个信号赋值。虽然遇到了一些大大小小的问题,但是通过向老师和同学请教以及在网络上查找,最终都得到了解决。其实解决问题的过程也是学习的过程,对Verilog和ISE的开发使用流程有了更多的了解。
通过这段时间的理论和实验的学习,对PLD数字系统的设计有了基本的了解,觉得Verilog是一门很实用并且很灵活的硬件描述语言,比如对于实现同一功能的模块,可以有好几种描述方式,但是如果说应用于工程的话,还是比较赞同李辉老师讲的那样,即使是多写一些代码,多占用一些硬件资源,也要保证稳定性。FPGA系统开发所涉及的内容相当的广泛,在课堂上讲的只不过是一些基础知识,如果要用到更深层次的应用,还需要自己付出更多的努力!
相关关键词: 计时器