基于BASYS3开发板的秒表设计以及应用

期末课设计,在这里记录一下开发思路。

1.摘要:

这是一款基于BASYS3开发板的秒表装置,其功能有:通过七段数码管显示当前秒表秒数,通过按键选择向上计时和向下计时,通过按键切换模式,实现左二数码管显示分钟,右二数码管显示秒和左二数码管显示秒,右二数码管显示百分之一秒两种模式的切换。设计亮点有,一、利用时钟使能得到不同的时钟而不是使用时钟分频来获得不同的时钟,提高了系统稳定性。二、显示界面符合实际。三、资源使用量少。

关键词:BASYS3 七段数码管 时钟使能

2.设计思路介绍

首先设计一个百分之一秒的时钟使能模块,其能记录主时钟上升沿并每百分之一秒输出一个使能信号,然后通过级联的方式,将百分之一秒使能信号作为一秒时钟使能模块的时钟触发信号,一秒时钟使能模块每秒输出秒使能信号,将秒使能信号作为分钟时钟使能模块的时钟触发信号,实现百分之一秒、一秒、一分钟定时器的设计。然后分别将三者的时钟使能信号传到三个计数器用于记录各个计时器使能信号的个数,接着通过一个选择器将需要显示的计数器的计数值传到显示模块,在显示模块中通过除数和取余的操作得出计数值的个位和十位,然后通过BCD译码器将相应信号给到相应数码管,同时设计一个200Hz的位选频率发生器,实现数码管的扫描显示。

(注:为了方便展示,这里并未给出reset信号和stop信号的功能,但实际项目中具有该功能)

3.模块介绍

3.1时钟模块

3.1.1 时钟分频和时钟使能模块介绍

板子上的晶振频率为100MHZ,但我们需要的信号是百分之一秒,即100Hz的时钟信号(给百分之一秒提供时钟信号)。实现的方法有两种,一种是使用分频器的方式,一种是使用时钟使能的方式。分频方式即在目标频率的前半个周期让时钟电平为正,后半个周期反转电平信号(以偶分频为例),此项目通过计算可知当计数100MHz的时钟的上升沿499999次时,100Hz的时钟信号取反,即可获得100Hz的时钟频率。而时钟使能方法是指在通过计数器记录时钟的次数,当计数器达到目标次数时输出一个使能信号,以此项目为例,当计数100MHz时钟信号999999次后输出使能信号,便可获得100Hz的信号。

                 时钟分频ASM图                                                                   时钟使能ASM图

3.1.2时钟分频和时钟使能的选择

在很多设计中,虽然内部不同模块的处理速度不同,但由于这些时钟是同源的,可以将它们转化为单一时钟处理;在ASIC中可以通过STA约束让分频始终和源时钟同相,但FPGA由于器件本身和工具的限制,分频时钟和源时钟的Skew不容易控制(使用锁相环分频是个例外),难以保证分频时钟和源时钟同相,因此推荐的方法是使用时钟使能,通过使用时钟使能可以避免时钟“满天飞”的情况,进而避免了不必要的亚稳态发生,在降低设计复杂度的同时也提高了设计的可靠性。[1]

3.1.3 时序测试:

1.时钟分频时序图

 

可见其达到计数值后翻转电平

注:由于测试需要,这里将计数初值设为4,

2.时钟使能时序图

 

可见其只有在计数值到达时会进行使能输出,其余时间输出为0

注:由于测试需要,这里将计数初值设为9,

3.总定时器时序

 

可见可以通过三者级联实现预设功能。

3.1.4 时钟使能模块代码

module clock_enable(

input wire clock,

input wire reset,

input wire stop,

input wire [31:0] number,

output reg enable

);

reg [31:0] counter;



always @(posedge clock or posedge reset or posedge stop)

begin

if (reset) begin   //reset信号判断

counter <= 0;   //有效清零

enable <= 0;

end

else if (stop) begin  //stop信号判断

counter <= counter; //有效保持

enable <= enable;

end

else  begin

if (counter >= number) begin   //如果计数值大于给定值,使能输出

counter <= 0;

enable <= 1;

end

else begin

counter <= counter + 1;  //未达到计数值,继续

enable <= 0;

end

end

end

endmodule

3.2 计数器模块

3.2.1 模块介绍

为了记录定时器记录的时间并把提供数码管将要显示的值,我这里使用三个计数器分别上面提到的三个计数器计数,以得到相应的时间。计数器内部设有进位判断逻辑,限制s、min的值在59内,百分之一秒的值在99内

 

计数器ASM图

3.2.2 时序测试

计数器时序图

 

可见其工作正常,每一个使能信号到达时,对于时钟计数器计数加1.

3.2.3 计数器代码

