30天自制操作系统-第7天笔记

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); //通知PICIRQ-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
图片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.制作缓冲区

  1. 修改缓存结构体:
struct KEYBUF {
    unsigned char data[32];
    int next;
};

2 修改中断处理,提高缓存数据量

void inthandler21(int *esp)
/* 中断 */
{
    unsigned char data ;
    io_out8(PIC0_OCW2,0x61); //通知PICIRQ-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 改善和整理缓冲区

  1. 增加一个结构体 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); //通知PICIRQ-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.从鼠标接收数据

  1. 在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); //通知PIC1IRQ-12”已经受理完毕
    io_out8(PIC0_OCW2,0x62); //通知PIC0IRQ-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.结果显示:
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值