以下内容均以Xilinx的Nexys3作为开发板
 
1.PS/2键盘简介

虽然Nexys3开发板是利用USB接口搭载键盘,但是其原理与PS/2键盘完全相同,现在就仅以PS/2键盘为例讲解如何将键盘搭载在开发板上。代码程序均在Nexys3上经过测试。

PS/2标准键盘使用6个接口,各个接口定义如下:

 
1:DATA,数据信号
2:N.C.,不连接
3:GND,地
4:VCC,+5V电源
5:CLK,时钟
6:N.C.,不连接

而对于USB键盘,有用的接口只有两个CLK以及DATA,同时需要+5V供电。这点很重要,但是FPGA的CMOS最大供电是3.3V,如何解决这个问题笔者也是花费了一番周折,文章末会提到。

PS/2标准的数据帧格式与串口通讯很相似,USB就是串口通讯的格式。起始为低电平,停止位为高电平。如果数据位中1的个数是偶数,校验位就为1;如果数据位中1的个数是奇数,校验位就为0,通常自己使用我们都不管校验位。其实就是奇校验。

                  图1 数据帧格式
 
2.键盘扫描码
 

当PC通过PS/2接口与从设备通信时,总是利用下降沿读取数据。键盘仅仅在数据线和时钟线都为高电平(即空闲态)时可以把数据传送给主机,一旦主机使用了总线,键盘在驱动总线前必须检查主机当前是否仍在发送数据。为了促进这一核查,时钟线将暂时作为发送完成信号。一旦主机把时钟线拉低,那么键盘将使时钟线变成高电平才可以传输数据。

PS/2型键盘主要使用扫描码来进行数据传输。每个按键被按下时都会被分配固定的扫描码,如果按键一直被按下,那么该按键码值将每隔100ms重复发送一次。当按键释放后,一个关键码F0发送后,该扫描码才会被发送。当使用上档键进行组合键时,也会产生上档键的码值,并且由主机决定到底是哪一个ASCII值。当组合键被释放后,一个E0和F0关键码发送后,按键扫描码才被发送。。大多数按键的扫描码如下图所示。

                    图2 键盘扫描码
 

主机也会向键盘发送数据。下面是主机可能发送的常用命令的清单。

ED  使NumLock,CapsLock和ScrollLock LED灯发光。在接收到ED后键盘反馈FA码,然后主机发送一个用来设置LED显示状态的字节:第0位控制ScrollLock置位,第1位控制NumLock置位,第2位控制CapsLock置位;

EE  用来进行键盘测试,当键盘接受EE后将反馈EE;

F3  设置扫描码重复频率,当键盘接受FA反馈F3后,主机将发送第二个字符用来设置重复频率。

FE  重新发送。FE将使键盘重新发送最近的扫描码。

FF  重置。重置键盘。

3.源程序简介

PS/2键盘模块接口定义:

 
首先,还是利用移位寄存器的方式捕捉PS/2键盘时钟线的下降沿。
reg ps2_clk_r0,ps2_clk_r1,ps2_clk_r2;
wire neg_ps2_clk; always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
ps2_clk_r0 <= 'b0;
ps2_clk_r1 <= 'b0;
ps2_clk_r2 <= 'b0;
end
else begin
ps2_clk_r0 <= ps2_clk;
ps2_clk_r1 <= ps2_clk_r0;
ps2_clk_r2 <= ps2_clk_r1;
end
end // end always assign neg_ps2_clk = ps2_clk_r2 & (~ps2_clk_r1);

neg_ps2_clk即为PS/2时钟信号下降沿的有效信号。然后,利用一个寄存器和计数器,存储8位有效数据帧。

//------------------------------------------------------
// 接受来自PS/2键盘的数据存储器
reg [:] ps2_byte_r; // 来自PS/2的数据寄存器
reg [:] temp_data; // 当前接受数据寄存器
reg [:] num; always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
num <= 'd0;
temp_data <= 'd0;
end
else if (neg_ps2_clk) begin
case (num)
'd0: begin
num <= num + 'b1;
end
'd1: begin
num <= num + 'b1;
temp_data[] <= ps2_data;
end
'd2: begin
num <= num + 'b1;
temp_data[] <= ps2_data;
end
'd3: begin
num <= num + 'b1;
temp_data[] <= ps2_data;
end
'd4: begin
num <= num + 'b1;
temp_data[] <= ps2_data;
end
'd5: begin
num <= num + 'b1;
temp_data[] <= ps2_data;
end
'd6: begin
num <= num + 'b1;
temp_data[] <= ps2_data;
end
'd7: begin
num <= num + 'b1;
temp_data[] <= ps2_data;
end
'd8: begin
num <= num + 'b1;
temp_data[] <= ps2_data;
end
'd9: begin
num <= num + 'b1;
end
'd10: begin
num <= 'b0;
end
default: num <= 'd0;
endcase
end
end // end always

