PS/2作为电脑的标准输入接口,用于鼠标键盘等设备。PS/2只需要一个简单的接口(2个IO口),就可以外扩鼠标、键盘等,是单片机理想的输入外扩方式。
MiniSTM32也自带了PS/2接口,可以用来驱动标准的鼠标、键盘等外设,也可以用来驱动一些PS/2接口的小键盘。本节将向大家介绍,如何在ALIENTEK MiniSTM32开发板上,通过PS/2接口来驱动电脑鼠标。本节分为如下几个部分:
3.23.1 PS/2简介
3.23.2 硬件设计
3.23.3 软件设计
3.23.4 下载与测试
3.23.1 PS/2简介
PS/2是电脑上常见的接口之一,用于鼠标、键盘等设备。一般情况下,PS/2接口的鼠标为绿色,键盘为紫色。
PS/2接口是输入装置接口,而不是传输接口。所以PS2口根本没有传输速率的概念,只有扫描速率。在Windows环境下,ps/2鼠标的采样率默认为60次/秒,USB鼠标的采样率为120次/秒。较高的采样率理论上可以提高鼠标的移动精度。
物理上的PS/2端口可有2种,一种是5脚的,一种是六脚的。下面给出这两种PS/2接口的引脚定义图:
图3.23.1.1PS/2引脚定义图
从图中可以看出,不管是5脚还是6脚的PS/2接头,都是有4跟有用的线连接:时钟线、数据线、电源线、地线。PS/2设备的电源是5V的,而数据线和时钟线均是集电极开路的,这两根信号线都需要接一个上拉电阻(开发板上使用的是10K)。
PS/2 鼠标和键盘遵循一种双向同步串行协议,换句话说每次数据线上发送一位数据并且每在时钟线上发一个脉冲就被读入。键盘/鼠标可以发送数据到主机,而主机也可以发送数据到设备,但主机总是在总线上有优先权,它可以在任何时候抑制来自于键盘/鼠标的通讯,只要把时钟拉低即可。
从设备到主机的数据在时钟信号的下降沿被主机读取,而从主机到设备的数据在时钟信号的上升沿被设备读取。不论通信方向如何,时钟总是由设备产生的,最大的时钟频率为33Khz,大多数设备工作在10~20Khz。
鼠标键盘,采用的是一种每帧包含11/12位的串行协议,这些位的含义如下:
图 3.23.1.2鼠标/键盘帧数据格式
上图中校验位的含义是:如果数据位中包含偶数个1,则校验位为1;如果数据位中包含奇数个1,则校验位为0。数据位中的1的个数加上校验位总为奇数(奇校验),用于数据侦错。当主机发送数据给键盘/鼠标的时候,设备会发送一个握手信号来应答数据已经被收到了,该位不会出现在设备到主机的通信中。
设备到主机的通信过程:
正常情况下数据线和时钟线都是高电平,当键盘/鼠标有数据要发送时,它先检测时钟线,确认时钟线是高电平。如果不是,则是主机抑制了通信,设备必须缓冲任何要发送的数据,直到重新获得总线的控制权(键盘有16 字节的缓冲区而鼠标的缓冲区仅存储最后一个要发送的数据包)。如果时钟线是高电平,设备就可以开始传送数据了。
设备到主机的数据在时钟线的下降沿被主机读入,如下图所示:
图3.23.1.3设备到主机通信时序图
主机可以在设备发送数据的时候拉低时钟线来来放弃当前数据的传送。
主机到设备的通信过程:
主机到设备的通信与设备到主机的通信有点不同,因为PS/2的时钟总是由设备产生的,如果主机要发送数据,则它必须首先把时钟线和数据线设置为请求发送状态。请求发送状态通过如下过程实现:
1.拉低时钟线至少100us以抑制通信。
2.拉低数据线,以应用“请求发送”,然后释放时钟线。
设备在不超过10ms的时间内就会检测这个状态,当设备检测到这个状态后,它将开始产生时钟信号,并且在设备提供的时钟脉冲驱动下输入八个数据位和一个停止位。主机仅当时钟线为低的时候改变数据线,而数据在时钟脉冲的上升沿被锁存,这与发生在设备到主机通讯的过程中正好相反。
主机到设备的通信时序图如下图所示:
图3.23.1.4主机到设备通信时序图
以上简单介绍了PS/2协议的通信过程,更多的介绍请参考《PS/2技术参考》一文。本节我们要驱动一个PS/2鼠标,所以接下来简单介绍一下PS/2鼠标的相关信息。
标准的PS/2鼠标支持下面的输入:X(左右)位移、Y(上下)位移、左键、中键和右键。但是我们目前用到鼠标大都还有滚轮,有的还有更多的按键,这就是所谓的Intellimouse。它支持5个鼠标按键和三个位移轴(左右、上下和滚轮)。
标准的鼠标有两个计数器保持位移的跟踪:X 位移计数器和Y 位移计数器。可存放9 位的2 进制补码,并且每个计数器都有相关的溢出标志。它们的内容连同三个鼠标按钮的状态一起以三字节移动数据包的形式发送给主机,位移计数器表示从最后一次位移数据包被送往主机后所发生的位移量。
标准PS/2鼠标发送唯一和按键信息以3字节的数据包格式发给主机,三个数据包的意义如下图:
图3.23.1.5 标准鼠标位移数据包格式
位移计数器是一个9位2的补码整数,其最高位作为符号位出现在位移数据包的第一个字节里。这些计数器在鼠标读取输入发现有位移时被更新。这些值是自从最后一次发送位移数据包给主机后位移的累计量(即最后一次包发给主机后位移计数器被复位位移计数器可表示的值的范围是-255 到+255)。如果超过了范围,相应的溢出位就会被置位,并在复位之前,计数器不会再增减。
而所谓的Intellimouse,因为多了2个按键和一个滚轮,所以Intellimouse的一个位移数据包由4个字节组成,如下图所示:

