第六章 PS2键盘驱动设计与验证
在我们的电子系统中,当需要用到大量的按键输入时,普通的独立按键和矩阵键盘已经无法满足我们的输入需求,这个时候,我们需要使用一种功能更加强大的键盘,来帮助我们输入更多的信息。在pc机上,我们经常使用104键的键盘,这种键盘与pc机的接口,可分为USB接口和PS2接口,我们FPGA要实现USB接口比较困难,因为USB的接口线路,不是标准的TTL电平,而PS2接口,则使用标准的TTL电平,那么我们今天就使用FPGA来解码驱动一个采用PS2接口的pc机键盘,用这个键盘来扩展我们FPGA的输入系统,以使我们方便输入更的信息。 实验目的实现采用PS2协议的PC机键盘的解码,最终将PS2键盘作为FPGA系统的一个标准输入设备。 实验原理 PS2键盘的内部结构我们不需要过多的去关注,我们只需要关心其接口协议,正确的解码其发送过来的按键信息即可,至于解码到的按键信息该怎么处理,不同的应用有不同的处理方式,这里就不做过多的介绍。PS2协议的简单描述如下: PS2协议总共由两根线组成,一根时钟线和一根数据线。这里我们将采用PS2协议的键盘称为从机,将控制和解码PS2协议的一方成为主机,生活中最常见的主机便是我们的PC机。PS2总线协议的两根线中,时钟线传输时钟信号,该时钟信号始终由从机,即键盘产生。PS2协议发送一个字节的数据总共有11位,分别为 PS2从机发送一个完整数据包的时序图如下所示:
图2-1 PS2从机发送数据时序图 相信熟悉UART协议的同学一眼就能看出来,PS2协议和我们最熟悉的UART通信协议非常相似,那么我们的工作就简单了,既然键盘按照这个协议发送数据,我们FPGA作为主机,只需要正确的实现该协议的解码,将其中的8位数据位读取出来即可。由图可知,数据在时钟的下降沿处是稳定的,因此我们只需要去捕获时钟信号的下降沿,并在检测到这个下降沿时去读取数据线上的电平,就能够正确的读到数据。 以上是PS2协议中从机到主机的一个通讯过程,实际在PS2协议中,包含了从机到主机和主机到从机的通信时序,只是在我们进行PS2键盘的解码时,可以不需要进行主机到从机的通信,因此这部分内容小梅哥就不在这里讲解了,如果大家以后要解码PS2鼠标的话,就会用到主机到从机的通信了。 上面只是简单的介绍了PS2从机到主机的通信协议,我们知道了键盘是一个字节一个字节的往主机发送数据的,但是,每个字节代表了什么内容呢,我们还需要对照键盘编码对照表来查看。
键盘扫描码分为第一套扫描码、第二套扫描码和第三套扫描码,我们日常生活中常见的扫描码绝大多数采用第二套扫描码,因此这里小梅哥就只附上第二套扫描码的内容。
实际一个按键由按下到释放时键盘的响应过程如下图所示:
只要一个键被按下,这个键的通码(MAKE)就被发送到计算机。通码只表示键盘上的一个按键,它不表示印刷在按键上的那个字符。这就意味着在通码和ASCII码之间没有已定义好的关联, 直到主机把扫描码翻译成一个字符或命令。 虽然多数第二套通码都只有一个字节宽,但也有少数“扩展按键”的通码是两字节或四字节宽,这类的通码第一个字节总是为E0H(如“END”、“HOME”……)。正如键按下通码就被发往计算机一样, 只要键一释放, 断码就会被发送。每个键都有它自己唯一的通码,它们也都有唯一的断码。幸运的是,你不用总是通过查表来找出按键的断码―― 在通码和断码之间存在着必然的联系。 多数第二套断码有两字节长,它们的第一个字节是F0H, 第二个字节则是这个键的通码。
例如,键盘上按键“A”的通码为“1C”,段码为F0 1C当我们按下键盘上的“A”键时,键盘就会往主机发送”A”键对应的通码(MAKE)”1C”,如果你一直按下这个按键不释放,那么在一个短暂的延时(机打延迟)之后,键盘会再次开始,以一定的速率(机打速率)持续向主机发送”1C“,直到该按键被释放。在该按键被释放后,键盘将会向主机发送“A ”的断码(Break),即首先发送“F0”,然后下一个字节再马上发送“1C”。发送顺序如下: - 短按并立即释放:
- 键盘检测到按下按键A
- 键盘发送通码1C
- 键盘检测到释放按键A
- 键盘发送断码F0 1C。
- 长按再释放:
- 键盘检测到按下按键A
- 键盘发送通码1C
- 延时短暂时间(机打延迟)
- 键盘检测到按键A依旧被按下
- 键盘发送通码1C
- 延时短暂时间(机打速率)
- 键盘发送通码1C
- 延时短暂时间(机打速率)
- ……
- 键盘检测到按键A被释放
- 键盘发送断码码F0 1C。
如果我们按下的是“END”、“PAGE UP”等扩展按键时,会怎么样呢?这里,以”END”键举例。当”END“键被按下后,键盘会首先向主机发送“E0”,发送完成后,又会接着发送下一个字节“69”,释放时也与前面的普通按键类似,先发送“E0”,然后发送“F0”,最后再发送“69”。 由上述分析可知,我们FPGA在解码到一次数据后,还需要对这个数据进行分析判断,判断该数据是否为断码标志“F0”以及扩展码标志”E0“。
硬件设计
架构设计 本实验我们进行PS2键盘的解码实验,并将解码到的结果显示在数码管上,同时,为了使我们更加直观的感受到按键被按下和释放,小梅哥在这里增加了一个蜂鸣器,当有按键按下或释放(包括长按时每接收到一个通码)时,蜂鸣器发出一个短暂的响声,来反馈给操作者,让我们知道我们的解码模块解码到了按键信息。设计结构如下图所示:
图4-1 led实验模块组织结构图 详细端口名及其意义如下
表4-1 独立按键检测实验端口说明
因为存在模块间的连接,因此有部分内部信号,下表为内部信号的名称和功能说明
表4-2 独立按键检测实验内部信号说明
代码分析 这里,解码的关键是PS2接口的时钟信号,该时钟为异步时钟,我们需要通过边沿检测的方式来检测其下降沿,以便根据下降沿的个数来确定每个时钟我们因该做什么,边沿检测的电路,前面几个实验已经讲过很多次了,这里便不再做过多的解释,贴上代码即可:
一个PS2的数据包总共由11位组成,因此会有11个时钟下降沿,因此我们必须对下降沿的个数准确计数,才能保证我们能够解码得到正确的数据,这里,使用我们的PS2时钟下降沿标志信号来使能我们的计数器自加,当计数器加到11后,表示一个数据包接收完成,将计数器清零,等待下一个下降沿的到来,相关代码如下:
接下来,就是根据时钟下降沿的计数个数,来读取对应位的数据了,因为采用了非阻塞赋值的方式,因此,PS2时钟下降沿到来时,此时Cnt1执行自加1操作,但同时如果也来用Cnt1的值来确定数据位数,就一定会造成错误,因为此时,Cnt1的加1操作并没有执行,而是会在下一个时钟上升沿到来之时才变,因此,为了保证我们使用的Cnt1的数据是已经更新了的,我们需要在Cnt1已经变化之后再来使用其值做判断,即在PS2时钟下降沿检测成功后,滞后一个系统时钟周期后再来读取PS2_Din上的值,比较简单的操作方式就是将PS2时钟下降沿检测标志信号再用寄存器打一拍,对应代码如下:
可能这里相对比较难以理解,希望大家结合仿真结果自学揣摩体会。 接下来就是根据Cnt1的计数值来读取每一位的数据了,这部分代码很简单,如下所示:
通过以上操作,我们就能正确的解码PS2键盘发送过来的每一个字节的数据了,但是,这些数据代表了什么呢,如果是断码标志,或者是长码标志,我们又该如何进行操作呢,这里,小梅哥先贴上我的处理代码:
这里,小梅哥使用了两个标志寄存器,当检测数据完成后,即Cnt1=11时,就对解码到到数据进行判断,如果Data_tmp == 8'hE0,则解码到到数据为长码(扩展码)标志,此时便将长码标志寄存器置1,如果Data_tmp == 8'hF0,则解码到到数据为断码标志,此时便将断码标志寄存器置1。然后,当解码到其他数据(如单字节通码或双子节通码的第二个字节)后,便将解码到的数据连同断码和长码标志寄存器的状态输出,并给出按键检测成功标志(Key_Flag置1)。
仿真分析为了对小梅哥设计的PS2键盘解码驱动进行验证,小梅哥编写了一个Testbench来模拟键盘发送数据,通过观察键盘解码驱动的输出来验证该解码模块的正确性,关于模拟键盘发送数据,在一份介绍PS2协议的手册中有如下描述: 我们推荐仿真键盘/鼠标采用下面的过程发送一字节的数据到主机: - 等待Clock线为高电平,即等待主机释放Clock线;
- 延时50us;
- 判断Clock线是否为高电平?No―― 跳到第1步;
- Data线是否为高电平?No――放弃(跳到从主机读取字节的程序中) 。
- 延迟20us,输出起始位(0) , 然后延迟20us, 再拉低Clock线保持40us后释放Clock线, 形成一个脉冲;
- 延时20us,测试Clock线是否为高电平?No―― 跳到第1步;
- 输出第1个数据位,然后延时20us, 再拉低Clock线保持40us后释放Clock线, 形成一个脉冲;
- 重复6-7步发送剩下的7个数据位和校验位;
- 延时20us,测试Clock线是否为高电平?No―― 跳到第1步;
因此,我们的模拟键盘发送数据的过程只需要依照上面的流程来即可,这里贴上小梅哥编写的testbench:
testbench中使用了一个主任务“Send_data”来模拟键盘的数据发送,并使用了其他几个基于此任务的任务来模拟按键按下(press_key)、按键释放(release_key)、普通按键按下+释放(Key_Event)、扩展按键按下+释放的过程(Long_Key_Event),通过模拟进行部分按键的按下和释放操作,来观察解码模块的结果,便可获知解码是否成功。
以下为小仿真结果,与发送的数据一致,因此表明PS2解码是成功的。
下板验证这里,小梅哥在芯航线FPGA学习套件上进行验证验证结果如下图: 其中,第三个数码管,为0表示普通按键通码,为2表示普通按键断码,为1表示扩展按键通码,为3表示扩展按键断码。
如有更多问题,欢迎加入芯航线FPGA 技术支持***流学习:472607506 小梅哥 芯航线电子工作室
|