通过当前按键状态,判断通码还是断码,并保存在ps2_byte_r的8位寄存器内。

//-------------------------------------
reg key_f0; // 松键标志位
reg ps2_state_r; // 当前状态,高电平表示有键按下 always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
key_f0 <= 'b0;
ps2_state_r <= 'b0;
ps2_byte_r <= 'd0;
end
else if (num == 'd10) begin // 刚传输一个字节
if (temp_data == 'hf0) begin // 断码的第一个字节
key_f0 <= 'b1;
end
else begin
if (key_f0) begin // 存储通码
ps2_state_r <= 'b1;
ps2_byte_r <= temp_data;
key_f0 <= 'b0;
end
else begin
ps2_state_r <= 'b0;
key_f0 <= 'b0;
end
end
end
else ps2_state_r <= 'b0;
end // end always

利用case判断不同的通码,来决定字符的ASCII。

//---------------------------------------
reg [:] ps2_ascii; //接受相应的asciiI always @(posedge clk) begin
case (ps2_byte_r)
'h15: ps2_ascii = 8'h51; //Q
'h1d: ps2_ascii = 8'h57; //W
'h24: ps2_ascii = 8'h45; //E
'h2d: ps2_ascii = 8'h52; //R
'h2c: ps2_ascii = 8'h54; //T
'h35: ps2_ascii = 8'h59; //Y
'h3c: ps2_ascii = 8'h55; //U
'h43: ps2_ascii = 8'h49; //I
'h44: ps2_ascii = 8'h4f; //O
'h4d: ps2_ascii = 8'h50; //P
'h1c: ps2_ascii = 8'h41; //A
'h1b: ps2_ascii = 8'h53; //S
'h23: ps2_ascii = 8'h44; //D
'h2b: ps2_ascii = 8'h46; //F
'h34: ps2_ascii = 8'h47; //G
'h33: ps2_ascii = 8'h48; //H
'h3b: ps2_ascii = 8'h4a; //J
'h42: ps2_ascii = 8'h4b; //K
'h4b: ps2_ascii = 8'h4c; //L
'h1a: ps2_ascii = 8'h5a; //Z
'h22: ps2_ascii = 8'h58; //X
'h21: ps2_ascii = 8'h43; //C
'h2a: ps2_ascii = 8'h56; //V
'h32: ps2_ascii = 8'h42; //B
'h31: ps2_ascii = 8'h4e; //N
'h3a: ps2_ascii = 8'h4d; //M
default ps2_ascii = 'hfe;
endcase
end assign ps2_byte = ps2_ascii;
assign ps2_state = ps2_state_r;

以上就是程序代码的主要部分。最重要的还是管脚分配文件如何解决FPGA供电不足的问题。其实也很简单,只是我们平时不常用罢了。而且这也是官方标准ucf文件的一个错误。只需要将PS/2键盘的时钟线与数据线上拉即可,详细内容如下(只列举PS/2键盘部分):

NET "ps2_clk" LOC = L12 | IOSTANDARD = LVCMOS33 | PULLUP;

NET "ps2_data" LOC = J13 | IOSTANDARD = LVCMOS33 | PULLUP;

至此,笔者也只是将PS/2键盘搭载到了开发板上。但是如何更加灵活的利用键盘以及VGA,还需要仔细的设计各个寄存器的功能以及用法。

以下Demo内容需要连接VGA接口,按动键盘的A~Z的任意键,LED灯会显示对应的ASCII值。若按动A键,屏幕会显示字符a。(因为没有时间折腾字符提取软件,rom比较小只存了a的一个字符。喜欢的朋友也可以增加很多其他的字符。)若按动其他键,屏幕只显示一个白色矩形。

4.源程序

PS2键盘源程序.rar

以上内容均可以在百度网盘下载http://pan.baidu.com/share/link?shareid=940132753&uk=1092766566
 

【原创】FPGA开发手记(三) PS/2键盘的更多相关文章

  1. 【原创】FPGA开发手记(二) VGA接口

    以下内容均以Xilinx的Nexys3作为开发板 1.VGA接口介绍 首先,先看电路图(3*5为例): 标准VGA一共15个接口,但是实际应用的接口信号只用五个:HSYNC,行同步信号:VSYNC,场 ...

  2. 【原创】FPGA开发手记(一) UART接口

    以下内容均以Xilinx的Nexys3作为开发板 1. UART简介 UART(即Universal Asynchronous Receiver Transmitter 通用异步收发器)是广泛使用的串 ...

  3. FPGA开发流程1(详述每一环节的物理含义和实现目标)

    要知道,要把一件事情做好,不管是做哪们技术还是办什么手续,明白这个事情的流程非常关键,它决定了这件事情的顺利进行与否.同样,我们学习FPGA开发数字系统这个技术,先撇开使用这个技术的基础编程语言的具体 ...

  4. FPGA开发流程

    需求说明:Verilog设计 内容       :FPGA开发基本流程及注意事项 来自       :时间的诗 原文来自:http://www.dzsc.com/data/2015-3-16/1080 ...

  5. 【读书笔记】iOS-开发技巧-三种收起键盘的方法

    - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typica ...

  6. Lucene.Net 2.3.1开发介绍 —— 三、索引(一)

    原文:Lucene.Net 2.3.1开发介绍 -- 三.索引(一) 在说索引之前,先说说索引是什么?为什么要索引?怎么索引? 先想想看,假如现在有一个文本,我们会怎么去搜索.比如,有一个string ...

  7. 微信公众号开发《三》微信JS-SDK之地理位置的获取,集成百度地图实现在线地图搜索

    本次讲解微信开发第三篇:获取用户地址位置信息,是非常常用的功能,特别是服务行业公众号,尤为需要该功能,本次讲解的就是如何调用微信JS-SDK接口,获取用户位置信息,并结合百度地铁,实现在线地图搜索,与 ...

  8. Xilinx FPGA开发环境vivado使用流程

    Xilinx FPGA开发环境vivado使用流程 1.启动vivado 2016.1 2.选择Create New Project 3.指定工程名字和工程存放目录 4.选择RTL Project 5 ...

  9. 带你从零学ReactNative开发跨平台App开发(三)

    ReactNative跨平台开发系列教程: 带你从零学ReactNative开发跨平台App开发(一) 带你从零学ReactNative开发跨平台App开发(二) 带你从零学ReactNative开发 ...

随机推荐

  1. 第二十篇、自定义UIButton(设置title和image的位置)

    #import "CustomButton.h" #define ImageW 15 #define ImageH 15 #define KRadio 0.75 @implemen ...

  2. 代理的使用 一(helloworld级别)

    个人理解(估计,半年一年后,在看到这篇文章的时候,会觉得,当时真的弱爆了) 当我们自定义view的时候,比如说view上面有几个按钮,那么我们在别的地方使用这个view的时候,怎么来处理这些点击事件呢 ...

  3. UITableViewCell左滑的时候添加多个按钮的方法(iOS8+)以及UIRefreshControl(iOS6+)的使用。

    之前想在cell左滑的时候添加更多的按钮而不是只有‘删除’按钮如下所示,貌似不是一件简单的事.但是现在只要实现几个方法就行了. 代码写的比较垃圾,重在理解这个知识.. . 具体代码: // //  T ...

  4. 第11条:谨慎地覆盖clone

    Clone提供一种语言之外的机制:无需调用构造器就可以创建对象. 它的通用约定非常弱: 创建和返回该对象的一个拷贝.这个拷贝的精确含义取决于该对象的类.一般含义是,对于任何对象x,表达式x.clone ...

  5. 关于js与php互相传值的介绍【转载+自身总结】

    JS是前台的语言,PHP是后台的语言,初学时会经常出现前后台分不清的情况(我当初就是这样的,现在有时也在犯),我当初的想法是就把前后台当成两个岛,他们是无法跨越的,HTML就像一座桥,当你想要把一座岛 ...

  6. Qt-获取网络接口信息的综合示例

    在前面的文章中介绍了与 获 取 本 机 网 络 信 息 相 关 的 类 常 用 的 有 4 个 , 分 别 是 : QHostAddress, QHostInfo, QNetworkInterface ...

  7. linux RedHat6.4下nginx安装

    安装rpm 检测是否有已安装rpm包: rpm–qa | grep pcre rpm–qa | grep zlib rpm–qa | grep openssl 若没有则需安装(这些包可以在redhat ...

  8. javascripct导图

    分别归类为: 1 .javascript变量 2. javascript运算符 3. javascript数组 4. javascript流程语句 5. javascript字符串函数 6. java ...

  9. centos用yum安装mysql-server

    1.安装:#yum -y install mysql-server 2.修改配置:#vi /etc/my.cnf 暂时修改一下编码(添加在密码下方添加): default-character-set ...

  10. 51nod贪心算法入门-----独木舟问题

    独木舟问题 n个人,已知每个人体重,独木舟承重固定,每只独木舟最多坐两个人,可以坐一个人或者两个人.显然要求总重量不超过独木舟承重,假设每个人体重也不超过独木舟承重,问最少需要几只独木舟? 分析:按照 ...