经典的verilog键盘扫描程序

合集下载

(整理)经典的verilog键盘程序

(整理)经典的verilog键盘程序
经典的verilog键盘扫描程序
2.环境影评价工作等级的划分依据
2.规划环境影响评价的内容
报告内容有:建设项目基本情况、建设项目所在地自然环境社会环境简况、环境质量状况、主要环境保护目标、评价适用标准、工程内容及规模、与本项目有关的原有污染情况及主要环境问题、建设项目工程分析、项目主要污染物产生及预计排放情况、环境影响分析、建设项目拟采取的防治措施及预期治理效果、结论与建议等。2.环境影响评价工程师职业资格制度
3.评估环境影响的价值(最重要的一步):采用环境经济学的环境经济损益分析方法,对量化后的环境功能损害后果进行货币化估价,即对建设项目的环境费用或环境效益进行估价。
(1)生产力变动法

基于FPGA的键盘扫描程序的设计

基于FPGA的键盘扫描程序的设计

摘要在现代电子工业的控制电路中,键盘扫描和显示电路对系统的调试和设置有着重要的作用。

随着EDA技术的发展,基于FPGA的扫描键盘因其结构简单,能有效防止机械键盘按键抖动带来的数据错误等优点在许多电子设备中都得到了广泛的应用。

本文主要是设计一个基于FPGA的键盘扫描程序,该设计在EDA工具Quarutus II9.0上开发完成,以Creat-SOPC2000实验箱上的4*4矩阵键盘为硬件实体,设计键盘扫描程序,将程序划分为时序产生模块、键盘扫描模块、弹跳消除模块、键值译码模块四个模块,时序产生模块为键盘扫描和弹跳消除模块产生时钟信号,键盘扫描模块采用行扫描法对4*4矩阵键盘进行扫描,键值译码模块将所按键值译码为共阳极8位7段数码管的显示码,几个模块组合起来实现键盘扫描的设计要求。

最后对程序进行仿真分析和硬件验证。

仿真结果表明,该系统具有集成度高、稳定性好、设计灵活和设计效率高等优点。

关键词: FPGA,Quartus II,VHDL,键盘扫描ABSTRACTIn the modern electronics industry controlling-circuit, the keyboard scanning and display circuit plays an important role in debugging and setting the system. With the development of EDA technology, FPGA-based scanning keyboard have been widely used in many electronic devices because of its simple structure, and it also can effectively prevent mechanical keyboard jitter caused by data errors.This article primarily designed an FPGA-based keyboard scan procedures, this design is developed on the EDA tools—— Quarutus II9.0 and designed the keyboard scan program, using the Creat-SOPC2000 experimental box 4 * 4 matrix keyboard as the hardware entity .the program is divided into four modules as the timing generation module, a keyboard scanning module, bounce cancellation module and the decoding module. The timing generation module generates the clock signal for the keyboard scanning and bounce elimination module, the keyboard scanning module using the line scanning method to sweep the 4* 4 matrix keyboard, key decoder module decodes the key value for the common anode eight 7-segment display code. Several modules assembles together to meet the keyboard scanning design requirements. Finally, conducting simulation analysis by the program and verifying the hardware.Simulation results show that the system has many advantages such as high integration, good stability, high efficiency, flexible design and high design efficiency.Keywords: FPGA,Quartus II,VHDL,keyboard scanning目录摘要 (I)ABSTRACT .......................................................................................................... I I 第1章绪论 (1)1.1 课题的研究背景 (1)1.2 课题的研究意义 (2)1.3 本文的主要工作 (2)第2章FPGA开发工具简介 (3)2.1 FPGA概述 (3)2.2 VHDL语言以及Quartus II应用 (3)2.3 本章小结 (4)第3章基于FPGA的键盘扫描程序的设计 (3)3.1 键盘扫描程序的总体电路设计 (5)3.1.1 矩阵式键盘扫描的工作原理 (6)3.1.2 数码管的显示原理 (7)3.2 键盘扫描电路各主要功能模块的设计 (8)3.2.1 时序产生模块 (8)3.2.2 键盘扫描模块 (9)3.2.3 弹跳消除模块 (11)3.2.4 键盘译码电路 (13)3.2.5 键盘扫描程序的顶层文件设计 (15)3.3本章小结 (16)第4章键盘扫描程序的波形仿真及硬件验证 (17)4.1 系统仿真 (17)4.1.1 消抖电路仿真 (17)4.1.2 键盘时钟信号仿真 (18)4.1.3 键盘扫描信号仿真 (18)4.1.4 键盘译码电路仿真 (19)4.1.5 键盘扫描总体电路仿真 (21)4.2引脚的锁定 (22)4.3硬件验证 (23)4.4本章小结 (25)结论 (26)参考文献 (27)附录 (28)致谢 (32)第1章绪论1.1 课题的研究背景在现代计算机与电子系统中,一般都采用通用式的标准键盘将所需的数据和指令等信息通过键盘输入到计算机和电子系统,以此来实现人机之间的接口交互。

51单片机键盘扫描程序7294详细介绍

51单片机键盘扫描程序7294详细介绍

51单片机键盘扫描程序7294详细介绍1. 前言随着人们对电子产品的需求不断增加,微处理器成为现代电子设备中必不可少的一个组成部分。

其中,单片机作为一种嵌入式微处理器,由于其功能强大、价格低廉和易于编程等优点,被广泛应用于各个领域。

在单片机应用中,键盘扫描技术是常见的一种应用技术。

它既可以用于普通键盘,也可以用于定制键盘或遥控器等输入设备。

在51单片机中,键盘扫描程序7294是最为常用和经典的键盘扫描程序之一。

本文将详细介绍7294程序的原理、功能和实现方法。

2. 概述7294程序是一种基于矩阵扫描的键盘输入程序,也称为键盘扫描程序。

该程序主要由两个部分组成,即扫描部分和解码部分。

扫描部分是通过读取每个行端口和列端口的状态,得出当前按下的键位信息。

在实现过程中,通常采用交错式扫描,即先扫描行端口再扫描列端口。

这种方式可以避免多个键同时按下时无法识别的情况。

解码部分负责将扫描部分得到的行列矩阵转换成对应的键位信息。

这里我们可以采用查表法或者位运算法来实现。

3. 原理主要原理7294程序的主要工作原理如下:(1)行列扫描首先,程序将所有行端口设为输出,所有列端口设为输入。

接着,程序对每个行端口进行扫描,每次只将一个行端口输出高电平,同时读取所有列端口的状态。

如果任意一个列端口检测到低电平,说明该列与当前行对应的键被按下,程序将该键位信息保存下来。

反之,如果所有列端口均输出高电平,说明该行无按键按下。

(2)解码当扫描部分输出一个键位矩阵后,解码部分即开始工作。

首先,程序将每个键位的状态 (按下或放开)保存到一个矩阵中。

接着,程序通过查表法或者位运算法将该矩阵转换成对应的键位信息,然后提交给主程序进行后续处理。

4. 具体实现为了更好地理解7294程序的实现步骤,我们这里以4x4矩阵键盘为例展示其具体实现过程。

(1)硬件连接首先,将4个行端口 (行1~行4)和4个列端口 (列1~列4)分别连接到51单片机的IO口,如图所示:(2)扫描过程接着,通过编写程序实现键盘的扫描过程。

PS2键盘接口Verilog程序

PS2键盘接口Verilog程序

之前探讨过PS/2键盘编解码以及数据传输协议,这次自己动手实现了利用FPGA FPGA现场可编程逻辑门阵列(FPGA, Field Programmable Gate Array),是一个含有可编辑元件的半导体设备,可供使用者现场程式化的逻辑门阵列元件。

FPGA是在PAL、GAL、CPLD 等可编辑器件的基础上进一步发展的产物。

[全文]接收键盘编码,然后通过串口串口串口是计算机上一种非常通用的设备通信协议,大多数计算机包含两个基于RS232的串口。

串口同时也是仪器仪表设备的通信协议,并可用于获取远程采集设备的数据。

[全文]传输到PC。

做的比较简单,只是通过FPGAFPGA现场可编程逻辑门阵列(FPGA, Field Programmable Gate Array),是一个含有可编辑元件的半导体设备,可供使用者现场程式化的逻辑门阵列元件。

FPGA是在PAL、GAL、CPLD等可编辑器件的基础上进一步发展的产物。

