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
相关推荐
FPGA小徐1 小时前
FPGA 数字信号处理(二):并行 FIR 滤波器的 Verilog 全流程设计与实现
fpga开发
国科安芯3 小时前
基于AS32S601ZIT2型抗辐照MCU的商业航天卫星姿态确定与控制系统研究
单片机·嵌入式硬件·安全·fpga开发·架构·risc-v
ALINX技术博客3 小时前
【黑金云课堂】FPGA技术教程FPGA基础:I2C 总线通信技术
fpga开发·i2c
Hello-FPGA4 小时前
Xilinx KU040 FPGA Camera Link 图像采集
c++·fpga开发
明德扬4 小时前
AD采集卡应用示例交流:从传感器采集到高速信号验证
fpga开发
傻童:CPU4 小时前
PS与PL之间的交互
fpga开发
神奇元创16 小时前
商用级光路加速卡:大模型推理的极速落地方案
python·神经网络·fpga开发·dsp开发
FPGA小徐1 天前
深度神经网络FPGA设计进展、实现与展望
fpga开发
FPGA小徐1 天前
FPGA数字信号处理(一)数字混频实现详解|NCO/DDS原理、有符号数避坑、直流滤除工程实战
fpga开发
Passionate.Z1 天前
基于FPGA的CLAHE自适应限制对比度直方图均衡算法硬件verilog实现
图像处理·嵌入式硬件·算法·fpga开发·fpga