module display_number(

input wire clock,

input wire reset,

input wire stop,

input wire en_ms,

input wire up,

output reg [6:0] displayed_number

);

always @(posedge clock or posedge reset or posedge stop)

begin

if (reset)

displayed_number <= 0;  //计数器清零

else if (stop)

displayed_number <= displayed_number; //计数器保持

else

begin

if (en_ms) begin  //判断是否为百分之一秒计数,控制其值在100以下

case(up)

1'b1:

if(displayed_number>=99)

displayed_number <= 0;

else displayed_number <= displayed_number + 1'b1; //向上计数

1'b0:if(displayed_number<=0)

displayed_number <= 99;

else displayed_number <= displayed_number - 1'b1; //向下计数

default:displayed_number <= displayed_number;

endcase

end

else //若不是百分之一秒计数,控制值在60以下

case(up)

1'b1:

if(displayed_number>=59)

displayed_number <= 0;

else displayed_number <= displayed_number + 1'b1;//向上计数

1'b0:if(displayed_number<=0)

displayed_number <= 59;

else displayed_number <= displayed_number - 1'b1;//向下计数

default:displayed_number <= displayed_number;

endcase

end

end

endmodule

3.3 位选模块

3.3.1动态扫描原理介绍

动态扫描显示利用了时分原理和人的视觉暂留现象。例如,4位扫描数码显示.器将时间划分为4个扫描周期: 周期1一>周期2一>周期3一>周期4,每个周期只选通一位数据。在周期1显示第1个数码,周期2显示第2个数码管。在扫描四个周期后,又重新按顺序循环。如果扫描的速度足够快,人的感觉就象4个数码同时显示。

3.3.2模块设计

本项目数码管有四个,所以我定义了一个两位宽的位选信号LED_activating_counter来进行位选,这个位选模块的原理就是利用寄存器refresh的长度进行计时,这里refresh为18位寄存器,每1/100MHz*2^18次方刷新一次,即2.6ms刷新一次

3.3.3模块代码

always @(posedge clock_100Mhz or posedge reset) //refresh为18位寄存器

begin

if(reset==1)

refresh_counter <= 0;

else

refresh_counter <= refresh_counter + 1;

end

assign LED_activating_counter = refresh_counter[17:16];//每1/100MHz*2^18次方刷新一次,即2.6ms刷新一次

3.4取值模块

3.4.1取值原理介绍

因为数据为整型存储,将十位数除以10便能得到10位,以10取余便能得到个位,以27为例,除以10整数剩2,取出十位,以10取余得到7,取出个位

3.4.2 模块设计

首先利用选择器将需要显示的时间的计数器值传入取值模块中,然后取值模块通过取余和除10的方法获得计数值的个位和十位,然后将其值存到LED_BCD寄存器中,为后续的显示电路提供BCD码。

取值模块AMS图

3.4.3时序测试:

模块时序图

可看出段选信号变换正常。

(注:由于测试需要,这里测试时间只给了1ms,而位选信号变换是2.6ms,所以这里位选值为0是正常的)

多路选择器代码

always @(posedge clock_100Mhz)

begin

if(choice==1)     //choice为1就数码管低两位显示百分之一秒,高两位显示秒。

begin temp_display[7:0]<= displayed_number_10ms;

temp_display[15:8]<=displayed_number_s;end

Else  //否则数码管低两位显示秒,高两位显示分钟。

begin temp_display[7:0]<= displayed_number_s;

temp_display[15:8]<=displayed_number_min;end

End

取值模块代码

module display(

input wire [1:0] LED_activating_counter,

input wire [15:0] displayed_number,

output reg [3:0] Anode_Activate,

output reg [6:0] LED_BCD

);

always @(*)

begin

case (LED_activating_counter)

2'b00: begin

Anode_Activate = 4'b0111;

// 数码管1亮

LED_BCD = displayed_number[15:8]/10;

// 取高八位的十位

end

2'b01: begin

Anode_Activate = 4'b1011;

// 数码管2亮

LED_BCD = displayed_number[15:8]%10;

// 取高八位的个位

end

2'b10: begin

Anode_Activate = 4'b1101;

// 数码管3亮

LED_BCD = displayed_number[7:0]/10;

// 取低八位的十位

end

2'b11: begin

Anode_Activate = 4'b1110;

// 数码管4亮

LED_BCD = displayed_number[7:0]%10;

// 取低八位的个位   

end

endcase

end

endmodule

3.5数码管显示模块

3.5.1七段数码管显示原理

