0 实验环境
0.1 软件环境
- ISE 14.7
- win10
- vivado 2017.4
0.2 硬件设备
- ISE适用的FPGA开发板:ALINK AX309
1 需求
能够灵活控制4个LED灯
2 Verilog实现
`timescale 1ns / 1ps
//
// Create Date: 14:18:20 08/08/2020
// Module Name: led
// Revision 0.01 - File Created
//
module led(input clk,input rst,output reg led);//define the time counterreg [31:0] timer;// cycle counter:from 0 to 4 secalways@(posedge clk or negedge rst)beginif (rst == 1'b0)timer <= 32'd0; //when the reset signal valid,time counter clearingelse if (timer == 32'd39_999_999) //4 seconds count(50M*4-1=199999999)timer <= 32'd0; //count done,clearing the time counterelsetimer <= timer + 32'd1; //timer counter = timer counter + 1end// LED controlalways@(posedge clk or negedge rst)begin if (rst == 1'b0) led <= 1'b0; //when the reset signal activeelse if (timer == 32'd49_999_999) //time counter count to 1st sec,LED1 lightenled <= 1'b1;else if(timer == 32'd99_999_999)led <= 1'b0;endendmodule
功能说明:
- 输入:时钟clk和复位键rst信号(clk是50MHz)
- 输出:发出控制一个led灯的信号
- 对于led信号,初始为0,间隔1秒,变成1,再间隔1秒,变成0,循环往复
时间说明:
50MHz对应的时钟周期是0.02μs,因此,1s需要 50 * 10^6
个时钟周期。
初始的timer = 0
,因此,实际的1s,对应timer = 32'd_49_999_999
,也就是50_000_000
个时钟周期。
3 仿真测试(略)
不是本次实验的重点,略。
4 综合测试
直接在ISE软件执行综合即可。
5 管脚分配
这是本文的重点。 需要理解
- Verilog代码(
.v
文件)如何与ucf
文件建立关联 - 代码如何与实际的硬件平台管脚建立关联
5.1 建立.ucf
文件
我们先在ISE建立一个.ucf
文件,然后分配管脚。
关于具体的管脚分配信息,需要参照开发板使用说明书。
NET "clk" LOC = T8 | TNM_NET = sys_clk_pin;
TIMESPEC TS_sys_clk_pin = PERIOD sys_clk_pin 50000 kHz;##
NET rst LOC = L3 | IOSTANDARD = "LVCMOS33"; ## reset pushbutton
##########LED Pin define#####################
NET led LOC = P5 | IOSTANDARD = "LVCMOS33"; ## LED1
重要的说明
- 以上代码直接被开发板说明给出,不需要自己改,除非你有特定需求
- 需要注意的是自己编写的Verilog代码的信号名称,必须与上述代码的
NET
后面的信号保持一致。例如
- 时钟信号必须是
clk
- 复位信号必须是
rst
- LED灯信号必须是
led
NET
后面的内容,是与Verilog代码信号建立关联,而LOC
后面的内容,则是与硬件设备的引脚建立关联,之后的部分是电压,可以先不管。
重要的公式:NET “端口名称” LOC = 引脚编号 | IOSTANDARD = “电压” ;
这是非常重要的,我们在进行管脚分配的时候,就是按照这样的方式分配的。
- 代码模拟的硬件设备,突出的就是输入输出端口,与Verilog设计有关
- 硬件设备,突出的就是引脚,与硬件有关
- 红色的双箭头,就是二者的关联,与
.ucf
文件有关,它的NET端口名
必须和Verilog端口名一样,LOC管脚编号
以及电压,必须和硬件设备一样
对于以下ucf
内容
########LED Pin define#####################
NET led<0> LOC = P4 | IOSTANDARD = "LVCMOS33"; ## LED1
NET led<1> LOC = N5 | IOSTANDARD = "LVCMOS33"; ## LED2
NET led<2> LOC = P5 | IOSTANDARD = "LVCMOS33"; ## LED3
NET led<3> LOC = M6 | IOSTANDARD = "LVCMOS33"; ## LED4
值得注意的是<0>
这部分。
首先,led引脚的位宽是1,嗯,通常引脚是1位,这样灵活性高(还是得参考对应的说明文档)。
LED的说明如下
你很容易知道LED灯引脚位宽是1,为0的时候不亮,为1的时候点亮。
########LED Pin define#####################
NET led<0> LOC = P4 | IOSTANDARD = "LVCMOS33"; ## LED1
NET led<1> LOC = N5 | IOSTANDARD = "LVCMOS33"; ## LED2
NET led<2> LOC = P5 | IOSTANDARD = "LVCMOS33"; ## LED3
NET led<3> LOC = M6 | IOSTANDARD = "LVCMOS33"; ## LED4
但是这与<>
无关,引脚的事情,是LOC
后面内容的事情,<>
是端口的事情,那么,尖括号对应端口究竟是怎么回事?
猜想,然后试一下就好了!
我们之前的led输出信号是1位,现在我们改一下
output reg[1:0] led
然后再把LED control改改
// LED controlalways@(posedge clk or negedge rst)begin if (rst == 1'b0) led <= 1'b0; else if (timer == 32'd19_999_999) led <= 2'b01;else if(timer == 32'd39_999_999)led <= 2'b10;end
注意变化,关注led <= 2'b01;
,
然后我们再改改.ucf
文件
########LED Pin define#####################
NET led<0> LOC = P4 | IOSTANDARD = "LVCMOS33"; ## LED1
NET led<1> LOC = N5 | IOSTANDARD = "LVCMOS33"; ## LED2
之后上板测试,很容易得到结论。
如果你还没有得到,不妨试一下3位宽,4位宽的led信号。
结论是:led<0>
的0
对应的是output reg[1:0] led
信号的led[0]
,而led<1>
对应的是led[1]
。
分治思想:区分端口名与管脚编号
对于.ucf
文件
NET
的值是端口名,与Verilog中的端口名称完全一致,如果是多位宽,则按照上面的结论写上<number>
LOC
的值是管脚编号,根据你的需求,你需要将合适的管脚(对应的器件)与合适的端口建立连接
对于同样一个led<0>
,它可以分配的引脚有多种选择,不过,需要遵循的是
- 引脚对应的器件必须是LED灯
- 引脚不能发生冲突(例如2个端口接到了同一个引脚,并且端口信号同一时间发出不同信息)
需要注意:
对于没有的端口号,不能分配管脚!
这是显而易见的,不过还是得多提示一下。
实验思维
很多时候,不管是书籍还是说明文档,都不可能详细描述所有细节,但是,你依然可以通过试验程序,猜测得出结论,然后你需要多次验证(通过实验,资料等)。
信息 = 位 + 上下文
以往,我们对于二进制数字1000
和0001
的反应可能是对应十进制8
和1
,但是对于本实验(假设用了4个LED灯),它的含义就是只有LED4亮
和只有LED1亮
。
这也充分诠释了二进制信息含义 = 位 + 上下文
的含义。