初学FPGA,跟随特权的视频,但是按键消抖的历程仿真不成功
初学FPGA,跟随特权的视频,这几天正好开始弄特权的那个按键消抖的程序,因为用的不是特权的板子,自己的板子上只有两个按键和两个led显示灯,所以将特权的代码改了下。将代码修改之后烧入芯片中,功能可以实现消抖,因为学习写写testbench,就拿按键消抖的代码在modelsim下进行仿真,发现仿真过不了,以为是自己程序改错了。于是将特权的程序进行modelsim仿真,发现他的程序在modelsim下仿真结果和我的一样。实在不知道什么原因。现贴上特权的verilog程序和我自己写的testbech代码,以及modelsim仿真波形,麻烦帮看看问题出在哪里。在此谢过。特权的按键检测程序:
//说明:当三个独立按键的某一个被按下后,相应的LED被点亮;
// 再次按下后,LED熄灭,按键控制LED亮灭
module sw_debounce(
clk,rst_n,
sw1_n,sw2_n,sw3_n,
led_d1,led_d2,led_d3
);
input clk; //主时钟信号,50MHz
input rst_n; //复位信号,低有效
input sw1_n,sw2_n,sw3_n; //三个独立按键,低表示按下
outputled_d1,led_d2,led_d3; //发光二极管,分别由按键控制
//---------------------------------------------------------------------------
reg key_rst;
always @(posedge clkor negedge rst_n)
if (!rst_n) key_rst <= 3'b111;
else key_rst <= {sw3_n,sw2_n,sw1_n};
reg key_rst_r; //每个时钟周期的上升沿将low_sw信号锁存到low_sw_r中
always @ ( posedge clkor negedge rst_n )
if (!rst_n) key_rst_r <= 3'b111;
else key_rst_r <= key_rst;
//当寄存器key_rst由1变为0时,led_an的值变为高,维持一个时钟周期
wire key_an = key_rst_r & ( ~key_rst);
//---------------------------------------------------------------------------
regcnt; //计数寄存器
always @ (posedge clkor negedge rst_n)
if (!rst_n) cnt <= 20'd0; //异步复位
else if(key_an) cnt <=20'd0;
else cnt <= cnt + 1'b1;
reg low_sw;
always @(posedge clkor negedge rst_n)
if (!rst_n) low_sw <= 3'b111;
else if (cnt == 20'hfffff) //满20ms,将按键值锁存到寄存器low_sw中 cnt == 20'hfffff
low_sw <= {sw3_n,sw2_n,sw1_n};
//---------------------------------------------------------------------------
reg low_sw_r; //每个时钟周期的上升沿将low_sw信号锁存到low_sw_r中
always @ ( posedge clkor negedge rst_n )
if (!rst_n) low_sw_r <= 3'b111;
else low_sw_r <= low_sw;
//当寄存器low_sw由1变为0时,led_ctrl的值变为高,维持一个时钟周期
wire led_ctrl = low_sw_r & ( ~low_sw);
reg d1;
reg d2;
reg d3;
always @ (posedge clk or negedge rst_n)
if (!rst_n) begin
d1 <= 1'b0;
d2 <= 1'b0;
d3 <= 1'b0;
end
else begin //某个按键值变化时,LED将做亮灭翻转
if ( led_ctrl ) d1 <= ~d1;
if ( led_ctrl ) d2 <= ~d2;
if ( led_ctrl ) d3 <= ~d3;
end
assign led_d3 = d1 ? 1'b1 : 1'b0; //LED翻转输出
assign led_d2 = d2 ? 1'b1 : 1'b0;
assign led_d1 = d3 ? 1'b1 : 1'b0;
endmodule
自己写的testbench代码
`timescale 10 ns/ 1 ps
module sw_debounce_vlg_tst();
// constants
// general purpose registers
reg eachvec;
// test vector input registers
reg clk;
reg rst_n;
reg sw1_n;
reg sw2_n;
reg sw3_n;
// wires
wire led_d1;
wire led_d2;
wire led_d3;
// assign statements (if any)
sw_debounce i1 (
// port map - connection between master ports and signals/registers
.clk(clk),
.led_d1(led_d1),
.led_d2(led_d2),
.led_d3(led_d3),
.rst_n(rst_n),
.sw1_n(sw1_n),
.sw2_n(sw2_n),
.sw3_n(sw3_n)
);
initial
begin
clk = 1'b0;
forever
begin
#10 clk = ~clk;
end
end
initial
begin
rst_n = 1'b0;
#100;
rst_n = 1'b1;
end
initial
begin
sw1_n = 1'b1;
sw2_n = 1'b1;
sw3_n = 1'b1;
#1000000
sw1_n = 1'b0;
sw2_n = 1'b0;
sw3_n = 1'b0;
#7000000
sw1_n = 1'b1;
sw2_n = 1'b1;
sw3_n = 1'b1;
#3000000
$stop;
end
endmodule
下面是特权的代码的仿真波形,模拟一下按键的按下,有30mS的按下延时
你测下你仿真的时钟 clk,应该不是50MHz,而是5Mhz吧
DepravedLucien 发表于 2014-7-30 09:34
你测下你仿真的时钟 clk,应该不是50MHz,而是5Mhz吧
你是正确的,我clk波形时钟错了,改成50MHz。现在仿真通过了
DepravedLucien 发表于 2014-7-30 09:34
你测下你仿真的时钟 clk,应该不是50MHz,而是5Mhz吧
你好,我这边还有一个疑问,我自己按照特权的思路自己写的按键消抖程序,我下载到开发板上,可以控制led灯翻转,但是仿真也过不了。我找了两个多小时。在代码中间加上了一个测试输出引脚,用来输出clk/4的方波,但是什么波形都没有。麻烦帮看一下哪里出问题了。谢谢了。
按键检测消抖代码:
module key_scan(
key_in,
led_out,
clk,
rst_n,
test_pin);
/* 端口声明 */
input key_in; /* 两个按键输入,低电平有效*/
input clk; /* 时钟输入 */
input rst_n; /* 复位输入,低电平有效复位 */
output led_out; /* led驱动输出,高电平驱动led发光 */
output test_pin;
reg led_out;
reg test_pin;
initial
begin
test_pin <= 1'b0;
end
/*************************************************/
/* 模块功能实现 */
/* 在clk时钟下,保存当前clk上升沿时key的输入值 */
reg temp1_key_in;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
temp1_key_in <= 2'b11;
else
temp1_key_in <= key_in;
end
/* 在clk时钟下,保存上一次的clk上升沿时key的输入值 */
reg temp2_key_in;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
temp2_key_in <= 2'b11;
else
temp2_key_in <= temp1_key_in;
end
/* 判断出在clk时钟下,按键在两次时钟采样值不同的按键,即被按下的按键 */
wire temp3_key_in;
assign temp3_key_in = temp2_key_in & (~temp1_key_in);
/* 产生20ms的计时时间 */
parameter COUNT_TOP_20MS = 20'hF4240; /* 定义20mS计时的定时器上限 */
reg count;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
count <= 20'b0;
else
begin
if(count == COUNT_TOP_20MS || temp3_key_in != 2'b00)
count <= 20'b0;
else
count <= count + 1'b1;
end
end
/* test pin,it should output wave */
reg cnt;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
cnt <= 2'b00;
else
begin
cnt <= cnt + 2'b1;
test_pin = (cnt==2'b11)?(~test_pin):(test_pin);
end
end
/* 以20mS为时间基准,记录当前20mS时的按键输入值 */
reg temp4_key_in;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
temp4_key_in <= 2'b11;
else if(count == (COUNT_TOP_20MS-1))
begin
temp4_key_in <= key_in;
end
end
/* 以20mS为时间基准,记录前一个20mS时的按键输入值 */
reg temp5_key_in;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
temp5_key_in <= 2'b11;
else if(count == (COUNT_TOP_20MS-1))
begin
temp5_key_in <= temp4_key_in;
end
end
/* 根据两次20mS前后的采样值来判断按键在去抖动之后的按键值 */
wire temp6_key_in;
assign temp6_key_in = temp5_key_in & (~temp4_key_in);
/* 根据按键的去抖动之后的输入值来判断led驱动引脚输出什么电平 */
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
led_out <= 2'b00; /* 复位时将输入低电平,led灯熄灭 */
else
begin
case(temp6_key_in)
2'b11:led_out <= ~led_out;
2'b10:led_out <= ~led_out;
2'b01:led_out <= ~led_out;
default:;
endcase
end
end
endmodule
testbench代码
// Copyright (C) 1991-2009 Altera Corporation
// Your use of Altera Corporation's design tools, logic functions
// and other software and tools, and its AMPP partner logic
// functions, and any output files from any of the foregoing
// (including device programming or simulation files), and any
// associated documentation or information are expressly subject
// to the terms and conditions of the Altera Program License
// Subscription Agreement, Altera MegaCore Function License
// Agreement, or other applicable license agreement, including,
// without limitation, that your use is for the sole purpose of
// programming logic devices manufactured by Altera and sold by
// Altera or its authorized distributors.Please refer to the
// applicable agreement for further details.
// *****************************************************************************
// This file contains a Verilog test bench template that is freely editable to
// suit user's needs .Comments are provided in each section to help the user
// fill out necessary details.
// *****************************************************************************
// Generated on "07/30/2014 00:13:51"
// Verilog Test Bench template for design : key_scan
//
// Simulation tool : ModelSim (Verilog)
//
`timescale 10 ns/ 1 ps
module key_scan_vlg_tst();
// constants
// general purpose registers
reg eachvec;
// test vector input registers
reg clk;
reg key_in;
reg rst_n;
// wires
wire led_out;
wire test_pin;
// assign statements (if any)
key_scan i1 (
// port map - connection between master ports and signals/registers
.clk(clk),
.key_in(key_in),
.led_out(led_out),
.rst_n(rst_n),
.test_pin(test_pin)
);
initial
begin
clk = 1'b0;
rst_n = 1'b1;
forever
begin
#1 clk <= ~clk;
end
end
initial
begin
key_in <= 2'b11;
#1000000
key_in <= 2'b01;
#3000000
key_in <= 2'b11;
#3000000
$stop;
end
endmodule
以下下是我的仿真波形:
下面是我clk的放大波形,这个没有弄错了。clk周期刚好是20ns
这个debounce的思路就按键输入的降沿复位cnt,当cnt溢出时再次检查按键输入,如果还是低电平,LED翻转
cnt溢出的时间为(10×2)*(2**20) = 20971520
那么按键按下保持的时间至少要大于这个值
所以,testbench第54行改为
#23000000
就可以看到LED翻转了 wzd5230 发表于 2014-7-30 12:26
你好,我这边还有一个疑问,我自己按照特权的思路自己写的按键消抖程序,我下载到开发板上,可以控制led ...
1、代码中 为 test_pin赋初值不使用initial语句,在always里面赋值;
2、testbench中复位有效一段时间,你现在复位一直为1; DepravedLucien 发表于 2014-7-30 13:54
1、代码中 为 test_pin赋初值不使用initial语句,在always里面赋值;
2、testbench中复位有效一段时间, ...
我找到错误了,是我的按键消抖代码有问题,我不理解的是那个复位信号为什么在testbench中要让其初始复位一段时间,一直让其是1‘b1(即不复位)的话,为什么那个测试引脚无法输出1/4的clk频率的信号,只要在testbench中加上复位,这个测试信号就可以正常输出。 wzd5230 发表于 2014-7-30 22:50
我找到错误了,是我的按键消抖代码有问题,我不理解的是那个复位信号为什么在testbench中要让其初始复位 ...
因为它是仿真啊,如果你是下载到芯片上,可能没问题,仿真的话就得为其赋初值,否则它会是不确定状态,就是你仿真波形看到的“红色”的线,它的状态是X,所以你的功能无法继续跑下去 DepravedLucien 发表于 2014-8-1 09:14
因为它是仿真啊,如果你是下载到芯片上,可能没问题,仿真的话就得为其赋初值,否则它会是不确定状态,就 ...
哦,知道了,非常感谢你的回答,谢谢你!! DepravedLucien 发表于 2014-8-1 09:14
因为它是仿真啊,如果你是下载到芯片上,可能没问题,仿真的话就得为其赋初值,否则它会是不确定状态,就 ...
又来麻烦你了,我用jtag方式下载程序但是有时候会出现程序没有运行的情况,或者运行不正常,重新下载一次就可以了,不知道你有遇到这个问题吗?就是驱动数码管的程序,然后用到了外部50MHz时钟。没有特殊的地方。 wzd5230 发表于 2014-8-2 09:02
又来麻烦你了,我用jtag方式下载程序但是有时候会出现程序没有运行的情况,或者运行不正常,重新下载一次 ...
你使用的是开发板么?有没有例程,例程每次下载会有这个问题么?
这个我觉得需要确认是程序下载的问题,还是程序本身设计的问题;
可以通过signaltap来调试
也有可能是usb blaster的问题
DepravedLucien 发表于 2014-8-6 17:56
你使用的是开发板么?有没有例程,例程每次下载会有这个问题么?
这个我觉得需要确认是程序下载的问题, ...
使用的是开发板,之前没有遇到过这种情况,就上次自己写的程序,烧进去出现两次,后面再烧又没有这个现象了。
我用的是usb blaster。后面使用中我再观察吧,如果遇到问题我再和你交流。
非常感谢
页:
[1]