OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 1272|回复: 0

[国产FPGA] 《ATK-DFPGL22G 之FPGA开发指南》第十章 按键控制蜂鸣器实验

[复制链接]

1117

主题

1128

帖子

2

精华

超级版主

Rank: 8Rank: 8

积分
4666
金钱
4666
注册时间
2019-5-8
在线时间
1224 小时
发表于 2023-11-6 16:35:58 | 显示全部楼层 |阅读模式
本帖最后由 正点原子运营 于 2023-11-6 16:35 编辑

第十章 按键控制蜂鸣器实验
1)实验平台:正点原子 ATK-DFPGL22G开发板

2) 章节摘自【正点原子】ATK-DFPGL22G之FPGA开发指南_V1.0

3)购买链接:https://detail.tmall.com/item_o.htm?id=692712955836

4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/fpga/zdyz-PGL22G.html

5)正点原子官方B站:https://space.bilibili.com/394620890

6)FPGA技术交流QQ群:435699340

155537c2odj87vz1z9vj6l.jpg

155537nfqovl2gg9faaol9.png

蜂鸣器(Buzzer)是现代常用的一种电子发声器,主要用于产生声音信号。蜂鸣器在生活中已经得到广泛使用,其典型应用包括医疗,消防等领域的各种报警装置以及日常生活中的各种警报器等。本章我们主要学习如何使用按键来控制蜂鸣器发声。
本章包括以下几个部分:   
1.1          蜂鸣器简介
1.2          实验任务
1.3          硬件设计
1.4          程序设计
1.5          下载验证

1.1 蜂鸣器简介
蜂鸣器按照驱动方式主要分为有源蜂鸣器和无源蜂鸣器,其主要区别为蜂鸣器内部是否含有震荡源。一般的有源蜂鸣器内部自带了震荡源,只要通电就会发声。而无源蜂鸣器由于不含内部震荡源,需要外接震荡信号才能发声。                              
image001.png
图 10.1.1 有源蜂鸣器(左)和无源蜂鸣器(右)

如上图所示,从外观上看,两种蜂鸣器很相似,如将两种蜂鸣器的引脚都朝上放置,能看到绿色电路板的是无源蜂鸣器,没有电路板而用黑胶封闭的一种是有源蜂鸣器。

相较于有源蜂鸣器,无源蜂鸣器成本更低,且发声频率可控。而有源蜂鸣器控制相对简单,由于内部自带震荡源,只要加上合适的直流电压即可发声。本次实验使用的蜂鸣器为有源蜂鸣器。

1.2 实验任务
本节实验任务是使用ATK-DFPGL22G开发板上的KEY0按键来控制蜂鸣器发声。初始状态为蜂鸣器鸣叫,按下按键后蜂鸣器停止鸣叫,再次按下开关,蜂鸣器重新鸣叫。

1.3 硬件设计
image003.png
图 10.3.1 蜂鸣器控制电路原理图

上图为蜂鸣器控制电路的原理图。由于ATK-DFPGL22G开发板的IO驱动电压只有1.35V,所以我们在蜂鸣器的驱动电路中加入三级管Q25,以将开发板的IO驱动电压放大,然后再驱动蜂鸣器。

本实验的管脚分配如下表所示:
QQ截图20231106163358.png
表 10.3.1 按键控制蜂鸣器实验管脚分配
对应的FDC约束语句如下所示:
  1. create_clock-name {clk} [get_ports {sys_clk}] -period {20} -waveform {0.000 10.000}
  2. define_attribute{p:beep} {PAP_IO_DIRECTION} {OUTPUT}
  3. define_attribute{p:beep} {PAP_IO_LOC} {P3}
  4. define_attribute{p:beep} {PAP_IO_VCCIO} {1.5}
  5. define_attribute{p:beep} {PAP_IO_STANDARD} {LVCMOS15}
  6. define_attribute{p:beep} {PAP_IO_DRIVE} {4}
  7. define_attribute{p:beep} {PAP_IO_PULLUP} {TRUE}
  8. define_attribute{p:beep} {PAP_IO_SLEW} {SLOW}
  9. define_attribute{p:key} {PAP_IO_DIRECTION} {INPUT}
  10. define_attribute{p:key} {PAP_IO_LOC} {F2}
  11. define_attribute{p:key} {PAP_IO_VCCIO} {1.5}
  12. define_attribute{p:key} {PAP_IO_STANDARD} {LVCMOS15}
  13. define_attribute{p:key} {PAP_IO_PULLUP} {TRUE}
  14. define_attribute{p:sys_clk} {PAP_IO_DIRECTION} {INPUT}
  15. define_attribute{p:sys_clk} {PAP_IO_LOC} {B5}
  16. define_attribute{p:sys_clk} {PAP_IO_VCCIO} {3.3}
  17. define_attribute{p:sys_clk} {PAP_IO_STANDARD} {LVCMOS33}
  18. define_attribute{p:sys_clk} {PAP_IO_PULLUP} {TRUE}
  19. define_attribute{p:sys_rst_n} {PAP_IO_DIRECTION} {INPUT}
  20. define_attribute{p:sys_rst_n} {PAP_IO_LOC} {G5}
  21. define_attribute{p:sys_rst_n} {PAP_IO_VCCIO} {1.5}
  22. define_attribute{p:sys_rst_n} {PAP_IO_STANDARD} {LVCMOS15}
  23. define_attribute{p:sys_rst_n} {PAP_IO_PULLUP} {TRUE}
