本帖最后由 正点原子运营 于 2023-11-4 11:41 编辑
第九章 按键控制LED灯实验
1)实验平台:正点原子 ATK-DFPGL22G开发板
2) 章节摘自【正点原子】ATK-DFPGL22G之FPGA开发指南_V1.0
6)FPGA技术交流QQ群:435699340
按键是常用的一种控制器件。生活中我们可以见到各种形式的按键,由于其结构简单,成本低廉等特点,在家电、数码产品、玩具等方面有广泛的应用。本章我们将介绍如何使用按键来控制LED闪烁的方式。 本章包括以下几个部分: 1.1 按键简介 1.2 实验任务 1.3 硬件设计 1.4 程序设计 1.5 下载验证
1.1 按键简介按键开关是一种电子开关,属于电子元器件类。我们的开发板上有两种按键开关:第一种是本实验所使用的轻触式按键开关(如图 9.1.1),简称轻触开关。使用时以向开关的操作方向施加压力使内部电路闭合接通,当撤销压力时开关断开,其内部结构是靠金属弹片受力后发生形变来实现通断的;第二种是自锁按键(如图 9.1.2),自锁按键第一次按下后保持接通,即自锁,第二次按下后,开关断开,同时开关按钮弹出来,开发板上的电源键就是这种开关。 1.2 实验任务本节实验任务是使用ATK-DFPGL22G开发板上的KEY1~KEY3按键来控制开发板上的LED0~ LED3四个LED的闪烁方式。没有按键按下时,四个LED全部熄灭;如果按键0按下,则四个LED从右向左呈现流水灯效果;如果按键1按下,则四个LED从左向右呈现流水灯效果;如果按键2按下,则四个LED同时闪烁;如果按键3按下,则四个LED保持全亮。
1.3 硬件设计开发板上按键的原理图如下图所示: 如图 9.3.1所示,开发板上的四个按键未按下时,输出高电平,按下后,输出低电平。
本实验的管脚分配如下表所示:
对应的FDC约束语句如下所示: - create_clock -name {clk} [get_ports {sys_clk}]-period {20} -waveform {0.000 10.000}
- define_attribute {p:led[3]}{PAP_IO_DIRECTION} {OUTPUT}
- define_attribute {p:led[3]}{PAP_IO_LOC} {G1}
- define_attribute {p:led[3]} {PAP_IO_VCCIO}{1.5}
- define_attribute {p:led[3]}{PAP_IO_STANDARD} {LVCMOS15}
- define_attribute {p:led[3]}{PAP_IO_DRIVE} {4}
- define_attribute {p:led[3]}{PAP_IO_PULLUP} {TRUE}
- define_attribute {p:led[3]}{PAP_IO_SLEW} {SLOW}
- define_attribute {p:led[2]} {PAP_IO_DIRECTION}{OUTPUT}
- define_attribute {p:led[2]}{PAP_IO_LOC} {J7}
- define_attribute {p:led[2]}{PAP_IO_VCCIO} {1.5}
- define_attribute {p:led[2]}{PAP_IO_STANDARD} {LVCMOS15}
- define_attribute {p:led[2]}{PAP_IO_DRIVE} {4}
- define_attribute {p:led[2]} {PAP_IO_PULLUP}{TRUE}
- define_attribute {p:led[2]}{PAP_IO_SLEW} {SLOW}
- define_attribute {p:led[1]}{PAP_IO_DIRECTION} {OUTPUT}
- define_attribute {p:led[1]}{PAP_IO_LOC} {J6}
- define_attribute {p:led[1]}{PAP_IO_VCCIO} {1.5}
- define_attribute {p:led[1]}{PAP_IO_STANDARD} {LVCMOS15}
- define_attribute {p:led[1]}{PAP_IO_DRIVE} {4}
- define_attribute {p:led[1]}{PAP_IO_PULLUP} {TRUE}
- define_attribute {p:led[1]}{PAP_IO_SLEW} {SLOW}
- define_attribute {p:led[0]}{PAP_IO_DIRECTION} {OUTPUT}
- define_attribute {p:led[0]} {PAP_IO_LOC}{F3}
- define_attribute {p:led[0]}{PAP_IO_VCCIO} {1.5}
- define_attribute {p:led[0]}{PAP_IO_STANDARD} {LVCMOS15}
- define_attribute {p:led[0]}{PAP_IO_DRIVE} {4}
- define_attribute {p:led[0]}{PAP_IO_PULLUP} {TRUE}
- define_attribute {p:led[0]}{PAP_IO_SLEW} {SLOW}
- define_attribute {p:key[3]}{PAP_IO_DIRECTION} {INPUT}
- define_attribute {p:key[3]}{PAP_IO_LOC} {G3}
- define_attribute {p:key[3]}{PAP_IO_VCCIO} {1.5}
- define_attribute {p:key[3]}{PAP_IO_STANDARD} {LVCMOS15}
- define_attribute {p:key[3]} {PAP_IO_PULLUP}{TRUE}
- define_attribute {p:key[2]}{PAP_IO_DIRECTION} {INPUT}
- define_attribute {p:key[2]}{PAP_IO_LOC} {H6}
- define_attribute {p:key[2]}{PAP_IO_VCCIO} {1.5}
- define_attribute {p:key[2]}{PAP_IO_STANDARD} {LVCMOS15}
- define_attribute {p:key[2]}{PAP_IO_PULLUP} {TRUE}
- define_attribute {p:key[1]}{PAP_IO_DIRECTION} {INPUT}
- define_attribute {p:key[1]}{PAP_IO_LOC} {H5}
- define_attribute {p:key[1]}{PAP_IO_VCCIO} {1.5}
- define_attribute {p:key[1]}{PAP_IO_STANDARD} {LVCMOS15}
- define_attribute {p:key[1]}{PAP_IO_PULLUP} {TRUE}
- define_attribute {p:key[0]}{PAP_IO_DIRECTION} {INPUT}
- define_attribute {p:key[0]}{PAP_IO_LOC} {F2}
- define_attribute {p:key[0]}{PAP_IO_VCCIO} {1.5}
- define_attribute {p:key[0]}{PAP_IO_STANDARD} {LVCMOS15}
- define_attribute {p:key[0]}{PAP_IO_PULLUP} {TRUE}
- define_attribute {p:sys_clk}{PAP_IO_DIRECTION} {INPUT}
- define_attribute {p:sys_clk}{PAP_IO_LOC} {B5}
- define_attribute {p:sys_clk}{PAP_IO_VCCIO} {3.3}
- define_attribute {p:sys_clk}{PAP_IO_STANDARD} {LVCMOS33}
- define_attribute {p:sys_clk}{PAP_IO_PULLUP} {TRUE}
- define_attribute {p:sys_rst_n}{PAP_IO_DIRECTION} {INPUT}
- define_attribute {p:sys_rst_n}{PAP_IO_LOC} {G5}
- define_attribute {p:sys_rst_n}{PAP_IO_VCCIO} {1.5}
- define_attribute {p:sys_rst_n}{PAP_IO_STANDARD} {LVCMOS15}
- define_attribute {p:sys_rst_n}{PAP_IO_PULLUP} {TRUE}
复制代码
1.4 程序设计按键控制LED系统框图如下图所示: 在图 9.4.1中,计数器对50MHz时钟进行计数,从而达到计时的目的。计数器在每次计时到0.2秒的时候,就改变LED的显示状态,然后清零并重新开始计数。
根据四个按键(KEY0~KEY3)的状态,分别设置LED的显示模式(是流水灯,或是同时闪烁,或是同时常亮)。
按键控制led模块的代码如下所示: - 1 module key_led(
- 2 input sys_clk , //50Mhz系统时钟
- 3 input sys_rst_n, //系统复位,低有效
- 4 input [3:0 key, //按键输入信号
- 5 output reg [3:0 led //LED输出信号
- 6 );
- 7
- 8 //reg define
- 9 reg [23:0 cnt;
- 10 reg [1:0 led_control;
- 11
- 12 //用于计数0.2s的计数器
- 13 always @ (posedge sys_clk or negedge sys_rst_n) begin
- 14 if(!sys_rst_n)
- 15 cnt<=24'd9_999_999;
- 16 else if(cnt<24'd9_999_999)
- 17 cnt<=cnt+1;
- 18 else
- 19 cnt<=0;
- 20 end
- 21
- 22 //用于led灯状态的选择
- 23 always @(posedge sys_clk or negedge sys_rst_n) begin
- 24 if (!sys_rst_n)
- 25 led_control <= 2'b00;
- 26 else if(cnt == 24'd9_999_999)
- 27 led_control <= led_control + 1'b1;
- 28 else
- 29 led_control <= led_control;
- 30 end
- 31
- 32 //识别按键,切换显示模式
- 33 always @(posedge sys_clk or negedge sys_rst_n) begin
- 34 if(!sys_rst_n) begin
- 35 led<=4'b 0000;
- 36 end
- 37 else if(key[0]== 0) //按键1按下时,从右向左的流水灯效果
- 38 case (led_control)
- 39 2'b00 : led<=4'b1000;
- 40 2'b01 : led<=4'b0100;
- 41 2'b10 : led<=4'b0010;
- 42 2'b11 : led<=4'b0001;
- 43 default : led<=4'b0000;
- 44 endcase
- 45 else if(key[1]== 0) //按键1按下时,从右向左的流水灯效果
- 46 case (led_control)
- 47 2'b00 : led<=4'b0001;
- 48 2'b01 : led<=4'b0010;
- 49 2'b10 : led<=4'b0100;
- 50 2'b11 : led<=4'b1000;
- 51 default : led<=4'b0000;
- 52 endcase
- 53 else if (key[2]==0) //按键2按下时,LED闪烁
- 54 case (led_control)
- 55 2'b00 : led<=4'b1111;
- 56 2'b01 : led<=4'b0000;
- 57 2'b10 : led<=4'b1111;
- 58 2'b11 : led<=4'b0000;
- 59 default : led<=4'b0000;
- 60 endcase
- 61 else if (key[3]==0) //按键3按下时,LED全亮
- 62 led<=4'b1111;
- 63 else
- 64 led<=4'b0000; //无按键按下时,LED熄灭
- 65 end
- 66
- 67 endmodule
复制代码代码主要分为三个部分,第13至20行对系统时钟计数,当计数时间达0.2s时,计数器清零,同时使led_control在四个状态(00,01,10,11)内依次变化。第33至65行利用case语句实现对按键状态的检测,当不同的按键按下时,led随着led_control的变化,被赋予不同的值。
1.5 下载验证 连接开发板的电源和下载器,并打开电源开关。在工程编译之后,将生成的sbit文件下载到开发板中。下载完成之后,开发板上四个LED处于熄灭状态。然后按下KEY1,可以看到四个LED从右向左呈现流水灯效果;按下KEY2,可以看到四个LED同时闪烁盘;按下KEY3,可以看到四个LED保持长亮,如下图所示:
|