• EDA实验-----4*4矩阵键盘与数码管显示测试(Quartus ‖)


    目录

    一、实验目的

    二、实验仪器设备

    三、实验原理

    四、实验要求

    五、实验步骤

    六、实验报告

    七、实验过程

    1.矩阵键盘按键原理

    2.数码管原理

    3.分频器代码

     4.电路图连接

     5.文件烧录


     

    一、实验目的

    1. 了解数码管的工作原理;
    2. 掌握4*4矩阵键盘和数码管显示的编程方法。
    3. 学会用于Verilog语言进行程序设计。

    二、实验仪器设备

    1. PC机一台。
    2. FPGA实验开发系统一套。

    三、实验原理

    本实验通过扫描4*4矩阵键盘的值,在数码管上显示对应按钮的编号数据。矩阵键盘及数码管电路如下所示。

    b5731399c96e4300b93feb6b8d6b7ab0.png

    a2e0cec5e6b84f93b222318559042156.png 

    四、实验要求

    1. 预习教材中的相关内容。
    2. 阅读并熟悉本次实验的内容。
    3. 完成实验内容。

    五、实验步骤

    1. 启动 Quartus II 建立一个空白工程,选择的器件为 Altera 公司的 Cyclone 系列的 EP2C8Q240C8芯片,命名为 keyarray.qpf;
    2. 新建一个 Schematic File 文件,命名为 keyarray.bdf分别新建 3 个 Verilog HDL File 文件,分别命名为 seg_show.v、 divclk.v、 keyarraycontrol.v。输入程序代码并保存(对应源程序 8),然后进行综合编译。若在编译过程中发现错误,则找出错误并更正错误,直至编译成功为止。
    3. 从设计文件创建模块(FileàCreat UpdateàCreat Symbol Files for Current File) ,seg_show.v 生成名为 seg_show.bsf; divclk.v 生成名为 divclk.bsf; keyarraycontrol.v 生成名为keyarraycontrol.bsf;
    4. 在 keyarray.bdf 文件中,在空白处双击鼠标左键,在 Symbol 对话框左上角的 libraries 中,分别将 Project 下的 seg_show, divclk, keyarraycontrol 模块放在图形文件 keyarray.bdf 中,加入输入、输出引脚,双击每个引脚,进行引脚命名,并锁定管脚,将未使用的引脚设置为三态输入(一定要设置,否则可能会损坏芯片);

      12a080d545ca442a932eceeeca2128fa.png

    5. 将 keyarray.bdf 设置为顶层实体。对该工程文件进行全程编译处理,若在编译过程中出现错误,则找出错误并更正,直至编译通过为止;
    6. 将 USB-Blaster 下载电缆的两端分别连接到 PC 机的 USB 接口和 EDA 实验箱上的 JTAG 下载口上,打开电源,执行下载命令,把程序下载到 FPGA 器件中,此时,即可在 EDA 实验箱上通过按下相应的按键使蜂鸣器发出对应的音符声响。

    完整的顶层模块原理图如图所示:308baaf78f574596add4486f5ddd43bb.png

    六、实验报告

    1. 总结Verilog设计多路选择器使用的最基本与核心的语法知识。
    2. 对仿真的结果进行分析。
    3. 讨论自己在设计过程中遇到的问题、解决的过程以及收获体会。

    七、实验过程

    创建项目、创建Verilog文件、写代码、进行波形仿真、画出电路图、设置管脚和三态、烧录文件

    1.矩阵键盘按键原理

    在讲实验过程之前,先讲讲相关的原理,不知道原理的话就很难去写代码。

    2fa17b571f7e4ce0857c707e4f0c422e.png

    d20180ba4d504e73abdfeb3195f8812d.png

    矩阵按键模块是先按行选取到某一行,然后再选列,跟矩阵选择某一个点的原理是一样的,如果按下这个按键的时候,此时两边的开关是接通的,这时候就会返回到一个矩阵按键回馈的信息,我们只需要去读取到这个信息,然后再根据行列的相关位置,把这个信息转换为相对于的数字返回即可。

    Verilog代码(读取到矩阵按键按下的位置,输出相对于的数字):

    1. module keyarraycontrol(clk,rst,row,col,keydata);
    2. input clk;
    3. input rst;
    4. input [3:0] row;
    5. output reg[3:0] col;
    6. output reg[3:0] keydata;
    7. reg keyint;
    8. reg [19:0] cnt;
    9. //分频获得键盘扫描频率
    10. always @ (posedge clk, negedge rst)
    11. if (!rst)
    12. cnt <= 0;
    13. else
    14. cnt <= cnt + 1'b1;
    15. //将计数的最高位赋给key_clk
    16. wire key_clk = cnt[19]; // (2^20/50M = 21)ms
    17. //设定扫描状态判断参数
    18. parameter NO_KEY_PRESSED = 6'b000_001; // 如果没有按键按下的时候
    19. parameter SCAN_COL0 = 6'b000_010; // 按下第一行按键
    20. parameter SCAN_COL1 = 6'b000_100; // 按下第二行按键
    21. parameter SCAN_COL2 = 6'b001_000; // 按下第三行按键
    22. parameter SCAN_COL3 = 6'b010_000; // 按下第四行按键
    23. parameter KEY_PRESSED = 6'b100_000; // 有按键按下状态
    24. reg [5:0] current_state, next_state; // 当前状态,,,下一个状态
    25. always @ (posedge key_clk, negedge rst)
    26. if (!rst)
    27. current_state <= NO_KEY_PRESSED;
    28. else
    29. current_state <= next_state;
    30. //
    31. always @ *
    32. case (current_state)
    33. NO_KEY_PRESSED : //
    34. if (row != 4'hF)
    35. next_state = SCAN_COL0;
    36. else
    37. next_state = NO_KEY_PRESSED;
    38. SCAN_COL0 : //
    39. if (row != 4'hF)
    40. next_state = KEY_PRESSED;
    41. else
    42. next_state = SCAN_COL1;
    43. SCAN_COL1 : //
    44. if (row != 4'hF)
    45. next_state = KEY_PRESSED;
    46. else
    47. next_state = SCAN_COL2;
    48. SCAN_COL2 : //
    49. if (row != 4'hF)
    50. next_state = KEY_PRESSED;
    51. else
    52. next_state = SCAN_COL3;
    53. SCAN_COL3 : //
    54. if (row != 4'hF)
    55. next_state = KEY_PRESSED;
    56. else
    57. next_state = NO_KEY_PRESSED;
    58. KEY_PRESSED : //
    59. if (row != 4'hF)
    60. next_state = KEY_PRESSED;
    61. else
    62. next_state = NO_KEY_PRESSED;
    63. endcase
    64. reg [3:0] col_val, row_val; //
    65. always @ (posedge key_clk, negedge rst)
    66. if (!rst)
    67. begin
    68. col<= 4'h0;
    69. keyint<=0;
    70. end
    71. else
    72. case (next_state)
    73. NO_KEY_PRESSED : //
    74. begin
    75. col <= 4'h0;
    76. keyint <= 0; //
    77. end
    78. SCAN_COL0 : //
    79. col <= 4'b1110;
    80. SCAN_COL1 :
    81. col <= 4'b1101;
    82. SCAN_COL2 : //
    83. col <= 4'b1011;
    84. SCAN_COL3 : //
    85. col <= 4'b0111;
    86. KEY_PRESSED : //
    87. begin
    88. col_val<= col; // 得到列的值
    89. row_val<= row; // 得到行的值
    90. keyint <= 1; //
    91. end
    92. endcase
    93. always @ (posedge key_clk, negedge rst)
    94. if (!rst)
    95. keydata <= 16'h0000;
    96. else
    97. if (keyint)
    98. case ({col_val, row_val})
    99. 8'b1110_1110 : keydata <= 8'd0;
    100. 8'b1110_1101 : keydata <= 8'd4;
    101. 8'b1110_1011 : keydata <= 8'd8;
    102. 8'b1110_0111 : keydata <= 8'd12;
    103. 8'b1101_1110 : keydata <= 8'd1;
    104. 8'b1101_1101 : keydata <= 8'd5;
    105. 8'b1101_1011 : keydata <= 8'd9;
    106. 8'b1101_0111 : keydata <= 8'd13;
    107. 8'b1011_1110 : keydata <= 8'd2;
    108. 8'b1011_1101 : keydata <= 8'd6;
    109. 8'b1011_1011 : keydata <= 8'd10;
    110. 8'b1011_0111 : keydata <= 8'd14;
    111. 8'b0111_1110 : keydata <= 8'd3;
    112. 8'b0111_1101 : keydata <= 8'd7;
    113. 8'b0111_1011 : keydata <= 8'd11;
    114. 8'b0111_0111 : keydata <= 8'd15;
    115. default: keydata <= keydata;
    116. endcase
    117. else
    118. keydata <= keydata;
    119. endmodule

    2.数码管原理

    a9fa396583f94ec78dd1558ef394d994.png

    数码管分为共阴和共阳两种,通过选择器的高低电平去判断选取到的位数,所以数码管的读取是先选择位,然后再去显示亮的灯。下图所示,下面的74HC573芯片是用于选位处理的(这个芯片必须接地或者接上低电平才可以正常工作),由于上面的U1也是同一个芯片,所以这里先进行选位的时候要先把上面的那个芯片锁住,然后下面的芯片工作,这里我们不难看出这是一个共阴的数码管,每一个数码管的选位都是连接到阴极处的(接地),所以选位的时候只需要去进行连接到地,那就可以实现通电。选完位之后,就开始选段,所以这时候要锁住下面的芯片,让上面的工作,这个数码管的选段是根据某一个段通入高电平才会亮,其每一段对应的电平位置是 hgfedcba,比如通入8个电平: 0000 0110,那么就会显示数字1,因为只有b和c段亮了。

    b5731399c96e4300b93feb6b8d6b7ab0.png

    数码管生成器模拟软件:数码管 代码 生成器 (treee.com.cn)

    Verilog代码(获取到相对于的数字,然后在数码管静态显示出来): 

    1. module seg(clk, data, sel_lock, seg_lock, gpio);
    2. input clk;
    3. input[3:0] data;
    4. output reg sel_lock;
    5. output reg seg_lock;
    6. output [7:0] gpio;
    7. reg [7:0] gpio;
    8. reg [3:0] disp_dat;
    9. reg cnt;
    10. reg [12:0] cnt2;
    11. always@(posedge clk)
    12. //cnt2 = cnt2 + 1;
    13. //if (cnt <1000)
    14. begin
    15. cnt = cnt + 1;
    16. cnt2 = cnt2 + 1;
    17. if (cnt)
    18. begin
    19. sel_lock = 1'b1;
    20. seg_lock = 1'b0;
    21. gpio = 8'h00;
    22. #20 sel_lock = 1'b0;
    23. seg_lock = 1'b1;
    24. end
    25. else
    26. begin
    27. sel_lock = 1'b0;
    28. seg_lock = 1'b1;
    29. disp_dat = data;
    30. case(disp_dat)
    31. 4'h0:gpio=8'h3f; //0 0011 1111
    32. 4'h1:gpio=8'h06; //1 0000 0110
    33. 4'h2:gpio=8'h5b; //2
    34. 4'h3:gpio=8'h4f; //3
    35. 4'h4:gpio=8'h66; //4
    36. 4'h5:gpio=8'h6d; //5
    37. 4'h6:gpio=8'h7d; //6
    38. 4'h7:gpio=8'h07; //7
    39. 4'h8:gpio=8'h7f; //8
    40. 4'h9:gpio=8'h6f; //9
    41. 4'ha:gpio=8'h77; //a
    42. 4'hb:gpio=8'h7c; //b
    43. 4'hc:gpio=8'h39; //c
    44. 4'hd:gpio=8'h5e; //d
    45. 4'he:gpio=8'h79; //e
    46. 4'hf:gpio=8'h71; //f
    47. endcase
    48. #20 sel_lock = 1'b1;
    49. seg_lock = 1'b0;
    50. end
    51. end
    52. endmodule

    3.分频器代码

    1. module divclk(inclk,outclk);
    2. input inclk;
    3. output outclk;
    4. reg outclk;
    5. reg [16:0] cnt;
    6. initial
    7. begin
    8. cnt=0;
    9. outclk=0;
    10. end
    11. always @(posedge inclk)
    12. begin
    13. cnt=cnt+1;
    14. if (cnt==0)
    15. outclk = outclk+1;
    16. end
    17. endmodule

     4.电路图连接

    写好了Verilog代码,就进行分析错误,分析无误后,我们就对这些代码生成子模块文件。然后就创建block文件开始连接电路图,电路图以及管脚配置如下:7965bcb8120242cbbafe06f67ddef94b.png

     5.文件烧录

    弄好了之后就是最后一步操作了,把没用到的管脚设置三态,然后烧录文件。

    点击Assignment, Device

    72fc4c7b723a4590974b9fe2e43a9c73.png

    然后点击这里,设置管脚。 

    ab08cd8cd2a5450983f6f094f87f0865.png 选择第一个就行了,就是把多余的管脚设置三态。a779aee811ee4689a875b6f7b7ec78af.png

     然后就是编译运行文件,运行无误。8fda9f81c00f49318748cc490cbd77b8.png

    点击此处,烧录文件。 

    ea76d796dcb248c3b5125fdc9a9d0662.png 

    这里我们会看到,下面有一个芯片,这个也就是我们写好了的sof文件,然后就是通过你的电脑接口去连接到开发板,如果你看到上面有一个No Hardware的时候,你点击旁边的按钮进行接口设置,设置为USB接口即可(USB线连接了你的开发板就会自动显示出来的)。最后点击start就可以进行烧录了。 

    以上就是本期的全部内容了,我们下一次见!

    分享一张壁纸:9537723833a24b41bace354bce482686.png

     

  • 相关阅读:
    闭包的理解
    【服务器】 如何私网转换成人人可以访问的公网?#采用花生壳
    【集成学习】对已训练好的模型进行投票
    2023版:深度比较几种.NET Excel导出库的性能差异
    UE MotionBlur源码解析
    代码随想录算法训练营第四十三天| LeetCode1049. 最后一块石头的重量 II、LeetCode494. 目标和、LeetCode474. 一和零
    深度学习(生成式模型)——Classifier Free Guidance Diffusion
    CentOS 搭建本地 yum 源方式 安装 httpd 服务
    TS 函数 配合接口
    Docker 常用命令全解析:提升对雷池社区版的使用经验
  • 原文地址:https://blog.csdn.net/m0_73633088/article/details/134489814