数码管是一种半导体发光器件,其基本单元是发光二极管。数码管按段数分为七段数码管和八段数码管,八段数码管比七段数码管多一个发光二极管单元(多一个小数点显示);按发光二极管单元连接方式分为共阳极数码管和共阴极数码管。共阳数码管是指将所有发光二极管的阳极接到一起形成公共阳极(COM)的数码管。共阳数码管在应用时应将公共极COM接到+5V,当某一字段发光二极管的阴极为低电平时,相应字段就点亮。当某一字段的阴极为高电平时,相应字段就不亮。共阴数码管是指将所有发光二极管的阴极接到一起形成公共阴极(COM)的数码管。共阴数码管在应用时应将公共极COM接到地线GND上,当某一字段发光二极管的阳极为高电平时,相应字段就点亮。当某一字段的阳极为低电平时,相应字段就不亮。[2]

四位数码管引脚图

 

 

BCD-七段显示译码器

实验中运用到的数码管为八段共阳极数码管,当小数点对应的发光二极管为高电平时,小数点不显示。

3.5.2 七段数码管显示代码:

always @(*)

begin

case (LED_BCD_change)

4'b0000: LED_out = 7'b0000001; // "0"     

4'b0001: LED_out = 7'b1001111; // "1"

4'b0010: LED_out = 7'b0010010; // "2"

4'b0011: LED_out = 7'b0000110; // "3"

4'b0100: LED_out = 7'b1001100; // "4"

4'b0101: LED_out = 7'b0100100; // "5"

4'b0110: LED_out = 7'b0100000; // "6"

4'b0111: LED_out = 7'b0001111; // "7"

4'b1000: LED_out = 7'b0000000; // "8"     

4'b1001: LED_out = 7'b0000100; // "9"

default: LED_out = 7'b0000001; // "0"

endcase

end
  1. 总体项目测试

4.1测试代码

