FPGA实现按键控制LED灯实验

  按键是常用的一种控制器件。生活中我们可以见到各种形式的按键,由于其结构简单,成本低廉等特点,在家电、数码产品、玩具等方面有广泛的应用。

本实验我们将介绍如何使用按键控制多个LED的亮灭。

1. 按键简介

  按键开关是一种电子开关,属于电子元器件类。

我们的开发板上有两种按键开关:

  第一种是本实验所使用的轻触式按键开关(如下图1),简称轻触开关。

    使用时以向开关的操作方向施加压力使内部电路闭合接通,当撤销压力时开关断开,其内部结构是靠金属弹片受力后发生形变来实现通断的;

  第二种是自锁按键(如下图2),自锁按键第一次按下后保持接通,即自锁,第二次按下后,开关断开,同时开关按钮弹出来。

开发板上的电源键就是第一种开关。

图1 轻触式按键

 

图2 自锁式按键

2. 实验任务

   使用开发板上的四个按键控制四个LED灯。不同按键按下时,四个LED灯显示不同效果。(由于按键1被复位键占用,故本实验中使用按键2、按键3、按键4控制LED灯显示四种状态)

    当按下按键2时,4个LED灯显示从右向左流水灯效果。

    当按下按键3时,4个LED灯显示从左向右流水灯效果。

    当按下按键4时,4个LED灯闪烁

3. 硬件设计

  本实验中,系统时钟、复位按键、按键和LED灯的管脚如下表所示。

 

 

 按键控制LED管脚分配图

 4. 程序设计

 

 

系统框图

运行代码:

/***********************************************************************
Filename     : key_led.v
Author       : 
Company      : 
Mail         : 
Device       : Altera
Enviroment   : Win10,Quartus16.1,modelsim 10.4
Created date : 
Version      : V1.0
Description  : 
Sim          :
Modified by  :
Modified date:
Version      :
Description  :
************************************************************************/
module key_led (
  input i_sys_clk,/* 系统时钟信号50MHz */
  input i_sys_rst_n,/* 系统复位信号,低有效 */
  input [2:0] i_key,/* 按键输入信号 */
  output [3:0] o_led/* LED输出信号 */
);
/* 定义0.2s计数寄存器 */
parameter p_0_2s_counter = 10_000_000;
reg [23:0] r_0_2s_counter = 24'd0;
always @ (posedge i_sys_clk or negedge i_sys_rst_n)
begin
  if (~i_sys_rst_n)
    r_0_2s_counter <= 24'd0;
  else if (r_0_2s_counter == (p_0_2s_counter - 1'b1))
    r_0_2s_counter <= 24'd0;
  else
    r_0_2s_counter <= r_0_2s_counter + 1'b1;
end
/* 定义LED状态转换寄存器 */
reg [1:0] r_led_state_switch = 2'd0;
always @ (posedge i_sys_clk or negedge i_sys_rst_n)
begin
  if (~i_sys_rst_n)
    r_led_state_switch <= 2'b00;
  else if (r_0_2s_counter == (p_0_2s_counter - 1'b1))
    r_led_state_switch <= r_led_state_switch + 1'b1;
  else
    r_led_state_switch <= r_led_state_switch;
end
/* 识别按键,切换显示模式 */
reg [3:0] r_led;
always @ (posedge i_sys_clk or negedge i_sys_rst_n)
begin
  if (~i_sys_rst_n)
    r_led <= 4'b0000;
  /* 按键2按下时,从右向左流水灯效果 */
  else if (i_key[0] == 1'b0)
    case (r_led_state_switch)
      2'b00 : r_led <= 4'b1000;
      2'b01 : r_led <= 4'b0100;
      2'b10 : r_led <= 4'b0010;
      2'b11 : r_led <= 4'b0001;
      default : r_led <= 4'b0000;
    endcase
  /* 按键3按下时,从左向右流水灯效果 */
  else if (i_key[1] == 1'b0)
  case (r_led_state_switch)
    2'b00 : r_led <= 4'b0001;
    2'b01 : r_led <= 4'b0010;
    2'b10 : r_led <= 4'b0100;
    2'b11 : r_led <= 4'b1000;
    default : r_led <= 4'b0000;
  endcase
  /* 按键4按下时,LED闪烁 */
  else if (i_key[2] == 1'b0)
  case (r_led_state_switch)
    2'b00 : r_led <= 4'b1111;
    2'b01 : r_led <= 4'b0000;
    2'b10 : r_led <= 4'b1111;
    2'b11 : r_led <= 4'b0000;
    default : r_led <= 4'b0000;
  endcase
  /* 无按键按下时,LED熄灭 */
  else
    r_led <= 4'b0000;
end
assign o_led = r_led;
endmodule

 

 

 

 

 

转载于:https://www.cnblogs.com/ltybk/p/11549779.html

  • 0
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
nrf51822并没有PWM模块,但是如果巧妙的结合PPI模块,并加上一个定时器中断就可以轻松的实现了PWM,思路是这样的: 定时器使用三个比较器 cc0、cc1和cc2,当三个比较器任何一产生比较事件的时候都会通过PPI去翻转GPIO的引脚,在初始化的时候这样设置这三个比较器: NRF_TIMER2->CC[0] = MAX_SAMPLE_LEVELS + next_sample_get(); NRF_TIMER2->CC[1] = MAX_SAMPLE_LEVELS; // CC2 will be set on the first CC1 interrupt. NRF_TIMER2->CC[2] = 0; 这是初始化的配置,到这里会有一个思考,这样的话计数器技术到cc0的时候依然会继续的往下计数,那这样的话他的再溢出的值就将回到cc2的时候也就是归零的时候,那这样的波形就分为了三段了,这不是我们所需要的,那这样要实现PWM就要把cc2的比较值往后挪,让他超过cc0,并且cc2到之前的一个比较值是固定的,这样就需要从新设置cc2的值,还有一个办法就是当计数器到cc0的时候请求中断重置计数器,但是这样做有一个问题就是进入中断是需要时间的,而当计数器到达cc0的时候就需要重置,同时计数器的下一个值就是cc2,这样就会造成冲突,所以我们使用了第一种方案。 具体实现是这样的,使能cc1比较中断,在第一次中断中重新设置cc1,让他的值变成了两倍,同时从新设置cc2,让他的值变成了cc1+N,N就是占空比参数,在第二次中断中,也是从新设置cc1,但是和上一次中断不同的是这时候设置的是cc0,而不是cc2 这样造成的计数器溢出值是这样的:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值