首页 > 其他分享 >FPGA入门笔记007_A——按键消抖模块设计与验证(状态机、$random、仿真模型、task语法)

FPGA入门笔记007_A——按键消抖模块设计与验证(状态机、$random、仿真模型、task语法)

时间:2023-11-30 11:11:20浏览次数:32  
标签:状态 task FPGA Clk 状态机 key 按键 Rst reg

实验现象:

每次按下按键0,4个LED显示状态以二进制加法格式加1。

每次按下按键1,4个LED显示状态以二进制加法格式减1。

知识点:

1、testbench中随机数发生函数$random的使用;

2、仿真模型的概念

1、按键波形分析:

按键波形分析

按键未按,FPGA管脚检测到高电平。

按键按下,FPGA管脚检测到低电平。

2、设置四个状态:

1、未按下时,空闲态;

2、抖动滤除状态;

3、按下稳定状态;

4、释放抖动滤除状态

localparam
    IDEL    = 4'b0001,	//空闲状态
    FILTER0 = 4'b0010,	//抖动滤除状态
    DOWN    = 4'b0100,	//按下稳定状态
    FILTER1 = 4'b1000;	//释放抖动滤除状态

reg [3:0]state;

3、状态迁移图:

IDEL:空闲状态

FILTER:抖动滤除状态(过了20ms后还未出现上升沿,进入DOWN状态,否则进入IDEL状态)

DOWN:按下稳定状态

FILTER1:释放抖动滤除状态((过了20ms后还未出现下降沿,进入IDEL状态,否则进入DOWN状态))

微信图片编辑_20231128140608

4、消抖模块模型:

微信图片编辑_20231128144710

module key_filter(
	Clk,
	Rst_n,
	key_in,
	key_flag,
	key_state
);
	
	input Clk;	//时钟信号
	input Rst_n;	//复位信号
	input key_in;	//按键输入信号
	
	output reg key_flag;	//按键状态标志信号
	output reg key_state;	//按键状态信号
    
endmodule

5、边沿检测电路:微信图片编辑_20231128150318

reg key_tmp0,key_tmp1;
wire pedge,nedge;

always@(posedge Clk or negedge Rst_n)
if(!Rst_n)begin
    key_tmp0 <= 1'b0;
    key_tmp1 <= 1'b0;
end
else begin
    key_tmp0 <= key_in;
    key_tmp1 <= key_tmp0;
end

assign nedge = !key_tmp0 & key_tmp1;	//下降沿
assign pedge = key_tmp0 & !key_tmp1;	//上升沿

6、设置20ms计数器

reg [19:0]cnt;	//计数器
reg en_cnt;	//使能计数寄存器,控制计数器cnt
reg cnt_full;	//计满标志信号

always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
	cnt <= 20'd0;
else if(en_cnt)
    cnt <= cnt + 1'b1;
else
    cnt <= 20'd0;

always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
	cnt_full <= 1'b0;
else if(cnt == 999_999)	//计数1_000_000次
    cnt_full <= 1'b1;
else
    cnt_full <= 1'b0;

7、设置状态机

always@(posedge Clk or negedge Rst_n)
if(!Rst_n)begin
    en_cnt <= 1'b0;
    state <= IDEL;
    key_flag <= 1'b0;
    key_state <= 1'b1;
end
else begin
	case(state)
        IDEL:begin
            key_flag <= 1'b0;
            if(nedge)begin	//出现下降沿,转到FILTER0状态
                state <= FILTER0;
                en_cnt <= 1'b1;	//开始计数
            end
            else
                state <= IDEL;
        end
        FILTER0:
            if(cnt_full)begin	//计数器计满,转到DOWN状态
                key_flag <= 1'b1;
                key_state <= 1'b0;
                state <= DOWN;
                en_cnt <= 1'b0;	//停止计数,并使计数器清零
            end
        	else if(pedge)begin	//出现上升沿,转到IDEL状态
            	state <= IDEL;
            	en_cnt <= 1'b0;	//停止计数,并使计数器清零
       		end
        	else
            	state <= FILTER0;
        DOWN:begin
            key_flag <= 1'b0;
            if(pedge)begin	//出现上升沿,转到FILTER0状态
                state <= FILTER1;
                en_cnt <= 1'b1;	//开始计数
            end
            else
                state <= DOWN;
        end
        FILTER1:
            if(cnt_full)begin	//计数器计满,转到IDEL状态
                key_flag <= 1'b1;
                key_state <= 1'b1;
                state <= IDEL;
                en_cnt <= 1'b0;	//停止计数,并使计数器清零
            end
      		else if(nedge)begin	//出下降沿,转到DOWN状态
            	state <= DOWN;	
                en_cnt <= 1'b0;	//停止计数,并使计数器清零
        	end
        	else
            	state <= FILTER1;
        default:begin
            state <= IDEL;
            en_cnt <=1'b0;
            key_flag <= 1'b0;
            key_state <= 1'b1;
        end
    endcase
end

8、状态图(State Machine Viewer):

微信截图_20231128163821

9、设置testbench文件(仿真模型)

9.1、设置仿真模型key_model.v