`timescale 1ns/1ns

module Seven_segment_LED_Display_Controller_Test();

reg clock_100Mhz;

reg reset;

reg stop;

reg [1:0] choice;

reg up_down_choice;

wire [3:0] Anode_Activate;

wire [6:0] LED_out;

Seven_segment_LED_Display_Controller dut (

.clock_100Mhz(clock_100Mhz),

.reset(reset),

.stop(stop),

.choice(choice),

.up_down_choice(up_down_choice),

.Anode_Activate(Anode_Activate),

.LED_out(LED_out)

);



// Testbench code

initial begin

// Initialize inputs

clock_100Mhz = 0;

reset = 1;

stop = 0;

choice = 0;

up_down_choice=1;

#10 reset=0;// Test with 10ms time scale

#100000 up_down_choice=0;

#100010 reset=1;

#100020 reset=0;

#100030 stop=1;

#100040 stop=0;

//up_down_choice = 0;

end

always #10 clock_100Mhz=~clock_100Mhz;

endmodule

4.2时序图

 

可看出其工作输出正常

  1. 上板测试
    1. 约束文件
//下排按键左起第一个控制reset信号,第二个控制stop信号,第三个模式切换,第四个向上向下计数模式切换

# Clock signal

set_property PACKAGE_PIN W5 [get_ports clock_100Mhz]       

set_property IOSTANDARD LVCMOS33 [get_ports clock_100Mhz]

set_property PACKAGE_PIN R2 [get_ports reset]     

set_property IOSTANDARD LVCMOS33 [get_ports reset]

set_property PACKAGE_PIN T1 [get_ports stop]     

set_property IOSTANDARD LVCMOS33 [get_ports stop]

set_property PACKAGE_PIN U1 [get_ports choice]     

set_property IOSTANDARD LVCMOS33 [get_ports choice]

set_property PACKAGE_PIN W2 [get_ports up_down_choice]     

set_property IOSTANDARD LVCMOS33 [get_ports up_down_choice]



#seven-segment LED display

set_property PACKAGE_PIN W7 [get_ports {LED_out[6]}]                    

set_property IOSTANDARD LVCMOS33 [get_ports {LED_out[6]}]

set_property PACKAGE_PIN W6 [get_ports {LED_out[5]}]                    

set_property IOSTANDARD LVCMOS33 [get_ports {LED_out[5]}]

set_property PACKAGE_PIN U8 [get_ports {LED_out[4]}]                    

set_property IOSTANDARD LVCMOS33 [get_ports {LED_out[4]}]

set_property PACKAGE_PIN V8 [get_ports {LED_out[3]}]                    

set_property IOSTANDARD LVCMOS33 [get_ports {LED_out[3]}]

set_property PACKAGE_PIN U5 [get_ports {LED_out[2]}]                    

set_property IOSTANDARD LVCMOS33 [get_ports {LED_out[2]}]

set_property PACKAGE_PIN V5 [get_ports {LED_out[1]}]                    

set_property IOSTANDARD LVCMOS33 [get_ports {LED_out[1]}]

set_property PACKAGE_PIN U7 [get_ports {LED_out[0]}]                    

set_property IOSTANDARD LVCMOS33 [get_ports {LED_out[0]}]

set_property PACKAGE_PIN U2 [get_ports {Anode_Activate[0]}]                    

set_property IOSTANDARD LVCMOS33 [get_ports {Anode_Activate[0]}]

set_property PACKAGE_PIN U4 [get_ports {Anode_Activate[1]}]                    

set_property IOSTANDARD LVCMOS33 [get_ports {Anode_Activate[1]}]

set_property PACKAGE_PIN V4 [get_ports {Anode_Activate[2]}]               

set_property IOSTANDARD LVCMOS33 [get_ports {Anode_Activate[2]}]

set_property PACKAGE_PIN W4 [get_ports {Anode_Activate[3]}]          

set_property IOSTANDARD LVCMOS33 [get_ports {Anode_Activate[3]}]

    1. 现象

 

现象正确,功能正常,可以实现清零,暂停,计时模式切换,上下计数模式切换

实验总结

本项目使用时钟使能信号对不同时间需求进行计数,效果很好,实现了预期功能,计时功能与手机计时器对比误差在可接受范围内,实验成功。

实验心得:这次实验是第一次进行这样大规模的硬件语言代码编写,遇到了很多问题,也对项目建设有了更深的理解。

  1. 体会到了寄存器位宽对工程的影响,有时一个位宽设置错误会导致很多预料不到的错误,需要花很多时间取排查,以后在位宽设置时一定会注意。
  2. 对阻塞赋值和非阻塞赋值有了更深入的理解,赋值方式错了真的会造成很多意外的bug。
  3. 设计时序逻辑时一定要清晰,不然实现不了功能也找不到原因。
  4. 分模块化编程可以使代码编写更加直观,也使逻辑更加清晰,同时增加了代码的复用性,减少了重复性工作。

参考文献

  1. verilog的时钟分频与时钟使能https://www.elecfans.com/d/1972527.html
  2. 七段数码管 知乎盐选 | Arduino 编程 (zhihu.com)

  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Basys3介绍: Digilent 的 Basys3 是一款采用 Xilinx Artix 7 FPGA 架构的入门级 FPGA 板,专门用于 Vivado 设计套件。 Basys3 是广受欢迎的 Basys 入门级 FPGA 板系列的最新成员。 Basys3 具有所有 Basys 板的标准特性:全套现成的硬件、大量板载 I/O 设备、所有必要的 FPGA 支持电路和免费版开发工具,且全部以学生价格提供。 Basys3原理图截图: Digilent 现在推出 Basys3,通过提升特性集为学生们带来更好的专业级工程代表产品。 这些改进包括: 更多 I/O: 双用户接口开关、双板载输出数量、升级了外部端口(从 6 引脚、单排 Pmod 到 12 引脚、双排 Pmod)和 USB UART 桥接器。 现代编程的挑战: 由于从 Spartan 3E 系列到 Artix 7 类器件的迁移,Basys3 增加了大量硬件功能。 这款新型 Artix FPGA 器件逻辑单元数提升了 15 倍(从 2,160 到 33,280),从倍增器升级到真正的 DSP 切片。 该器件的 RAM 还增加了 26 倍以上。 业内首款 SOC 加强型设计套件: 对 Basys3 的最大变化就是升级到 Xilinx Vivado 设计套件。 Vivado 设计套件是全球专业工程师使用的最先进设计工具链。 Vivado 凭借扩充的功能改进了 ISE 的用户体验,如与 Vivado IP 积分器的基于块的 IP 的集成,将开发时间减少到 1/10 的 Vivado 高级合成(仅可用于 Vivado 系统版),以及带 DSP 系统发生器的基于模型的 DSP 设计集成。 特性 5200 个切片中有 33,280 的逻辑单元(每个切片包含四个 6 输入 LUT 和 8 个触发器) 1,800 Kb 的快速块 RAM 5 个时钟管理模块,每个都提供锁相环 (PLL) 90 个 DSP 切片 超过 450 MHz 的内部时钟速度 片载模数转换器 (XADC) 16 个用户开关 16 个用户 LED 5 个用户按钮 4 位 7 段显示 4 个 Pmod 连接器3 个标准 12 引脚 Pmod 1 个双用途 XADC 信号/标准 Pmod 12 位 VGA 输出 USB UART 桥接器 串行闪存 用于 FPGA 编程和通信的 Digilent USB JTAG 端口 用于鼠标、键盘和记忆棒的 USB HID 主机 实物购买链接:https://www.eeboard.com/shop/?c=products&a=index&_k...
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值