?? ps2.c
字號:
#include "ps2.h"
#include "usart.h"
//////////////////////////////////////////////////////////////////////////////////
//本程序只供學習使用,未經作者許可,不得用于其它任何用途
//Mini STM32開發板
//PS2 驅動代碼
//正點原子@ALIENTEK
//技術論壇:www.openedv.com
//修改日期:2010/6/17
//版本:V1.0
//版權所有,盜版必究。
//Copyright(C) 正點原子 2009-2019
//All rights reserved
//////////////////////////////////////////////////////////////////////////////////
//PS2產生的時鐘頻率在10~20Khz(最大33K)
//高/低電平的持續時間為25~50us之間.
//PS2_Status當前狀態標志
//[5:4]:當前工作的模式;[7]:接收到一次數據
//[6]:校驗錯誤;[3:0]:收到的數據長度;
u8 PS2_Status=CMDMODE; //默認為命令模式
u8 PS2_DATA_BUF[16]; //ps2數據緩存區
//位計數器
u8 BIT_Count=0;
//中斷15~10處理函數
//每11個bit,為接收1個字節
//每接收完一個包(11位)后,設備至少會等待50ms再發送下一個包
//只做了鼠標部分,鍵盤部分暫時未加入
//CHECK OK 2010/5/2
void EXTI15_10_IRQHandler(void)
{
static u8 tempdata=0;
static u8 parity=0;
if(EXTI->PR&(1<<15))//中斷15產生了相應的中斷
{
EXTI->PR=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)
{
case CMDMODE://命令模式下,每收到一個字節都會產生接收完成
PS2_Dis_Data_Report();//禁止數據傳輸
PS2_Status|=1<<7; //標記得到數據
break;
case KEYBOARD:
break;
case MOUSE:
if(MOUSE_ID==0)//標準鼠標,3個字節
{
if((PS2_Status&0x0f)==3)
{
PS2_Status|=1<<7;//標記得到數據
PS2_Dis_Data_Report();//禁止數據傳輸
}
}else if(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;
}
}
}
//禁止數據傳輸
//把時鐘線拉低,禁止數據傳輸
//CHECK OK 2010/5/2
void PS2_Dis_Data_Report(void)
{
PS2_Set_Int(0); //關閉中斷
PS2_SET_SCL_OUT();//設置SCL為輸出
PS2_SCL_OUT=0; //抑制傳輸
}
//使能數據傳輸
//釋放時鐘線
//CHECK OK 2010/5/2
void PS2_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,關閉;
//CHECK OK 2010/5/2
void PS2_Set_Int(u8 en)
{
EXTI->PR=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,超時溢出;
//CHECK OK 2010/5/2
u8 Wait_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,則產生了錯誤
//CHECK OK 2010/5/2
u8 PS2_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;
}else if(t>5500||PS2_Status&0x40)break;//超時溢出/接收錯誤
}
PS2_En_Data_Report();//使能數據傳輸
return temp;
}
//發送一個命令到PS2.
//返回值:0,無錯誤,其他,錯誤代碼
u8 PS2_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初始化
//CHECK OK 2010/5/2
void PS2_Init(void)
{
RCC->APB2ENR|=1<<2; //使能PORTA時鐘
JTAG_Set(JTAG_SWD_DISABLE);
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
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -