搜索
bottom↓
回复: 0

【正点原子FPGA连载】第十章按键控制蜂鸣器实验

[复制链接]

出0入234汤圆

发表于 2021-1-23 15:18:03 | 显示全部楼层 |阅读模式
1)实验平台:正点原子超越者FPGA开发板
2)  章节摘自【正点原子】超越者之FPGA开发指南
3)购买链接:https://item.taobao.com/item.htm?&id=631660290421
4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/fpga/zdyz-chaoyuezhe.html
5)正点原子官方B站:https://space.bilibili.com/394620890
6)正点原子FPGA技术交流群:905624739 QQ群头像.png
100846rel79a9p4uelap24.jpg
100846f1ce1fg14zbg0va4.png

第十章按键控制蜂鸣器实验


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


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

图 10.1.1  左边为有源蜂鸣器 右边为无源蜂鸣器

10347.png

图 10.1.2  本次实验使用的有源蜂鸣器

如图 10.1.1所示,从外观上看,两种蜂鸣器很相似,如将两种蜂鸣器的引脚都朝上放置,可以看出有绿色电路板的一种是无源蜂鸣器,没有电路板而用黑胶封闭的一种是有源蜂鸣器。
相较于有源蜂鸣器,无源蜂鸣器成本更低,且发声频率可控。而有源蜂鸣器控制相对简单,由于内部自带震荡源,只要加上合适的直流电压即可发声。本次实验使用的蜂鸣器为图 10.1.2中的有源蜂鸣器。
10.2实验任务
本节实验任务是使用按键控制蜂鸣器发声。初始状态为蜂鸣器鸣叫,按下开关后蜂鸣器停止鸣叫,再次按下开关,蜂鸣器重新鸣叫。
10.3硬件设计
10821.png

图 10.3.1 蜂鸣器控制电路原理图


本实验的管脚分配如下表所示:

1031.png

101140.png

图 10.3.2 按键控制蜂鸣器管脚分配图

对应的 UCF 约束语句如下:
  1. # PlanAhead Generated physical constraints
  2. NET "sys_clk" LOC = N8 | IOSTANDARD = "LVCMOS33";
  3. NET "sys_rst_n" LOC = G16 | IOSTANDARD = "LVCMOS33";
  4. NET "key" LOC = P5 | IOSTANDARD = "LVCMOS33";
  5. NET "beep" LOC = P4 | IOSTANDARD = "LVCMOS33";
复制代码

10.4程序设计
由实验任务可知,我们只需要在按键按下时改变蜂鸣器的鸣叫状态,但实际上在按键按下的过程中存在按键抖动的干扰,体现在数字电路中就是不断变化的高低电平,为避免在抖动过程中采集到错误的按键状态,我们需要对按键数据进行消除抖动处理。因此本系统应至少包含按键消抖模块和蜂鸣器控制模块,按键控制蜂鸣器系统框图如图 10.4.1所示。
101669.png

图 10.4.1 按键控制蜂鸣器系统框图

这里我们补充下如何查看软件生成的模块端口及信号连接图。首先在对工程进行编译,然后双击【Synthesize - XST】下的【View RTL Schematic】,选择第二个选项【Start with a schematic of the top-level block】,点击OK,如图 10.4.2所示:
101930.png

图 10.4.2 打开端口及信号连接图

稍后就可以看到软件生成的模块端口及顶层信号连接图了,双击顶层信号连接图,即可看到各个模块之间的信号连接图,如图 10.4.3所示:
102102.png

图 10.4.3 端口及信号连接图

需要注意的是,必须已经执行过综合或编译之后,才能打开模块端口及信号连接图。打开之后,按下键盘的【Ctrl】键,滚动鼠标的滚轮可以对生成的连接图进行放大和缩小,就可以比较清晰地查看各个模块端口信号的连接。
由图 10.4.3的连接图可知,顶层模块例化了以下两个模块:按键消抖模块(key_debounce)和蜂鸣器控制模块(beep_control)。顶层模块(top_key_beep)完成了对另外两个模块的例化。按键消抖模块主要起到延时采样,防止按键抖动的干扰。蜂鸣器控制模块通过对按键信号的识别,起到控制蜂鸣器鸣叫的作用。
按键消抖模块(key_debounce):对按键信号延时采样,将消抖后的按键信号和按键数据有效信号输出至beep_control模块。
蜂鸣器控制模块(beep_control):根据输入的按键信号和按键数据有效信号,来控制蜂鸣器的鸣叫。
在这里我们介绍一下按键消抖的原理。通常我们所使用的开关为机械弹性开关,当我们按下或松开按键时,由于弹片的物理特性,不能立即闭合或断开,往往会在断开或闭合的短时间内产生机械抖动,消除这种抖动的过程即称为按键消抖。
按键消抖可分为硬件消抖和软件消抖。硬件消抖主要使用RS触发器或电容等方法实现消抖,一般在按键较少时使用。软件消抖的原理主要为按键按下或松开后延时5ms—20ms采样,也可以在检测到按键状态稳定后采样,即避开抖动区域后再采样,如图 10.4.4所示。
102862.png

图 10.4.4 按键消抖原理图

顶层模块代码如下:
  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_reg;
  13. 13
  14. 14 //*****************************************************
  15. 15 //**                    main code
  16. 16 //*****************************************************
  17. 17 always @(posedge sys_clk or negedge sys_rst_n) begin
  18. 18     if (!sys_rst_n) begin
  19. 19         key_reg   <= 1'b1;
  20. 20         delay_cnt <= 32'd0;
  21. 21     end
  22. 22     else begin
  23. 23         key_reg <= key;
  24. 24         if(key_reg != key)             //一旦检测到按键状态发生变化(有按键被按下或释放)
  25. 25             delay_cnt <= 32'd1000000;  //给延时计数器重新装载初始值(计数时间为20ms)
  26. 26         else if(key_reg == key) begin  //在按键状态稳定时,计数器递减,开始20ms倒计时
  27. 27                  if(delay_cnt > 32'd0)
  28. 28                      delay_cnt <= delay_cnt - 1'b1;
  29. 29                  else
  30. 30                      delay_cnt <= delay_cnt;
  31. 31              end           
  32. 32     end   
  33. 33 end
  34. 34
  35. 35 always @(posedge sys_clk or negedge sys_rst_n) begin
  36. 36     if (!sys_rst_n) begin
  37. 37         key_flag  <= 1'b0;
  38. 38         key_value <= 1'b1;         
  39. 39     end
  40. 40     else begin
  41. 41         if(delay_cnt == 32'd1) begin   //当计数器递减到1时,说明按键稳定状态维持了20ms
  42. 42             key_flag  <= 1'b1;         //此时消抖过程结束,给出一个时钟周期的标志信号
  43. 43             key_value <= key;          //并寄存此时按键的值
  44. 44         end
  45. 45         else begin
  46. 46             key_flag  <= 1'b0;
  47. 47             key_value <= key_value;
  48. 48         end  
  49. 49     end   
  50. 50 end
  51. 51     
  52. 52 endmodule
复制代码

程序中第25行不断检测按键状态,一旦发现按键状态发生改变,就给计数器delay_cnt赋初值1000000。在按键状态不发生改变时,delay_cnt递减从而实现倒计时的功能,在倒计时过程中,一旦检测到按键状态发生改变,则说明有抖动产生,此时重新给delay_cnt赋初值,并开始新一轮倒计时。在50Mhz时钟驱动下,delay_cnt若能由1000000递减至1,则说明按键状态保持稳定时间达20ms,此时输出一个时钟周期的通知信号key_flag,并将此时的按键数据寄存输出。
蜂鸣器控制模块的代码如下:
  1. 1   module beep_control(
  2. 2        //input
  3. 3        input        sys_clk,     //系统时钟
  4. 4        input        sys_rst_n,   //复位信号,低电平有效  
  5. 5        input        key_flag,    //按键有效信号
  6. 6        input        key_value,   //按键信号   
  7. 7        //output
  8. 8        output  reg  beep         //蜂鸣器控制信号  
  9. 9    );
  10. 10 //*****************************************************
  11. 11 //**                    main code
  12. 12 //*****************************************************
  13. 13     always @ (posedge sys_clk or negedge sys_rst_n)
  14. 14     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  endmodule
复制代码

beep初始状态为高电平,蜂鸣器鸣叫,当检测到按键有效信号key_flag为高电平,同时按键信号key_value为低电平时说明按键被有效按下,此时beep取反,蜂鸣器停止鸣叫。当按键再次按下时,beep再次取反,蜂鸣器重新开始鸣叫。
为了验证我们的程序,我们在modelsim内对代码进行仿真。
Test bench模块代码如下
  1. 1 `timescale 1 ns/ 1 ns
  2. 2  module tb_top_key_beep();
  3. 3  
  4. 4  //parameter define
  5. 5  parameter T = 20;
  6. 6  
  7. 7  //reg define
  8. 8  reg  key;
  9. 9  reg  sys_clk;
  10. 10 reg  sys_rst_n;
  11. 11 reg  key_value;
  12. 12
  13. 13 // wire define                                               
  14. 14 wire beep;
  15. 15
  16. 16 //*****************************************************
  17. 17 //**                    main code                  
  18. 18 //*****************************************************
  19. 19
  20. 20 //给信号初始值
  21. 21 initial begin
  22. 22     key                          <= 1'b1;
  23. 23     sys_clk                      <= 1'b0;
  24. 24     sys_rst_n                    <= 1'b0;
  25. 25     #20           sys_rst_n      <= 1'b1;  //在第20ns的时候复位信号信号拉高
  26. 26     #30           key            <= 1'b0;  //在第50ns的时候按下按键
  27. 27     #20           key            <= 1'b1;  //模拟抖动
  28. 28     #20           key            <= 1'b0;  //模拟抖动
  29. 29     #20           key            <= 1'b1;  //模拟抖动
  30. 30     #20           key            <= 1'b0;  //模拟抖动
  31. 31     #170          key            <= 1'b1;  //在第300ns的时候松开按键
  32. 32     #20           key            <= 1'b0;  //模拟抖动
  33. 33     #20           key            <= 1'b1;  //模拟抖动
  34. 34     #20           key            <= 1'b0;  //模拟抖动
  35. 35     #20           key            <= 1'b1;  //模拟抖动
  36. 36     #170          key            <= 1'b0;  //在第550ns的时候再次按下按键
  37. 37     #20           key            <= 1'b1;  //模拟抖动
  38. 38     #20           key            <= 1'b0;  //模拟抖动
  39. 39     #20           key            <= 1'b1;  //模拟抖动
  40. 40     #20           key            <= 1'b0;  //模拟抖动
  41. 41     #170          key            <= 1'b1;  //在第800ns的时候松开按键
  42. 42     #20           key            <= 1'b0;  //模拟抖动
  43. 43     #20           key            <= 1'b1;  //模拟抖动
  44. 44     #20           key            <= 1'b0;  //模拟抖动
  45. 45     #20           key            <= 1'b1;  //模拟抖动
  46. 46 end
  47. 47
  48. 48 //50Mhz的时钟,周期则为1/50Mhz=20ns,所以每10ns,电平取反一次  
  49. 49  always # (T/2) sys_clk <= ~sys_clk;
  50. 50
  51. 51 //例化key_beep模块                        
  52. 52 top_key_beep u1 (
  53. 53  .beep       (beep),
  54. 54  .key        (key),
  55. 55  .sys_clk    (sys_clk),
  56. 56  .sys_rst_n  (sys_rst_n)
  57. 57 );     
  58. 58                                             
  59. 59 endmodule
复制代码

仿真波形图如下:

108911.png

图 10.4.5 仿真波形图

测试代码中,为了方便仿真波形的查看,将按键消抖模块中的延时采样的延时时间改为四个时钟周期(将按键消抖模块中的第25行代码 delay_cnt <= 32'd1000000; 改为delay_cnt <= 32'd4;)。tb_key_beep模块中第22行到第45行为信号的激励。从图 10.4.5可以看到,第50ns时,将key拉低,并在50至130ns时模拟按键抖动,可见在按键抖动停止后的第4个时钟周期时,key_flag出现一个时钟周期的高电平,同时beep被拉低(蜂鸣器停止鸣叫);在第300ns时松开按键,随后模拟按键抖动,同理可知在抖动结束后的第四个时钟周期,key_flag信号被拉高。读者可以仔细观察仿真波形结合代码深入理解,仔细体会key_flag信号和key信号之间的关系。
10.5下载验证
首先我们打开按键控制蜂鸣器工程,在工程所在的路径下打开key_beep/prj/key_beep文件夹,在里面找到“key_beep.xise”并双击打开。注意工程所在的路径名只能由字母、数字以及下划线组成,不能出现中文、空格以及特殊字符等。key_beep工程打开后如图 10.5.1所示。
109537.png

图 10.5.1 按键控制蜂鸣器工程

工程打开后双击“Configure Target Device”一栏中的“Manage Configuration Project(iMAPCT)” (上图红框位置),在弹出的界面中双击“Boundary Scan”,下载界面如图 10.5.2所示。
109751.png

图 10.5.2 程序下载界面

如下图 10.5.3所示。将Xilinx下载器一端连接电脑,另一端与开发板上的JTAG下载口连接,然后连接电源线。
109894.png

图 10.5.3 超越者开发板实物图

打开电源开关,接下来我们下载程序,验证按键控制蜂鸣器功能。
开发板电源打开后,点击工具栏中的“Initialize chain”图标(图 10.5.4红框位置),添加工程目录下的“key_beep.bit”文件。然后双击“Program”将工程编译完成后得到的bit文件下载到开发板中,如图 10.5.5所示。
1010162.png

图 10.5.4 硬件连接

1010221.png

图 10.5.5 程序下载完成界面

下载完成后,就能在开发板上看到按键控制蜂鸣器的效果如下图所示。
1010316.png

图 10.5.6 按键控制蜂鸣器效果图


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

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-4-24 18:36

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

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