📄 ps2键盘(at45db011).c
字号:
unsigned char count;
unsigned int Temp;
byte=byte<<(16-num_of_bits);
for(count=0;count<num_of_bits;count++)
{
Temp=byte&0x8000;
if(Temp==0x8000) SPI45DB041_SI=1; //高位为“1”,则送“1”
else SPI45DB041_SI=0; //高位为“0”,则送“0”
SPI45DB041_SCK=1;
SPI45DB041_SCK=0;
byte<<=1;
}
}
/********************************************************\
* 函数名:ReadOnePageToBuffer1
作用域:外部文件调用
* 功能: 读主存储区一个页的数据到buffer1。
* 参数: PageAddress 需要读的主存储区的页地址
* 返回值:无
\********************************************************/
void ReadOnePageToBuffer(unsigned int PageAddress)
{
SPI45DB041_CS=0;
SPI45D041_WriteBits(0x53,8); //送8 bit 的命令字
SPI45D041_WriteBits(0x00,6); //送4 bit 的保留位
SPI45D041_WriteBits(PageAddress,9); //送11位的页地址
SPI45D041_WriteBits(0x00,9); //送9位的页内地址
SPI45DB041_CS=1;
SPI45DB041_CS=0;
SPI45D041_WriteBits(0x57,8); //读状态命令字(读页到Buffer2的命令)
gWait_Process_Timer=0;
while(gWait_Process_Timer<50)
{
if(SPI45D041_ReadByte() & 0x80 !=0) return; //bit=1,器件不忙
}
SPI45DB041_CS=1;
}
/********************************************************\
* 函数名:ReadByteFromBuffer1
作用域:外部文件调用
* 功能: 在buffer1中的一个指定地址读一个字节的数据
* 参数: ByteAddress 指定字节在页内的地址
* 返回值:
\********************************************************/
unsigned char ReadByteFromBuffer(unsigned int ByteAddress)
{
unsigned char Buffer1OneByte;
SPI45DB041_CS=0;
SPI45D041_WriteBits(0x54,8); //送8 bit 的命令字
SPI45D041_WriteBits(0x00,15); //送15 bit 的保留位
SPI45D041_WriteBits(ByteAddress,9);//送11位的页地址
SPI45D041_WriteBits(0x00,8); //送8 bit 的保留位
Buffer1OneByte=SPI45D041_ReadByte();
return(Buffer1OneByte);
}
/********************************************************\
* 函数名:ReadNextFromBuffer1
作用域:外部文件调用
* 功能: 读buffer1中的下一个地址的字节数据(配合的与ReadByteBuffer1一起使用)
* 参数: 无
* 返回值:Buffer1NextByte
\********************************************************/
unsigned char ReadNextFromBuffer(void)
{
unsigned char Buffer1NextByte;
Buffer1NextByte=SPI45D041_ReadByte();
return(Buffer1NextByte);
}
/********************************************************\
* 函数名:WriteOneByteToBuffer1
作用域:外部文件调用
* 功能: 在buffer1中的一个指定的地址写一个字节
* 参数:
* 返回值:
\********************************************************/
void WriteOneByteToBuffer(unsigned int ByteAddress,unsigned char WriteOneByte )
{
SPI45DB041_CS=0;
SPI45D041_WriteBits(0x84,8); //送8 bit 的命令字
SPI45D041_WriteBits(0x00,15); //送15 bit 的NOP
SPI45D041_WriteBits(ByteAddress,9); //送9 bit 的页内地址
SPI45D041_WriteBits(WriteOneByte,8);
}
/********************************************************\
* 函数名:WriteNextByteToBuffer1
作用域:外部文件调用
* 功能: 写buffer1中的下一个地址(必须配合WriteOneByteToBuffer1一起使用)
* 参数:
* 返回值:
\********************************************************/
void WriteNextByteToBuffer(unsigned char WriteNextOne)
{
SPI45D041_WriteBits(WriteNextOne,8);
}
/********************************************************\
作用域:外部文件调用
* 功能: 带自动刷新将buffer1写到主存储页
* 参数: 主存储页地址
* 返回值:无
\********************************************************/
void WriteBufferToPageWithErase(unsigned int PageAddress)
{
SPI45DB041_CS=0;
//nop();
SPI45D041_WriteBits(0x83,8); //送8 bit 的命令字
SPI45D041_WriteBits(0x00,6); //送4 bit 的保留位
SPI45D041_WriteBits(PageAddress,9); //送11 bit 的页地址
SPI45D041_WriteBits(0x00,9); //送9 bit 的NOP
SPI45DB041_CS=1;
SPI45DB041_CS=0;
//nop();
SPI45D041_WriteBits(0x57,8); //读状态命令字
gWait_Process_Timer=0;
while(gWait_Process_Timer < 200)
{
if((SPI45D041_ReadByte() & 0x80) != 0) break; //bit=1,器件不忙
}
SPI45DB041_CS=1;
}
/********************************************************\
* 函数名:WriteClearAllToBuffer1
作用域:外部文件调用
* 功能: 将Buffer1清零(必须配合WriteOneByteToBuffer1一起使用)
* 参数:
* 返回值:
\********************************************************/
void WriteClearAllBuffer(void)
{
unsigned int i;
WriteOneByteToBuffer(0x00,0);
for(i=0;i<263;i++)
{
WriteNextByteToBuffer(0);
}
SPI45DB041_CS=1;
}
//=========================================送一个字节到大键盘=====================================
//注意:每次跳出后都要抑制时钟线
bit Send_LKB_Data(unsigned char DataofSend)
{
bit cp;
unsigned char i;
unsigned int t;
unsigned char Data_of_Send;
Data_of_Send=DataofSend;
ACC=Data_of_Send; //如果累加器中“1”的个数为奇数,则P=1
if(P==0) cp=1; //如果数据位中包含偶数个1 校验位就会置1 如果数据位中
//包含奇数个1 校验位就会置0 数据位中1 的个数加上校验
//位总为奇数这就是奇校验这是用来错误检测
else cp=0;
TR0=0; //关闭定时器,以免影响时序
LKB_SDA=0; //拉低数据线请求发送
LKB_SCLK=1; //时钟线较权
for(t=0;;)
{
if(LKB_SCLK==1) break; //等待设备拉低数据线
t++;
if(t>=20000)
{
TR0=1;LKB_SCLK=0;
return(0);
}
}
for(i=0;i<8;i++)
{
for(t=0;;)
{
if(LKB_SCLK==0) break;
t++;
if(t>=200)
{
TR0=1;LKB_SDA=1;LKB_SCLK=0;
return(0);
}
}
if((Data_of_Send&(0x01<<i))!=0) LKB_SDA=1;
else LKB_SDA=0;
for(t=0;;)
{
if(LKB_SCLK==1) break;
t++;
if(t>=200)
{
TR0=1;LKB_SDA=1;LKB_SCLK=0;
return(0);
}
}
}
for(t=0;;)
{
if(LKB_SCLK==0) break;
t++;
if(t>=200)
{
TR0=1;LKB_SDA=1;LKB_SCLK=0;
return(0);
}
}
if(cp==1) LKB_SDA=1; //发校验位
else LKB_SDA=0;
for(t=0;;)
{
if(LKB_SCLK==1) break;
t++;
if(t>=200)
{
TR0=1;
LKB_SDA=1;LKB_SCLK=0;
return(0);
}
}
for(t=0;;)
{
if(LKB_SCLK==0) break;
t++;
if(t>=200)
{
TR0=1;LKB_SDA=1;LKB_SCLK=0;
return(0);
}
}
LKB_SDA=1; //释放数据线(相当于送停止位)
for(t=0;;)
{
if(LKB_SCLK==1) break; //等待设备拉低数据线
t++;
if(t>=200)
{
TR0=1;LKB_SCLK=0;
return(0);
}
}
for(t=0;;)
{
if(LKB_SCLK==0) break; //等待拉低时钟线
t++;
if(t>=200)
{
TR0=1;LKB_SCLK=0;
return(0);
}
}
if(LKB_SDA!=0) {TR0=1;LKB_SCLK=0;return(0);}
for(t=0;;)
{
if((LKB_SCLK==1)&&(LKB_SDA==1)) break; //等待拉高时钟线和数据线
t++;
if(t>=200)
{
TR0=1;LKB_SCLK=0;
return(0);
}
}
TR0=1;LKB_SCLK=0;
return(1);
}
//=========================================从大键盘接收1个字节=====================================
unsigned char Read_LKB_Data(unsigned char RDTime)
{
bit cp=0;
unsigned char i;
unsigned char k;
unsigned int t;
LKB_SCLK=1;
Code_Reci_Data_Timing=0;
while(1)
{
if(LKB_SDA==0) break;
if(Code_Reci_Data_Timing>RDTime) //20毫秒时间内键盘必须应答
{
LKB_SCLK=0;
return(0);
}
}
TR0=0;
if(Wait_LKB_Sclk_H_To_L()==0) {LKB_SCLK=0;TR0=1;return(0);} //1-等待,起始位不读
if(Wait_LKB_Sclk_L_To_H()==0) {LKB_SCLK=0;TR0=1;return(0);}
for(i=0;i<8;i++)
{
k=k>>1;
if(Wait_LKB_Sclk_H_To_L()==0) {LKB_SCLK=0;TR0=1;return(0);} //1-等待,起始位不读
if(LKB_SDA==1)
{
k=(k|0x80);
}
if(Wait_LKB_Sclk_L_To_H()==0) {LKB_SCLK=0;TR0=1;return(0);}
}
if(Wait_LKB_Sclk_H_To_L()==0) {LKB_SCLK=0;TR0=1;return(0);}
if(LKB_SDA==1) cp=1; //读校验位
if(Wait_LKB_Sclk_L_To_H()==0) {LKB_SCLK=0;TR0=1;return(0);}
if(Wait_LKB_Sclk_H_To_L()==0) {LKB_SCLK=0;TR0=1;return(0);} //等待停止位脉冲
for(t=0;;)
{
if(LKB_SDA==1) break; //等待拉高时钟线和数据线
t++;
if(t>=200)
{
TR0=1;LKB_SCLK=0;
return(0);
}
}
if(Wait_LKB_Sclk_L_To_H()==0) {} //等待高电平
TR0=1;
LKB_SCLK=0;
ACC=k;
if(P!=(!cp)) return(0);
return (k);
}
//================================================================================================
bit Wait_LKB_Sclk_H_To_L(void)
{
unsigned char i;
i=0;
while(LKB_SCLK==1)
{
i++;
if(i>=200) return(0);
}
return(1);
}
//================================================================================================
bit Wait_LKB_Sclk_L_To_H(void)
{
unsigned char i;
i=0;
while(1)
{
if(LKB_SCLK==1) break; //等待拉低时钟线
i++;
if(i>=200)
{
return(0);
}
}
return(1);
}
//==================用P4.0仿真RS232作为调试输出到串口供观察==================================
/*
void Emluator_RS232(unsigned char SendData)
{
Send_RS_Data=SendData;
Send_RS_Data=Send_RS_Data<<1;
Send_RS_Data=(Send_RS_Data|0xfc00);
Send_RS_Bit_Num=11;
TH1=0xfe; //在18.432MHz下的104uS定时
//TL1=0xc3;
TL1=0xe0;
TR0=0;
TR1=1;
while(Send_RS_Bit_Num!=0) {}
TR1=0;
TR0=1;
}
*/
/*
开机自检除了 FF 外, 还有 F2, ED, F3 这几个命令, 你有处理吗?
在特殊场合,例如开机键盘自检时,PC机会向PS/2键盘口发送自检命令,如果无响应则无法通过硬件检测而无法启动操作系统。因此在受控机开机时,单片机上电复位,在单片机应能接收到键盘的命令并作出响应。如果一秒后没收到,则受控机的CMOS设置忽略键盘自检,单片机不作响应继续执行下面的程序。
PC机复位键盘过程:先发复位命令FFH,单片机收到以FAH应答,PC机收到后,置时钟线和数据线为高电平,单片机检测到此状态开始内部自测试,测试完成发送AAH表示自检结束,否则发FDH表自检出错。
主机可通过向PS/2键盘发送命令对键盘进行设置或者获得键盘的状态等操作.每发送一个字节,主机都会从键盘获得一个应答0xFA(“重发
resend”和“回应echo”命令例外).驱动程序在键盘初始化过程中所用的指令:0xED,主机在该命令后跟随发送一个参数字节,用于指示键盘上Num Lock,Caps Lock,Scroll Lock Led的状态;0xF3,主机在这条命令后跟随发送一个字节参数定义键盘机打的速率和延时;0xF4,用于当主机发送0xF5禁止键盘后,重新使能键盘.
*/
/*
直接嵌入汇编代码的方法:
1、在 C 文件中要嵌入汇编代码片以如下方式加入汇编代码:
#pragma ASM
; Assembler Code Here
#pragma ENDASM
2、在 Project 窗口中包含汇编代码的 C 文件上右键,选择“Options for ...”,点击右边的“Generate Assembler SRC File”
和“Assemble SRC File”,使检查框由灰色变成黑色(有效)状态;
3、根据选择的编译模式,把相应的库文件(如 Small 模式时,是 Keil\C51\Lib\C51S.Lib)加入工程中, 该文件必须作为工程的最
后文件;
4、编译,即可生成目标代码。
*/
//=========================================================================================
//str1-----需要处理的数组,8BIT
//str2-----改好的数组(7BIT或者5BIT)
//length---str1数组的长度
//BIT_7_5--改成7位或者5位的标志
//返回值为数据是否正确,1不正确,0正确,
//Direction------正反向修改0--正向,1--反向
//要找到引导区,去掉0
//READER--- 轨道数
//=================================查找起始符============================================
//参数:DataAddr=要解码的字节数组首地址
// DataLenth=要解码的字节数组长度
// CodeBit=要解码的编码位数
//原理:在读磁卡位流时,低位在D7,高位在D0
// 通过位流查找标识头
// 找到标识头后,后面的位流按编码位数取字节,依次存放在当前的数组空间,并返回“0”作正确标志
//=================================================================================
bit FindStartSign_Decode(unsigned char *Array,unsigned char *Temp_Array,unsigned char length,unsigned char BIT_7_5,unsigned char Direction,unsigned char READER,unsigned char READER_NUM)
{
bit START=0;
bit OVER=0;
bit pr;
bit END_BIT=0;
unsigned char i,j,k,l,m;
unsigned char Temp_Data;
unsigned int B
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -