键盘控制器原理
①自己去看
②鼠标控制也属于键盘控制器的一部分
硬件图
代码
io_out8(PIC0_IMR, 0xf9); /* PIC1(11111001) 开启键盘和鼠标中断设置*/
io_out8(PIC1_IMR, 0xef); /* 从芯片设置:(11101111) */
keymouse.h中的宏定义,函数声明,结构体声明
#ifndef __KEYMOUSE_H__
#define __KEYMOUSE_H__
struct MOUSE_DEC
{
unsigned char MouseStatusBuf[3];//存放鼠标发送过来的三个字节
int MousePhase;//设置鼠标处于哪个周期
int nX, nY, nButton;
};
#define PORT_KEYDAT 0x0060 //端口60数据
#define PORT_KEYSTA 0x0064//获取键盘控制器状态
#define PORT_KEYCMD 0x0064//端口64 命令
#define KEYSTA_SEND_NOTREADY 0x02//键盘控制器没有准备好
//向端口64发送此命令 代表要向端口60发送数据了
#define KEYCMD_WRITE_MODE 0x60
//开启鼠标 键盘中断 并且使能
#define KBC_MODE 0x47
//鼠标应答
#define MOUSE_ACK 0xfa
//要使能鼠标
#define KEYCMD_SENDTO_MOUSE 0xd4
#define MOUSECMD_ENABLE 0xf4
void WaitKeyBoardCtrlReady(void);//等待键盘控制器准备完毕
void InitKeyBoard(void);//初始化 键盘控制器
void EnableMouse(struct MOUSE_DEC * pMouse);//激活鼠标
int MouseDecode(struct MOUSE_DEC * pMouse, unsigned char ucData);//把数据放入结构体
#endif
初始化键盘控制器
void WaitKeyBoardCtrlReady(void)//等待键盘控制器准备完毕
{
while(1)
{
if(0 == (io_in8(PORT_KEYSTA) & KEYSTA_SEND_NOTREADY) )
{
break;
}
}
return;
}
void InitKeyBoard(void)//初始化 键盘控制器
{
WaitKeyBoardCtrlReady();
//向0x64端口发送命令 下一个送入端口0x60的数据 要写入控制寄存器
io_out8(PORT_KEYCMD, KEYCMD_WRITE_MODE);
WaitKeyBoardCtrlReady();
//设置控制寄存器的模式
io_out8(PORT_KEYDAT, KBC_MODE);
return;
}
初始化鼠标
void EnableMouse(struct MOUSE_DEC * pMouse)//激活鼠标
{
WaitKeyBoardCtrlReady();
io_out8(PORT_KEYCMD, KEYCMD_SENDTO_MOUSE);
WaitKeyBoardCtrlReady();
io_out8(PORT_KEYDAT, MOUSECMD_ENABLE);
pMouse->MousePhase = 0;
return;
}
初始化键盘,鼠标的缓冲区
struct FIFO g_FifoKeyBoardBuf;
struct FIFO g_FifoMouseBuf;
unsigned char KeyBoardBuffer[32];//键盘的缓冲区
unsigned char MouseBuffer[256];//鼠标的缓冲区
InitFifo(&g_FifoKeyBoardBuf, 32, KeyBoardBuffer);
InitFifo(&g_FifoMouseBuf, 256, MouseBuffer);
①fifo.h中的内容
#ifndef __FIFO_H__
#define __FIFO_H__
#define FLAGES_OVERRUN 0x0001 //记录是否缓冲区溢出
#define BUFFER_VOERFLOW -1
#define BUFFER_EMPTY -2
//记录缓冲区的结构体
struct FIFO
{
unsigned char *pAdd;//缓冲区的起始地址
int nHead;//队列头
int nTail;//队列尾
int nFree;//空闲的数量
int nSize;//缓冲区总共大小
int nFlag;//记录标志
};
//初始化缓冲区
void InitFifo(struct FIFO *pTemp, int Size, unsigned char *pBuf);
//向缓冲区写入数据
int FifoSaveData(struct FIFO *pTemp, unsigned char Data);
//从缓冲区中读出数据
int FifoReadData(struct FIFO *pTemp);
//获取缓冲区的状态
int FifoStatus(struct FIFO *pTemp);
#endif
②fifo.c中的内容
void InitFifo(struct FIFO *pTemp, int Size, unsigned char *pBuf)
{
pTemp->pAdd = pBuf;
pTemp->nSize = Size;
pTemp->nFlag = 0;
pTemp->nFree = Size;
pTemp->nHead = 0;
pTemp->nTail = 0;
return ;
}
int FifoSaveData(struct FIFO *pTemp, unsigned char Data)
{
if(0 == pTemp->nFree)//如果没有空闲区
{
pTemp->nFlag |= FLAGES_OVERRUN;
return BUFFER_VOERFLOW;
}
//有空闲区 向尾部写入数据
pTemp->pAdd[pTemp->nTail] = Data;
pTemp->nTail++;
if(pTemp->nSize == pTemp->nTail)
{
pTemp->nTail = 0;
}
pTemp->nFree--;//空闲区减1
return 0;
}
int FifoReadData(struct FIFO *pTemp)
{
int nData;
//如果缓冲区是空的
if(pTemp->nFree == pTemp->nSize)
{
return BUFFER_EMPTY;
}
//取出数据
nData = pTemp->pAdd[pTemp->nHead];
pTemp->nHead++;
if(pTemp->nSize == pTemp->nHead)
{
pTemp->nHead = 0;
}
pTemp->nFree++;
return nData;
}
int FifoStatus(struct FIFO *pTemp)//缓冲区内的字符个数
{
return (pTemp->nSize) - (pTemp->nFree);
}
键盘和鼠标的中断处理函数
void IntHandler21(int *pEsp);//键盘是IRQ1
void IntHandler2C(int *pEsp);//鼠标是IRQ12
void IntHandler21(int *pEsp)
{
unsigned char ucData;
io_out8(PIC0_OCW2, 0x61);//通知PIC"IRQ-01已经处理完毕 可以继续中断"
ucData = io_in8(PORT_KEYBOARD_DATA);
//sprintf(szBuf, "%02x",ucData);
FifoSaveData(&g_FifoKeyBoardBuf,ucData);
return ;
}
void IntHandler2C(int *pEsp)
{
unsigned char ucData;
//通知PIC1 IRQ-12
io_out8(PIC1_OCW2, 0x64);
//通知PIC0 IRQ-02
io_out8(PIC0_OCW2, 0x62);
//从鼠标接受一个数据
ucData = io_in8(PORT_KEYDAT);
FifoSaveData(&g_FifoMouseBuf, ucData);
return;
}
获取鼠标状态
int MouseDecode(struct MOUSE_DEC * pMouse, unsigned char ucData)
{
if(0 == pMouse->MousePhase)
{
if(MOUSE_ACK == ucData)
{
pMouse->MousePhase = 1;
return 0;
}
}
else if(1 == pMouse->MousePhase)
{
if(0x08 == (ucData & 0xc8))//即X Y没有溢出
{
pMouse->MouseStatusBuf[0] = ucData;
pMouse->MousePhase = 2;
}
return 0;
}
else if(2 == pMouse->MousePhase)
{
pMouse->MouseStatusBuf[1] = ucData;
pMouse->MousePhase = 3;
return 0;
}
else if(3 == pMouse->MousePhase)
{
pMouse->MouseStatusBuf[2] = ucData;
pMouse->MousePhase = 1;
pMouse->nButton = pMouse->MouseStatusBuf[0] & 0x07;
//判断哪个键被按下了
pMouse->nX = pMouse->MouseStatusBuf[1];
pMouse->nY = pMouse->MouseStatusBuf[2];
if(0 != (pMouse->MouseStatusBuf[0] & 0x10) )
//即X方向发生了移动
{
pMouse->nX |= 0xffffff00;
}
if(0 != (pMouse->MouseStatusBuf[0] & 0x20) )
//即Y方向发生了移动
{
pMouse->nY |= 0xffffff00;
}
pMouse->nY = -pMouse->nY;
return 1;
}
}
总结
①首先要先开启键盘鼠标的中断
②初始化各自的缓冲区
③初始化键盘控制器,激活鼠标
④键盘,鼠标中断处理函数每次从 端口接受到一个字节放入到各自的缓冲区中
⑤调用鼠标解析函数来进行处理每次发来的三个字节,更改坐标,描绘鼠标