`timescale 1ns/1ns

module key_model(key);

	output reg key;
	
	reg [15:0]myrand;
	
	initial begin
		key = 1'b1;
		press_key;
		#10000;
		press_key;
		#10000;
		press_key;
		$stop;
	end
	
	task press_key;	//设置press_key任务
		begin
			repeat(50)begin
                myrand = {$random}%65536;	//产生0~65535之间的随机数
				#myrand key = ~key;
			end
			key = 0;
			#50000000;
			
			repeat(50)begin
				myrand = {$random}%65536;	//0~65535之间的随机数
				#myrand key = ~key;
			end
			key = 1;
			#50000000;
		end
	endtask

endmodule

9.2、设置testbench文件key_filter_tb.v

`timescale 1ns/1ns
`define clock_period 20

module key_filter_tb;

	reg Clk;
	reg Rst_n;
	wire key_in;	//key_in在此时相当于是一根线,所以设置为wire类型
	
	wire key_flag;
	wire key_state;

	key_filter key_filter0(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.key_in(key_in),
		.key_flag(key_flag),
		.key_state(key_state)
	);
	
	key_model key_model(.key(key_in));
	
	initial Clk = 1;
	always#(`clock_period/2) Clk = ~Clk;
	
	initial begin
		Rst_n = 1'b0;
		#(`clock_period*10) Rst_n = 1'b1;
		#(`clock_period*10 + 1);
	end

endmodule

9.3、将仿真模型与testbench文件链接

Assignments->Settings...->Test Benches...->Edit...

微信截图_20231130110128

在testbench文件夹中选中key_model文件,点击Add

微信截图_20231130110321

标签:状态,task,FPGA,Clk,状态机,key,按键,Rst,reg
From: https://www.cnblogs.com/little55/p/17866867.html

相关文章

  • 聪明办法学python-task05
    python要点注释单行注释以#开头多行注释可以用多个#号,还有'''和""".程序员最讨厌的10件事:0:别人的代码不写注释​1:给自己的代码写注释。行与缩进python最鲜明的特色就是不需要使用{},而是通过缩进来代替代码块同一个代码块的......
  • 聪明方法学python task5 条件/代码风格
    条件控制elif代替了C语言中的elseif缩进划分代码块嵌套if仍然成立多返回语句defabs(n):  ifn<0:    return-n  returnn match-case类比switch-case语句_可以匹配一切。deftest(a):​•matcha:​•case1:​•......
  • 聪明办法学python—task05&选学01
    条件语句if语句:1.elseif——>elif2.后面是冒号3.其余与c语言相同循环结构while循环while条件:bodystatmentsfor-in循环for变量in字符串/范围/集合:statements结束循环breakcontinuereturn与c语言相同 ......
  • task3
    8.条件if...:......​ 如果if里面只有一条执行的语句的话,可以不换行直接一行接着写,eg:if...:......​ if-elif-else​ match...case:match...变量:case...:...case...:...case_:#排除以上情况剩下的所有情况...​......
  • 聪明办法学Python Task05 & 选学01
    聪明办法学Python学习笔记Chapter4条件Conditionalsif语句ifstatementConditionalsMakeDecisionsif语句流程一个例子deff(x):print("A",end="")ifx==0:print("B",end="")print("C",end=&......
  • FPGA 实现SPI 主机双工通信 CS前后肩可调 操作时钟频率可调 ,SPI模式可调,传输位宽可
    1//testbench2`timescale1ns/1ns3modulelcd_spi_m_tb();4regrst_n_i;5regspi_clkx_i;6reg[31:0]spi_data_i;7regspi_start;8regspi_miso_r1,spi_miso_r2;9wirespi_miso_i;10wire[0:0]spi_done;11wir......
  • 11.26-task5-条件
    条件if语句if(condition):后面为condition为trueelse:后面为false布尔表达式的使用:我们知道当布尔值为true是返回值为1,false时返回值为0他的返回值意思是:检查n是否为负数,若为负数n<0为true=1n>=0为false=0,+前面就为1*-n,+后就为0,为正数时逻辑相同ifelse推导式......
  • 11.29-task5-代码风格
    代码风格代码风格介绍修饰代码的前提是代码没有bug。。。两幅图中的代码对比,显然后一幅图的代码更加简洁,易懂。也方便之后很长时间后的再理解。缩进tab==4个空格当函数有多参数时换行当一个语句的字符数过长,要换行运算符对齐导入规范导入时要遵循同级文......
  • 聪明办法学python-task5
    条件if语句if<条件判断1>:<执行1>elif<条件判断2>:<执行2>elif<条件判断3>:<执行3>else:<执行4>条件判断从上向下匹配,当满足条件时执行对应的块内语句,后续的elif和else都不再执行。if-else推导式(python语法糖)returnnif(n>=0)else-neg:绝对值函数(在pyt......
  • # 聪明办法学Python Task 3
    聪明办法学PythonChap4:条件使用布尔表达式n=1(n<0)*1#0(n>=0)*2#2判断值为Flase时在数值计算上等价于0,为True时在数值计算上等价于1多个判断ifa:passelifb:passelifc:passelse:passif推导式defabs1(n):ifn>0:returnn......