一:背景介绍
今天早上开工,将按键控制LED的循环左移一位,这一功能实现了一把,这是一个基础功能,我想要的最终实现方式是:状态机FSM;
进阶版本是:状态机通过按键控制其条件的转变,实现多个功能的轮流展示
说到按键电路,大家脑海里首先反应出的就是:按键消抖;
二:知识问答
我想问几个问题:
1)按键消抖有几种方法呢?
两种
2)哪两种呢?
硬件方法 + 软件方法;
3)软件方法如何实现呢?
避过按键的抖动时间
4)按键的抖动期是多长?
5ms~~10ms(网络给出的,其实也差不多了,10ms的抖动期,一般课题,都可以正确实现)
三:思路解析
说到消抖,单片机里已经给出了方法,也就是:如果监测到按键按下(按键出现低电平),跳过10ms的抖动期,然后再检测,是否仍然为低电平,如果是,那就是真的按下了;
那么FPGA呢,是不是也是这种方法?
也可以这样做的,没有问题的,但是使用FPGA延时,需要注意的是:当按键按下后,会不会多次操作某一功能;这是关键,切记;
我推荐的是另一种方法;计数停止法。
核心思想:
如果监测到按键按下(按键出现低电平),那么就开始计数,如果计数到10ms时,仍然为0,则确定为:按键按下,计数停止
如果监测到按键未按下,或者,按键松开,计数值清零,然后一直计数,知道计满10ms为止。
四:框图
在此简略,稍后附上
五:小结
循环左移是一个简单地 实验,添加了按键消抖,在简单里加点料。
我现在还没有尝试使用状态机,写出描述语句,我的打算是:等所有课题或者项目的语句,描述了清楚后再用状态机;
简单铸就雄伟
我先将目前学习过的知识进行一个汇总,然后再逐个提升,简单心思,如此而已;
什么都想做,什么都想一步到位,那是牛人干的事情,作为一个普通人士,我选择逐层提升;
不要瞧不上,LED灯循环左移之类的,举3个例子:串口DB9,使用串行数据传输;SPI,使用串行数据传输;IIC,使用串行数据传输,数据需要移动,左移和右移是不是就用上 了。
大项目也是是由诸多的小项目汇总而成,小项目都还没用搞定,大项目也只能望海兴叹.。
就写这么多的,没法口吐莲花,简单的东西都能讲出花,就此搁笔,与诸君分享。
六:程序
//======================================//
//==Fosc : 50MHz
//==Timescale : 1ns/1ns
//==File name : huxideng.v
//==Date : 2016-09-28
//==Author : CY
//==Function : 每按键一次,一个LED灯循环亮灭
//==Description:
// 当没有按键 按下时,flag—_10ms=1'b0;
// 当有 按键 按下时,flag_10ms=1'b1;
//
//======================================//
module key_new(
input wire sclk,
input wire rst_n,
input wire key_in,
output reg key_value
);
//==========================//
parameter T_10ms=19'd499_999;
//==========================//
reg [18:0] cnt_10ms;
reg flag_10ms;
//==========cnt_10ms==========//
always@(posedge sclk or negedge rst_n)
if(!rst_n)
cnt_10ms <=19'd0;
else if(key_in==1'b1) //没有这一句,意味着是可以累积计数的,如此会出现,即使遇到1就停止计数,一旦监测到0就会累加计数;
cnt_10ms <=19'd0; //我们实际需要的是:key_in=1时,清零,遇到0时就累积加,所以,必须要添加此句
else if(cnt_10ms==T_10ms) //为的是cnt_10ms>T_10ms,如此就不会执行 cnt_10ms <=cnt_10ms+1'b1;
cnt_10ms <=19'd500_000;
// else if(key_in==1'b0) //
else if(key_in==1'b0&&cnt_10ms<=T_10ms) //目的 是:计数T_10ms+1'b1之后,就不加1
cnt_10ms <=cnt_10ms+1'b1;
//==========flag_10ms========//
always@(posedge sclk or negedge rst_n)
if(!rst_n)
flag_10ms <=1'b0; //因为key_value要取反,所以光有flag_10ms=0是不行的,还需要key_in==1'b0;按下了才有效果
else if(cnt_10ms==T_10ms-1'b1)
flag_10ms <=1'b1;
else
flag_10ms <=1'b0;
//==================//
always@(posedge sclk or negedge rst_n)
if(!rst_n)
key_value <=1'b0; //我看到是LED上电就亮,我还就奇怪了,不可能的啊!后来看看电路图,
// else if(flag_10ms==1'b1) //原来LED是高电平亮,我的初始化key_value<=1'b1;
else if(flag_10ms==1'b1&&key_in==1'b0)//所以不管怎么修改电路,都是LED开机就亮,修正为0时,就可以 了
key_value <=~key_value;
// key_value<=1'b0;
// else
// key_value <=1'b1;
endmodule