ZYNQ从入门到秃头05 LED闪烁实验 && 按键控制LED实验Verilog(PL)

Posted “逛丢一只鞋”

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ZYNQ从入门到秃头05 LED闪烁实验 && 按键控制LED实验Verilog(PL)相关的知识,希望对你有一定的参考价值。


LED灯闪烁作为一个经典 的入门实验, 其 地位堪比 编程界的“ Hello World!!”。对于ZYNQ依然不例外

LED,又 名 发光 二极管 。 LED灯工作电流很小(有的仅零点几毫安即可发光) 抗冲击和抗震性能好,可靠性高,寿命长 。由于 这些优点, LED灯 被 广泛用 在 仪器 仪表中作指示灯 、 液晶屏背光源 等 诸多领域 。

发光二极管与普通二极管一样具有单向导电性。 给 它 加上 阳极 正向电压后 ,通过 5mA左右 的电流就可以 使 二极管发光 。 通过 二极管 的 电流 越大, 发出 的光 亮度 越强 。不 过 我们一般将 电流限定在 3~20mA之间 ,否则电流过大就会烧坏二极管。

本节实验任务 是使 ALINX 7020底板上的 PL LED1和 PL LED2以固定的频率交替闪烁。

LED闪烁实验Verilog(PL)

硬件设计

老规矩,这种依然是以原理图为依托


我们可以根据原理图的连线关系确定 LED 和 PL 管脚的绑定关系 。

原理图中以 PS_MIO 开头的 IO 都是 PS 端 IO ,不需要绑定,也不能绑定

PL_LED0和 PL_LED1的阴极通过 470 欧姆的电阻连到地( GND)上,阳极由 ZYNQ PL的 IO管脚控制, LED与地之间的电阻起到限流作用。

本实验中,系统时钟、按键复位以及两个LED端口的管脚 分配如下表所示,其中复位按键和两个LED位于底板上,时钟位于核心板上:

程序设计

由于发光二极管的 阳 极与 ZYNQ的 管脚 相连,只需要改变与 LED灯 相连的 ZYNQ管脚 的 电平, LED灯的 亮灭状态就会发生变化 。当ZYNQ管脚 为低 电平 时 LED灯 点亮 为高 电平 时, LED灯熄灭。