复制代码

1.4 程序设计
由实验任务可知,我们只需要在按键按下时改变蜂鸣器的鸣叫状态即可。但实际上在按键按下的过程中存在按键抖动的干扰,体现在数字电路中就是不断变化的高低电平。为避免在抖动过程中采集到错误的按键状态,我们需要对按键数据进行消除抖动处理。

在这里我们先介绍一下按键消抖的原理。通常我们所使用的开关为机械弹性开关,当我们按下或松开按键时,由于弹片的物理特性,不能立即闭合或断开,往往会在断开或闭合的短时间内产生机械抖动,。消除这种抖动的过程即称为按键消抖。

按键消抖可分为硬件消抖和软件消抖。硬件消抖主要使用RS触发器或电容等方法在硬件电路上实现消抖,一般在按键较少时使用。软件消抖的原理主要为按键按下或松开后,由处理器延时5ms至20ms,然后再对按键状态进行采样并判断。如下图所示:
image005.png
图 10.4.1 按键消抖原理图

由上面的分析可知,本次实验中的系统至少包含按键消抖和蜂鸣器控制两个模块。系统框图如下图所示:
image007.png
图 10.4.2 按键控制蜂鸣器系统框图

图 10.4.2中,按键消抖模块用于消除按键的抖动,消抖之后的信号用于控制蜂鸣器的鸣叫状态。

程序中各模块端口及信号连接如下图所示:
image009.png
图 10.4.3 端口及信号连接图

由上图系统框图可知,代码部分包括三个模块。顶层模块(top_key_beep),作用为完成对另外两个模块的例化。按键消抖模块(key_debounce),主要用于对按键进行抖动滤除。按键控制蜂鸣器模块(beep_control),识别按键按下的那一刻,并对蜂鸣器的鸣叫状态进行翻转。

顶层模块代码如下:
  1. 1  module top_key_beep(
  2. 2         input        sys_clk,       //时钟信号50Mhz
  3. 3         input       sys_rst_n,     //复位信号
  4. 4         
  5. 5         input        key,           //按键信号      
  6. 6         output      beep           //蜂鸣器控制信号
  7. 7         );
  8. 8         
  9. 9  //wire define
  10. 10 wire key_value;
  11. 11 wire key_flag;
  12. 12
  13. 13 //*****************************************************
  14. 14 //**                    main code
  15. 15 //*****************************************************
  16. 16
  17. 17 //例化按键消抖模块
  18. 18 key_debounce u_key_debounce(
  19. 19      .sys_clk        (sys_clk),
  20. 20      .sys_rst_n      (sys_rst_n),
  21. 21      
  22. 22      .key            (key),
  23. 23      .key_flag       (key_flag),
  24. 24      .key_value      (key_value)
  25. 25      );
  26. 26   
  27. 27 //例化蜂鸣器控制模块
  28. 28 beep_control u_beep_control(
  29. 29      .sys_clk        (sys_clk),
  30. 30      .sys_rst_n      (sys_rst_n),
  31. 31      
  32. 32      .key_flag       (key_flag),      
  33. 33      .key_value      (key_value),
  34. 34      .beep           (beep)
  35. 35      );
  36. 36      
  37. 37 endmodule
