贴上源码,是Keil for ARM环境下编译的.
#include "Board.h" #include "AT91SAM7S64a.H" /* AT91SAMT7S64 definitions */ #include "lib_AT91SAM7S64a.h" #include "DataTypeDef.h" #include "DriverTimer.h"
#define DISABLE #define ENABLE //sbit PS2Kbd_Data = P1^0; //sbit PS2Kbd_Clk = P1^1;
#define PS2ClkToLow() AT91F_PIO_OutputEnable( AT91C_BASE_PIOA, PS2_CLK ) #define PS2ClkToHigh() AT91F_PIO_OutputDisable( AT91C_BASE_PIOA, PS2_CLK ) #define PS2DataToLow() AT91F_PIO_OutputEnable( AT91C_BASE_PIOA, PS2_Data ) #define PS2DataToHigh() AT91F_PIO_OutputDisable( AT91C_BASE_PIOA, PS2_Data )
#define PS2DataTransEnable() AT91F_PIO_OutputDisable( AT91C_BASE_PIOA, PS2_CLK ) #define PS2DataTransDisable() AT91F_PIO_OutputEnable( AT91C_BASE_PIOA, PS2_CLK )
uchar ucPS2CommErrFlag = 0;
//#define PS2KBD_DataIn T0 //#define PS2KBD_CLKIn INT1
//初始化硬件适应于PS/2接口进行通讯 void InitPS2HardWart(void) { AT91F_PIO_CfgOpendrain(AT91C_BASE_PIOA,PS2_CLK|PS2_Data); AT91F_PIO_CfgPullup(AT91C_BASE_PIOA,PS2_CLK|PS2_Data); PS2DataToHigh(); PS2ClkToLow(); // AT91F_PIO_MultiDriverEnable(AT91C_BASE_PIOA,PS2_CLK); // AT91F_PIO_MultiDriverEnable(AT91C_BASE_PIOA,PS2_Data); }
static bool GetPS2DataStatus(void) { unsigned int n; n = AT91F_PIO_GetInput( AT91C_BASE_PIOA);
return(n&PS2_Data);
}
static bool GetPS2ClkStatus(void) { unsigned int n; n = AT91F_PIO_GetInput( AT91C_BASE_PIOA);
return((n&PS2_CLK) ); }
/* static void Delay10Us(uchar ucDelayCount) { register uchar uci;
if(ucDelayCount == 0) { return; } for( ;ucDelayCount>0;ucDelayCount--) { for(uci=0; uci<30; uci++) { // _nop_(); } } } */
void Delay10Us(uchar ucDelayCount) { Delay_10US(ucDelayCount); }
static void CaptureClkLow(void) { while(1) { if(GetPS2ClkStatus()) { break; } }
while(1) { if(!GetPS2ClkStatus()) { // if(!GetPS2ClkStatus()) // { break; // } } } }
static void CaptureClkHigh(void) { while(1) { if(!GetPS2ClkStatus()) { break; } }
while(1) { if(GetPS2ClkStatus()) { // if(GetPS2ClkStatus()) // { 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
"); //先计算发送数据的奇校验值备用 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 ucCount; bool ucOddValue; uchar ucTempVal; uchar ucResult; uint uiDelayCount;
ucOddValue = true;
DISABLE; //Host释放总线控制权,让PS/2设备转换到数据发送状态,想发就快发,待会MCU要去干别的了. PS2DataTransEnable(); // Delay_10US(1); // PS2Kbd_Data=1; // PS2Kbd_Clk=1; // uiDelayCount = 0x1fffff; //关键时间 //捕获时钟下降沿,有超时退出机制,这段时间就是让PS/2设备响应时间 while(--uiDelayCount) { if(!GetPS2ClkStatus()) { // DISABLE; break; } }
//已经查询过了,没有数据要发上来,俺MCU去返回干别的去了. if(GetPS2ClkStatus()) //Repeat check { *ucGetChar = 0;
PS2DataTransDisable(); 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 = 2; // ComShowString(COM_1,"Odd Check ERR"); ENABLE; return false; // } } //获取停止位,必定为1 CaptureClkLow(); if(!GetPS2DataStatus()) { // if(!GetPS2DataStatus()) // {
ucPS2CommErrFlag = 3; // 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));
}
|
|