芯嵌 stm32 www.51stm32.com
Copyright © 2009-2014 福州芯嵌工作室 ALL rights reserved 1
STM32入门系列教程
基于 STM32 的 PS2 鼠标驱动
RevisionRevisionRevisionRevision 1111.01.01.01.01
( 2013-06-08 )
芯嵌 stm32 www.51stm32.com
Copyright © 2009-2014 福州芯嵌工作室 ALL rights reserved 2
笔者原本以为 PS2鼠标驱动,只要用到 2个 GPIO 引脚,一个数据口,一个
时钟同步着通信,应该很简单,没想到花了 2 天时间,当然也彻底了解了 PS2
鼠标的通信协议和工作过程,受益匪浅。本教程参考大量网络资料,不仅适合芯
嵌 stm32开发板的 PS2鼠标驱动,也可作为其他 stm32开发板的驱动参考。
原则上,对于初学者来说,PS2鼠标的驱动程序学习,需要理解以下方面的
内容:
1) PS2鼠标内部工作原理;(第一、二章)
2) PS2通信协议;(第三章)
3) PS2鼠标是“设备”,stm32板是“主机”,这个不难理解。
先简单地让大家有个概念:要使得 PS2鼠标工作,stm32板子需要发出一个
命令(拉低时钟线),告知鼠标做好准备,之后鼠标可以接收一些命令数据。鼠
标就知道当前 stm32板子想干啥。当鼠标开始工作,它内部自己有缓存,有传感
器,可以把一些信息收集(比如 X轴 Y 轴移动的距离,鼠标按键信息)返回到
stm32板。于是 stm32主机就开始分析这些信息,做出相应的处理。
看起来不难,实际上详细分析倒不是容易的事,先看 PS2鼠标工作原理吧。
备注:以下内容是笔者参考很多 PS2 资料(PS2 鼠标资料,PS2 协议通信,51
单片机的 PS2 驱动后才写出来的,这里非常感谢各位提供材料的网友。特别感
谢编辑《PS2鼠标接口程序设计总结.doc》的网友,谢谢!)。
第一章 PS2PS2PS2PS2鼠标内部工作原理
1.11.11.11.1 PS2PS2PS2PS2鼠标基本工作原理鼠标基本工作原理鼠标基本工作原理鼠标基本工作原理
标准的PS/2鼠标,能通过传感器识别输入X(左右)位移、Y(上下)位移、左
键、中键和右键鼠标的信息,它以一个固定的频率读取这些输入,并更新不同的
计数器,然后标记出反映的移动和按键状态。
标准的鼠标有两个计数器,保持位移的跟踪,X位移计数器和Y位移计数器。
可存放9位的2进制补码,并且每个计数器都有相关的溢出标志,它们的内容连同
三个鼠标按钮的状态一起以三字节移动数据包的形式发送给主机。位移计数器表
示从最后一次位移数据包被送往主机后,有位移量发生。
当鼠标读取它的输入的时候,它记录按键的当前状态,然后检查位移,如果
位移发生它就增加(对正位移)或减少(对负位移)X和/或Y位移计数器的值。
如果有一个计数器溢出了就设置相应的溢出标志。
为了对以上数据包有一个详细的认识,这里先给出数据包
:
表1 3字节数据包格式
序号 D7 D6 D5 D4 D3 D2 D1 D0
芯嵌 stm32 www.51stm32.com
Copyright © 2009-2014 福州芯嵌工作室 ALL rights reserved 3
Byte1
Y
overflow
X
overflow
Y
sign
bit
X
sign
bit
Always1
Middle
Btn
Right
Btn
Left
Btn
Byte2 X Movement
Byte3 Y Movement
PS2协议中,数据包都是按照这样的格式发送的。注意到,Byte1这行,
有X sign bit,这表示X坐标位移的有符号位(因为要表示左移还是右移)。鉴
于此,位移计数器是一个9位2进制的补码整数。它的最高位作为符号位出现。更
详细的信息,请参考光盘里的《PS2参考资料》,在光盘目录:芯嵌stm32外设资
源学习资料中。
那么,这些格式的数据包,怎样传输到主机呢?或者主机又是以怎样的方式,
把命令数据传送给鼠标呢?这就是PS2通信协议的内容。请参考后续第二章节内
容。
1.21.21.21.2 鼠标分辨率和缩放比例鼠标分辨率和缩放比例鼠标分辨率和缩放比例鼠标分辨率和缩放比例
现在来看另一个问
,鼠标的分辨率和缩放比例。举例:鼠标向左移动 1mm,
那么 LCD 上的光标,是否也理所当然地移动 1mm?非也。这里有一个比例问题,
即分辨率和缩放比例。缺省的分辨率为 4 个计数单位/毫米,主机可以用设置分
辨率 0xE8 命令改变这个值。缩放比例,缺省情况下鼠标使用 1:1 比例。主机
可以用设置比例 2:1(0xE7)命令选择 2:1比例。
表2 缩放比例算法运算表
位移增量值
值
0 0
1 1
2 1
3 3
4 6
5 9
N>5 2*N
对初学者来说,这里建议,先不用管分辨率和缩放比例的问题,尽量先把 PS2
鼠标驱动起来,能工作了,慢慢一步一步再详细地实现 PS2鼠标的所有功能(实
际上,实现这些也简单,就是配置寄存器而已,只是对 PS2 来说,配置寄存器
是需要主机发命令,PS2自己接收到命令才能配置。虽然只是多了一个通信过程,
但对初学者可算难上加难。而 stm32若想配置寄存器,直接设置寄存器某个位即
可)。
以上讲解的是一个鼠标最基本的内容。可是目前,最流行的鼠标,都有一个
滚轮(在左键和右键的中间),这个又是怎么处理呢?
芯嵌 stm32 www.51stm32.com
Copyright © 2009-2014 福州芯嵌工作室 ALL rights reserved 4
1.31.31.31.3 IntelimouseIntelimouseIntelimouseIntelimouse的扩展的扩展的扩展的扩展
为了使用滚轮等扩展功能,就需要用微软的 Intellimouse。它包括支持五个鼠
标按键和三个位移轴(左右上下和滚轮)。这些附加特征要求使用 4字节的位移
数据包,而不是标准 3 字节包,因为标准 PS/2 鼠标驱动不认识这个数据包的格
式,因此微软的 Intellimouse 要求严格按照标准 PS/2 鼠标来操作。除非它知道
驱动程序支持扩展数据包格式,如果微软的 Intellimouse 用于一台只支持标准
PS/2 鼠标的计算机它依然是有功能的,只是滚轮和第 4 5 个按键不起作用。注
意,这说明了,我们写驱动的时候,只写 3个字节的驱动,照样适用于所有鼠标。
只是多功能的鼠标,某些功能不起作用而已(因为驱动程序没有体现)。当然,
建议既然写了,就要写 Intellimouse扩展的鼠标驱动,毕竟现在几乎所有的鼠标
都是带滚轮的。
微软的 Intellimouse工作起来象标准的 PS/2 鼠标,(也就是使用 3 字节位移
数据包,和标准 PS/2 鼠标一样回应所有命令报告设备 ID 0x00)。
要进入滚轮模式,主机应该发送如下的命令序列:
设置采样速率 200
设置采样速率 100
设置采样速率 80
要进入滚轮+5键模式,主机应该发送如下的命令序列:
设置采样速率 200
设置采样速率 200
设置采样速率 80
主机然后应该发布“获得设备 ID” 命令 0xF2 并等待回应,如果安装的是
是标准 PS/2 鼠标非 Intellimouse,它回应设备 ID 是 0x00。在这种情况下主机会
辨认出实际这个鼠标没有滚轮并继续把它当作是标准 PS/2 鼠标。但是如果安装
的是微软的 Intellimouse 它返回的 ID 是 0x03。这就告诉主机挂接的定点设备有
滚轮,并且主机认为鼠标使用 4 字节的位移数据包,如表 3所示:
表 3 4字节数据包格式
D7 D6 D5 D4 D3 D2 D1 D0
Byte1
Y
overflow
X
overflow
Y
sign
bit
X
sign
bit
Always1
Middle
Btn
Right
Btn
Left
Btn
Byte2 X Movement
Byte3 Y Movement
Byte4Byte4Byte4Byte4 ZZZZMovementMovementMovementMovement
芯嵌 stm32 www.51stm32.com
Copyright © 2009-2014 福州芯嵌工作室 ALL rights reserved 5
很明显,3字节的数据包和 4字节的数据包,区别就在于第 4字节。Z 位移
是 2 的补码,表示滚轮自上次数据报告以来的位移,有效值的范围在-8 到+7,
这意味着数值实际只有低四位,高四位仅用作符号扩展位。
主机接着发布“获得设备 ID”命令(0xF2)并等待回应,微软的 Intellimouse
用 0x04 这样设备 ID 应答并且使用如下的 4 字节位移数据包,如表 4所示:
表 4 五键 4字节数据包格式
D7 D6 D5 D4 D3 D2 D1 D0
Byte1
Y
overflow
X
overflow
Y
sign
bit
X
sign
bit
Always1
Middle
Btn
Right
Btn
Left
Btn
Byte2 X Movement
Byte3 Y Movement
Byte4Byte4Byte4Byte4 Always0 Always0 Btn Btn Z3 Z2 Z1 Z0
Z0-Z3是 2的补码,用于表示从上次数据报告以来滚轮的位移量,有效范围
从-8 到+7。
第 4键 Btn:1=第 4键按下了;0=第 4键没有按下。
第 5键 Btn:1=第 5键按下了;0=第 5键没有按下。
第二章第二章第二章第二章 鼠标工作模式和命令集鼠标工作模式和命令集鼠标工作模式和命令集鼠标工作模式和命令集
2.12.12.12.1 工作模式工作模式工作模式工作模式
根据鼠标工作的模式来处理的数据报告有四种标准的工作模式。
●Reset——鼠标在上电或收到“Reset”(0xFF)命令后进入Reset 模式;Reset
模式进入后,鼠标自动完成一些测试,并做好缺省配置,比如:
1)采样速率100 采样点/秒
2)分辨率4 个计数值/毫米
3)缩放比例1:1
4)数据报告被禁止
注意,正是因为有最后一项检测(数据报告禁止),这就意味着鼠标在没收
到“使能数据报告”(0xF4)命令之前不会发送任何位移数据包给主机。这些测
试完成后,如果测试正确,会返回主机一个信号(0XAA)。错误就返回0XFC。如
果主机收到了不是0xAA的回应,它可能重新给鼠标供电,这样来引起鼠标复位并
重新执行BAT。接着BAT完成代码(0xAA 或0xFC)的后面鼠标发送它的设备ID
0x00。 这个ID 用来区别设备是键盘还是处于扩展模式中的鼠标(从发复位命令
到鼠标发送它的设备ID时间大概为360mS)。
芯嵌 stm32 www.51stm32.com
Copyright © 2009-2014 福州芯嵌工作室 ALL rights reserved 6
●Stream——这是缺省模式在Reset执行完成后,也是多数软件使用鼠标的模式。
如果主机先前把鼠标设置到了Remote模式,那它可以发送Set Stream Mode
(0xEA)命令给鼠标,让鼠标重新进入Stream模式。
我们所有的鼠标正常工作,都是在这个模式中的。下面两个模式,简单介绍,因
为几乎用不到。
●Remote——在某些情况下Remote模式很有用可以通过发送Set Remote Mode
(0xF0)命令进入。
●Wrap——除了为测试鼠标和它的主机之间的连接外这个模式不是特别地有
用。Wrap模式可以通过发送Set Wrap Mode(0xEE)命令给鼠标来进入,要退出
Wrap 模式主机必须发布Reset(0xFF)命令或Reset Wrap Mode(0xEC)命令。
如果Reset(0xFF)命令收到了,鼠标将进入Reset 模式。如果收到的是Reset Wrap
Mode(0xEC)命令鼠标将进入Wrap 模式前的那个模式。(注意鼠标同样可以
进入extended操作模式,正如本文后面所述但是这不是标准PS/2 鼠标的
特征)。
2.22.22.22.2 命令集命令集命令集命令集
(以下文字照抄网络资料的部分)
下面列出的是仅可发送给鼠标的命令,如果鼠标工作在 Stream 模式,主机在
发送任何其他命令之前,要先禁止数据报告(命令 0xF5)。
● 0xFF (Reset)——鼠标用应答 0xFA,回应这条命令并进入 Reset模式
● 0xFE (Resend)——只要从鼠标收到无效数据,主机就发送这条命令,鼠标的
回应是重新发送它最后发给主机的数据包。如果鼠标用了另外一个非法的包来回
应主机,要么发布另一条 Resend 命令,要么发布 Error 命令要么让鼠标重新上
电来复位它,或者禁止通讯把时钟线拉低,采取什么样的动作取决于主机。
● 0xF6 (Set Defaults)——鼠标用应答 0xFA来回应,然后载入如下的值:采样
率=100,分辨率 = 4 个值/毫米、比例 1 :1 禁止数据报告,接着鼠标清空它所
有的位移计数器,并进入 stream 模式。
● 0xF5 (Disable Data Reporting)——鼠标用应答 0xFA回应命令,然后禁止数据
报告,并复位它的位移计数器。这仅对 Stream 模式下的数据报告有效。并且它
不能禁止采样。禁止的 stream模式功能与 remote 模式相同。
● 0xF4 (Enable Data Reporting)——鼠标用应答 0xFA回应命令,然后使能数据
报告,并复位它的位移计数器。这条命令可以对在 Remote模式或 Stream 模式下
的鼠标发布。但只对 Stream模式下的数据报告有效。
● 0xF3 (Set Sample Rate)——鼠标用应答 0xFA 回应命令,然后从主机读入一个
或更多字节。鼠标保留这个字节作为新的采样速率在收到采样速率后,鼠标再次
芯嵌 stm32 www.51stm32.com
Copyright © 2009-2014 福州芯嵌工作室 ALL rights reserved 7
用应答 0xFA 回应,并复位它的位移计数器。有效的采样速率是 10、20、40 、
60、80、100和 200 采样点/秒。
● 0xF2 (Get Device ID)——鼠标用应答 0xFA 回应命令,后面跟着它的设备 ID,
对标准 PS/2 鼠标来说是 0x00;鼠标同样会复位它的位移计数器。
● 0xF0(Set Remote Mode)——鼠标用应答 0xFA回应,然后复位它的位移计数
器并进入盘 Remote模式。
● 0xEE(Set Wrap Mode)——鼠标用应答 0xFA回应,然后复位它的位移计数器
并进入 wrap 模式。
● 0xEC(Reset Wrap Mode)——鼠标用应答 0xFA回应,然后复位它的位移计数
器并进入 wrap 模式之前的那个模式(stream模式或 remote 模式)。
● 0xEB(Read Data)——鼠标用应答 0xFA 回应,然后发送位移数据包。这是在
remote 模式中读数据的唯一方法,在数据包成功地被发送后,鼠标将复位它的位
移计数器。
● 0xEA (Set Stream Mode)——鼠标用应答 0xFA 回应,然后复位它的位移计数
器并进入 stream模式。
● 0xE9 (Status Request)——鼠标用应答 0xFA 回应,然后发送如表 1.5,3个字
节的状态包, 然后复位它的位移计数器。
表 1.5 鼠标状态包格式
Byte1 Always0 Mode Enable Scaling Always0 Left BtnMiddle Btn
Right Btn
Byte2 分辨率
Byte3 采样速率
右键、中键、左键 =1,表示键被按下;=0 ,表示键没有按下。
Scaling = 1缩放比例位 2:1; =0,比例为 1 :1;见命令 0xE7 和 0xE6。
Enable = 1表示数据报告被使能;=0,示数据报告被禁止;见命令 0xF5和 0xF4。
Mode = 1 表示 remote 模式被使能;=0,表示 stream 模式被使能;见命令 0xF0
和 0xEA。
● 0xE8 (Set Resolution )——鼠标用应答 0xFA 回应,然后从主机读取一个字
节,并再次用鼠标用应答 0xFA应然回应,然后复位它的位移计数器,从主机读
入的字节决定了分辨率如表 1.6所示:
表 1.6 鼠标位移分辩率对应表
主机发过来的数据 分辨率
0x00 1 计数值/毫米
0x01 2 计数值/毫米
芯嵌 stm32 www.51stm32.com
Copyright © 2009-2014 福州芯嵌工作室 ALL rights reserved 8
0x02 4 计数值/毫米
0x03 8 计数值/毫米
● 0xE7 (Set Scaling 2:1)——鼠标用应答 0xFA回应,然后使能 2:1比例。
● 0xE6 (Set Scaling 1:1)——鼠标用应答 0xFA回应,然后使能 1:1比例。
对于标准鼠标而言,只有(Resend )0xFE和(Error) 0xFC 命令会发送给主机。这两
条命令的工作情况和主机到设备间的命令一样。
注:
1、2 :1比例仅适用于 Stream 模式的自动数据报告中,对于回应 Read Data 0xEB
命令的报告数据是无效的。
2、鼠标和主机不缓冲 Resend 0xFF 命令,这意味着 0xFE 绝不会作为 Resend 命
令的回应来发送。
3、一个数据包可以是 3字节的位移数据包,或 4字节的位移数据包,Intellimouse
的或3 字节的状态包Status Request 0xE9命令或2字节的完成代码 ID包,0xAA 、
0x00或 0xFC、0x00或 1字节的命令回应。
4、当 PS/2数据线常置零时,PS/2鼠标将不断产生时钟脉冲。
第三章 PS/2PS/2PS/2PS/2通讯协议
PS2通讯协议是一种双向同步串行通讯协议。通讯的两端通过Clock(时钟脚)
同步,并通过Data(数据脚)交换数据。任何一方如果想抑制另外一方通讯时,
只需要把clock(时钟脚)拉到低电平。如果是PC机和PS2键盘间的通讯,则PC
机必须做主机,也就是说,PC机可以抑制PS2键盘发送数据,而PS2键盘则不会抑
制PC机发送数据, 也即主机总是在总线上有优先权。一般两设备间传输数据的最
大时钟频率是33KHz,大多数PS2设备工作在10~20KHz。推荐值在15KHz左右,也
就是说,clock(时钟脚)高、低电平的持续时间都为40μs。每一数据帧包含
11~12个位,具体含义如表5所列。
表5 PS/2通讯数据帧格式
表中,如果数据位中1的个数为偶数,校验位就为1;如果数据位中1的个数
为奇数,校验位就为0;总之,数据位中1的个数加上校验位中1的个数总为奇数,
因此总进行奇校验。
芯嵌 stm32 www.51stm32.com
Copyright © 2009-2014 福州芯嵌工作室 ALL rights reserved 9
3.13.13.13.1 PS/2PS/2PS/2PS/2设备到主机的通讯设备到主机的通讯设备到主机的通讯设备到主机的通讯
时钟频率为10-16.7kHz 。从时钟脉冲的上升沿到一个数据转变的时间至少
要有5微秒。数据变化到时钟脉冲的下降沿的时间至少要有5 微秒,并且不大于
25微秒。这个定时非常重要你应该严格遵循它。主机可以在第11个时钟脉冲停止
位之前把线拉低,导致设备放弃发送当前字节,这是非常罕见的。在停止位发送
后设备在发送下个包前至少应该等待50微秒。这将给主机时间,当它处理接收到
的字节时抑制发送(主机在收到每个包时通常自动做这个)。在主机释放抑制后,
设备至少应该在发送任何数据前等50微秒。其通讯时序图如图3.1所示。
从 PS2 向 PC 机发送一个字节可按照下面的步骤进行:
1) 检测时钟线电平,如果时钟线为低,则延时 50μs;
2) 检测判断时钟信号是否为高,为高,则向下执行,为低,则转到(1);
3) 检测数据线是否为高,如果为高则继续执行,如果为低,则放弃发送(此
时 PC 机在向 PS2 设备发送数据,所以 PS2 设备要转移到接收程序处接收
数据);
4) 延时 20μs(如果此时正在发送起始位,则应延时 40μs);
5) 输出起始位(0)到数据线上。这里要注意的是:在送出每一位后都要检测
时钟线,以确保 PC 机没有抑制 PS2 设备,如果有则中止发送;
6) 输出 8个数据位到数据线上;
7) 输出校验位;
8) 输出停止位(1);
9) 延时 30μs(如果在发送停止位时释放时钟信号则应延时 50μs);
按如下的过程发送单个位
1) 设置/复位数据
2) 延迟20微秒
3) 把时钟拉低
4) 延迟40微秒
5) 释放时钟
6) 延迟20微秒
芯嵌 stm32 www.51stm32.com
Copyright © 2009-2014 福州芯嵌工作室 ALL rights reserved 10
图3.1 设备到主机的通讯
3.23.23.23.2 主机到主机到主机到主机到 PS/2PS/2PS/2PS/2设备的通讯设备的通讯设备的通讯设备的通讯
首先PS/2 设备总是产生时钟信号,如果主机要发送数据它必须首先把时钟
和数据线设置为请求。发送状态如下示
● 通过下拉时钟线至少100微秒来抑制通讯
● 通过下拉数据线来应用请求,发送然后释放时钟
设备应该在不超过10 毫秒的间隔内就要检查这个状态。当设备检测到这个
状态,它将开始产生时钟信号,并且时钟脉冲标记下输入八个数据位和一个停止
位。主机仅当时钟线为低的时候改变数据线而数据在时钟脉冲的上升沿被锁存,
当发生在设备到主机通讯的过程中时正好相反。
在停止位发送后,设备要应答接收到的字节,就把数据线拉低并产生最后一
个时钟脉冲,如果主机在第11 个时钟脉冲后不释放数据线,设备将继续产生时
钟脉冲直到数据线被释放然后设备将产生一个错误。通讯时序图如图3.2、3.3
所示。
主机可以在第11 个时钟脉冲应答位前中止一次传送,只要下拉时钟线至少
100微秒。
主机必须按下面的步骤发送数据到PS/2设备
1) 把时钟线拉低至少100微秒
2) 把数据线拉低
3) 释放时钟线
4) 等待设备把时钟线拉低
5) 设置/复位数据线发送第一个数据位
6) 等待设备把时钟拉高
7) 等待设备把时钟拉低
8) 重复 5-7步发送剩下的7个数据位和校验位
9) 释放数据线
10) 等待设备把数据线拉低
11) 等待设备把时钟线拉低
12) 等待设备释放数据线和时钟线
芯嵌 stm32 www.51stm32.com
Copyright © 2009-2014 福州芯嵌工作室 ALL rights reserved 11
图3.2 主机到设备的通讯
图3.3 主机到设备通讯的详细过程
图3.3描述了两个重要的定时条件:a和b。a在主机最初把数据线拉低后,设
备开始产生时钟脉冲的时间,必须不大于15ms;b数据包被发送的时间,必须不
大于2ms 。如果这两个条件不满足,主机将产生一个错误。在包收到后,主机为
了处理数据立刻把时钟线拉低来抑制通讯,如果主机发送的命令要求有一个回
应,这个回应必须在主机释放时钟线后20ms之内被收到。如果没有收到则主机产
生一个错误,在设备到主机通讯的情况中,时钟改变后的5微秒内不应该发生数
据改变的情况。
第四章 PS2PS2PS2PS2驱动程序
芯嵌 stm32开发板为了更加明显地看出 PS2驱动成功,使用了 LCD 液晶屏,
当 PS2驱动成功,我们缓缓移动鼠标,就能看到 LCD 上的 X光标也做出相应的
移动。软件上,采用方法是中断获取数据的方法。此方法很明显的不足之处是,
不断地产生中断来驱动数据的接收,大大浪费了系统资源。程序思路如下:
SystemInit();
GPIO_Config();
EXTI_Config();
NVIC_Config();
FSMC_LCD_Init(); /* Configure FSMC */
LCD_Setup(); /* Init for LCD */
Init_PS2_Mouse();
从以上初始化过程可以看出,主要是配置GPIO引脚(此部分初始化的是 LED
灯,PS2的时钟和数据引脚),EXTI 中断初始化(确定中断线对应时钟引脚),
VNIC 初始化(比如优先级设定等),LCD 初始化,最后是 PS2自己的初始化(即
要上电复位,发送 0XFF等命令,让 PS2鼠标进入 stream模式正常工作)。
芯嵌 stm32 www.51stm32.com
Copyright © 2009-2014 福州芯嵌工作室 ALL rights reserved 12
以上除了 Init_PS2_Mouse();,其他每个部分的初始化我们都很了解了。而在
Init_PS2_Mouse();中,我们不采用上电复位的方式,而直接发送命令
PS2_Send_Cmd(0xFF);,要求 PS2鼠标立即复位,那么,如果复位顺利,必须会
返回三个数值,分别是 0XFA,0XAA, 0X00。第一个 0XFA是命令发送成功的标
志,第二个 0XAA是鼠标自检通过的标志,0X00 则是鼠标的设备 ID 号。
如果返回的不是这三个值,我们确认可能出现问题,就重新发送 0XFE,要
求鼠标重新传回一次数据。
注意到,我们在复位成功后,并不着急进行后续 while,而是又发送了一个
命令 0XF4,此命令使能数据报告,并复位它的位移计数器。正如我们之前提过
的:“鼠标在没收到“使能数据报告”(0xF4)命令之前不会发送任何位移数据
包给主机”。
以上是鼠标自己的初始化部分。为了让鼠标工作,我们根据 PS2通信协议,
编写了设备到主机的通信(这个部分由 CLK 中断服务程序实现),主机到设备的
通信(此部分即用来发送命令的),还有数据处理的部分。下面分别介绍。
4.14.14.14.1 函数函数函数函数 voidvoidvoidvoid PS2_Send_Cmd(u8PS2_Send_Cmd(u8PS2_Send_Cmd(u8PS2_Send_Cmd(u8 cmd)cmd)cmd)cmd)
此函数用来主机给设备发送命令之用,PS2通信协议建议按照如下步骤进行:
* 1) 把时钟线拉低至少 100微秒
* 2) 把数据线拉低
* 3) 释放时钟线
* 4) 等待设备把时钟线拉低
* 5) 设置/复位数据线发送第一个数据位
* 6) 等待设备把时钟拉高
* 7) 等待设备把时钟拉低
* 8) 重复 5-7步发送剩下的 7个数据位和校验位,停止位
* 9) 释放数据线
* 10) 等待设备把数据线拉低
* 11) 等待设备把时钟线拉低
* 12) 等待设备释放数据线和时钟线
对于普通 51单片机来说,实现这个过程并不难。但 stm32,则需要注意,因
为每个 IO 引脚并不像 51那样输入和输出随便通吃。Stm32的所有引脚,要通过
设置才可以设置为输入或者输出。比如:CLK 时钟是 PD7引脚,按照第 1步骤,
要拉低时钟引脚,此时,该引脚 PD7的信号是从 stm32到 PS2鼠标,因此对 stm32
来说,需要先设置为 PD7为“输出”。而在后续工作过程中,设备要提供(产生)
芯嵌 stm32 www.51stm32.com
Copyright © 2009-2014 福州芯嵌工作室 ALL rights reserved 13
时钟来维持正常的 PS协议通信,此时,就要求 PD7的信号是从设备传输到 stm32
的,也就是,相对于 STM32来说,PD7这时候是要设置为“输入”才可以。
相对应的,释放时钟线和数据线,请参考程序。注意,程序中,“等待设备
把时钟线拉低”,因为信号是从 PS2过来的,为了实现这个过程,我们使用了如
下方法:
1) 设置 PD7时钟信号为输入模式;
2) while(GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_7));
第 2)步骤即使用库函数 GPIO_ReadInputDataBit来检测 PD7是否已经被 PS2
拉低了。
其他操作方法类似,程序太长,这里没有全部给出,大家可以参考芯嵌 stm32
光盘中的例程。
4.24.24.24.2 函数函数函数函数 voidvoidvoidvoid EXTI9_5_IRQHandler(void)EXTI9_5_IRQHandler(void)EXTI9_5_IRQHandler(void)EXTI9_5_IRQHandler(void)
凡是从 PS2鼠标发送过来的数据,我们都采用中断进行。注意,这里讲的中
断接收数据,并不是一个中断能接收 1个完整的数据包,而是,一个中断只接收
一个数据位 bit。比如一个数据包有 4 个字节,为了接收其中一个字节数据,我
们设置了开始位,停止位,校验位,应答位等,因此,接收一个字节的数据,实
际上至少中断 11次,才能接收到 11个 bit。
接收数据,也有对应的步骤,请参考之前的文字。这里需要强调的是:
1) 检测时钟线电平,如果时钟线为低,则延时 50μs;
2) 检测判断时钟信号是否为高,为高,则向下执行,为低,则转到(1);
之前写的这前两步骤,是使用查询的方式,首先检测时钟线是否从低电平变
成高电平,以确定通信总线是否空闲。在芯嵌 stm32的例程中,由于中断模式设
置成“上升沿中断”,因此,实际上只要进入中断,就意味着 CLK 时钟线已经从
低电平变成高电平,所以,这两个步骤在进入中断时就完成了。
为了更明显地查看当前演示情况(鼠标移动时候,确实有数据接收并处理),
我们在一进入中断,就点灯,下次进中断就关灯,如此循环,只要在移动鼠标时,
发现 LED等在闪烁,就说明演示正确。
4.34.34.34.3 函数函数函数函数 voidvoidvoidvoid data_analyse(void)data_analyse(void)data_analyse(void)data_analyse(void)
此函数主要功能是,把接收到的数据(3-4 字节)进行分析,根据第 1 个字
节的 bit 标志,确定后续字节的操作。比如芯嵌 stm32例程要实现的是鼠标的移
动驱动 LCD 上光标的移动,那么就需要获取 X和 Y 的位移。因此需要确认第 1
个字节中的 X符号位,Y 符号位。根据符号位,即可知道 X 轴方向是左移还是
芯嵌 stm32 www.51stm32.com
Copyright © 2009-2014 福州芯嵌工作室 ALL rights reserved 14
右移,以确定要在原来的 X值上添加,还是减去。
以上就是 PS2鼠标在液晶屏上工作的原理过程,期待大家拍砖。如需拍砖,
请直接前往 www.51stm32.com猛拍,以促进芯嵌 STM32进一步改善教程,谢谢!
官方网站:http://www.51stm32.com/
官方淘宝:http://shop36353570.taobao.com/
PS2鼠标内部工作原理
1.1PS2鼠标基本工作原理
1.2鼠标分辨率和缩放比例
1.3Intelimouse的扩展
第二章鼠标工作模式和命令集
2.1工作模式
2.2命令集
第三章PS/2通讯协议
3.1PS/2设备到主机的通讯
3.2主机到PS/2设备的通讯
第四章PS2驱动程序
4.1函数voidPS2_Send_Cmd(u8cmd)
4.2函数voidEXTI9_5_IRQHandler(void)
4.3函数voiddata_analyse(void)