复制代码
在顶层模块中例化了按键消抖模块和按键控制蜂鸣器模块。

按键消抖模块代码如下:
  1. 1  module key_debounce(
  2. 2       input           sys_clk,          //外部50M时钟
  3. 3       input           sys_rst_n,        //外部复位信号,低有效
  4. 4      
  5. 5       input            key,              //外部按键输入
  6. 6       output reg       key_flag,         //按键数据有效信号
  7. 7       output reg       key_value         //按键消抖后的数据  
  8. 8       );
  9. 9  
  10. 10 //reg define   
  11. 11 reg [31:0 delay_cnt;
  12. 12 reg        key_reg0;
  13. 13 reg        key_reg1;
  14. 14
  15. 15 //*****************************************************
  16. 16 //**                    main code
  17. 17 //*****************************************************
  18. 18 always @(posedge sys_clk or negedge sys_rst_n) begin
  19. 19      if (!sys_rst_n) begin
  20. 20          key_reg0   <=1'b1;
  21. 21          key_reg1   <=1'b1;
  22. 22          delay_cnt <= 32'd0;
  23. 23      end
  24. 24      else begin
  25. 25          key_reg0 <= key;                     //将按键值延迟一拍
  26. 26          key_reg1 <= key_reg0;                //将按键值延迟两拍
  27. 27          if(key_reg1 != key_reg0)             //一旦检测到按键状态发生变化
  28. 28                                               //(有按键被按下或释放)
  29. 29              delay_cnt <= 32'd1000000;        //给延时计数器重新装载初始值
  30. 30                                               //(计数时间为20ms)
  31. 31          else if(key_reg1 ==key_reg0) begin //在按键状态稳定时,计数器递
  32. 32                                               //减,开始20ms倒计时
  33. 33                   if(delay_cnt > 32'd0)
  34. 34                       delay_cnt <= delay_cnt - 1'b1;
  35. 35                   else
  36. 36                      delay_cnt <= delay_cnt;
  37. 37               end           
  38. 38      end   
  39. 39 end
  40. 40
  41. 41 always @(posedge sys_clk or negedge sys_rst_n) begin
  42. 42      if (!sys_rst_n) begin
  43. 43          key_flag  <= 1'b0;
  44. 44          key_value <= 1'b1;         
  45. 45      end
  46. 46      else begin
  47. 47          if(delay_cnt == 32'd1) begin   //当计数器递减到1时,说明按键稳定
  48. 48                                         //状态维持了20ms
  49. 49              key_flag  <= 1'b1;         //此时消抖过程结束,给出一个时钟
  50. 50                                         //周期的标志信号
  51. 51              key_value <= key_reg1;     //并寄存此时按键的值
  52. 52          end
  53. 53          else begin
  54. 54              key_flag  <= 1'b0;
  55. 55              key_value <= key_value;
  56. 56          end  
  57. 57      end   
  58. 58 end
  59. 59      
  60. 60 endmodule
复制代码
代码中的第27行,每检测到按键被按下或松开,就让计数器从100_0000开始递减,时长20ms。在这20ms期间,每当有抖动产生,计数器就被重置回100_0000,即重新开始计时20ms。代码中的第47行,只有在计数器递减到1时,即此时计数器计时完了20ms,才会寄存按键的值。这样,每当按键被按下或松开,20ms内的抖动就被消除了。

蜂鸣器控制模块的代码如下:
  1. 1  module beep_control(
  2. 2         //input
  3. 3         input        sys_clk,     //系统时钟
  4. 4         input       sys_rst_n,   //复位信号,低电平有效
  5. 5         
  6. 6         input       key_flag,    //按键有效信号
  7. 7         input       key_value,   //消抖后的按键信号
  8. 8         output  reg  beep         //蜂鸣器控制信号  
  9. 9     );
  10. 10   
  11. 11 //*****************************************************
  12. 12 //**                    main code
  13. 13 //*****************************************************
  14. 14 always @ (posedge sys_clk or negedge sys_rst_n) begin
  15. 15      if(!sys_rst_n)
  16. 16          beep <= 1'b1;
  17. 17      else if(key_flag && (~key_value))  //判断按键是否有效按下
  18. 18          beep <= ~beep;        
  19. 19 end
  20. 20      
  21. 21 endmodule
复制代码
beep初始状态为高电平,蜂鸣器鸣叫。当key_flag拉高表明消抖之后的按键数据有效,此时若检测到按键值为0(即按键被按下),就将beep状态取反,以改变蜂鸣器的鸣叫状态。

为了验证我们的程序,我们在Modelsim内对代码进行仿真。为了减少仿真过程所需要的时间,这里我们将消抖时间间隔修改为80ns。如下图所示:
image011.png
图 10.4.4 仅用于仿真的代码

Testbench模块代码如下:
  1. 1   `timescale  1ns/1ns               // 定义仿真时间单位1ns和仿真时间精度为1ns
  2. 2   
  3. 3   module  key_beep_tb();               // 测试模块
  4. 4   
  5. 5   //输入
  6. 6   reg  sys_clk;                      //时钟信号
  7. 7   reg  sys_rst_n;                    // 复位信号
  8. 8   reg  key;
  9. 9   
  10. 10  
  11. 11  //输出
  12. 12  wire  beep;
  13. 13  //*****************************************************
  14. 14  //**                    maincode
  15. 15  //*****************************************************
  16. 16  
  17. 17  //给输入信号初始值
  18. 18  initial begin
  19. 19     key                =1'b1;
  20. 20     sys_clk            =1'b0;
  21. 21     sys_rst_n          =1'b0;  //复位
  22. 22      #20 sys_rst_n = 1'b1;     //在第21ns的时候复位信号信号拉高
  23. 23      #30  key =1'b0;  //在第50ns的时候按下按键
  24. 24      #20  key =1'b1;  //模拟抖动
  25. 25      #20  key =1'b0;  //模拟抖动
  26. 26      #20  key =1'b1;  //模拟抖动
  27. 27      #20  key =1'b0;  //模拟抖动
  28. 28      #170 key = 1'b1;  //在第300ns的时候松开按键
  29. 29      #20  key =1'b0;  //模拟抖动
  30. 30      #20  key =1'b1;  //模拟抖动
  31. 31      #20  key =1'b0;  //模拟抖动
  32. 32      #20  key =1'b1;  //模拟抖动
  33. 33      #170 key = 1'b0;  //在第550ns的时候再次按下按键
  34. 34      #20  key =1'b1;  //模拟抖动
  35. 35      #20  key =1'b0;  //模拟抖动
  36. 36      #20  key =1'b1;  //模拟抖动
  37. 37      #20  key =1'b0;  //模拟抖动
  38. 38      #170 key = 1'b1;  //在第800ns的时候松开按键
  39. 39      #20  key =1'b0;  //模拟抖动
  40. 40      #20  key =1'b1;  //模拟抖动
  41. 41      #20  key =1'b0;  //模拟抖动
  42. 42      #20  key =1'b1;  //模拟抖动
  43. 43  end
  44. 44  
  45. 45  //50Mhz的时钟,周期则为1/50Mhz=20ns,所以每10ns,电平取反一次
  46. 46  always #10sys_clk = ~sys_clk;
  47. 47  
  48. 48  //例化led模块
  49. 49 top_key_beep  u0_top_key_beep (
  50. 50      .sys_clk     (sys_clk  ),
  51. 51      .sys_rst_n   (sys_rst_n),
  52. 52      .key         (key      ),
  53. 53      .beep        (beep     )
  54. 54  );
  55. 55  
  56. 56  endmodule
复制代码
仿真得到的波形图如下图所示:
image013.png
图 10.4.5 仿真波形图

从图 10.4.5中可以看到,第一次将key拉低,并模拟按键抖动,可见在按键抖动停止后的第四个时钟周期时,key_flag出现一个时钟周期的高电平,同时beep被拉低(蜂鸣器停止鸣叫);在松开按键时,也模拟按键抖动,同理可知在抖动结束后的第四个时钟周期,key_flag信号被拉高。读者可以仔细观察仿真波形结合代码深入理解,仔细体会key_flag信号和key信号之间的关系。

1.5 下载验证
连接开发板的电源和下载器,并打开电源开关。在工程编译之后,将生成的sbit文件下载到开发板中。下载完成后,蜂鸣器处于鸣叫状态。然后按下按键KEY0,蜂鸣器停止鸣叫。再次按下按键,蜂鸣器再次开始鸣叫。如下图所示:
image015.png
图 10.5.1 ATK-DFPGL22G开发板上的蜂鸣器

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-22 16:58

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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