把大写字母A-Z转换成相应的ASCII码,只要字母按键被按下,就能在串口串口串口是计算机上一种非常通用的设备通信协议,大多数计算机包含两个基于RS232的串口。

串口同时也是仪器仪表设备的通信协议,并可用于获取远程采集设备的数据。

调试助手里显示相应大写字母。

下面就共享代码吧!除了顶层模块,三个底层模块分别为PS/2传输处理模块、串口传输模块以及串口波特率选择模块(下面只给出顶层模块和PS/2传输处理模块的verilog代码)。

module ps2_key(clk,rst_n,ps2k_clk,ps2k_data,RS232_tx);input clk; //50M时钟信号input rst_n; //复位信号input ps2k_clk; //PS2接口时钟信号input ps2k_data; //PS2接口数据信号output rs232_tx; // RS232发送数据信号wire[7:0] ps2_by te; // 1byte键值wire ps2_state; //按键状态标志位wire bps_start; //接收到数据后,波特率时钟启动信号置位wire clk_bps; // clk_bps的高电平为接收或者发送数据位的中间采样点ps2scan ps2scan( .clk(clk), //按键扫描模块.rst_n(rst_n),.ps2k_clk(ps2k_clk),.ps2k_data(ps2k_data),.ps2_byte(ps2_byte),.ps2_state(ps2_state));speed_select speed_select( .clk(clk),.rst_n(rst_n),.bps_start(bps_start),.clk_bps(clk_bps));my_uart_tx my_uart_tx( .clk(clk),.rst_n(rst_n),.clk_bps(clk_bps),.rx_data(ps2_byte),.rx_int(ps2_state),.rs232_tx(rs232_tx),.bps_start(bps_start));Endmodulemodule ps2scan(clk,rst_n,ps2k_clk,ps2k_data,ps2_byte,ps2_state); input clk; //50M时钟信号input rst_n; //复位信号input ps2k_clk; //PS2接口时钟信号input ps2k_data; //PS2接口数据信号output[7:0] ps2_byte; // 1byte键值,只做简单的按键扫描output ps2_state; //键盘当前状态,ps2_state=1表示有键被按下//------------------------------------------reg ps2k_clk_r0,ps2k_clk_r1,ps2k_clk_r2; //ps2k_clk状态寄存器//wire pos_ps2k_clk; // ps2k_clk上升沿标志位wire neg_ps2k_clk; // ps2k_clk下降沿标志位always @ (posedge clk or negedge rst_n) beginif(!rst_n) beginps2k_clk_r0 <= 1'b0;ps2k_clk_r1 <= 1'b0;ps2k_clk_r2 <= 1'b0;endelse begin //锁存状态,进行滤波ps2k_clk_r0 <= ps2k_clk;ps2k_clk_r1 <= ps2k_clk_r0;ps2k_clk_r2 <= ps2k_clk_r1;endendassign neg_ps2k_clk = ~ps2k_clk_r1 & ps2k_clk_r2; //下降沿//------------------------------------------reg[7:0] ps2_byte_r; //PC接收来自PS2的一个字节数据存储器存储器存储器是用来存储程序和数据的部件,有了存储器,计算机才有记忆功能,才能保证正常工作。

Verilog HDL 编写 4.4 3.3键盘程序

Verilog HDL 编写 4.4  3.3键盘程序