图3.23.1.6 Intellimouse鼠标位移数据包格式
Z0-Z3是2的补码,用于表示从上次数据报告以来滚轮的位移量。有效范围从-8 到+7,第四键如果按下,则4th Btn位被置位,如果没有按下,则4th Btn位为0。第五键也与此类似。
鼠标的介绍我们就简单的介绍到这里,详细的说明请参考《PS/2技术参考》第三章 PS/2鼠标接口(第36页)。
3.23.2 硬件设计
本节实验功能简介:开机的时候先检测是否有鼠标接入,如果没有/检测错误,则提示错误代码。只有在检测到PS/2鼠标之后才开始后续操作,当检测到鼠标之后,就在LCD上显示鼠标位移数据包的内容,并转换为坐标值,在LCD上显示,如果有按键按下,则会提示你按下的是哪个按键。同样我们也是用LED0来指示程序正在运行。
所要用到的硬件资源如下:
1)STM32F103RBT6。
2)DS0(外部LED0)。
3)TFTLCD液晶模块。
4)PS2鼠标。
前面三部分,在之前的实例已经介绍过了,下面简单看一下PS/2接口与STM32的连接电路图,如下图所示:
图3.23.2.1 PS/2与STM32的连接电路图
可以看到,PS/2接口与STM32的连接仅仅2个IO口,但是是与JTAG/SMD复用的,所以在开启了PS/2以后,JTAG与SMD都不能使用了。
3.23.3 软件设计
打开上一节的工程,首先在HARDWARE文件夹下新建一个PS2和MOUSE的文件夹。在PS2文件夹里面新建ps2.c和ps2.h两个文件。然后在MOUSE文件夹下新建mouse.c和mouse.h两个文件。并将这个两个文件夹加入头文件包含路径。
打开ps2.c,输入如下代码:
#include"ps2.h"
#include"usart.h"
//MiniSTM32开发板
//PS2驱动代码
//正点原子@ALIENTEK
//2010/6/17
//PS2产生的时钟频率在10~20Khz(最大33K)
//高/低电平的持续时间为25~50us之间.
//PS2_Status当前状态标志
//[5:4]:当前工作的模式;[7]:接收到一次数据
//[6]:校验错误;[3:0]:收到的数据长度;
u8PS2_Status=CMDMODE; //默认为命令模式
u8PS2_DATA_BUF[16]; //ps2数据缓存区
//位计数器
u8BIT_Count=0;
//中断15~10处理函数
//每11个bit,为接收1个字节
//每接收完一个包(11位)后,设备至少会等待50ms再发送下一个包
//只做了鼠标部分,键盘部分暂时未加入
//CHECKOK 2010/5/2
voidEXTI15_10_IRQHandler(void)
{ static u8 tempdata=0;
static u8 parity=0;
if(EXTI-> R&(1<<15))//中断15产生了相应的中断
{ EXTI-> R=1<<15; //清除LINE15上的中断标志位
if(BIT_Count==0)
{ parity=0;
tempdata=0;
}
BIT_Count++;
if(BIT_Count>1&&BIT_Count<10)//这里获得数据
{ tempdata>>=1;
if(PS2_SDA)
{ tempdata|=0x80;
parity++;//记录1的个数
}
}else if(BIT_Count==10)//得到校验位
{ if(PS2_SDA)parity|=0x80;//校验位为1
}
if(BIT_Count==11)//接收到1个字节的数据了
{ BIT_Count=parity&0x7f;//取得1的个数
if(((BIT_Count%2==0)&&(parity&0x80))||((BIT_Count%2==1)&&(parity&0x80)==0))//奇偶校验OK
{ //PS2_Status|=1<<7;//标记得到数据 BIT_Count=PS2_Status&0x0f;
PS2_DATA_BUF[BIT_Count]=tempdata;//保存数据
if(BIT_Count<15)PS2_Status++; //数据长度加1
BIT_Count=PS2_Status&0x30; //得到模式
switch(BIT_Count)
{
caseCMDMODE://命令模式下,每收到一个字节都会产生接收完成
PS2_Dis_Data_Report();//禁止数据传输
PS2_Status|=1<<7;//标记得到数据
break;
caseKEYBOARD:
break;
caseMOUSE:
if(MOUSE_ID==0)//标准鼠标,3个字节
{
if((PS2_Status&0x0f)==3)
{
PS2_Status|=1<<7;//标记得到数据
PS2_Dis_Data_Report();//禁止数据传输
}
}elseif(MOUSE_ID==3)//扩展鼠标,4个字节
{
if((PS2_Status&0x0f)==4)
{
PS2_Status|=1<<7;//标记得到数据
PS2_Dis_Data_Report();//禁止数据传输
}
}
break;
}
}else
{
PS2_Status|=1<<6;//标记校验错误
PS2_Status&=0xf0;//清除接收数据计数器
}
BIT_Count=0;
}
}
}
//禁止数据传输
//把时钟线拉低,禁止数据传输
//CHECKOK 2010/5/2
voidPS2_Dis_Data_Report(void)
{
PS2_Set_Int(0); //关闭中断
PS2_SET_SCL_OUT();//设置SCL为输出
PS2_SCL_OUT=0; //抑制传输
}
//使能数据传输
//释放时钟线
//CHECKOK 2010/5/2
voidPS2_En_Data_Report(void)
{
PS2_SET_SCL_IN(); //设置SCL为输入
PS2_SET_SDA_IN(); //SDA IN
PS2_SCL_OUT=1; //上拉
PS2_SDA_OUT=1;
PS2_Set_Int(1); //开启中断
}
//PS2中断屏蔽设置
//en:1,开启;0,关闭;
//CHECKOK 2010/5/2
voidPS2_Set_Int(u8 en)
{ EXTI-> R=1<<15; //清除LINE15上的中断标志位
if(en)EXTI->IMR|=1<<15;//不屏蔽line15上的中断
else EXTI->IMR&=~(1<<15);//屏蔽line15上的中断
}
//等待PS2时钟线sta状态改变
//sta:1,等待变为1;0,等待变为0;
//返回值:0,时钟线变成了sta;1,超时溢出;
//CHECKOK 2010/5/2
u8Wait_PS2_Scl(u8 sta)
{
u16 t=0;
sta=!sta;
while(PS2_SCL==sta)
{ delay_us(1);
t++;
if(t>16000)return 1;//时间溢出 (设备会在10ms内检测这个状态)
}
return 0;//被拉低了
}
//在发送命令/数据之后,等待设备应带,该函数用来获取应答
//返回得到的值
//返回0,且PS2_Status.6=1,则产生了错误
//CHECKOK 2010/5/2
u8PS2_Get_Byte(void)
{
u16 t=0;
u8 temp=0;
while(1)//最大等待55ms
{ t++;
delay_us(10);
if(PS2_Status&0x80)//得到了一次数据
{ temp=PS2_DATA_BUF[PS2_Status&0x0f-1];
PS2_Status&=0x70;//清除计数器,接收到数据标记
break;
}elseif(t>5500||PS2_Status&0x40)break;//超时溢出/接收错误
}
PS2_En_Data_Report();//使能数据传输
return temp;
}
//发送一个命令到PS2.
//返回值:0,无错误,其他,错误代码
u8PS2_Send_Cmd(u8 cmd)
{
u8 i;
u8 high=0;//记录1的个数
PS2_Set_Int(0); //屏蔽中断
PS2_SET_SCL_OUT();//设置SCL为输出
PS2_SET_SDA_OUT();//SDA OUT
PS2_SCL_OUT=0;//拉低时钟线
delay_us(120);//保持至少100us
PS2_SDA_OUT=0;//拉低数据线
delay_us(10);
PS2_SET_SCL_IN();//释放时钟线,这里PS2设备得到第一个位,开始位
PS2_SCL_OUT=1;
if(Wait_PS2_Scl(0)==0)//等待时钟拉低
{ for(i=0;i<8;i++)
{ if(cmd&0x01)
{
PS2_SDA_OUT=1;
high++;
}else PS2_SDA_OUT=0;
cmd>>=1;
//这些地方没有检测错误,因为这些地方不会产生死循环
Wait_PS2_Scl(1);//等待时钟拉高 发送8个位
Wait_PS2_Scl(0);//等待时钟拉低
}
if((high%2)==0)PS2_SDA_OUT=1;//发送校验位 10
else PS2_SDA_OUT=0;
Wait_PS2_Scl(1); //等待时钟拉高 10位
Wait_PS2_Scl(0); //等待时钟拉低
PS2_SDA_OUT=1; //发送停止位 11
Wait_PS2_Scl(1);//等待时钟拉高 11位
PS2_SET_SDA_IN();//SDA in
Wait_PS2_Scl(0);//等待时钟拉低
if(PS2_SDA==0)Wait_PS2_Scl(1);//等待时钟拉高 12位
else
{ PS2_En_Data_Report();
return 1;//发送失败
}
}else
{ PS2_En_Data_Report();
return 2;//发送失败
}
PS2_En_Data_Report();
return 0; //发送成功
}
//PS2初始化
//CHECKOK 2010/5/2
voidPS2_Init(void)
{RCC->APB2ENR|=1<<2; //使能PORTA时钟
RCC->APB2ENR|=1<<0; //开启辅助时钟
AFIO->MAPR&=~(7<<24);
AFIO->MAPR|=4<<24; //关闭JTAG
GPIOA->CRH&=0X0F0FFFFF;//PA13,15设置成输入
GPIOA->CRH|=0X80800000;//PA13,15设置成输出
GPIOA->ODR|=5<<13;
AFIO->EXTICR[3]&=0XFFFF0FFF;//EXTI15映射到PA15
AFIO->EXTICR[3]|=0<<12; //EXTI15映射到PA15
EXTI->IMR|=1<<15; //开启line15上的中断
EXTI->EMR|=1<<15; //不屏蔽line15上的事件
EXTI->FTSR|=1<<15; //line15 上事件下降沿触发
MY_NVIC_Init(1,2,EXTI15_10_IRQChannel,2);//分配到第二组,抢占2,响应3
}
该部分为底层的PS/2协议驱动程序,采用中断接收PS/2设备产生的时钟信号,然后解析。保存ps2.c文件,并加入到HARDWARE组下,然后打开ps2.h,在该文件里面输入如下代码:
#ifndef__PS2_H
#define__PS2_H
#include"delay.h"
#include"sys.h"
//MiniSTM32开发板
//PS2驱动代码
//正点原子@ALIENTEK
//2010/6/17
//物理接口定义
//PS2输入
#definePS2_SCL PAin(15) //PA15
#definePS2_SDA PAin(13) //PA13
//PS2输出
#definePS2_SCL_OUT PAout(15) //PA15
#definePS2_SDA_OUT PAout(13) //PA13
//设置PS2_SCL输入输出状态.
#definePS2_SET_SCL_IN() {GPIOA->CRH&=0X0FFFFFFF;GPIOA->CRH|=0X80000000;}
#definePS2_SET_SCL_OUT() {GPIOA->CRH&=0X0FFFFFFF;GPIOA->CRH|=0X30000000;}
//设置PS2_SDA输入输出状态.
#definePS2_SET_SDA_IN() {GPIOA->CRH&=0XFF0FFFFF;GPIOA->CRH|=0X00800000;}
#definePS2_SET_SDA_OUT() {GPIOA->CRH&=0XFF0FFFFF;GPIOA->CRH|=0X00300000;}
#defineMOUSE 0X20 //鼠标模式
#defineKEYBOARD 0X10 //键盘模式
#defineCMDMODE 0X00 //发送命令
//PS2_Status当前状态标志
//[5:4]:当前工作的模式;[7]:接收到一次数据
//[6]:校验错误;[3:0]:收到的数据长度;
externu8 PS2_Status; //定义为命令模式
externu8 PS2_DATA_BUF[16]; //ps2数据缓存区
externu8 MOUSE_ID;
voidPS2_Init(void);
u8PS2_Send_Cmd(u8 cmd);
voidPS2_Set_Int(u8 en);
u8PS2_Get_Byte(void);
voidPS2_En_Data_Report(void);
voidPS2_Dis_Data_Report(void);
#endif
此部分代码我们不多说,保存。然后打开mouse.c,输入如下代码:
#include"mouse.h"
#include"usart.h"
#include"lcd.h"
//MiniSTM32开发板
//鼠标 驱动代码
//正点原子@ALIENTEK
//2010/6/17
u8MOUSE_ID;//用来标记鼠标ID
PS2_MouseMouseX;
//处理MOUSE的数据
//CHECKOK 2010/5/2
voidMouse_Data_Pro(void)
{
MouseX.x_pos+=(signed char)PS2_DATA_BUF[1];
MouseX.y_pos+=(signed char)PS2_DATA_BUF[2];
MouseX.z_pos+=(signed char)PS2_DATA_BUF[3];
MouseX.bt_mask=PS2_DATA_BUF[0]&0X07;//取出掩码
}
//初始化鼠标
//返回:0,初始化成功
//其他:错误代码
//CHECKOK 2010/5/2
u8Init_Mouse(void)
{
u8 t;
PS2_Init();
PS2_Status=CMDMODE; //进入命令模式
delay_ms(500); //等待上电复位完成
t=PS2_Send_Cmd(PS_RESET); //复位鼠标
if(t!=0)return 1;
t=PS2_Get_Byte();
if(t!=0XFA)return 2;
t=0;
while((PS2_Status&0x80)==0)//等待复位完毕
{ t++;
delay_ms(10);
if(t>50)return 3;
}
PS2_Get_Byte();//得到0XAA
PS2_Get_Byte();//得到ID 0X00
//进入滚轮模式的特殊初始化序列
PS2_Send_Cmd(SET_SAMPLE_RATE);//进入设置采样率
if(PS2_Get_Byte()!=0XFA)return 4;//传输失败
PS2_Send_Cmd(0XC8);//采样率200
if(PS2_Get_Byte()!=0XFA)return 5;//传输失败
PS2_Send_Cmd(SET_SAMPLE_RATE);//进入设置采样率
if(PS2_Get_Byte()!=0XFA)return 6;//传输失败
PS2_Send_Cmd(0X64);//采样率100
if(PS2_Get_Byte()!=0XFA)return 7;//传输失败
PS2_Send_Cmd(SET_SAMPLE_RATE);//进入设置采样率
if(PS2_Get_Byte()!=0XFA)return 8;//传输失败
PS2_Send_Cmd(0X50);//采样率80
if(PS2_Get_Byte()!=0XFA)return 9;//传输失败
//序列完成
PS2_Send_Cmd(GET_DEVICE_ID); //读取ID
if(PS2_Get_Byte()!=0XFA)return 10;//传输失败
MOUSE_ID=PS2_Get_Byte();//得到MOUSE ID
PS2_Send_Cmd(SET_SAMPLE_RATE);//再次进入设置采样率
if(PS2_Get_Byte()!=0XFA)return 11;//传输失败
PS2_Send_Cmd(0X0A);//采样率10
if(PS2_Get_Byte()!=0XFA)return 12;//传输失败
PS2_Send_Cmd(GET_DEVICE_ID); //读取ID
if(PS2_Get_Byte()!=0XFA)return 13;//传输失败
MOUSE_ID=PS2_Get_Byte();//得到MOUSE ID
PS2_Send_Cmd(SET_RESOLUTION); //设置分辨率
if(PS2_Get_Byte()!=0XFA)return 14;//传输失败
PS2_Send_Cmd(0X03);//8点/mm
if(PS2_Get_Byte()!=0XFA)return 15;//传输失败
PS2_Send_Cmd(SET_SCALING11); //设置缩放比率为1:1
if(PS2_Get_Byte()!=0XFA)return 16;//传输失败
PS2_Send_Cmd(SET_SAMPLE_RATE);//设置采样率
if(PS2_Get_Byte()!=0XFA)return 17;//传输失败
PS2_Send_Cmd(0X28);//40
if(PS2_Get_Byte()!=0XFA)return 18;//传输失败
PS2_Send_Cmd(EN_DATA_REPORT); //使能数据报告
if(PS2_Get_Byte()!=0XFA)return 19;//传输失败
PS2_Status=MOUSE;//进入鼠标模式
return 0;//无错误,初始化成功
}
该部分仅2个函数,Init_Mouse用于初始化鼠标,让鼠标进入Intellimouse模式,里面的初始化序列完全按照《PS/2技术参考》里面介绍的来设计。另外一个函数就是将收到的数据简单处理一下。保存mouse.c,然后打开mouse.h,输入如下内容:
#ifndef__MOUSE_H
#define__MOUSE_H
#include"ps2.h"
//MiniSTM32开发板
//鼠标 驱动代码
//正点原子@ALIENTEK
//2010/6/17
//HOST->DEVICE的命令集
#definePS_RESET 0XFF //复位命令 回应0XFA
#defineRESEND 0XFE//再次发送
#defineSET_DEFAULT 0XF6 //使用默认设置 回应0XFA
#defineDIS_DATA_REPORT 0XF5 //禁用数据报告 回应0XFA
#defineEN_DATA_REPORT 0XF4 //使能数据报告 回应0XFA
#defineSET_SAMPLE_RATE 0XF3//设置采样速率 回应0XFA
#defineGET_DEVICE_ID 0XF2 //得到设备ID 回应0XFA+ID
#defineSET_REMOTE_MODE 0XF0 //设置到REMOTE模式 回应OXFA
#defineSET_WRAP_MODE 0XEE //设置到WRAP模式 回应0XFA
#defineRST_WRAP_MODE 0XEC //回到WRAP之前的模式 回应0XFA
#defineREAD_DATA 0XEB //读取数据回应0XFA+位移数据包
#defineSET_STREAM_MODE 0XEA //设置到STREAM模式 回应0XFA
#defineSTATUS_REQUEST 0XE9 //请求得到状态 回应0XFA+3个字节
#defineSET_RESOLUTION 0XE8 //设置分辨率 回应OXFA+读取1个字节+应带0XFA
#defineSET_SCALING21 0XE7 //设置缩放比率为2:1 回应0XFA
#defineSET_SCALING11 0XE6 //设置缩放比率为1:1 回应0XFA
//DEVICE->HOST的指令
#defineERROR 0XFC//错误
//#defineRESEND 0XFE//再次发送
//鼠标结构体
typedefstruct
{ short x_pos;//横坐标
short y_pos;//纵坐标
short z_pos;//滚轮坐标
u8 bt_mask;//按键标识,bit2中间键;bit1,右键;bit0,左键
}PS2_Mouse;
externPS2_Mouse MouseX;
externu8 MOUSE_ID;//鼠标ID,0X00,表示标准鼠标(3字节);0X03表示扩展鼠标(4字节)
u8Init_Mouse(void);
voidMouse_Data_Pro(void);
#endif
该部分代码定义了一个鼠标结构体,用于存放鼠标相关的数据,并对鼠标的相关命令进行了宏定义。保存此部分代码,我们就剩下最后一步了,打开test.c文件,在里面修改main函数如下:
intmain(void)
{ u8 t;
u8 errcnt=0;
Stm32_Clock_Init(9);//系统时钟设置
delay_init(72); //延时初始化
uart_init(72,9600); //串口1初始化
LCD_Init(); //初始化液晶
//KEY_Init(); //按键初始化
LED_Init(); //LED初始化
POINT_COLOR=RED;//设置字体为红色
LCD_ShowString(60,50,"MiniSTM32");
LCD_ShowString(60,70,"PS2 MouseTEST");
LCD_ShowString(60,90,"ATOM@ALIENTEK");
LCD_ShowString(60,110,"2010/6/17");
RST:t=Init_Mouse();
if(t==0)LCD_ShowString(60,130,"MouseInit OK!");
else
{ printf("ERROR_CODE:%d\n",t);
LCD_ShowString(60,130,"ErrorCODE:");
LCD_ShowNum(148,130,t,3,16);//填充模式
LED0=!LED0;
//delay_ms(500);
goto RST;
}
POINT_COLOR=BLUE;
LCD_ShowString(60,150,"MouseID:");
LCD_ShowNum(132,150,MOUSE_ID,3,16);//填充模式
LCD_ShowString(30,170,"BUF[0]:");
LCD_ShowString(30,186,"BUF[1]:");
LCD_ShowString(30,202,"BUF[2]:");
if(MOUSE_ID==3)LCD_ShowString(30,218,"BUF[3]:");
LCD_ShowString(90+30,170,"X POS:");
LCD_ShowString(90+30,186,"Y POS:");
LCD_ShowString(90+30,202,"Z POS:");
if(MOUSE_ID==3)LCD_ShowString(90+30,218,"BUTTON:");
t=0;
while(1)
{ if(PS2_Status&0x80)//得到了一次数据
{ LCD_ShowNum(56+30,170,PS2_DATA_BUF[0],3,16);//填充模LCD_ShowNum(56+30,186,PS2_DATA_BUF[1],3,16);//填充模式LCD_ShowNum(56+30,202,PS2_DATA_BUF[2],3,16);//填充模式
if(MOUSE_ID==3)LCD_ShowNum(56+30,218,PS2_DATA_BUF[3],3,16);//填充模式
Mouse_Data_Pro();//处理数据
LCD_ShowNum(146+30,170,MouseX.x_pos,5,16);//填充模式
LCD_ShowNum(146+30,186,MouseX.y_pos,5,16);//填充模式
if(MOUSE_ID==3)LCD_ShowNum(146+30,202,MouseX.z_pos,5,16);//填充模式
if(MouseX.bt_mask&0x01)LCD_ShowString(146+30,218,"LEFT");
elseLCD_ShowString(146+30,218," ");
if(MouseX.bt_mask&0x02)LCD_ShowString(146+30,234,"RIGHT");
elseLCD_ShowString(146+30,234," ");
if(MouseX.bt_mask&0x04)LCD_ShowString(146+30,250,"MIDDLE");
elseLCD_ShowString(146+30,250," ");
PS2_Status=MOUSE;
PS2_En_Data_Report();//使能数据报告
}else if(PS2_Status&0x40)
{errcnt++;
PS2_Status=MOUSE;
LCD_ShowNum(86+30,234,errcnt,3,16);//填充模式
}
t++;
delay_ms(1);
if(t==200)
{ t=0; LED0=!LED0;
}
}
}
至此,PS/2鼠标实验的软件设计部分就结束了。
3.23.4 下载与测试
在代码编译成功之后,我们通过下载代码到ALIENTEK MiniSTM32开发板上,可以看到LCD显示如下内容(假定PS/2鼠标已经接上,并且初始化成功):
图3.23.4.1 PS/2鼠标实验显示结果
移动鼠标,或者按动按键,就可以看到上面的数据不断变化,证明我们的鼠标已经成功被驱动了,接下来我们就可以使用鼠标来控制STM32了。
|