4 流水灯实验 4.1 LED简介 LED是什么?全称:Light Emitting Diode,发光二极管。
4.2 硬件设计 下面来看一下本次实验的硬件设计部分,也就是LED硬件电路,我们这里是将FPGA引脚直接连接到了发光二极管的阳极,然后LED的阴极接了一个电阻,电阻另一端连接到GND。所以引脚给高电平则LED亮,反之则熄灭。
注意,上面两个是PL的引脚,下面这两个PS的引脚。那由于底板上面只有两个灯,所以说我们是用两个灯来实现流水灯效果。
可以发现它这里都串联了一个电阻,其主要是起到一个限流的作用,就说限制流过发光二极管的电流。
4.3 实验任务 本节的实验任务是使用开发板上的两个/四个LED灯顺序点亮并熄灭循环往复产生流水灯的效果,流水的间隔时间为0.5s。
4.4 程序设计 首先,按照2.2小节,构建好项目的4大文件夹。
然后,使用思维导图软件绘制系统框图:
接着,使用Visio绘制模块框图,来确定最终的设计:
新手在编写代码之前,可以先画一下波形图,看着波形图写代码思路会更加清晰。
编写代码 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 module flow_led( input sys_clk, input sys_rst_n, output reg [3 :0 ] led ); reg [24 :0 ] cnt; always @(posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) cnt <= 25'd0 ; else if (cnt < (25'd25000000 - 25'd1 )) cnt <= cnt + 25'd1 ; else cnt<= 25'd0 ; end always @(posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) led <= 4'b0001 ; else if (cnt == (25'd25000000 - 25'd1 )) led <= {led[2 :0 ], led[3 ]}; else ; end endmodule
仿真验证 :
上面编写好了代码,但是这个代码编写的对不对,有没有语法错误,包括它的功能正不正确,还不知道。接下来可以通过仿真对代码进行验证,通过对比仿真的波形图,查看与前面绘制的波形图是否一致,来判断这个代码的编写的对不对。
对模块进行仿真,需要先编写tb测试文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 `timescale 1ns/1ns module tb_flow_led(); parameter CLK_PERIOD = 20 ; reg sys_clk; reg sys_rst_n; wire [3 :0 ] led; initial begin sys_clk <= 1'b0 ; sys_rst_n <= 1'b0 ; #200 sys_rst_n <= 1'b1 ; end always #(CLK_PERIOD/2) sys_clk = ~sys_clk; flow_led u_flow_led( .sys_clk (sys_clk ), .sys_rst_n (sys_rst_n), .led (led) ); endmodule
打开Modelsim软件进行仿真。
4.5 下载验证 打开Vivado,创建新的工程,起名为flow_led。根据之前的步骤一步一步创建好新工程。
首先,看一下RTL原理图,如下图所示:
然后,约束管脚。这里需要结合板子的PCB原理图,约束完成后,点击ctrl+s保存。保存完成之后,可以打开打开约束文件查看约束代码程序。
本实验比较简单,即使不加时序约束应该问题也不大,这里示例一下如何添加时序约束。这里需要对输入时钟做一个周期约束,也就是告诉Vivado软件输入的系统时钟频率是多少,然后Vivado软件就会基于这个时钟进行布局布线。
时序约束代码:
1 2 3 # 时序约束 create_clock -period 20 .000 -name sys_clk [get_ports sys_clk] # 简单解释:创建一个时钟,周期是20 ns,对应的端口是系统时钟sys_clk,也即对系统时钟的周期进行了约束
接下来,就可以生成比特流文件(是不是二进制文件???),等待编译完成,产生下载文件,在下载之前可以打开综合后的原理图看一下:
最后,连接开发板的下载口,下载程序。
5 按键控制LED灯亮灭实验 基本流程和上面的“流水灯”实验一致,这里就简写了。
实验任务 :本节的实验任务是使用开发板上的两个/四个按键控制两个/四个LED灯的亮灭。按下不同的按键,LED灯呈现不同的效果。
按键状态
LED显示效果
无按键按下
四个LED灯全灭
按下KEY0
自左向右的流水灯
按下KEY1
自右向左的流水灯
按下KEY2
四个灯同时闪烁
按下KEY3
四个灯全亮
使用思维导图,绘制系统框图
接着,使用Visio绘制模块框图,来确定最终的设计:
再来画一下波形图:
编写程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 module flow_led( input sys_clk, input sys_rst_n, input [1 :0 ] key, output reg [3 :0 ] led ); parameter CNT_MAX = 25'd25000000 ; reg [24 :0 ] cnt; reg led_flag; always @(posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) cnt <= 25'd0 ; else if (cnt < (CNT_MAX - 25'd1 )) cnt <= cnt + 25'd1 ; else cnt<= 25'd0 ; end always @(posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) led_flag <= 1'b0 ; else if (cnt == (CNT_MAX - 25'd1 )) led_flag <= ~led_flag else ; end always @(posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) led <= 2'b00 ; else begin case (key) 2'b11 : led <= 2'b00 ; 2'b10 : if (led_flag == 1'b0 ) led <= 2'b01 ; else led <= 2'b10 ; 2'b01 : if (led_flag == 1'b0 ) led <= 2'b01 ; else led <= 2'b10 ; 2'b00 : ; default : ; endcase end end endmodule
创建仿真文件(tench bench文件)进行仿真
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 `timescale 1ns/1ns module tb_key_led(); parameter CLK_PERIOD = 20 ; parameter TB_CNT_MAX = 25'd25000000 ; reg sys_clk; reg sys_rst_n; reg [1 :0 ] key; wire [3 :0 ] led; initial begin sys_clk <= 1'b0 ; sys_rst_n <= 1'b0 ; key <= 2 b'11 ; #200 sys_rst_n <= 1'b1 ; #2000 key <= 2 b'10 ; #2000 key <= 2 b'00 ; #2000 key <= 2 b'01 ; #2000 key <= 2 b'00 ; end always #(CLK_PERIOD/2) sys_clk = ~sys_clk; key_led #( .CNT_MAX (TB_CNT_MAX) ) key_led u_key_led( .sys_clk (sys_clk ), .sys_rst_n (sys_rst_n), .key (key), .led (led) ); endmodule
使用Modelsim软件进行仿真。
打开Vivado,创建新的工程,起名为key_led。根据之前的步骤一步一步创建好新工程。
添加约束文件:
综合后生成比特流文件,下载到板卡中。
6 触摸按键控制LED灯亮灭实验 6.1 触摸按键简介 6.1.1 触摸按键初识
触摸按键:通过轻触的形式,实现传统意义机械式按键的功能。
分类:电阻式、电容式、红外感应式和表面声波式。
电容式触摸按键的优点与缺点:
优点
无机械装置,使用寿命长
面板不需要开孔
产品更加美观简洁
防水可以做到很好
不需要按键消抖
灵活性高,多种输出模式
缺点
要单独的触摸芯片(触摸IC),实现对电容变化检测以及对电容按键的配置(什么情况输出高低电平)
没有传统机械式控层以反馈感
按键较多时,占用空间大,成本高
6.1.2 触摸IC简介 触摸IC:电容式触摸芯片是为实现人体触摸而设计的集成电路,可替代传统机械式轻触按键,且触摸界面防水防尘、自由定制、美观耐用。
常用的触摸IC有:AR101、JL223B和JL523B等。
触摸IC的引脚:
触摸IC模式配置说明:
6.2 硬件设计 触摸按键原理图
6.3 实验任务 本节的实验任务是使用触摸按键控制LED灯的亮灭,开发板上电后LED为点亮状态,手指触摸后LED熄灭;当再次触摸时,LED点亮。(自锁模式 )
6.4 程序设计 6.4.1 思维导图分析模块
6.4.2 系统框图和波形图
6.4.3 编写程序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 module touch_led( input sYs_clk, input sys_rst_n, input touch_key, output led ); reg touch_key_d0;reg touch_key_d1,wire pos_touch_key;assign pos_touch_key = ~touch_key_d1 & touch_key_d0; always @ (posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) begin touch_key_d0 <= 1'b0 ; touch_key_d1 <= 1'b0 ; end else begin touch_key_d0 <= touch_key; touch_key_d1 <= touch_key_d0; end end always @(posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) led <= 1'b1 ; else if (pos_touch_key) led <= ~led; else led <= led; end endmodule
6.4.4 仿真
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 `timescale 1ns/1ns module tb_touch_led(); parameter CLK_PERIOD = 20 ; parameter TB_CNT_MAX = 25'd25000000 ; reg sys_clk; reg sys_rst_n; reg touch_key; wire led; initial begin sys_clk <= 1'b0 ; sys_rst_n <= 1'b0 ; touch_key <= 1 b'0 ; #200 sys_rst_n <= 1'b1 ; #1000 touch_key <= 2 b'1 ; #2000 touch_key <= 2 b'0 ; #1000 touch_key <= 2 b'1 ; #2000 touch_key <= 2 b'0 ; end always #(CLK_PERIOD/2) sys_clk = ~sys_clk; key_led #( .CNT_MAX (TB_CNT_MAX) ) touch_led u_touch_led( .sys_clk (sys_clk ), .sys_rst_n (sys_rst_n), .touch_key (touch_key), .led (led) ); endmodule
6.5 下载验证 打开Vivado,创建新的工程,起名为touch_led。根据之前的步骤一步一步创建好新工程。
添加约束文件:
生成比特流文件,下载到板子中验证。
补充:异步信号同步
touch_key是一个异步信号,对于这个异步信号的一个同步呢一般都是通过打拍 的方式,比方说打两拍,打两拍之后这个信号就是同步到时钟域了。
要注意的是,就是说打一拍的时候,其实有的时候会出现一个问题——比方要采这个异步信号,如果说时钟刚好采到这个异步信号的一个边缘的位置,就说它变化的位置,这个时候会出现有可能踩不准确的情况,它其实就是一种亚稳态 了,亚稳态就是指这个触发器的输出在规定的时间之内不能达到一个稳定的状态,其实就是指这里的_d0,它就是对这个异步信号打一拍,如果说你刚好打的位置就是变化的位置,那么_d0它会出现一个亚稳态,它采到的值有可能是零、有可能是一。所以说这就容易出现问题。
打一拍它会出现亚稳态,那么可以采用打2拍、打3拍 的方式,来得到一个上升沿。
7 按键控制蜂鸣器实验 8 呼吸灯实验 8.1 呼吸灯简介 呼吸灯:由灭渐亮,然后再由亮渐灭,模仿人呼吸方式的LED灯。
呼吸灯原理:PWM(Pulse Width Modulation),脉冲宽度调制。
8.2 实验任务 本节实验任务是使用正点原子FPGA开发板上的LED,实现呼吸灯的效果,即由灭渐亮,然后再由亮渐灭(渐亮和渐灭的时间为2s)。
8.3 程序设计 8.3.1 思维导图分析模块
8.3.2 系统框图和波形图
8.3.3 编写程序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 module breath_led( input sys_clk, input sys_rst_n, output reg led ); parameter CNT_2US_MAX = 7'd100 ;parameter CNT_2MS_MAX = 10'd1000 ;parameter CNT_2S_MAX = 10'd1000 ; reg [6 :0 ] cnt_2us;reg [9 :0 ] cnt_2ms;reg [9 :0 ] cnt_2s;reg inc_dec_flag; always @(posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) cnt_2us <= 7'b0 ; else if (cnt_2us == (CNT_2US_MAX - 7'b1 )) cnt_2us <= 7'b0 ; else cnt_2us <= cnt_2us + 7'b1 ; end always @ (posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) cnt_2ms <= 10'b0 ; else if (cnt_2us == (CNT_2US_MAX - 7'b1 ) && cnt_2ms == (CNT_2MS_MAX = 10'b1 ) cnt_2ms <= 10'b0 ; else if (cnt_2us == (CNT_2US_MAX - 7'b1 )) cnt_2ms <= cnt_2ms + 10'b1 ; else cnt_2ms <= cnt_2ms; end always @(posedge sys_clk or negedge sys_rst_n) begin if (sys_rst_n) cnt_2s <= 10'b0 ; else if (cnt_2us == (CNT_2US_MAX - 7'b1 ) && cnt_2ms = (CNT_2MS_MAX = 10'b1 ) && cnt_2s = (CNT_2S_MAX - 10'b1 )) cnt_2s <= 10'b0 ; else if (cnt_2us == (CNT_2US MAX - 7'b1 ) && cnt_2ms == (CNT_2MS_MAX = 10'b1 )) cnt_2s <= cnt_2s + 10'b1 ; else cnt_2s <= cnt_2s; end always @(posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) inc_dec_flag <= 1'b0 ; else if (cnt_2us == (CNT_2US_MAX - 7'b1 ) && cnt_2ms == (CNT_2MS MAX = 10 b1) && cnt_2s == (CNT_2S_MAX - 10'b1 )) inc_dec_flag <= ~inc_dec_flag; else inc_dec_flag <= inc_dec_flag; end always @ (posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) led <= 1'b0 ; else if ((inc_dec_flag == 1'b0 && cnt_2ms <= cnt_2s) || (inc_dec_flag == 1'b1 && cnt_2ms >= cnt_2s)) led <= 1'b1 ; else led <= 1'b0 ; end endmodule
8.3.4 仿真
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 `timescale 1ns/1ns module tb_breath_led();parameter CLK_PERIOD = 20 ; parameter CNT_2US_MAX = 7'd1 ;parameter CNT_2MS_MAX = 10'd10 ;parameter CNT_2S_MAX = 10'd10 ;reg sys_clk; reg sys_rst_n;wire [3 :0 ] led;initial begin sys_clk <= 1'b0 ; sys_rst_n <= 1'b0 ; #200 sys_rst_n <= 1'b1 ; end always #(CLK_PERIOD/2) sys_clk = ~sys_clk;breath_led #( .CNT_2US_MAX (CNT_2US_MAX) .CNT_2MS_MAX (CNT_2MS_MAX) .CNT_2S_MAX (CNT_2S_MAX) ) u_breath_led( .sys_clk (sys_clk ), .sys_rst_n (sys_rst_n ), .led (led ) ); endmodule
8.4 下载验证 打开Vivado,创建新的工程,起名为breath_led。根据之前的步骤一步一步创建好新工程。