⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ps2接口的底层驱动.txt

📁 PS/2接口的底层驱动 //作者:古道热肠 //Email:xg_2004_sy@126.com //Blog: gdrc.bolg.21ic.com //版本:1.0 //完成日期:200
💻 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 + -