1.获取按键编码
#define PORT_KEYDAT 0x0060
void inthandler21(int *esp)
/* 键盘中断 */
{
struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;
unsigned char data ,s[4];
io_out8(PIC0_OCW2,0x61); //通知PIC“IRQ-01”已经受理完毕
data = io_in8(PORT_KEYDAT);
sprintf(s,"%02X",data);
boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 0, 16, 15, 31);
putfonts8_asc(binfo->vram, binfo->scrnx, 0, 16, COL8_FFFFFF, s);//向屏幕输出s
for (;;) {
io_hlt();
}
}
分析:
io_out8(PIC0_OCW2,0x61); 这句话告诉IPC“已经知道发生了IRQ1中断”。如果是IRQ3中断,则写成0x63.也就是说,将“0x60+IRQ号码”输出给OCW2就可以了。执行这句话之后,PIC继续监视IRQ1中断是否发生。反过来,如果忘记执行,PIC将不再监视。
下面:从编号为0x60的设备输入的8位信息是按键编码,0x60的设备就是键盘。
执行结果:图片1
2. 加快中断处理
1.添加缓冲标志,在bootpack.h 中加入:
/* int.c */
struct KEYBUF {
unsigned char data, flag;
};
2.在int.c中处理中断:
#define PORT_KEYDAT 0x0060
struct KEYBUF keybuf;
void inthandler21(int *esp)
/* 中断 */
{
unsigned char data ;
io_out8(PIC0_OCW2,0x61); //通知PIC“IRQ-01”已经受理完毕
data = io_in8(PORT_KEYDAT);
if(keybuf.flag == 0){ //如果flag==0,说明之前的数据已经被打印,接下来把刚刚键盘输入的字符缓存
keybuf.data = data;
keybuf.flag = 1; //设置标志位1,
}
return;
}
3.在主函数中处理中断(主函数中的for循环修改如下):
for (;;) {
//io_hlt();
io_cli();
if(keybuf.flag == 0){
io_stihlt();
}else{
i = keybuf.data;
keybuf.flag = 0;
io_sti();
sprintf(s,"%02X",i);
boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 0, 16, 15, 31);
putfonts8_asc(binfo->vram, binfo->scrnx, 0, 16, COL8_FFFFFF, s);//向屏幕打印s
}
}
实现结果:缓冲区只能存储一个字节,出现问题:
结果与图1类似
3.制作缓冲区
- 修改缓存结构体:
struct KEYBUF {
unsigned char data[32];
int next;
};
2 修改中断处理,提高缓存数据量
void inthandler21(int *esp)
/* 中断 */
{
unsigned char data ;
io_out8(PIC0_OCW2,0x61); //通知PIC“IRQ-01”已经受理完毕
data = io_in8(PORT_KEYDAT);
if(keybuf.next < 32){ //可以缓存32个字符
keybuf.data[keybuf.next] = data;
keybuf.next ++; //缓存数+1
}
return;
}
3.修改输出:
for (;;) {
//io_hlt();
io_cli();
if(keybuf.next == 0){
io_stihlt();
}else{
i = keybuf.data[0];
keybuf.next--;
//向前移一位
for(j = 0; j < keybuf.next; j++){
keybuf.data[j] = keybuf.data[j+1];
}
io_sti();
sprintf(s,"%02X",i);
boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 0, 16, 15, 31);
putfonts8_asc(binfo->vram, binfo->scrnx, 0, 16, COL8_FFFFFF, s);//向屏幕打印s
}
}
结果与图1类似
4、5 改善和整理缓冲区
- 增加一个结构体 FIFO8
/* fifo.c */
struct FIFO8 {
unsigned char *buf;
int p, q, size, free, flags;
};
其中 :
p: 下一个写入的数据的位置
q : 下一个读出的数据的位置
size : 缓冲区总字节数
free: 保存缓冲区没有数据的字节数
2. 增加一个文件fifo.c,具体功能查看注释:
/* FIFO */
#include "bootpack.h"
#define FLAGS_OVERRUN 0x0001
void fifo8_init(struct FIFO8 *fifo, int size, unsigned char *buf)
/* FIFO初始化 */
{
fifo->size = size;
fifo->buf = buf;
fifo->free = size; /* 空闲的大小 */
fifo->flags = 0;
fifo->p = 0; /* 下一个数据写入的位置 */
fifo->q = 0; /* 下一个数据读入的位置 */
return;
}
int fifo8_put(struct FIFO8 *fifo, unsigned char data)
/* 向FIFO传送数据并保存 */
{
if (fifo->free == 0) {
/* 空余没有了,溢出 */
fifo->flags |= FLAGS_OVERRUN;
return -1;
}
fifo->buf[fifo->p] = data;
fifo->p++;
if (fifo->p == fifo->size) {
fifo->p = 0;
}
fifo->free--;
return 0;
}
int fifo8_get(struct FIFO8 *fifo)
/* FIFO获取一个数据 */
{
int data;
if (fifo->free == fifo->size) {
/* 如果缓冲区为空,则返回-1 */
return -1;
}
data = fifo->buf[fifo->q];
fifo->q++;
if (fifo->q == fifo->size) {
fifo->q = 0;
}
fifo->free++;
return data;
}
int fifo8_status(struct FIFO8 *fifo)
/*报告一下积攒了多少数据 */
{
return fifo->size - fifo->free;
}
3 修改中断函数:
struct FIFO8 keyfifo;
void inthandler21(int *esp)
/* 中断 */
{
unsigned char data ;
io_out8(PIC0_OCW2,0x61); //通知PIC“IRQ-01”已经受理完毕
data = io_in8(PORT_KEYDAT);
fifo8_put(&keyfifo, data);
return;
}
4 修改主函数:
fifo8_init(&keyfifo, 32, keybuf); //初始化keybuf
for (;;) {
//io_hlt();
io_cli();
if(fifo8_status(&keyfifo) == 0){
io_stihlt();
}else{
i = fifo8_get(&keyfifo);
io_sti();
sprintf(s,"%02X",i);
boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 0, 16, 15, 31);
putfonts8_asc(binfo->vram, binfo->scrnx, 0, 16, COL8_FFFFFF, s);//向屏幕打印s
}
}
5 修改Make file文件:增加fifo.obj
6 make run
结果与图1类似
6、7.从鼠标接收数据
- 在bootpack.c 中添加3个函数:
#define PORT_KEYDAT 0x0060
#define PORT_KEYSTA 0x0064
#define PORT_KEYCMD 0x0064
#define KEYSTA_SEND_NOTREADY 0x02
#define KEYCMD_WRITE_MODE 0x60
#define KBC_MODE 0x47
void wait_KBC_sendready(void)
{
/* 等待键盘控制电路准备完毕 */
for (;;) {
if ((io_in8(PORT_KEYSTA) & KEYSTA_SEND_NOTREADY) == 0) {
break;
}
}
return;
}
void init_keyboard(void)
{
/* 初始化键盘控制电路 */
wait_KBC_sendready();
io_out8(PORT_KEYCMD, KEYCMD_WRITE_MODE);
wait_KBC_sendready();
io_out8(PORT_KEYDAT, KBC_MODE);
return;
}
#define KEYCMD_SENDTO_MOUSE 0xd4
#define MOUSECMD_ENABLE 0xf4
void enable_mouse(void)
{
/* 激活鼠标 */
wait_KBC_sendready();
io_out8(PORT_KEYCMD, KEYCMD_SENDTO_MOUSE);
wait_KBC_sendready();
io_out8(PORT_KEYDAT, MOUSECMD_ENABLE);
return; /* 顺利的话,键盘控制其会返送回ACK(0xfa) */
}
2 设置鼠标中断
void inthandler2c(int *esp)
/* 鼠标中断 */
{
unsigned char data ;
io_out8(PIC1_OCW2,0x64); //通知PIC1“IRQ-12”已经受理完毕
io_out8(PIC0_OCW2,0x62); //通知PIC0“IRQ-02”已经受理完毕
data = io_in8(PORT_KEYDAT);
fifo8_put(&mousefifo, data);
return;
}
3 修改主函数的显示
for (;;) {
//io_hlt();
io_cli();
if(fifo8_status(&keyfifo) + fifo8_status(&mousefifo) == 0){
io_stihlt();
}else{
if (fifo8_status(&keyfifo) != 0) {
i = fifo8_get(&keyfifo);
io_sti();
sprintf(s, "%02X", i);
boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 0, 16, 15, 31);
putfonts8_asc(binfo->vram, binfo->scrnx, 0, 16, COL8_FFFFFF, s);
} else if (fifo8_status(&mousefifo) != 0) {
i = fifo8_get(&mousefifo);
io_sti();
sprintf(s, "%02X", i);
boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 32, 16, 47, 31);
putfonts8_asc(binfo->vram, binfo->scrnx, 32, 16, COL8_FFFFFF, s);
}
}
}
4.结果显示: