搜索
bottom↓
回复: 11

初学FPGA,跟随特权的视频,但是按键消抖的历程仿真不成功

[复制链接]

出0入0汤圆

发表于 2014-7-30 01:40:25 | 显示全部楼层 |阅读模式
初学FPGA,跟随特权的视频,这几天正好开始弄特权的那个按键消抖的程序,因为用的不是特权的板子,自己的板子上只有两个按键和两个led显示灯,所以将特权的代码改了下。将代码修改之后烧入芯片中,功能可以实现消抖,因为学习写写testbench,就拿按键消抖的代码在modelsim下进行仿真,发现仿真过不了,以为是自己程序改错了。于是将特权的程序进行modelsim仿真,发现他的程序在modelsim下仿真结果和我的一样。实在不知道什么原因。现贴上特权的verilog程序和我自己写的testbech代码,以及modelsim仿真波形,麻烦帮看看问题出在哪里。在此谢过。

特权的按键检测程序:
  1. //说明:当三个独立按键的某一个被按下后,相应的LED被点亮;
  2. //                再次按下后,LED熄灭,按键控制LED亮灭

  3. module sw_debounce(
  4.                     clk,rst_n,
  5.                         sw1_n,sw2_n,sw3_n,
  6.                            led_d1,led_d2,led_d3
  7.                     );

  8. input   clk;        //主时钟信号,50MHz
  9. input   rst_n;        //复位信号,低有效
  10. input   sw1_n,sw2_n,sw3_n;         //三个独立按键,低表示按下
  11. output  led_d1,led_d2,led_d3;        //发光二极管,分别由按键控制

  12. //---------------------------------------------------------------------------
  13. reg[2:0] key_rst;  

  14. always @(posedge clk  or negedge rst_n)
  15.     if (!rst_n) key_rst <= 3'b111;
  16.     else key_rst <= {sw3_n,sw2_n,sw1_n};

  17. reg[2:0] key_rst_r;       //每个时钟周期的上升沿将low_sw信号锁存到low_sw_r中

  18. always @ ( posedge clk  or negedge rst_n )
  19.     if (!rst_n) key_rst_r <= 3'b111;
  20.     else key_rst_r <= key_rst;
  21.    
  22. //当寄存器key_rst由1变为0时,led_an的值变为高,维持一个时钟周期
  23. wire[2:0] key_an = key_rst_r & ( ~key_rst);

  24. //---------------------------------------------------------------------------
  25. reg[19:0]  cnt;        //计数寄存器

  26. always @ (posedge clk  or negedge rst_n)
  27.     if (!rst_n) cnt <= 20'd0;        //异步复位
  28.         else if(key_an) cnt <=20'd0;
  29.     else cnt <= cnt + 1'b1;
  30.   
  31. reg[2:0] low_sw;

  32. always @(posedge clk  or negedge rst_n)
  33.     if (!rst_n) low_sw <= 3'b111;
  34.     else if (cnt == 20'hfffff)         //满20ms,将按键值锁存到寄存器low_sw中         cnt == 20'hfffff
  35.       low_sw <= {sw3_n,sw2_n,sw1_n};
  36.       
  37. //---------------------------------------------------------------------------
  38. reg  [2:0] low_sw_r;       //每个时钟周期的上升沿将low_sw信号锁存到low_sw_r中

  39. always @ ( posedge clk  or negedge rst_n )
  40.     if (!rst_n) low_sw_r <= 3'b111;
  41.     else low_sw_r <= low_sw;
  42.    
  43. //当寄存器low_sw由1变为0时,led_ctrl的值变为高,维持一个时钟周期
  44. wire[2:0] led_ctrl = low_sw_r[2:0] & ( ~low_sw[2:0]);

  45. reg d1;
  46. reg d2;
  47. reg d3;
  48.   
  49. always @ (posedge clk or negedge rst_n)
  50.     if (!rst_n) begin
  51.         d1 <= 1'b0;
  52.         d2 <= 1'b0;
  53.         d3 <= 1'b0;
  54.       end
  55.     else begin                //某个按键值变化时,LED将做亮灭翻转
  56.         if ( led_ctrl[0] ) d1 <= ~d1;       
  57.         if ( led_ctrl[1] ) d2 <= ~d2;
  58.         if ( led_ctrl[2] ) d3 <= ~d3;
  59.       end

  60. assign led_d3 = d1 ? 1'b1 : 1'b0;                //LED翻转输出
  61. assign led_d2 = d2 ? 1'b1 : 1'b0;
  62. assign led_d1 = d3 ? 1'b1 : 1'b0;
  63.   
  64. endmodule
复制代码


自己写的testbench代码
  1. `timescale 10 ns/ 1 ps
  2. module sw_debounce_vlg_tst();
  3. // constants                                          
  4. // general purpose registers
  5. reg eachvec;
  6. // test vector input registers
  7. reg clk;
  8. reg rst_n;
  9. reg sw1_n;
  10. reg sw2_n;
  11. reg sw3_n;
  12. // wires                                               
  13. wire led_d1;
  14. wire led_d2;
  15. wire led_d3;

  16. // assign statements (if any)                          
  17. sw_debounce i1 (
  18. // port map - connection between master ports and signals/registers   
  19.         .clk(clk),
  20.         .led_d1(led_d1),
  21.         .led_d2(led_d2),
  22.         .led_d3(led_d3),
  23.         .rst_n(rst_n),
  24.         .sw1_n(sw1_n),
  25.         .sw2_n(sw2_n),
  26.         .sw3_n(sw3_n)
  27. );
  28. initial
  29. begin
  30.   clk = 1'b0;
  31.   forever
  32.   begin
  33.     #10 clk = ~clk;
  34.   end
  35. end               

  36.   initial
  37.   begin
  38.     rst_n = 1'b0;
  39.     #100;
  40.     rst_n = 1'b1;
  41.   end            
  42.   
  43.   initial
  44.   begin
  45.     sw1_n = 1'b1;
  46.     sw2_n = 1'b1;
  47.     sw3_n = 1'b1;
  48.     #1000000
  49.     sw1_n = 1'b0;
  50.     sw2_n = 1'b0;
  51.     sw3_n = 1'b0;
  52.     #7000000
  53.     sw1_n = 1'b1;
  54.     sw2_n = 1'b1;
  55.     sw3_n = 1'b1;
  56.     #3000000
  57.     $stop;
  58.   end
  59. endmodule
复制代码


下面是特权的代码的仿真波形,模拟一下按键的按下,有30mS的按下延时

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

发表于 2014-7-30 09:34:50 | 显示全部楼层
你测下你仿真的时钟 clk,应该不是50MHz,而是5Mhz吧

出0入0汤圆

 楼主| 发表于 2014-7-30 12:14:29 | 显示全部楼层
DepravedLucien 发表于 2014-7-30 09:34
你测下你仿真的时钟 clk,应该不是50MHz,而是5Mhz吧

你是正确的,我clk波形时钟错了,改成50MHz。现在仿真通过了

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2014-7-30 12:26:48 | 显示全部楼层
DepravedLucien 发表于 2014-7-30 09:34
你测下你仿真的时钟 clk,应该不是50MHz,而是5Mhz吧

你好,我这边还有一个疑问,我自己按照特权的思路自己写的按键消抖程序,我下载到开发板上,可以控制led灯翻转,但是仿真也过不了。我找了两个多小时。在代码中间加上了一个测试输出引脚,用来输出clk/4的方波,但是什么波形都没有。麻烦帮看一下哪里出问题了。谢谢了。

按键检测消抖代码:
  1. module key_scan(
  2.         key_in,
  3.         led_out,
  4.         clk,
  5.         rst_n,
  6.         test_pin);

  7.         /* 端口声明 */
  8.         input[1:0] key_in;                                                                        /* 两个按键输入,低电平有效*/
  9.         input clk;                                                                                            /* 时钟输入 */
  10.         input rst_n;                                                                                    /* 复位输入,低电平有效复位 */
  11.         output[1:0] led_out;                                                                /* led驱动输出,高电平驱动led发光 */
  12.         output test_pin;
  13.        
  14.         reg[1:0] led_out;
  15.         reg test_pin;
  16.        
  17.         initial
  18.         begin
  19.     test_pin <= 1'b0;
  20.   end
  21.         /*************************************************/
  22.         /* 模块功能实现 */
  23.        
  24.         /* 在clk时钟下,保存当前clk上升沿时key的输入值 */
  25.         reg[1:0] temp1_key_in;               
  26.         always@(posedge clk or negedge rst_n)
  27.         begin
  28.                 if(!rst_n)
  29.                         temp1_key_in <= 2'b11;
  30.                 else
  31.                         temp1_key_in <= key_in;
  32.         end
  33.        
  34.         /* 在clk时钟下,保存上一次的clk上升沿时key的输入值 */
  35.         reg[1:0] temp2_key_in;
  36.         always@(posedge clk or negedge rst_n)
  37.         begin
  38.                 if(!rst_n)
  39.                         temp2_key_in <= 2'b11;
  40.                 else
  41.                         temp2_key_in <= temp1_key_in;
  42.         end
  43.        
  44.         /* 判断出在clk时钟下,按键在两次时钟采样值不同的按键,即被按下的按键 */
  45.         wire[1:0] temp3_key_in;
  46.         assign temp3_key_in = temp2_key_in & (~temp1_key_in);

  47.         /* 产生20ms的计时时间 */
  48.         parameter COUNT_TOP_20MS = 20'hF4240;                                /* 定义20mS计时的定时器上限 */
  49.         reg[19:0] count;
  50.         always@(posedge clk or negedge rst_n)
  51.         begin
  52.                 if(!rst_n)
  53.                         count <= 20'b0;
  54.                 else
  55.                 begin
  56.                         if(count == COUNT_TOP_20MS || temp3_key_in != 2'b00)
  57.                                 count <= 20'b0;
  58.                         else
  59.                                 count <= count + 1'b1;
  60.                 end
  61.         end
  62.        
  63.         /* test pin,it should output wave */
  64.         reg[1:0] cnt;
  65.         always@(posedge clk or negedge rst_n)
  66.         begin
  67.     if(!rst_n)
  68.       cnt <= 2'b00;
  69.     else
  70.     begin
  71.       cnt <= cnt + 2'b1;
  72.       test_pin = (cnt==2'b11)?(~test_pin):(test_pin);
  73.     end
  74.   end
  75.        
  76.         /* 以20mS为时间基准,记录当前20mS时的按键输入值 */
  77.         reg[1:0] temp4_key_in;
  78.         always@(posedge clk or negedge rst_n)
  79.         begin
  80.                 if(!rst_n)
  81.                         temp4_key_in <= 2'b11;
  82.                 else if(count == (COUNT_TOP_20MS-1))
  83.                 begin
  84.                         temp4_key_in <= key_in;
  85.                 end
  86.         end
  87.        
  88.         /* 以20mS为时间基准,记录前一个20mS时的按键输入值 */
  89.         reg[1:0] temp5_key_in;
  90.         always@(posedge clk or negedge rst_n)
  91.         begin
  92.                 if(!rst_n)
  93.                         temp5_key_in <= 2'b11;
  94.                 else if(count == (COUNT_TOP_20MS-1))
  95.                 begin
  96.                         temp5_key_in <= temp4_key_in;
  97.                 end
  98.         end
  99.        
  100.         /* 根据两次20mS前后的采样值来判断按键在去抖动之后的按键值 */
  101.         wire[1:0] temp6_key_in;
  102.         assign temp6_key_in = temp5_key_in & (~temp4_key_in);
  103.        
  104.         /* 根据按键的去抖动之后的输入值来判断led驱动引脚输出什么电平 */
  105.         always@(posedge clk or negedge rst_n)
  106.         begin
  107.                 if(!rst_n)
  108.                         led_out <= 2'b00;                                                                /* 复位时将输入低电平,led灯熄灭 */
  109.                 else
  110.                 begin
  111.                         case(temp6_key_in)
  112.                                 2'b11:led_out <= ~led_out;
  113.                                 2'b10:led_out[1] <= ~led_out[1];
  114.                                 2'b01:led_out[0] <= ~led_out[0];
  115.                                 default:;
  116.                         endcase
  117.                 end
  118.         end

  119. endmodule
  120.        
复制代码


testbench代码
  1. // Copyright (C) 1991-2009 Altera Corporation
  2. // Your use of Altera Corporation's design tools, logic functions
  3. // and other software and tools, and its AMPP partner logic
  4. // functions, and any output files from any of the foregoing
  5. // (including device programming or simulation files), and any
  6. // associated documentation or information are expressly subject
  7. // to the terms and conditions of the Altera Program License
  8. // Subscription Agreement, Altera MegaCore Function License
  9. // Agreement, or other applicable license agreement, including,
  10. // without limitation, that your use is for the sole purpose of
  11. // programming logic devices manufactured by Altera and sold by
  12. // Altera or its authorized distributors.  Please refer to the
  13. // applicable agreement for further details.

  14. // *****************************************************************************
  15. // This file contains a Verilog test bench template that is freely editable to  
  16. // suit user's needs .Comments are provided in each section to help the user   
  17. // fill out necessary details.                                                  
  18. // *****************************************************************************
  19. // Generated on "07/30/2014 00:13:51"
  20.                                                                                 
  21. // Verilog Test Bench template for design : key_scan
  22. //
  23. // Simulation tool : ModelSim (Verilog)
  24. //

  25. `timescale 10 ns/ 1 ps
  26. module key_scan_vlg_tst();
  27. // constants                                          
  28. // general purpose registers
  29. reg eachvec;
  30. // test vector input registers
  31. reg clk;
  32. reg [1:0] key_in;
  33. reg rst_n;
  34. // wires                                               
  35. wire [1:0]  led_out;
  36. wire test_pin;

  37. // assign statements (if any)                          
  38. key_scan i1 (
  39. // port map - connection between master ports and signals/registers   
  40.         .clk(clk),
  41.         .key_in(key_in),
  42.         .led_out(led_out),
  43.         .rst_n(rst_n),
  44.         .test_pin(test_pin)
  45. );
  46. initial
  47. begin
  48.   clk = 1'b0;
  49.   rst_n = 1'b1;
  50.   forever
  51.   begin
  52.   #1 clk <= ~clk;
  53.   end
  54. end

  55. initial
  56. begin
  57.   key_in <= 2'b11;
  58.   #1000000
  59.   key_in <= 2'b01;
  60.   #3000000
  61.   key_in <= 2'b11;
  62.   #3000000
  63.   $stop;
  64. end                                                   
  65. endmodule
复制代码


以下下是我的仿真波形:


下面是我clk的放大波形,这个没有弄错了。clk周期刚好是20ns

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入17汤圆

发表于 2014-7-30 12:49:25 | 显示全部楼层
这个debounce的思路就按键输入的降沿复位cnt,当cnt溢出时再次检查按键输入,如果还是低电平,LED翻转
cnt溢出的时间为(10×2)*(2**20) = 20971520
那么按键按下保持的时间至少要大于这个值
所以,testbench第54行改为
#23000000
就可以看到LED翻转了

出0入0汤圆

发表于 2014-7-30 13:54:29 | 显示全部楼层
wzd5230 发表于 2014-7-30 12:26
你好,我这边还有一个疑问,我自己按照特权的思路自己写的按键消抖程序,我下载到开发板上,可以控制led ...

1、代码中 为 test_pin赋初值不使用initial语句,在always里面赋值;
2、testbench中复位有效一段时间,你现在复位一直为1;

出0入0汤圆

 楼主| 发表于 2014-7-30 22:50:49 | 显示全部楼层
DepravedLucien 发表于 2014-7-30 13:54
1、代码中 为 test_pin赋初值不使用initial语句,在always里面赋值;
2、testbench中复位有效一段时间, ...

我找到错误了,是我的按键消抖代码有问题,我不理解的是那个复位信号为什么在testbench中要让其初始复位一段时间,一直让其是1‘b1(即不复位)的话,为什么那个测试引脚无法输出1/4的clk频率的信号,只要在testbench中加上复位,这个测试信号就可以正常输出。

出0入0汤圆

发表于 2014-8-1 09:14:02 | 显示全部楼层
wzd5230 发表于 2014-7-30 22:50
我找到错误了,是我的按键消抖代码有问题,我不理解的是那个复位信号为什么在testbench中要让其初始复位 ...

因为它是仿真啊,如果你是下载到芯片上,可能没问题,仿真的话就得为其赋初值,否则它会是不确定状态,就是你仿真波形看到的“红色”的线,它的状态是X,所以你的功能无法继续跑下去

出0入0汤圆

 楼主| 发表于 2014-8-1 14:01:45 | 显示全部楼层
DepravedLucien 发表于 2014-8-1 09:14
因为它是仿真啊,如果你是下载到芯片上,可能没问题,仿真的话就得为其赋初值,否则它会是不确定状态,就 ...

哦,知道了,非常感谢你的回答,谢谢你!!

出0入0汤圆

 楼主| 发表于 2014-8-2 09:02:48 | 显示全部楼层
DepravedLucien 发表于 2014-8-1 09:14
因为它是仿真啊,如果你是下载到芯片上,可能没问题,仿真的话就得为其赋初值,否则它会是不确定状态,就 ...

又来麻烦你了,我用jtag方式下载程序但是有时候会出现程序没有运行的情况,或者运行不正常,重新下载一次就可以了,不知道你有遇到这个问题吗?就是驱动数码管的程序,然后用到了外部50MHz时钟。没有特殊的地方。

出0入0汤圆

发表于 2014-8-6 17:56:03 | 显示全部楼层
wzd5230 发表于 2014-8-2 09:02
又来麻烦你了,我用jtag方式下载程序但是有时候会出现程序没有运行的情况,或者运行不正常,重新下载一次 ...


你使用的是开发板么?有没有例程,例程每次下载会有这个问题么?
这个我觉得需要确认是程序下载的问题,还是程序本身设计的问题;
可以通过signaltap来调试
也有可能是usb blaster的问题

出0入0汤圆

 楼主| 发表于 2014-8-6 21:18:01 | 显示全部楼层
DepravedLucien 发表于 2014-8-6 17:56
你使用的是开发板么?有没有例程,例程每次下载会有这个问题么?
这个我觉得需要确认是程序下载的问题, ...

使用的是开发板,之前没有遇到过这种情况,就上次自己写的程序,烧进去出现两次,后面再烧又没有这个现象了。
我用的是usb blaster。后面使用中我再观察吧,如果遇到问题我再和你交流。
非常感谢
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-24 03:30

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表