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
相关推荐
s9123601011 天前
FPGA眼图
fpga开发
北京青翼科技1 天前
【PCIe732】青翼PCIe采集卡-优质光纤卡- PCIe接口-万兆光纤卡
图像处理·人工智能·fpga开发·智能硬件·嵌入式实时数据库
minglie11 天前
verilog信号命名规范
fpga开发
XINVRY-FPGA1 天前
中阶FPGA效能红线重新划定! AMD第2代Kintex UltraScale+登场,记忆体频宽跃升5倍
嵌入式硬件·fpga开发·硬件工程·dsp开发·fpga
南檐巷上学1 天前
基于FPGA的音频信号监测识别系统
fpga开发·音频·verilog·fpga·傅立叶分析·fft·快速傅里叶变换
Aaron15882 天前
基于RFSOC的数字射频存储技术应用分析
c语言·人工智能·驱动开发·算法·fpga开发·硬件工程·信号处理
碎碎思2 天前
当 FPGA 遇见怀旧计算:486 与 Atari ST 的硬件级重生
fpga开发
数字芯片实验室2 天前
怎么定义芯片上的异步时钟?
单片机·嵌入式硬件·fpga开发
unicrom_深圳市由你创科技2 天前
基于ARM+DSP+FPGA异构计算架构的高速ADC采集卡定制方案
arm开发·fpga开发
北京青翼科技2 天前
高速采集卡丨AD 采集丨 多通道数据采集卡丨高速数据采集系统丨青翼科技FMC 子卡
图像处理·人工智能·fpga开发·信号处理·智能硬件