创建Verilog HDL文件

  1. 点击 Project Manager 下的 Add Sources 图标(或者使用快捷键 Alt+A
  2. 选择添加或创建设计源文件“ Add or create design sources 点击“ Next
  3. 选择创建文件“ Create File
  4. 文件名“ File name ”设置为 led ”,点击 OK
  5. 点击“ Finish 完成“ led.v ”文件添加
  6. 在弹出的模块定义“ Define Module 中可以指定“ led.v ”文件的模块名称 Modulename 这里默认不变为“ led ”,还可以指定一些端口,这里暂时不指定,点击 OK ”。
  7. 在弹出的对话框中选择“ Yes
  8. 双击“ led.v ”可以打开文件,然后编辑

编写Verilog

其中,计数器对50MHz时钟进行计数,从而达到计时的目的。

计数器在每次计时到 1秒之后清零,然后重新开始计数,计数的值用于控制 LED的显示状态。当计数器的值小于 0.5s时,就把 LED0点亮并把 LED1熄灭;每当计数器的值大于 0.5s时,就把 LED0熄灭并把 LED1点亮,以此实现两个 LED的交替闪烁。

module led_twinkle(
    input          sys_clk  ,  //系统时钟
    input          sys_rst_n,  //系统复位,低电平有效

    output  [1:0]  led         //LED灯
);

//reg define
reg  [25:0]  cnt ;

//*****************************************************
//**                    main code
//*****************************************************

//对计数器的值进行判断,以输出LED的状态
assign led = (cnt < 26'd2500_0000) ? 2'b01 : 2'b10 ;
//assign led = (cnt < 26'd5)         ? 2'b01 : 2'b10 ;  //仅用于仿真

//计数器在0~5000_000之间进行计数
always @ (posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        cnt <= 26'd0;
    else if(cnt < 26'd5000_0000)
//  else if(cnt < 26'd10)  //仅用于仿真
        cnt <= cnt + 1'b1;
    else
        cnt <= 26'd0;
end

endmodule

endmodule

上述是一个简单的实现过程,控制两个灯闪烁

为了更加深入理解,下面 这个代码控制4个灯,然后交替闪烁

module led_flash(
	input	sys_clk,		// 系统时钟
	input	sys_rst_n,		// 系统复位,低电平有效
	
	output	reg [3 : 0]	led
    );
    
reg	[31 : 0] cnt; 
reg [3 : 0] led_flag;
//*********************************************************
//**                     main
//*********************************************************


// 计数器在0~5000_0000之间进行计数
always @ ( posedge sys_clk or negedge sys_rst_n ) begin
	
	if( !sys_rst_n ) begin
		cnt <= 32'd0;
		led_flag <= 0;
	end 
	else if(cnt < 32'd18_000_000) begin
		cnt <= cnt + 1'b1;
		led_flag <= 0;
	end
	else if(cnt >= 32'd18_000_000 && cnt < 32'd36_000_000) begin
		cnt <= cnt + 1'b1;
		led_flag <= 1;
	end
	else if(cnt >= 32'd36_000_000 && cnt < 32'd50_000_000) begin
		cnt <= cnt + 1'b1;
		led_flag <= 2;
	end
	else if(cnt >= 32'd50_000_000) begin
		cnt <= 32'd0;
		led_flag <= 0;
	end

end
    
always @ (*) begin
	case (led_flag)
		4'd0 : led = 4'b1111;
		4'd1 : led = 4'b1010;
		4'd2 : led = 4'b0101;
		default : led = 4'b1111; 
	endcase
end

endmodule

添加管脚约束

Vivado使用的约束文件格式为 xdc 文件。 xdc 文件里主要是完成管脚的约束 时钟的约束 ,以及组的约束。这里我们需要对 led.v 程序中的输入输出端口分配到 FPGA 的真实管脚上 。

添加时序约束

一个FPGA 设计除了管脚分配以外,还有一个重要的约束,那就是时序约束,这里通过向导方式演示如果进行一个时序约束。

  1. 点击“ Run Synthesis ”开始综合

  2. 弹出对话框点击“ OK

  3. 综合完成以后点击“ Cancel

  4. 点击“ Constraint s Wizard

  5. 在弹出的窗口中点击“ Next

  6. 时序约束向导分析出设计中的时钟,这里把“ sys_clk ”频率设置为 5 0Mhz ,然后点击“Skip to Finish ”结束时序约束向导。

这个时候 led.xdc 文件已经更新,点击“ Reload ”重新加载文件,并保存文件

生成BIT文件

  1. 编译的过程可以细分为综合、布局布线、生成 bit 文件等,这里我们直接点击“ GenerateBitstream 直接生成 bit 文件。
  2. 在弹出的对话框中可以选择任务数量,这里和 CPU 核心数有关,一般数字越大,编译越快,点击“ OK
  3. 编译中没有任何错误,编译完成,弹出一个对话框让我们选择后续操作, 可以选择Open Hardware Manger ”,当然,也可以选择 Cancel 我们这里选择 “ Cancel”,先不下载。

Vivado仿真

接下来我们不妨小试牛刀,利用Vivado 自带的 仿真工具来输出波形验证 流水灯程序 设计结果和我们的预想是否一致 注意:在生成 bit 文件之前也可以仿真 。 具体步骤如下:

1) 设置 Vivado 的仿真配置 右 击 SIMULATION 中 Simulation Settings 。

2) 在 Simulation Settings 窗口中进行如下图来配置,这里设置成 50ms (根据需要自行设定其它按默认设置,单击 OK 完成。

3) 添加 激励测试文件 ,点击 Project Manager 下的 Add Sources 图标 按下图设置后单击 Next

4) 点击 Create File 生成仿真激励文件 。


在弹出的对话框中输入激励文件的名字,这里我们输入名为tb_led_test。

5) 点击 Finish 按钮返回。


这里我们先不添加IO Ports ,点击 OK 。

在 Simulation Sources 目录下多了一个刚才添加的 vtf_led_test 文件。双击打开这个文件,可以看到里面只有 module 名的定义,其它都没有。

6) 接下去我们需要编写这个 tb_led_test.v 文件的内容。首先定义输入和输出信号,然后需要实例化 led_test 模块 让 led_test 程序作为本测试程序的一部分。再 添加复位和时钟的激励。完成后的 tb_led_test.v 文件如下:


`timescale 1ns / 1ps 
// 
// Module Name: tb_led_test 
// 
module tb_led_test; 
// Inputs 
reg sys_clk; 
reg sys_rst_n ; 
// Outputs 
wire [3:0] led; 
// Instantiate the Unit Under Test (UUT) 
led_flash uut_led_flash ( 
	.sys_clk(sys_clk), 
	.sys_rst_n(sys_rst_n), 
	.led(led) 
	);
initial begin 
// Initialize Inputs 
	sys_clk = 0; 
	sys_rst_n = 0 ; 
	#1000 ; 
	sys_rst_n = 1; 
end 
//Create clock 
always #10 sys_clk = ~ sys_clk; 

endmodule
  1. 编写好后保存, tb_ led_test .v 自动 成了这个仿真 Hierarchy 的顶层了,它下面是设计文件led_test .v
  2. 点击 Run Simulation 按钮,再选择 Run Behavioral Simulation 。这里我们做一下行为级的仿真就可以了。

    10.在 弹出 仿真界面 后 如下图,界面是仿真软件自动运行到仿真设置的 50ms 的波形。

    由于LED[3 0] 在程序中设计的状态变化时间长,而仿真又比较耗时,在这里观测 timer[31:0] 计数器变化。把它放到 Wave 中观察 点击 Scope 界面下的 uut 再右键选择 Objects 界面下的 timer在弹出的下拉菜单里选择 Add Wave Window 。

11.点击如下标注的 Restart 按钮复位一下,再点击 Run All 按钮。(需要耐心!!!) 可以 看到仿真波形与设计相符。( 注意 :仿真的时间越长,仿真的波形文件占用的磁盘空间越大,波形文件在工程目录的 xx.sim 文件夹)

下载

编译工程并生成比特流.bit文件后,点击 Vivado左侧“ Flow Navigator”窗口最下面的 Open Hardware Manager”按钮如 下图所示 。

此时将Xilinx下载器一 端连 接 电脑, 另 一端 与 开发板上 的 JTAG下载 口连接,开发板 连接电源线

注意!一定要先把下载器的一端连接到了电脑、另一端连接了JTAG接口之后,再给开发板上电!否则,对开发板的 JTAG接口进行带电热插拔,有一定概率会损坏 JTAG接口!

开发板连接好电源线和下载器后,打开开发板电源开关,点击 Hardware”窗口中的 “Auto Connect”图标,如下图所示:

可以看到 JTAG 扫描到 arm 和 FPGA 内核

选择 xc 7z020 _1 ,右键 Program Device…

在弹出窗口中点击“ Program

下载完成以后,我们可以看到 4 颗 LED 开始每秒变化一次。到此为止 Vivado 简单流程体验完成。后面的章节会介绍如果把程序烧录到 Flash ,需要 PS 系统的配合才能完成,只有PL 的工程不能直接烧写 Flash 。

按键控制LED实验Verilog(PL)

硬件设计

AX7020开发板的 PL 部分板载了 4 个用户按键 (KEY1~KEY4), 按键的信号连接到 ZYNQ 的BANK34 和 BANK35 的 IO 上。 按键 都 为低电平有效 , 没有按下时,信号为高;按键按下时,信号为低。





程序设计

按键控制LED系统框图 如下图 所示:

计数器对 50MHz时钟进行计数,从而达到计时的目的。 计数器在每次计时到 0.5秒的时候,就改变 LED的显示状态,然后清零并重新开始计数。

然后根据两个按键(KEY0和 KEY1)的状态,在不同的 LED状态下,分别设置 LED的显示模式(是同时闪烁,或者交替闪烁)。

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2021/12/20 17:25:22
// Design Name: 
// Module Name: led_key
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module led_key(
    input	sys_clk ,
	input	sys_rst_n ,
	
	input		[1 : 0] key ,
	output reg	[1 : 0] led
);
    
// reg define
reg	[24 : 0]	cnt;
reg				led_ctrl;

//***************************************************** 
//** main code 
//*****************************************************

// 计数器 产生计时器
always @ (posedge sys_clk or negedge sys_rst_n) begin
    if( !sys_rst_n )
        cnt <= 25'd0;
    else if( cnt <= 25'd5_000_000 ) 
        cnt <= cnt + 1'b1;
    else
        cnt <= 25'd0;
end

//每隔100ms就更改LED闪烁状态
always @ (posedge sys_clk or negedge sys_rst_n) begin
    if( !sys_rst_n ) 
        led_ctrl <= 1'b0;
    else if( cnt == 25'd5_000_000 )
        led_ctrl <= ~led_ctrl;
end

//根据按键的状态以及LED的闪烁状态来赋值LED
always @ ( posedge sys_clk or negedge sys_rst_n ) begin

    if( !sys_rst_n ) 
        led <= 2'b11;
    else case ( key )
        //如果按键0按下,则两个LED交替闪烁
        2'b10 : 
            if( led_ctrl == 1'b0 )  
                led <= 2'b01;
            else
                led <= 2'b10;
        //如果按键1按下,则两个LED同时闪烁
        2'b01 : 
            if( led_ctrl == 1'b0 )  
                led <= 2'b11;
            else
                led <= 2'b00;
        //如果两个按键都未按下,则两个LED都保持点亮
         2'b11 : 
            led <= 2'b00;

        default: ;
    endcase
end

endmodule

连接开发板的电源和下载器,并打开电源开关。在工程编译之后,将生成的bit文件下载到开发板中。下载完成之后,底板上 两个 PL LED处于 点亮状态。然后 按下 PL_KEY0,可以看到 两个 PL LED交替闪烁;按下 PL_KEY1,可以看到 两个 PL的 LED同时闪烁。

以上是关于ZYNQ从入门到秃头05 LED闪烁实验 && 按键控制LED实验Verilog(PL)的主要内容,如果未能解决你的问题,请参考以下文章

ZYNQ从入门到秃头10 DDS增强版实验ADDA测试(基于ALINX 7020 && AN108)

ZYNQ从入门到秃头07 FPGA 片内 RAM && ROM 读写测试实验

ZYNQ从入门到秃头07 FPGA 片内 RAM && ROM 读写测试实验

ZYNQ从入门到秃头10 DAC FIFO实验(AXI-stream FIFO IP核配置)

ZYNQ从入门到秃头08 FPGA片内异步FIFO读写测试实验

ZYNQ从入门到秃头08 FPGA片内异步FIFO读写测试实验