📄 ps2接口的底层驱动.txt
字号:
// 贴上俺以前用的PS/2接口的底层驱动来助兴—Q版注释
/*------------------------------------------------------------------
//作者:古道热肠
//Email:xg_2004_sy@126.com
//Blog: gdrc.bolg.21ic.com
//版本:1.0
//完成日期:2008-10-14
//硬件平台,51单片机IO口模拟PS/2协议与PS/2设备通讯
--------------------------------------------------------------------*/
//#include<conio.h>
#include "..\..\inc\includes.h"
sbit PS2Kbd_Data = P1^1;
sbit PS2Kbd_Clk = P1^2;
#define PS2ClkToLow() PS2Kbd_Clk=0
#define PS2ClkToHigh() PS2Kbd_Clk=1
#define PS2DataToLow() PS2Kbd_Data=0
#define PS2DataToHigh() PS2Kbd_Data=1
#define PS2DataTransEnable() PS2Kbd_Clk = 1
#define PS2DataTransDisable() PS2Kbd_Clk = 0
uchar ucPS2CommErrFlag = 0;
static bool GetPS2DataStatus(void)
{
// PS2Kbd_Data=1;
return(PS2Kbd_Data);
}
static bool GetPS2ClkStatus(void)
{
// PS2Kbd_Clk=1;
return(PS2Kbd_Clk);
}
static void Delay10Us(uchar ucDelayCount)
{
register uchar uci;
if(ucDelayCount == 0)
{
return;
}
for( ;ucDelayCount>0;ucDelayCount--)
{
for(uci=0; uci<30; uci++)
{
_nop_();
}
}
}
static void CaptureClkLow(void)
{
while(1)
{
if(GetPS2ClkStatus() == 1)
{
break;
}
}
while(1)
{
if(GetPS2ClkStatus() == 0)
{
if(GetPS2ClkStatus() == 0)
{
break;
}
}
}
}
static void CaptureClkHigh(void)
{
while(1)
{
if(GetPS2ClkStatus() == 0)
{
break;
}
}
while(1)
{
if(GetPS2ClkStatus() == 1)
{
if(GetPS2ClkStatus() == 1)
{
break;
}
}
}
}
/**************************************************
功能介绍:实现向PS2口发送1个字符的功能。
入口参数: 待发送的字符
返回: 发送是否成功。true 表示成功
备注:
***************************************************/
bool PS2_SendChar(uchar ucSendChar)
{
uchar ucCount;
bool ucOddValue;
uchar ucTempVal;
ucOddValue = true;
ucTempVal = ucSendChar;
// ComShowString(COM_1,"start Test pS2");
// printf("start Send char to Ps2 Kbd\n");
//先计算发送数据的奇校验值备用
for(ucCount=0; ucCount<8; ucCount++)
{
if(ucTempVal & 0x01)
{
ucOddValue = !ucOddValue;
}
ucTempVal >>= 1;
}
//抢占PS/2总线的控制权
PS2ClkToLow();
PS2DataToLow();
Delay10Us(10); //Delay100uS
DISABLE;
PS2ClkToHigh(); //通知PS/2设备,时机已成熟
//等待PS/2设备切换角色并发起数据接收的时序
ucTempVal = ucSendChar;
for(ucCount=0; ucCount<8; ucCount++)
{
//以下函数未设超时退出机制,如果设备不响应会死循环.
CaptureClkLow();
//捕获到下降沿后改变数据线的值.
if(ucTempVal & 0x01)
{
PS2DataToHigh();
}
else
{
PS2DataToLow();
}
ucTempVal >>= 1;
//发送到P2/2的数据位会在时钟的上升沿锁入PS/2设备中的.
}
//发送校验位
CaptureClkLow();
if(ucOddValue)
{
PS2DataToHigh();
}
else
{
PS2DataToLow();
}
//发送停止位
CaptureClkLow();
PS2DataToHigh();
//最后一个脉冲表示设备响应
//备注:根据PS/2协议,主机发往PS/2的数据在设备没有确认前,想取消还来得及
// 方法就是我先将数据线拉低,不让设备拉低应答,设备就会丢弃接收到的数据
// 至今想不明白IBM当年设计PS/2接口时为何要加这个规定.
CaptureClkLow();
if(GetPS2DataStatus() == 0)
{
CaptureClkHigh();
ENABLE;
return true;
}
else
{
CaptureClkHigh();
ENABLE;
return false;
}
}
//从PS/2端口获取PS/2发送的字符
static bool PS2_ReadChar(uchar *ucGetChar)
{
uchar data ucCount;
bool ucOddValue;
uchar ucTempVal;
uchar ucResult;
uint data uiDelayCount;
ucOddValue = true;
DISABLE;
//Host释放总线控制权,让PS/2设备转换到数据发送状态,想发就快发,待会MCU要去干别的了.
PS2DataTransEnable();
PS2Kbd_Data=1;
PS2Kbd_Clk=1;
//
uiDelayCount = 0x1ff; //关键时间
//捕获时钟下降沿,有超时退出机制,这段时间就是让PS/2设备响应时间
while(--uiDelayCount)
{
if(GetPS2ClkStatus() == 0)
{
// DISABLE;
break;
}
}
//已经查询过了,没有数据要发上来,俺MCU去返回干别的去了.
if(GetPS2ClkStatus() != 0) //Repeat check
{
*ucGetChar = 0;
ENABLE;
return false;
}
//每位在时钟的下降沿被主机读入
//读取起始位必定为0
if(GetPS2DataStatus())
{
if(GetPS2DataStatus())
{
*ucGetChar = 0;
ucPS2CommErrFlag = 1;
ComShowString(COM_1,"START BIT ERR");
ENABLE;
return false;
}
}
//读完起始位开始读取数据位
ucTempVal = 0x01;
ucResult = 0;
for(ucCount=0; ucCount<8; ucCount++)
{
CaptureClkLow();
if(GetPS2DataStatus())
{
ucResult |= ucTempVal;
ucOddValue = !ucOddValue; //计算校验值
}
ucTempVal <<= 1;
}
//读取奇校验位
CaptureClkLow();
if(GetPS2DataStatus() != ucOddValue)
{ //防抖动,不理想.
if(GetPS2DataStatus() != ucOddValue)
{
ucPS2CommErrFlag = 1;
ComShowString(COM_1,"Odd Check ERR");
ENABLE;
return false;
}
}
//获取停止位,必定为1
CaptureClkLow();
if(GetPS2DataStatus() == 0)
{
if(GetPS2DataStatus() == 0)
{
ucPS2CommErrFlag = 1;
ComShowString(COM_1,"STOP BIT ERR");
ENABLE;
return false;
}
}
//数据读取完成,置标志和结果转运
*ucGetChar = ucResult;
ucPS2CommErrFlag = 0;
//等待发送事件完成
CaptureClkHigh();
//禁止PS/2设备发送新数据,俺MCU有绝对控制权,要先去看看其它事件是否发生.有按键数据先自己缓存
PS2DataTransDisable();
ENABLE;
return true;
}
/**************************************************
功能介绍:实现从PS2口接收1个字符的功能。
入口参数: 接收字符存放的缓冲区指针
返回: 接收是否成功。true 表示成功
备注: 有延时等待发生。
***************************************************/
bool PS2_GetChar(uchar *ucGetChar)
{
/*
if(ucPS2CommErrFlag)
{
PS2_SendChar(0xFE);
BeepShort();
}
*/
return (PS2_ReadChar(ucGetChar));
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -