Arduino开发实例PS2键盘驱动
Arduino开发实例-PS/2键盘驱动
PS/2键盘驱动
1、PS/2通信协议介绍
物理 PS/2 端口是 6 针 DIN 连接器。 连接器引脚如下所示:

Vcc/Ground 为设备提供电源 (5V),而 Data 和 Clock 是两条集电极开路线,带有上拉电阻到 Vcc。 电阻值并不重要(1 – 10 KOhm),最小值给出最短的上升时间,而较大的值允许更少的功耗。
PS/2 协议是一种双向串行同步协议。 当数据线和时钟线为高电平时,总线空闲,键盘/鼠标可以开始传输数据; 主机可以随时通过将时钟线拉低 100 微秒来禁止传输。 设备总是产生时钟信号,如果主机想要通信,它可以通过将时钟线拉低(禁止设备传输)、将数据线拉低然后释放时钟线来实现:这是发送的请求 状态并告诉设备开始生成时钟脉冲。
总线状态如下:
数据 = 高电平,时钟 = 高电平:空闲状态。
数据 = 高电平,时钟 = 低电平:禁止通信。
数据 = 低电平,时钟 = 高电平:主机请求发送
数据帧由 11 位或 12 位组成(取决于数据方向):
- 一个起始位(总是低)
- 8 个数据位,LSB 在前
- 奇校验位
- 一个停止位(总是高)
- 一个确认位(从主机传输到设备时,设备将数据线拉低)
如果数据位中有偶数个 1,则设置奇偶校验位,如果数据位中有奇数个 1,则重置 (0)。数据位中 1 的数量加上奇偶校验位总是加起来为奇数(奇校验)。这用于错误检测。键盘/鼠标必须检查该位,如果不正确,它应该像收到无效命令一样响应。
从设备发送到主机的数据在时钟信号的下降沿被读取;从主机发送到设备的数据在上升沿被读取。时钟频率必须在 10 - 16.7 kHz 范围内。这意味着时钟必须高 30 - 50 微秒,低 30 - 50 微秒。
1)设备到主机通信
数据线和时钟线都是集电极开路。 每条线和+5V之间接一个电阻,所以总线空闲状态为高。 当键盘或鼠标要发送信息时,它首先检查时钟线以确保它处于高逻辑电平。 如果不是,则主机正在禁止通信,并且设备必须缓冲任何要发送的数据,直到主机释放时钟。 在设备可以开始传输其数据之前,时钟线必须连续保持高电平至少 50 微秒。
1 个起始位。 这始终为 0。
8 个数据位,最低有效位在前。
1 个奇偶校验位(奇校验)。
1 个停止位。 这始终是 1。
设备检查时钟线的状态:如果它为高电平,则开始传输数据(时钟线必须在设备开始传输之前连续保持高电平至少 50 微秒)。 设备产生时钟脉冲,数据必须在时钟信号的下降沿稳定,在上升沿后变化:

从数据跳变到时钟信号下降沿的时间必须大于 5 微秒且小于 25 微秒,而从时钟信号的上升沿到数据跳变的时间必须至少为 5 微秒(因此我们可以采样 时钟信号低电平期间的数据,而高电平期间数据变化)。 如果主机通过在第 11 个时钟脉冲之前将时钟拉低 100 微秒来禁止传输,则设备必须在时钟线再次为高电平时重新发送帧(并且主机不再禁止通信)。 在通信被禁止时创建的任何数据都必须被缓冲(为此目的,键盘有一个 16 字节的缓冲区,而鼠标只存储当前的移动数据包)。
例如,扫描从键盘发送到计算机的“Q”键 (15h) 的代码。 通道 A 是时钟信号; 通道 B 是数据信号。

2)主机到设备通信
由于设备总是产生时钟信号,主机必须通过将时钟线拉低 100 微秒,然后将数据线拉低并再次拉高时钟线,将时钟线和数据线置于请求发送状态
- a)当设备检测到这种状态时,它将开始产生时钟脉冲,并将时钟输入帧的数据位
- b)主机在时钟为低电平时更改数据,而设备在时钟为高电平时对数据线进行采样(此 与设备到主机通信期间发生的情况相反):


由上图可以知道,主机要查找两个时间量:
- (a) 是主机最初将时钟线拉低后设备开始产生时钟脉冲的时间,该时间不得超过 15 毫秒。
- (b) 是发送数据包所需的时间,必须不大于 2ms。 如果不满足这些时间限制中的任何一个,则主机应生成错误。 收到“ack”后,主机可以立即将时钟线拉低以在处理数据时禁止通信。 如果主机发送的命令需要响应,则必须在主机释放时钟线后 20 毫秒内收到该响应。 如果这没有发生,主机会生成错误。
输入停止位后,设备将数据线拉低以确认数据,然后产生最后一个时钟脉冲并释放数据和时钟线。 主机到设备的通信对于向键盘发送命令很有用。
主机到设备通信步骤如下:
1)将时钟线拉低至少 100 微秒。
2)将数据线拉低。
3)释放时钟线。
4)等待设备将时钟线拉低。
5)设置/复位数据线以发送第一个数据位
6)等待设备将时钟拉高。
7)等待设备将时钟拉低。
8)对其他 7 个数据位和奇偶校验位重复步骤 5-7
9)释放数据线。
10)等待设备将数据拉低。
11)等待设备将时钟拉低。
12)等待设备释放数据和时钟
2、PS/2键盘鼠标驱动
键盘是由板载控制器监控的按键矩阵,称为**键盘编码器(Keyboard Encoder)**。 该控制器监控哪个键被按下或释放,并将相应的数据发送到主机。
控制器向主机发送的数据是已按下或释放的键的扫描码(Scan Code控制器扫描键盘是否有按键)。 有两种代码:Make Code和 Break Code。 每当按下或按住一个键时都会发送一个 Make Code; 释放键时会发送Break Code。
键盘上的每个键都有其唯一的Make Code和Scan Code,因此主机可以通过查看扫描码知道哪个键发生了什么。 所有的扫码组成一个扫码集:有三个Scan Code集(Scan Code Set 1、Scan Code Set 2或Scan Code Set 3),所有现代键盘默认为Scan Code Set 2:

即使大多数Make Code只有一个字节长,也有一些扩展Make Code由两个或四个字节组成(所有这些扫描码都以字节 0xE0 开头)。
每当按下一个键时,就会向主机发送一个扫描码。 需要注意的是,扫描码对应于键盘上的物理键,与特定字符集的字符无关,主机将扫描码转换为匹配字符。
当一个键被释放时,一个Break Code被发送到主机:Break Code是前面有 0xF0 的Make Code(扩展键Break Code是 0xE0、0xF0 和键码)。
当一个键被按下时,该键变为**打字键(Typematic )**,并且(片刻之后)键盘将继续发送它的 Make Code,直到它被释放或按下另一个键。 打字键数据不会在键盘内缓冲:当按下多个键时,只有最后一个键变成打字键,即使其他键可能仍被按下,打字重复也会停止。
重置时,键盘执行所谓的 BAT(Basic Assurance Test,基本保证测试),如果成功则发送 0xAA,如果失败则发送 0xFC(如果有,键盘上的 LED 会闪烁)。
3、Arduino 驱动PS/2键盘实现
本次PS/2驱动支持库:https://github.com/PaulStoffregen/PS2Keyboard
接线示例如下:

简单示例如下:
1 | #include <PS2Keyboard.h> |

文章来源: https://iotsmart.blog.csdn.net/article/details/127932248