这里有一段4*4的,哪位大哥能帮我改成3*3的,谢谢!!! module Verilog1(clk,//50MHZreset,row,//行col,//列key_value//键值);input clk,reset;input [3:0] row;output [3:0] col;output [3:0] key_value;reg [3:0] col;reg [3:0] key_value;reg [5:0] count;//delay_20msreg [2:0] state;//状态标志reg key_flag;//按键标志位reg clk_500khz;//500KHZ时钟信号reg [3:0] col_reg;//寄存扫描列值reg [3:0] row_reg;//寄存扫描行值always @(posedge clk or negedge reset)if(!reset)begin clk_500khz<=0; count<=0;endelsebeginif(count>=50)begin clk_500khz<=~clk_500khz;count<=0;endelse count<=count+1;endalways @(posedge clk_500khz or negedge reset) if(!reset)begin col<=4'b0000;state<=0;endelsebegincase (state)0:begincol[3:0]<=4'b0000;key_flag<=1'b0;if(row[3:0]!=4'b1111)begin state<=1;col[3:0]<=4'b1110;end //有键按下,扫描第一行else state<=0;end1:beginif(row[3:0]!=4'b1111)begin state<=5;end//判断是否是第一行elsebegin state<=2;col[3:0]<=4'b1101;end//扫描第二行end2:beginif(row[3:0]!=4'b1111)begin state<=5;end//判断是否是第二行elsebegin state<=3;col[3:0]<=4'b1011;end//扫描第三行end3:beginif(row[3:0]!=4'b1111)begin state<=5;end//判断是否是第三一行elsebegin state<=4;col[3:0]<=4'b0111;end//扫描第四行end4:beginif(row[3:0]!=4'b1111)begin state<=5;end//判断是否是第一行else state<=0;end5:beginif(row[3:0]!=4'b1111)begincol_reg<=col;//保存扫描列值row_reg<=row;//保存扫描行值state<=5;key_flag<=1'b1;//有键按下endelsebegin state<=0;endendendcaseendalways @(clk_500khz or col_reg or row_reg) beginif(key_flag==1'b1)begincase ({col_reg,row_reg})8'b1110_1110:key_value<=0;8'b1110_1101:key_value<=1;8'b1110_1011:key_value<=2;8'b1110_0111:key_value<=3;8'b1101_1110:key_value<=4;8'b1101_1101:key_value<=5;8'b1101_1011:key_value<=6;8'b1101_0111:key_value<=7;8'b1011_1110:key_value<=8;8'b1011_1101:key_value<=9;8'b1011_1011:key_value<=10;8'b1011_0111:key_value<=11;8'b0111_1110:key_value<=12;8'b0111_1101:key_value<=13;8'b0111_1011:key_value<=14;8'b0111_0111:key_value<=15;endcaseendendendmodule提问者:roddyni - 二级3*3module Verilog1(clk,//50MHZreset,row,//行col,//列key_value//键值);input clk,reset;input [2:0] row;output [2:0] col;output [3:0] key_value;reg [2:0] col;reg [3:0] key_value;reg [5:0] count;//delay_20msreg [2:0] state;//状态标志reg key_flag;//按键标志位reg clk_500khz;//500KHZ时钟信号reg [2:0] col_reg;//寄存扫描列值reg [2:0] row_reg;//寄存扫描行值always @(posedge clk or negedge reset)if(!reset)begin clk_500khz<=0; count<=0;endelsebeginif(count>=50)begin clk_500khz<=~clk_500khz;count<=0;endelse count<=count+1;endalways @(posedge clk_500khz or negedge reset) if(!reset)begin col<=3'b000;state<=0;endelsebegincase (state)0:begincol[2:0]<=3'b000;key_flag<=1'b0;if(row[2:0]!=3'b111)begin state<=1;col[2:0]<=3'b110;end //有键按下,扫描第一行else state<=0;end1:beginif(row[2:0]!=3'b111)begin state<=4;end//判断是否是第一行elsebegin state<=2;col[2:0]<=3'b101;end//扫描第二行end2:beginif(row[2:0]!=3'b111)begin state<=4;end//判断是否是第二行elsebegin state<=3;col[2:0]<=3'b011;end//扫描第三行end3:beginif(row[2:0]!=3'b111)begin state<=4;end//判断是否是第一行else state<=0;end4:beginif(row[2:0]!=3'b111)begincol_reg<=col;//保存扫描列值row_reg<=row;//保存扫描行值state<=4;key_flag<=1'b1;//有键按下endelsebegin state<=0;endendendcaseendalways @(clk_500khz or col_reg or row_reg) beginif(key_flag==1'b1)begincase ({col_reg,row_reg})6'b110_110:key_value<=0;6'b110_101:key_value<=1;6'b110_011:key_value<=2;6'b101_110:key_value<=3;6'b101_101:key_value<=4;6'b101_011:key_value<=5;6'b011_110:key_value<=6;6'b011_101:key_value<=7;6'b011_011:key_value<=8;endcaseendendendmodule3。

经典的verilog键盘扫描程序

经典的verilog键盘扫描程序

经典的verilog键盘扫描程序作者:ilove314拿到威百仕( VibesIC )的板子后就迫不及待的开始我的学习计划,从最基础的分频程序开始,但看到这个键盘扫描程序后,直呼经典,有相见恨晚的感觉,还想说一句:威百仕( VibesIC ),我很看好你!WHY?待我慢慢道来,这个程序的综合后是0error,0warning。

想想自己编码的时候那个warning是满天飞,现在才明白HDL设计有那么讲究了,代码所设计的不仅仅是简单的逻辑以及时序的关系,更重要的是你要在代码中不仅要表现出每一个寄存器,甚至每一个走线。

想想我写过的代码,只注意到了前者,从没有注意过后者,还洋洋自得以为自己也算是个高手了,现在想来,实在惭愧啊!学习学习在学习,这也重新激发了我对HDL设计的激情,威百仕给了我一个方向,那我可要开始努力喽!废话说了一大堆,看程序吧:(本代码经过ise7.1i综合并下载到SP306板上验证通过)//当三个独立按键的某一个被按下后,相应的LED被点亮;再次按下后,LED熄灭,按键控制LED亮灭module key_debounce(clk,rst_n,s1_n,s2_n,s3_n,s4_n,s5_n,led_d1,led_d2,led_d3,led_d 4,led_d5);input clk; //主时钟信号,10MHzinput rst_n; //复位信号,低有效input s1_n,s2_n,s3_n,s4_n,s5_n;output led_d1,led_d2,led_d3,led_d4,led_d5;reg[4:0] s_rst;always @(posedge clk or negedge rst_n)if (!rst_n) s_rst <= 5'b11111;else s_rst <= {s5_n,s4_n,s3_n,s2_n,s1_n};reg[4:0] s_rst_r;always @ ( posedge clk or negedge rst_n )if (!rst_n) s_rst_r <= 5'b11111;else s_rst_r <= s_rst;wire[4:0] s_an = s_rst_r & ( ~s_rst);reg[19:0] cnt; //计数寄存器always @ (posedge clk or negedge rst_n)if (!rst_n) cnt <= 20'd0; //异步复位else if(s_an) cnt <=20'd0;else cnt <= cnt + 1'b1;reg[4:0] low_s;always @(posedge clk or negedge rst_n)if (!rst_n) low_s <= 5'b11111;else if (cnt == 20'h30D40)low_s <= {s5_n,s4_n,s3_n,s2_n,s1_n};reg [4:0] low_s_r;always @ ( posedge clk or negedge rst_n )if (!rst_n) low_s_r <= 5'b11111;else low_s_r <= low_s;wire[4:0] led_ctrl = low_s_r[4:0] & ( ~low_s[4:0]);reg d1,d2,d3,d4,d5;always @ (posedge clk or negedge rst_n)if (!rst_n) begind1 <= 1'b0;d2 <= 1'b0;d3 <= 1'b0;d4 <= 1'b0;d5 <= 1'b0; endelse begin //if ( led_ctrl[0] ) d1 <= ~d1;if ( led_ctrl[1] ) d2 <= ~d2;if ( led_ctrl[2] ) d3 <= ~d3;if ( led_ctrl[3] ) d4 <= ~d4;if ( led_ctrl[4] ) d5 <= ~d5; endassign led_d1 = d1 ? 1'b1 : 1'b0; //LED翻转输出assign led_d2 = d2 ? 1'b1 : 1'b0;assign led_d3 = d3 ? 1'b1 : 1'b0;assign led_d4 = d4 ? 1'b1 : 1'b0;assign led_d5 = d5 ? 1'b1 : 1'b0;endmodule也许初看起来这段代码似乎有点吃力,好多的always好多的wire啊,而我们通常用得最多的判断转移好像不是主流。

4×4矩阵键盘扫描

4×4矩阵键盘扫描

矩阵键盘(Verilog)module matrixKeyboard_drive(input i_clk,input i_rst_n,input [3:0] row, // 矩阵键盘行output reg [3:0] col, // 矩阵键盘列output reg [3:0] keyboard_val // 键盘值);//++++++++++++++++++++++++++++++++++++++// 分频部分开始//++++++++++++++++++++++++++++++++++++++reg [19:0] cnt; // 计数子always @ (posedge i_clk, negedge i_rst_n)if (!i_rst_n)cnt <= 0;elsecnt <= cnt + 1'b1;wire key_clk = cnt[19]; // (2^20/50M = 21)ms //--------------------------------------// 分频部分结束//--------------------------------------//++++++++++++++++++++++++++++++++++++++// 状态机部分开始//++++++++++++++++++++++++++++++++++++++// 状态数较少,独热码编码parameter NO_KEY_PRESSED = 6'b000_001; // 没有按键按下parameter SCAN_COL0 = 6'b000_010; // 扫描第0列parameter SCAN_COL1 = 6'b000_100; // 扫描第1列parameter SCAN_COL2 = 6'b001_000; // 扫描第2列parameter SCAN_COL3 = 6'b010_000; // 扫描第3列parameter KEY_PRESSED = 6'b100_000; // 有按键按下reg [5:0] current_state, next_state; // 现态、次态always @ (posedge key_clk, negedge i_rst_n)if (!i_rst_n)current_state <= NO_KEY_PRESSED;elsecurrent_state <= next_state;// 根据条件转移状态always @ *case (current_state)NO_KEY_PRESSED : // 没有按键按下if (row != 4'hF)next_state = SCAN_COL0;elsenext_state = NO_KEY_PRESSED;SCAN_COL0 : // 扫描第0列if (row != 4'hF)next_state = KEY_PRESSED;elsenext_state = SCAN_COL1;SCAN_COL1 : // 扫描第1列if (row != 4'hF)next_state = KEY_PRESSED;elsenext_state = SCAN_COL2;SCAN_COL2 : // 扫描第2列if (row != 4'hF)next_state = KEY_PRESSED;elsenext_state = SCAN_COL3;SCAN_COL3 : // 扫描第3列if (row != 4'hF)next_state = KEY_PRESSED;elsenext_state = NO_KEY_PRESSED;KEY_PRESSED : // 有按键按下if (row != 4'hF)next_state = KEY_PRESSED;elsenext_state = NO_KEY_PRESSED;endcasereg key_pressed_flag; // 键盘按下标志reg [3:0] col_val, row_val; // 列值、行值// 根据次态,给相应寄存器赋值always @ (posedge key_clk, negedge i_rst_n)if (!i_rst_n)begincol <= 4'h0;key_pressed_flag <= 0;endelsecase (next_state)NO_KEY_PRESSED : // 没有按键按下begincol <= 4'h0;key_pressed_flag <= 0; // 清键盘按下标志endSCAN_COL0 : // 扫描第0列col <= 4'b1110;SCAN_COL1 : // 扫描第1列col <= 4'b1101;SCAN_COL2 : // 扫描第2列col <= 4'b1011;SCAN_COL3 : // 扫描第3列col <= 4'b0111;KEY_PRESSED : // 有按键按下begincol_val <= col; // 锁存列值row_val <= row; // 锁存行值 key_pressed_flag <= 1; // 置键盘按下标志endendcase//--------------------------------------// 状态机部分结束//--------------------------------------//++++++++++++++++++++++++++++++++++++++// 扫描行列值部分开始//++++++++++++++++++++++++++++++++++++++always @ (posedge key_clk, negedge i_rst_n)if (!i_rst_n)keyboard_val <= 4'h0;elseif (key_pressed_flag)case ({col_val, row_val})8'b1110_1110 : keyboard_val <= 4'h0;8'b1110_1101 : keyboard_val <= 4'h4;8'b1110_1011 : keyboard_val <= 4'h8;8'b1110_0111 : keyboard_val <= 4'hC;8'b1101_1110 : keyboard_val <= 4'h1;8'b1101_1101 : keyboard_val <= 4'h5;8'b1101_1011 : keyboard_val <= 4'h9;8'b1101_0111 : keyboard_val <= 4'hD;8'b1011_1110 : keyboard_val <= 4'h2;8'b1011_1101 : keyboard_val <= 4'h6;8'b1011_1011 : keyboard_val <= 4'hA;8'b1011_0111 : keyboard_val <= 4'hE;8'b0111_1110 : keyboard_val <= 4'h3;8'b0111_1101 : keyboard_val <= 4'h7;8'b0111_1011 : keyboard_val <= 4'hB;8'b0111_0111 : keyboard_val <= 4'hF;endcase//--------------------------------------// 扫描行列值部分结束//--------------------------------------endmodule。

FPGA矩阵键盘扫描

FPGA矩阵键盘扫描

------------------------------------------------- --功能:4×4键盘扫描和获得键盘值--接口:clk -时钟输入-- lie -列值输入-- hang-行扫描输出-- qout-键盘值BCD码输出-------------------------------------------------library ieee;use ieee.std_logic_1164.all;use ieee.std_logic_unsigned.all;use ieee.std_logic_arith.all;entity keyboard isport(clk :in std_logic;lie :in std_logic_vector(3 downto 0);hang :out std_logic_vector(3 downto 0);qout :out std_logic_vector(3 downto 0));end keyboard;architecture behave of keyboard issignal cnt:std_logic_vector(1 downto 0);signal hang_tem:std_logic_vector(3 downto 0); signal tem:std_logic_vector(3 downto 0);signal reg:std_logic_vector(3 downto 0);begintem<=lie;process(clk)beginif clk'event and clk='1' thenif cnt="11" thencnt<="00";elsecnt<=cnt+1;end if;case cnt iswhen "00"=>hang_tem<="1101";if tem="1110" thenreg<="0000";elsif tem="1101" thenreg<="0001";elsif tem="1011" thenreg<="0010";elsif tem="0111" then reg<="0011";elsereg<=reg;end if;when "01"=>hang_tem<="1011";if tem="1110" thenreg<="0100";elsif tem="1101" then reg<="0101";elsif tem="1011" then reg<="0110";elsif tem="0111" then reg<="0111";elsereg<=reg;end if;when "10"=>hang_tem<="0111";if tem="1110" thenreg<="1000";elsif tem="1101" then reg<="1001";elsif tem="1011" then reg<="1010";elsif tem="0111" then reg<="1011";elsereg<=reg;end if;when "11"=>hang_tem<="1110";if tem="1110" thenreg<="1100";elsif tem="1101" then reg<="1101";elsif tem="1011" then reg<="1110";elsif tem="0111" then reg<="1111";elsereg<=reg;end if;when others=>hang_tem<="1111"; reg<=reg;end case;end if;hang<=hang_tem; qout<=reg;end process;end behave;。

4X4键盘扫描程序

4X4键盘扫描程序

4X4键盘扫描程序,采用查表方式,适用于AVR单片机。

此处为4X4键盘软件部分,硬件部分设计请参照:4X4键盘扫描电路分析。

此程序对应的键盘电路为:键盘状态扫描函数/*键盘扫描函数读取当前键盘的状态有按键按下返回相应按键值无按键按下返回"0x00"*/unsigned char key_read(void){unsigned char i;DDRA = 0x00;/*获取列地址*/PORTA = 0x0F;DDRA = 0xF0;此处应加入几uS延时;i = PINA;DDRA = 0x00;/*获取行地址*/PORTA = 0xF0;DDRA = 0x0F;此处应加入几uS延时;i |= PINA;DDRA = 0x00;/*输出复位*/PORTA = 0xFF;switch (i) {/*将按键码转换成键值*/ case 0x00: return 0x00;case 0xEE: return '1';case 0xDE: return '2';case 0xBE: return '3';case 0x7E: return 'A';case 0xED: return '4';case 0xDD: return '5';case 0xBD: return '6';case 0x7D: return 'B';case 0xEB: return '7';case 0xDB: return '8';case 0xBB: return '9';case 0x7B: return 'C';case 0xE7: return '*';case 0xD7: return '0';case 0xB7: return '#';case 0x77: return 'D';default : return 0x00;}}键盘读取函数/*按键获取函数获取按键信号,其中包含有状态记录及按键去颤抖。

带FIFO存储的FPGA键盘扫描器设计(仿真+代码)

带FIFO存储的FPGA键盘扫描器设计(仿真+代码)

带FIFO存储的键盘扫描器设计一、模块结构:1、Keypad:顶层模块,负责调用其他模块;2、clock_divider:将50MHZ系统时钟分频,产生clk_slow(500HZ)和clk_display(1KHZ);3、keypad_scaner:扫描键盘,并产生编码值,测试时连续写入键盘值;4、code_fifo:将键盘值存入FIFO;5、rd_toggle:对read信号去抖动;6、decode_display:将键盘编码值映射成数码管编码值,并产生驱动数码管信号;7、row_signal:产生row,用于测试;二、模块仿真结果:1、clock_divider:clk_slow为500HZ;clk_sidplay为1KHZ,数码管的刷新频率1KHZ就可避免数码管闪烁;2、keypad_scaner:黄色信号为{col,row}的组合信号和对应的编码输出code,红色信号valid_o为FIFO的写使能信号;3、code_fifo:写进FIFO的数据;两条红线rd_en与valid分别为FIFO的读使能和写使能,黄色信号线为FIFO的输出,在读使能有效时,读出0001、0010、0011、0100、0101、0110;4、rd_toggle:两条红线分别为rd_up_cnt、rd_lw_cnt,用于消抖时read高低电平的计数,规定大于10ms可认为按键稳定。

黄线为稳定的read输出。

5、decode_display:三条红线分别为两个数码管的驱动信号left_code、right_code以及两个数码管的位选信号cathode。

6、row_signal:7、顶层仿真:当read有效时,读出“00”,“01”,“02”,“03”,“04”;三、综合-布局布线综合布局布线通过;四、模块代码:1、Keypad:`timescale 1ns / 1ps//////////////////////////////////////////////////////////////////////////////////// Company:// Engineer://// Create Date: 21:37:47 05/13/2015// Design Name:// Module Name: keypad// Project Name:// Target Devices:// Tool versions:// Description://// Dependencies://// Revision:// Revision 0.01 - File Created// Additional Comments:////////////////////////////////////////////////////////////////////////////////////module keypad(clk,reset,read,row,col,left_code,right_code,cathode,empty,full);input clk;input reset;input read;input[3:0] row;output[3:0] col;output[6:0] left_code;output[6:0] right_code;output empty;output full;output[1:0] cathode;wire[3:0] code;wire[3:0] code_out;wire[1:0] cathode;keypad_scaner u_keypad_scaner(.clk(clk_slow),.reset(reset),.row(row),.col(col),.code(code),.valid_o(valid));clock_divider u_clock_divider(.clk(clk),.reset(reset),.clk_slow(clk_slow),.clk_display(clk_display));code_fifo u_code_fifo(.clk(clk_slow),.reset(reset),.code(code),.valid(valid),.rd_en(read_fifo),.dout(code_out),.full(full),.empty(empty));rd_toggle u_rd_toggle(.clk(clk),.reset(reset),.read(read),.read_fifo(read_fifo));decode_display u_decode_display(.clk(clk_display),.reset(reset),.code(code_out),.left_code(left_code),.right_code(right_code),.cathode(cathode));endmodule2、keypad_scaner:`timescale 1ns / 1ps//////////////////////////////////////////////////////////////////////////////////// Company:// Engineer://// Create Date: 16:05:31 05/13/2015// Design Name:// Module Name: keypad_scaner// Project Name:// Target Devices:// Tool versions:// Description://// Dependencies://// Revision:// Revision 0.01 - File Created// Additional Comments://////////////////////////////////////////////////////////////////////////////////// module keypad_scaner(clk,reset,row,col,code,valid_o);input clk ;input reset ;input[3:0] row ;output valid_o ;output[3:0] col ;output[3:0] code;reg valid;reg valid_tmp;reg[3:0] row_tmp;reg[3:0] num;reg[3:0] row_tmp1;reg[3:0] row_tmp2;reg[3:0] col ;reg[3:0] code ;reg[1:0] cnt ;wire valid_o;wire[7:0] key_sample;assign key_sample = {col,row};//列扫描信号always @(posedge clk or posedge reset)if(reset)begincnt <= 2'b0;col <= 4'b0000;endelsebegincnt <= cnt + 2'b01;case(cnt)2'b00 : col <= 4'b1000;2'b01 : col <= 4'b0100;2'b10 : col <= 4'b0010;2'b11 : col <= 4'b0001;endcaseendalways @(posedge clk or posedge reset) if(reset)code <= 4'b0000;elsebegincase(key_sample)//第一列扫描8'b1000_0001 : code <= 4'b0000;8'b1000_0010 : code <= 4'b0001;8'b1000_0100 : code <= 4'b0010;8'b1000_1000 : code <= 4'b0011;//第二列扫描8'b0100_0001 : code <= 4'b0100;8'b0100_0010 : code <= 4'b0101;8'b0100_0100 : code <= 4'b0110;8'b0100_1000 : code <= 4'b0111;//第三列扫描8'b0010_0001 : code <= 4'b1000;8'b0010_0010 : code <= 4'b1001;8'b0010_0100 : code <= 4'b1010;8'b0010_1000 : code <= 4'b1011;//第四列扫描8'b0001_0001 : code <= 4'b1100;8'b0001_0010 : code <= 4'b1101;8'b0001_0100 : code <= 4'b1110;8'b0001_1000 : code <= 4'b1111;default:code <= code;endcaseendalways @(posedge clk or posedge reset)if(reset)num <= 4'd0;else if(row == 4'b0000)num <= num + 4'd1;elsenum <= 4'd0;always @(posedge clk or posedge reset)if(reset)row_tmp <= 4'b0000;elserow_tmp <= row;always @(posedge clk or posedge reset)if(reset)valid <= 1'b0;else if(num > 4'd4)valid <= 1'b0;else if(row_tmp)valid <= 1'b1;elsevalid <= valid;always @(posedge clk or posedge reset)if(reset)valid_tmp <= 1'b0;elsevalid_tmp <= valid;assign valid_o = valid & (~valid_tmp);endmodule3、clock_divider`timescale 1ns / 1ps//////////////////////////////////////////////////////////////////////////////////// Company:// Engineer://// Create Date: 09:09:00 05/16/2015// Design Name:// Module Name: clock_divider// Project Name:// Target Devices:// Tool versions:// Description://// Dependencies://// Revision:// Revision 0.01 - File Created// Additional Comments://////////////////////////////////////////////////////////////////////////////////// module clock_divider(clk,reset,clk_slow,clk_display);input clk;input reset;output clk_slow;output clk_display;reg clk_slow;reg clk_display;reg[17:0] divide_cnt1;reg[19:0] divide_cnt2;always @(posedge clk or posedge reset)if(reset)divide_cnt1 <= 18'd0;else if(divide_cnt1 == 17'd100000)divide_cnt1 <= 18'd0;elsedivide_cnt1 <= divide_cnt1 + 18'd1;always @(posedge clk or posedge reset)if(reset)divide_cnt2 <= 20'd0;else if(divide_cnt2 == 20'd50000)divide_cnt2 <= 20'd0;elsedivide_cnt2 <= divide_cnt2 + 20'd1;always @(posedge clk or posedge reset)if(reset)clk_slow <= 1'b0;else if(divide_cnt1 <= 18'd50000)clk_slow <= 1'b1;elseclk_slow <= 1'b0;always @(posedge clk or posedge reset)if(reset)clk_display <= 1'b0;else if(divide_cnt2 <= 20'd25000)clk_display <= 1'b1;elseclk_display <= 1'b0;endmodule4、code_fifo`timescale 1ns / 1ps//////////////////////////////////////////////////////////////////////////////////// Company:// Engineer://// Create Date: 10:47:48 05/14/2015// Design Name:// Module Name: key_fifo// Project Name:// Target Devices:// Tool versions:// Description://// Dependencies://// Revision:// Revision 0.01 - File Created// Additional Comments:////////////////////////////////////////////////////////////////////////////////////module code_fifo(clk,reset,code,valid,rd_en,dout,full,empty);input clk;input reset;input valid;input rd_en;input[3:0] code;output[3:0] dout;output full;output empty;key_fifo u_key_fifo(.clk(clk),.rst(reset),.din(code),.wr_en(valid),.rd_en(rd_en),.dout(dout),.full(full),.empty(empty));Endmodule5、rd_toggle:`timescale 1ns / 1ps//////////////////////////////////////////////////////////////////////////////////// Company:// Engineer://// Create Date: 16:59:34 05/13/2015// Design Name:// Module Name: rd_toggle// Project Name:// Target Devices:// Tool versions:// Description://// Dependencies://// Revision:// Revision 0.01 - File Created// Additional Comments://////////////////////////////////////////////////////////////////////////////////// module rd_toggle(clk,reset,read,read_fifo);input clk;input reset;input read;output read_fifo;reg read_fifo;reg[23:0] rd_up_cnt; //按键输入高电平计数器reg[23:0] rd_lw_cnt; //按键输入低电平计数器//对输入进行采样、计数always @(posedge clk or posedge reset)if(reset)rd_up_cnt <= 24'd0;else if(read)rd_up_cnt <= rd_up_cnt + 24'd1;elserd_up_cnt <= 24'd0;always @(posedge clk or posedge reset)if(reset)rd_lw_cnt <= 24'd0;else if(!read)rd_lw_cnt <= rd_lw_cnt + 24'd1;elserd_lw_cnt <= 24'd0;always @(posedge clk or posedge reset)if(reset)read_fifo <= 1'b0;else if(rd_up_cnt == 24'h7A120) //大于10ms认为按键稳定read_fifo <= 1'b1;else if(rd_lw_cnt == 24'h7A120)read_fifo <= 1'b0;elseread_fifo <= read_fifo;endmodule6、decode_display:`timescale 1ns / 1ps//////////////////////////////////////////////////////////////////////////////////// Company:// Engineer://// Create Date: 17:19:56 05/13/2015// Design Name:// Module Name: decode_display// Project Name:// Target Devices:// Tool versions:// Description://// Dependencies://// Revision:// Revision 0.01 - File Created// Additional Comments:////////////////////////////////////////////////////////////////////////////////////module decode_display(clk,code,reset,left_code,right_code,cathode);input clk;input reset;input[3:0] code;output[6:0] left_code;output[6:0] right_code;output[1:0] cathode;reg[6:0] left_code;reg[6:0] right_code;reg[15:0] cnt; //动态扫描计数器reg[1:0] cathode; //片选信号;//七段数码管段选(共阳极)parameter ZERO = 7'b100_0000; parameter ONE = 7'b111_1001; parameter TWO = 7'b010_0100; parameter THREE = 7'b011_0000; parameter FOUR = 7'b001_1001; parameter FIVE = 7'b001_0010; parameter SIX = 7'b000_0010; parameter SEVEN = 7'b111_1000; parameter EIGHT = 7'b000_0000; parameter NINE = 7'b001_0000;always @(posedge clk or posedge reset)if(reset)cathode <= 2'b00;elsecase(cathode)2'b00 : cathode <= 2'b01;2'b01 : cathode <= 2'b10;2'b10 : cathode <= 2'b01;endcasealways @(code)case(code)4'b0000 : beginright_code <= ZERO;left_code <= ZERO;end4'b0001 : right_code <= ONE;4'b0010 : right_code <= TWO;4'b0011 : right_code <= THREE;4'b0100 : right_code <= FOUR;4'b0101 : right_code <= FIVE;4'b0110 : right_code <= SIX;4'b0111 : right_code <= SEVEN;4'b1000 : right_code <= EIGHT;4'b1001 : right_code <= NINE;4'b1010 : beginright_code <= ZERO;left_code <= ONE;end4'b1011 : beginright_code <= ONE;left_code <= ONE;end4'b1100 : beginleft_code <= ONE;right_code <= TWO;end4'b1101 : beginleft_code <= ONE;right_code <= THREE;end4'b1110 : beginleft_code <= ONE;right_code <= FOUR;end4'b1111 : beginleft_code <= ONE;right_code <= FIVE;enddefault : beginleft_code <= ZERO;right_code <= ZERO;endendcaseendmodule7、row_signal:`timescale 1ns / 1ps//////////////////////////////////////////////////////////////////////////////////// Company:// Engineer://// Create Date: 20:00:46 05/14/2015// Design Name:// Module Name: row_signal// Project Name:// Target Devices:// Tool versions:// Description://// Dependencies://// Revision:// Revision 0.01 - File Created// Additional Comments:////////////////////////////////////////////////////////////////////////////////////module row_signal(row,key,col);input[15:0] key;input[3:0] col;output[3:0] row;reg[3:0] row;always @(posedge key or col)beginrow[0] = key[0]&&col[3] || key[4]&&col[2] || key[8]&&col[1] || key[12]&&col[0];row[1] = key[1]&&col[3] || key[5]&&col[2] || key[9]&&col[1] || key[13]&&col[0];row[2] = key[2]&&col[3] || key[6]&&col[2] || key[10]&&col[1] || key[14]&&col[0];row[3] = key[3]&&col[3] || key[7]&&col[2] || key[11]&&col[1] || key[15]&&col[0];endendmodule8、keypad_tst:`timescale 1ns / 1ps////////////////////////////////////////////////////////////////////////////////// Company:// Engineer://// Create Date: 19:16:02 05/14/2015// Design Name: keypad// Module Name: D:/FPGAProject/Xilinx/keypad_design/keypad_tst.v // Project Name: keypad_design// Target Device:// Tool versions:// Description://// Verilog Test Fixture created by ISE for module: keypad//// Dependencies://// Revision:// Revision 0.01 - File Created// Additional Comments://////////////////////////////////////////////////////////////////////////////////module keypad_tst;// Inputsreg clk;reg reset;reg read;wire[3:0] row;reg[39:0] pressed;reg[15:0] key_s;// Outputswire[3:0] col;wire[6:0] left_code;wire[6:0] right_code;wire empty;wire full;wire[1:0] cathode;wire[15:0] key;integer j;integer k;// Instantiate the Unit Under Test (UUT)keypad uut (.clk(clk),.reset(reset),.read(read),.row(row),.col(col),.left_code(left_code),.right_code(right_code),.cathode(cathode),.empty(empty),.full(full));parameter[39:0] key_0 = "key_0"; parameter[39:0] key_1 = "key_1"; parameter[39:0] key_2 = "key_2"; parameter[39:0] key_3 = "key_3"; parameter[39:0] key_4 = "key_4"; parameter[39:0] key_5 = "key_5"; parameter[39:0] key_6 = "key_6"; parameter[39:0] key_7 = "key_7"; parameter[39:0] key_8 = "key_8"; parameter[39:0] key_9 = "key_9"; parameter[39:0] key_A = "key_A"; parameter[39:0] key_B = "key_B"; parameter[39:0] key_C = "key_C"; parameter[39:0] key_D = "key_D"; parameter[39:0] key_E = "key_E"; parameter[39:0] key_F = "key_F"; parameter[39:0] none = "none";row_signal u_row_signal(.row(row),.key(key),.col(col));initialbeginclk = 0;reset = 1;read = 0;//row = 0;#20 reset = 0;endalways @(key)case(key)16'h0000 : pressed = none;16'h0001 : pressed = key_0;16'h0002 : pressed = key_1;16'h0004 : pressed = key_2;16'h0008 : pressed = key_3;16'h0010 : pressed = key_4;16'h0020 : pressed = key_5;16'h0040 : pressed = key_6;16'h0080 : pressed = key_7;16'h0100 : pressed = key_8;16'h0200 : pressed = key_9;16'h0400 : pressed = key_A;16'h0800 : pressed = key_B;16'h1000 : pressed = key_C;16'h2000 : pressed = key_D;16'h4000 : pressed = key_E;16'h8000 : pressed = key_F;default : pressed = none;endcasealways #10 clk = ~clk;initialbeginfor(k=0; k<=1; k=k+1)beginkey_s=0;#50 for(j=0; j<=16; j=j+1)begin#40000000 key_s[j] = 1;#50000000 key_s = 0; //50msendendendassign key = key_s;initialbegin#400000000 read = 1;#200000000 read = 0; // 60ms#400000000 read = 1;// #200000000 read = 0;// #100000000 read = 1; // #200000000 read = 0; // #100000000 read = 1; // #700000000 read = 0; endendmodule。

【CPLD EPM570】Verilog实现按键检测

【CPLD EPM570】Verilog实现按键检测

Verilog实现按键检测1 原理图共5个按键,其中一个作为Reset按键(设计未加电容,可以考虑优化),每个按键采用一个IO检测,低电平表示有按键按下。

2 CPLD代码module key (clk_24m,reset_n,ledline, //调测用LED点灯信号。

Key_line //按键输入信号。

);input wire clk_24m;input wire reset_n;output wire [7:0] ledline;input wire [3:0] Key_line; //4个按键,每个按键一位IO。

/****************************************************************************** 按键检测信号是输入信号,内部加延迟去抖动,检测8个24M时钟周期,当检测到8个时钟周期都为低时,才确认按键按下。

******************************************************************************/ reg [7:0] Key_data_reg_delay[3:0];always @ (posedge clk_24m or negedge reset_n)beginif(reset_n == 1'b0)beginKey_data_reg_delay[0] <= 8'hff;Key_data_reg_delay[1] <= 8'hff;Key_data_reg_delay[2] <= 8'hff;Key_data_reg_delay[3] <= 8'hff;endelsebeginKey_data_reg_delay[0] <= { Key_data_reg_delay[0][6:0],Key_line[0] }; //通过移位时序去抖。

verilog_矩阵键盘

verilog_矩阵键盘

资料范本本资料为word版本,可以直接编辑和打印,感谢您的下载verilog_矩阵键盘地点:__________________时间:__________________说明:本资料适用于约定双方经过谈判,协商而共同承认,共同遵守的责任与义务,仅供参考,文档可直接下载或修改,不需要的部分可直接删除,使用时请详细阅读内容二、矩阵键盘显示电路设计(显示键盘值的平方)矩阵键盘显示电路的设计一、实验目的1、了解普通4×4 键盘扫描的原理。

2、进一步加深七段码管显示过程的理解。

3、了解对输入/输出端口的定义方法。

二、实验原理实现键盘有两种方案:一是采用现有的一些芯片实现键盘扫描;再就是用软件实现键盘扫描。

作为一个嵌入系统设计人员,总是会关心产品成本。

目前有很多芯片可以用来实现键盘扫描,但是键盘扫描的软件实现方法有助于缩减一个系统的重复开发成本,且只需要很少的 CPU 开销。

嵌入式控制器的功能能强,可能充分利用这一资源,这里就介绍一下软键盘的实现方案。

图 10-1 简单键盘电路通常在一个键盘中使用了一个瞬时接触开关,并且用如图 10-1 所示的简单电路,微处理器可以容易地检测到闭合。

当开关打开时,通过处理器的 I/O 口的一个上拉电阻提供逻辑 1;当开关闭合时,处理器的/IO口的输入将被拉低得到逻辑 0。

可遗憾的是,开关并不完善,因为当它们被按下或者被释放时,并不能够产生一个明确的 1或者 0。

尽管触点可能看起来稳定而且很快地闭合,但与微处理器快速的运行速度相比,这种动作是比较慢的。

当触点闭合时,其弹起就像一个球。

弹起效果将产生如图 10-2所示的好几个脉冲。

弹起的持续时间通常将维持在 5ms∼30ms 之间。

如果需要多个键,则可以将每个开关连接到微处理器上它自己的输入端口。

然而,当开关的数目增加时,这种方法将很快使用完所有的输入端口。

图 10-2 按键抖动键盘上阵列这些开关最有效的方法(当需要5个以上的键时)就形成了一个如图 10-3 所示的二维矩阵。

单片机典型矩阵键盘扫描程序

单片机典型矩阵键盘扫描程序

单片机典型矩阵键盘扫描程序#include "Key.h"static uchar GetKeyStatus();////$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$bit KeyProcess() // 为程序方便而设的返回值{uchar i,j;void (*pFunction)(); // 定义函数指针void (*code Tab[mHorizontalNumber][mVerticalNumber])()= // 定义函数表{ { ZeroKey, OneKey, FourKey, SevenKey },{ DotKey, TwoKey, FiveKey, EightKey },{ NegativeKey, ThreeKey, SixKey, NineKey },{ EnterOrShiftKey, CancelKey, OptionKey, PauseKey }}; // 二维数组,对对应16个按键NOP(); NOP();if(!bScanKey)return 0; // 扫描时间未到,返回(时间值在定时器中设定)bScanKey=0;NOP(); NOP();j=GetKeyStatus(); // 取键值,0xff为无效键,即无按键NOP(); NOP();if(bKeyDown||bKeyPress||bKeyUp){i=j>>4; j=j&0x0f; // 高半字节为行,低半字节为列if((i<mHorizontalNumber)&&(j<mVerticalNumber)){pFunction=Tab[j]; // 指向函数入口地址(*pFunction)(); // 调用函数}}}//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ // 判断按键状态:KeyFree,KeyDown,KeyPress,KeyUp,并返回键值//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ static uchar ucKey1,ucKey2,ucKeyBak;static uchar GetKeyCode();static uchar GetKeyStatus(){uchar c;NOP(); NOP();mHorizontalAllLow; // 行输入全为0mJugeVertical(c); // 判断是否有按键NOP(); NOP();if((ucKey1==0xff)&&(ucKey2==0xff)&&(c==0xff)){ // 三个值均为0xff,无按键bKeyDown=bKeyPress=bKeyUp=0;bKeyFree=TRUE; return 0xff; // 没按键}else{bKeyFree=0;if(c!=0xff)c=GetKeyCode(); // 扫描键值if((ucKey1==0xff)&&(ucKey2==c)){ucKey1=ucKey2; ucKey2=c;bKeyDown=TRUE; return c; // 键被按下}if((ucKey1==ucKey2)&&(ucKey2==c)){NOP();if(bKeyDown){bKeyPress=TRUE; // 键被按住bKeyDown=0;}return c;}if((ucKey1!=0xff)&&(ucKey2==0xff)&&(c==0xff)){ucKeyBak=ucKey1; ucKey1=ucKey2; ucKey2=c;if(bKeyPress){bKeyUp=TRUE; // 键弹起bKeyPress=0;}return ucKeyBak;}ucKey1=ucKey2; ucKey2=c;}return 0xff;}//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$// 本程序读按键的行列号值,将行列号组合成一个字节后返回, //// 若读键错误,或没按键均返回0xff。

经典的矩阵键盘扫描程序8

经典的矩阵键盘扫描程序8

键盘是单片机常用输入设备,在按键数量较多时,为了节省I/O口等单片机资源,一般采取扫描的方式来识别到底是哪一个键被按下。

即通过确定被按下的键处在哪一行哪一列来确定该键的位置,获取键值以启动相应的功能程序。

/***************************************************File Name :LED Debug*Autor :HR*Version :V1.0*Data :*Descrption :none*********************************************************************************************************/#include "include.h"JOB Job_Data; ----------1SYS_TimeHandler SYS_Time; ---------2MSG Msg_Key; /* 按键任务使用的结构体消息*/ ---------3uint16 test_a; ---------4 uint16 TX_Buff_Byte[25]; ---------4uint8 TX_Buff_ASIC[25]; ---------4/************************************************主程序************************************************/int main(){BSP_Init(); ---------5SYSTEM_LogShow (); ---------6for(;;) {SYS_100US_handler(); ---------7SYS_10MS_handler(); ---------8SYS_100MS_handler(); ---------9SYS_200MS_handler(); ---------10 }}8,SYS_10MS_handler();void SYS_10MS_handl er(void){if (SYS_Time.TimHandl er_10mS == SET){SYS_Time.TimHandl er_10mS = RESET;if (Job_Data.Fg_ShowLog == DISABLE){COMMOND_Ord erChang(Job_Data.WeldWorkSetMod e, Job_Data.MainMenu);USART_SendCod e();}}}4*4矩阵键盘的结构如图1(实物参考见万用板矩阵键盘制作技巧)。

FPGA实验四键盘扫描显示电路

FPGA实验四键盘扫描显示电路

实验四矩形键盘扫描显示电路设计一、实验目的:1、熟悉Verilog语言编写的键盘扫描显示电路。

2、在Libero软件中,并对其电路进行仿真。

二、实验原理:键盘扫描显示电路的Verilog HDL程序主要由3个always模块构成:第一个为模4计数器模块;第二个为完成对键盘进行扫描和编程的功能,在计数器的每个状态从FPGA内部送出一列扫描数据给键盘,然后读入经过去抖处理的4行数据,并根据行,列数据之间的关系,对按键进行编码,确定按下的是哪个键;第三个模块完成键值的显示,即显示按键的编号。

下面是个键盘扫描的程序,大家仿真分析下。

module scankey(outled,scansig,dsw,clk,keyvaule);input clk;//键盘扫描时钟信号input [3:0]dsw;//去抖后的按键信号output [3:0]scansig;//输出扫描信号给键盘output [7:0]keyvaule;output [7:0]outled; //输出七段码给共阴极数码管reg [3:0]scansig;reg [7:0]keyvaule;reg [7:0]outled;reg [1:0] q;always @(posedge clk)beginq<=q+1’b1;endalways @(q or dsw)case(q)2’b00: beginscansig=4’b0111;case (dsw)4'b0111: keyvaule=8'b0111_0111; //key04'b1011: keyvaule=8'b0111_1011; //44'b1101: keyvaule=8'b0111_1101; //84'b1110: keyvaule=8'b0111_1110; //cdefault : keyvaule=8'b1111_1111;endcaseend2’b01: beginscansig=4’b1011;case (dsw)4'b0111: keyvaule=8'b1011_0111; //key14'b1011: keyvaule=8'b1011_1011; //54'b1101: keyvaule=8'b1011_1101; //94'b1110: keyvaule=8'b1011_1110; //ddefault : keyvaule=8'b1111_1111;endcaseend2’b10: beginscansig=4’b1101;case (dsw)4'b0111: keyvaule=8'b1101_0111; //key24'b1011: keyvaule=8'b1101_1011; //64'b1101: keyvaule=8'b1101_1101; //a4'b1110: keyvaule=8'b1101_1110; //edefault : keyvaule=8'b1111_1111;endcaseend2’b11: beginscansig=4’b1110;case (dsw)4'b0111: keyvaule=8'b1110_0111; //key34'b1011: keyvaule=8'b1110_1011; //74'b1101: keyvaule=8'b1110_1101; //b4'b1110: keyvaule=8'b1110_1110; //fdefault : keyvaule=8'b1111_1111;endcaseendendcasealways@(keyvaule)case(keyvaule)8'b0111_0111: outled=8’h3f;8'b0111_1011: outled=8’h66;8'b0111_1101: outled=8’h7f;8'b0111_1110: outled=8’h39;8'b1011_0111: outled=8’h06;8'b1011_1011: outled=8’h6d;8'b1011_1101: outled=8’h6f;8'b1011_1110: outled=8’h5e;8'b1101_0111: outled=8’h5b;8'b1101_1011: outled=8’h7d;8'b1101_1101: outled=8’h77;8'b1101_1110: outled=8’h79;8'b1110_0111: outled=8’h4f;8'b1110_1011: outled=8’h07;8'b1110_1101: outled=8’h7c;8'b1110_1110: outled=8’h71;default: outled=8’h00;endcaseendmodule三、实验步骤:1、先分析Verilog语言编写键盘扫描显示电路。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

经典的verilog键盘扫描程序作者:ilove314拿到威百仕( VibesIC )的板子后就迫不及待的开始我的学习计划,从最基础的分频程序开始,但看到这个键盘扫描程序后,直呼经典,有相见恨晚的感觉,还想说一句:威百仕( VibesIC ),我很看好你!WHY?待我慢慢道来,这个程序的综合后是0error,0warning。

想想自己编码的时候那个warning是满天飞,现在才明白HDL设计有那么讲究了,代码所设计的不仅仅是简单的逻辑以及时序的关系,更重要的是你要在代码中要表现出每一个寄存器,甚至每一个走线。

想想我写过的代码,只注意到了前者,从没有注意过后者,还洋洋自得以为自己也算是个高手了,现在想来,实在惭愧啊!学习学习在学习,这也重新激发了我对HDL设计的激情,威百仕给了我一个方向,那我可要开始努力喽!废话说了一大堆,看程序吧:(本代码经过ise7.1i综合并下载到SP306板上验证通过)//当三个独立按键的某一个被按下后,相应的LED被点亮;再次按下后,LED熄灭,按键控制LED亮灭module key_debounce(clk,rst_n,s1_n,s2_n,s3_n,s4_n,s5_n,led_d1,led_d2,led_d3,led_d 4,led_d5);input clk; //主时钟信号,10MHzinput rst_n; //复位信号,低有效input s1_n,s2_n,s3_n,s4_n,s5_n;output led_d1,led_d2,led_d3,led_d4,led_d5;reg[4:0] s_rst;always @(posedge clk or negedge rst_n)if (!rst_n) s_rst <= 5'b11111;else s_rst <= {s5_n,s4_n,s3_n,s2_n,s1_n};reg[4:0] s_rst_r;always @ ( posedge clk or negedge rst_n )if (!rst_n) s_rst_r <= 5'b11111;else s_rst_r <= s_rst;wire[4:0] s_an = s_rst_r & ( ~s_rst);reg[19:0] cnt; //计数寄存器always @ (posedge clk or negedge rst_n)if (!rst_n) cnt <= 20'd0; //异步复位else if(s_an) cnt <=20'd0;else cnt <= cnt + 1'b1;reg[4:0] low_s;always @(posedge clk or negedge rst_n)if (!rst_n) low_s <= 5'b11111;else if (cnt == 20'h30D40)low_s <= {s5_n,s4_n,s3_n,s2_n,s1_n};reg [4:0] low_s_r;always @ ( posedge clk or negedge rst_n )if (!rst_n) low_s_r <= 5'b11111;else low_s_r <= low_s;wire[4:0] led_ctrl = low_s_r[4:0] & ( ~low_s[4:0]);reg d1,d2,d3,d4,d5;always @ (posedge clk or negedge rst_n)if (!rst_n) begind1 <= 1'b0;d2 <= 1'b0;d3 <= 1'b0;d4 <= 1'b0;d5 <= 1'b0; endelse begin //if ( led_ctrl[0] ) d1 <= ~d1;if ( led_ctrl[1] ) d2 <= ~d2;if ( led_ctrl[2] ) d3 <= ~d3;if ( led_ctrl[3] ) d4 <= ~d4;if ( led_ctrl[4] ) d5 <= ~d5; endassign led_d1 = d1 ? 1'b1 : 1'b0; //LED翻转输出assign led_d2 = d2 ? 1'b1 : 1'b0;assign led_d3 = d3 ? 1'b1 : 1'b0;assign led_d4 = d4 ? 1'b1 : 1'b0;assign led_d5 = d5 ? 1'b1 : 1'b0;endmodule也许初看起来这段代码似乎有点吃力,好多的always好多的wire啊,而我们通常用得最多的判断转移好像不是主流。

的确是这样,一个好的verilog代码,用多个always语句来分摊一个大的always来执行,会使得综合起来更快,这也是接前两篇日志说到代码优化的一个值得学习的方面。

其次是wire连线很多,你要是仔细研究代码,不难发现所有的锁存器的连线关系编程者都考虑到了,这样就不会平白无故的生成意想不到的寄存器了,这也是一个优秀代码的必备要素。

上面说的是代码风格,下面就看程序的编程思想吧。

前两个always语句里其实是做了一个20ms的计数,每隔20ms 就会读取键值,把这个键值放到寄存器low_sw中,接下来的一个always语句就是把low_sw的值锁存到low_sw_r里,这样以来,low_sw和low_sw_r就是前后两个时钟周期里的键值了,为什么要这样呢?看下一个语句吧:wire [2:0] led_ctrl = low_sw_r[2:0] & ( ~low_sw[2:0]);仔细分析,你会发现当没有键按下时,low_sw=low_sw_r=3’b111,此时的led_ctrl=3’b000;只有当low_sw和low_sw_r的某一位分别为0和1时,才可能使led_ctrl的值改变(也就是把led_ctrl的某一位拉高)。

那么这意味着当键值由1跳变到0时才可能把led_ctrl拉高。

回顾前面的20ms赋键值,也就是说每20ms内如果出现按键被按下,那么有一个时钟周期里led_ctrl是会被拉高的,而再看后面的程序,led_ctrl的置高就使得相应的LED灯的亮灭做一次改变,这就达到了目的。

verilog 键盘扫描程序之debug 作者:ilove314: EDN China上次的日志《经典的verilog 键盘扫描程序》承蒙厚爱,已成博客精华,在EDN 博客主页置顶多日。

但是我发现那个经典程序还是存在一点点小bug ,且听我慢慢道来。

先放上仿真波形来说明一下问题吧:仿真说明:由于20ms 检测一次按键值对于仿真来说太长了,所以只假定16个主时钟周期就做一次检测(也就是cnt[3]的下降沿锁存键值)。

图1,sw1_n 被按下(拉底)大约5个时钟周期(<16),而此时与其相应的led_d5却改变状态了。

说明的问题是,大多数时候按键消抖其实是到不了20ms 的。

其实这个小bug 通常在下载后,测试键盘是不会有什么感觉的。

但是问题是,如果真的出现那种抖动在20ms 以内(甚至远小于20ms )的外部干扰存在时,这个bug 就不可忽视了。

因此,在原程序的基础上,做了如下的改进。

其思想是在每个主时钟(50MHz )周期里都进行一次按键检测,如果前后两次键值改变了,说明有可能键盘被按下了,此时,在下一个时钟周期将复位20ms 计数值,然后20ms 后重新锁存键值,其它的和原程序基本相同,这样就达到了真正意义上的20ms 消抖。

重新修改代码后的仿真波形如下:点击看原图图2,可以看到此时在不满16个时钟周期的键值变化是不会然led 做出变化的。

图3,按键sw3_n 的按下时间明显超过了16个时钟周期,那么在cnt 重新记到16个时钟周期后,led_d4就做出了改变。

重新修改后的代码如下://当三个独立按键的某一个被按下后,相应的LED 被点亮;再次按下后,LED 熄灭,按键控制LED 亮灭key_led.vmodule key_led(input CLOCK_50,input Q_KEY,input [4:1] KEY,output reg [4:1] LED);//++++++++++++++++++++++++++++++++++++++// 获取键值开始//++++++++++++++++++++++++++++++++++++++wire [4:1] key_val; // 键值key_debounce u0(.i_clk (CLOCK_50),.i_rst_n (Q_KEY),.i_key (KEY),.o_key_val (key_val) // 按下为0,松开为1 );//--------------------------------------// 获取键值结束//--------------------------------------//++++++++++++++++++++++++++++++++++++++// 按下键后开关LED 开始//++++++++++++++++++++++++++++++++++++++always @ (posedge CLOCK_50, negedge Q_KEY)if (!Q_KEY)LED <= 4'hF; // 0灭1亮elsecase (1'b0)key_val[1] : LED[1] <= ~LED[1];key_val[2] : LED[2] <= ~LED[2];key_val[3] : LED[3] <= ~LED[3];key_val[4] : LED[4] <= ~LED[4];default : LED <= LED ; // 缺省亮灭情况不变 endcase//--------------------------------------// 按下键后开关LED 结束//--------------------------------------endmodulekey_debounce.vmodule key_debounce(input i_clk,input i_rst_n,input [4:1] i_key, // 按下为0,松开为1 output reg [4:1] o_key_val // 键值);//++++++++++++++++++++++++++++++++++++++reg [4:1] key_samp1, key_samp1_locked;// 将i_key采集至key_samp1always @ (posedge i_clk, negedge i_rst_n)if(!i_rst_n)key_samp1 <= 4'hF;elsekey_samp1 <= i_key;// 将key_samp1锁存至key_samp1_lockedalways @ (posedge i_clk, negedge i_rst_n)if(!i_rst_n)key_samp1_locked <= 4'hF;elsekey_samp1_locked <= key_samp1;//++++++++++++++++++++++++++++++++++++++wire [4:1] key_changed1;// 当key_samp1由1变为0时// key_changed1由0变为1,只维持一个时钟周期assign key_changed1 = key_samp1_locked & (~key_samp1); //++++++++++++++++++++++++++++++++++++++reg [19:0] cnt;// 一旦有按键按下,cnt立即被清零always @ (posedge i_clk, negedge i_rst_n)if(!i_rst_n)cnt <= 20'h0;else if(key_changed1)cnt <= 20'h0;elsecnt <= cnt + 1'b1;//++++++++++++++++++++++++++++++++++++++reg [4:1] key_samp2, key_samp2_locked;// 只有当按键不变化(不抖动),且维持20ms以上时// 才将i_key采集至key_samp2always @ (posedge i_clk, negedge i_rst_n)if(!i_rst_n)key_samp2 <= 4'hF;else if(cnt == 20'hF_FFFF) // 0xFFFFF/50M = 20.9715ms key_samp2 <= i_key;// 将key_samp2锁存至key_samp2_lockedalways @ (posedge i_clk, negedge i_rst_n)if(!i_rst_n)key_samp2_locked <= 4'hF;elsekey_samp2_locked <= key_samp2; //++++++++++++++++++++++++++++++++++++++wire [4:1] key_changed2;// 当key_samp2由1变为0时// key_changed2由0变为1,只维持一个时钟周期assign key_changed2 = key_samp2_locked & (~key_samp2); //++++++++++++++++++++++++++++++++++++++// 每次按键稳定后,输出键值// 按下为0,松开为1always @ (posedge i_clk, negedge i_rst_n)if(!i_rst_n)o_key_val <= 4'hF;elseo_key_val <= ~key_changed2;//--------------------------------------endmodule。

相关文档
最新文档