Zynq开发实践(FPGA之按键输入)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

led显示是数字电路中的输出部分,最简单的应用场景。那输入部分的话,就是按键。这样按键和led,就是最简单的输入和输出部分。很多开发板也是会以这两个case作为范例,来进行教学处理。这样学完之后,大家有一个基本的印象,即用fpga如何来描述输入输出电路。

1、按键的特点

其实按键最大的一个问题就是抖动。按键没有按下去的时候,一般就是一个高电平。但是按下去之后,就变成了低电平。中间呢,因为抖动的原因,还有可能恢复成高电平,这是比较麻烦的事情。后期按键恢复的时候,也会出现这个情况。

2、软件如何解决

大家解决这个问题之前,可以试想一下,如果是软件,该怎么解决。因为嵌入式mcu、和fpga两者本质上是一样的处理思路。处理fpga,只不过是把软件处理的思路转变成fpga描述电路。所以,我们如果是软件处理按键,一般这么来做,

复制代码
while(1)
{
    // read gpio value
    gpio_value = read_gpio();
    if(gpio_old == gpio_value)
    {
        sleep(5ms);
        continue;
    }

    sleep(10ms);
    gpio_value = read_gpio();
    if(gpio_old != gpio_value)
    {
        report_event(gpio_value);
        gpio_old = gpio_value;
    }
}

首先,我们需要定时轮询这个数值,如果相同,下次继续轮询。一旦发现不同,就需要sleep大约10ms。这个10ms就是去除硬件抖动的时间,再次读取gpio_value。如果发现还是发现不同,就及时上报。至于是上升沿上报,还是下降沿上报,就看自己的需求了。

3、fpga如何实现

本质上,fpga处理的方法和软件处理的方法是一样的。只不过fpga是并发处理,可以降低cpu轮询时间。并且fpga还有一个好处,那就是不管多少个gpio,对它来说都是一样的处理速度,本来每一个端口都是并发的。同样,我们首先需要依次读入信号,

复制代码
// input signal

always @(posedge clk or negedge rst)
	if(!rst) begin
		in1 <= 1'b1;
		in2 <= 1'b1;
	end 
	else begin
		in1 <= in;
		in2 <= in1;
	end

接着就是添加一个状态机。添加的目的,主要还是为了方便编写verilog,利用寄存器编写状态机可以让整个流程更加清晰。

复制代码
// state machine

always @(posedge clk or negedge rst) // state machine defined here
	if(!rst)
		state <= 1'b0;
	else if(in1 != in2 && state == 1'b0)
		state <= 1'b1;
	else if(count == `TIME_DELAY && state == 1'b1)
		state <= 1'b0;

软件处理的时候是统一计数10ms。那么硬件处理的时候,其实也需要进行计数处理。因为硬件触发可能存在抖动,如果发生这一情况,还需要重新开始计数处理,

复制代码
// about counter

always@(posedge clk or negedge rst)
	if(!rst)
		count <= 16'h0;
	else if(state == 1'b1) begin
		if(count == `TIME_DELAY || in1 != in2)
			count <= 16'h0;
		else
			count <= count + 16'h1;
	end

最后就是统一输出处理。等到计数时间达到要求的时候,才开始进行统一的输出。这个时候再根据输出来判断按键事件,就会容易很多。

复制代码
// out signal

always@(posedge clk or negedge rst)
	if(!rst)
		out1 <= 1'b1;
	else if(count == `TIME_DELAY && state == 1'b1)
		out1 <= in2;

always @(posedge clk or negedge rst)
	if(!rst)
		out2 <= 1'b1;
	else
		out2 <= out1;

// final result

always @(*)
	if(!rst)
		out = 1'b0;
	else if(!out1 & out2)
		out = 1'b1;
	else // or out1&!out2
		out = 1'b0;

4、验证和测试

代码写好之后,在上板子之前一定要自己仿真测试一下。一方面效率比较高,可以去除简单的语法错误,还可以验证功能,特别是corner case。这个时候,我们写的test case是这样的,

复制代码
`timescale 1ns/1ps
module test();
 
reg rst;
reg clk;
reg in;
wire out;
 
key key(.rst(rst),
    .clk(clk),
    .in(in),
	.out(out));
 
initial
    begin
        rst = 1;
		in = 1;
        clk = 0;
        #12 rst = 0;
        #21 rst = 1;
		#35 in = 0;
		#50 in = 1;
		#70 in = 0;
		#500 in = 1;
        #1000 $finish;
    end
 
 
initial
begin
    while(1)
    clk = #5 !clk;
end
 
initial
begin
    $dumpfile("hello.vcd");
    $dumpvars(0, test);
end
 
endmodule

执行之后,就是这样的逻辑图,

最后给出完整的verilog代码,有需求的同学可以好好看下按键输入是怎么处理的,

复制代码
module key(input clk, //50M clk
		input rst,
		input in,
		output reg out);

`define TIME_DELAY 16'h20

reg in1;
reg in2;
reg out1;
reg out2;
reg state;
reg[15:0] count;

// input signal

always @(posedge clk or negedge rst)
	if(!rst) begin
		in1 <= 1'b1;
		in2 <= 1'b1;
	end 
	else begin
		in1 <= in;
		in2 <= in1;
	end

// state machine

always @(posedge clk or negedge rst) // state machine defined here
	if(!rst)
		state <= 1'b0;
	else if(in1 != in2 && state == 1'b0)
		state <= 1'b1;
	else if(count == `TIME_DELAY && state == 1'b1)
		state <= 1'b0;

// about counter

always@(posedge clk or negedge rst)
	if(!rst)
		count <= 16'h0;
	else if(state == 1'b1) begin
		if(count == `TIME_DELAY || in1 != in2)
			count <= 16'h0;
		else
			count <= count + 16'h1;
	end

// out signal

always@(posedge clk or negedge rst)
	if(!rst)
		out1 <= 1'b1;
	else if(count == `TIME_DELAY && state == 1'b1)
		out1 <= in2;

always @(posedge clk or negedge rst)
	if(!rst)
		out2 <= 1'b1;
	else
		out2 <= out1;

// final result

always @(*)
	if(!rst)
		out = 1'b0;
	else if(!out1 & out2)
		out = 1'b1;
	else // or out1&!out2
		out = 1'b0;

endmodule
相关推荐
Js_cold1 小时前
FPGA DDR 地址映射-黄金法则
图像处理·fpga开发·音视频·视频
YoungUpUp8 小时前
【电子设计自动化(EDA)】Altium Designer25——电子设计自动化(EDA)软件版保姆级下载安装详细图文教程(附安装包)
运维·设计模式·fpga开发·自动化·eda·电路仿真·电子设计自动化
电子凉冰8 小时前
FPGA入门-计数器
fpga开发
FPGA_ADDA20 小时前
基于复旦微ZYNQ7015+VU3P 的双FMC 基带信号处理平台(国产率100%)
fpga开发·信号处理·全国产·vu3p·adda射频采集
9527华安1 天前
FPGA实现Aurora 64B66B图像视频传输,基于GTY高速收发器,提供2套工程源码和技术支持
fpga开发·音视频·aurora·高速收发器·gty·aurora 64b66b
我是苹果,不是香蕉2 天前
【FPGA Interlaken协议】
fpga开发
碎碎思2 天前
“邪修“FPGA[~秘笈]
fpga开发
不会留有遗憾2 天前
【FPGA】VGA显示-贪吃蛇
fpga开发
9527华安3 天前
FPGA实现Aurora 64B66B数据回环传输,基于GTY高速收发器,提供4套工程源码和技术支持
fpga开发·aurora·高速收发器·gty·64b66b