分享

第07天,FIFO + 鼠标控制《30天自制操作系统学习笔记》

 山峰云绕 2022-04-14

移动鼠标还是有难度的,先搞清楚键盘事件

第07天,FIFO + 鼠标控制《30天自制操作系统学习笔记》

获取按键编码

更新:int.c

#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);
    return;
}

io_out8(PIC0_OCW2, 0x61); 作用是通知PIC,IRQ1中断啦!

中断IRQ1的编号是0x61
中断IRQ3的编号是0x63

将“0x60+IRQ号码”输出给OCW2,此时PIC继续监视IRQ1中断是否发生。
如果忘记输出给OCW2,那么PIC不再监视,意味着键盘输入无效

第07天,FIFO + 鼠标控制《30天自制操作系统学习笔记》

编号0x0060的设备 = 键盘

按下按键之后,会显示出一个数字(十六进制)
松开按键之后,会显示出一个数字(十六进制)

测试:打开cmd,输入make run

第07天,FIFO + 鼠标控制《30天自制操作系统学习笔记》

加快中断处理

目前字符显示的内容被放在了中断处理程序中。这种方式打断CPU本来工作,不再接收别的中断,所以中断速度太慢,出现不连贯的现象

  1. 先将按键的编码接收
  2. 保存到变量
  3. 然后由HariMain偶尔查看该变量
  4. 如果,发现有数据变动,就显示出来

更新:int.c

struct KEYBUF {
		unsigned char data, flag;
};

#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) {                             
        keybuf.data = data; 
        keybuf.flag = 1;
    }
    return;
}

键盘输入时需要缓冲区,
定义了 一个构造体keybuf,
如果flag是0,表示缓冲区为空,
如果flag是1,就表示缓冲区中存有数据。

接下来,通过HariMain功能查看变量,发生变动显示字符。

更新:bootpack.c

for (;;) {
    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);
    }
}

由于作者创建的缓冲区只能存储一个字节,而ctrl是两个字节,所以按下和松开ctrl键的时候只显示第一个字节,恰巧第一个字节又相同,所以看起来没反应。

制作FIFO缓冲区

解决方法就是扩展缓冲区大小。


之前说过,缓冲区有两种方式
FIFO属于第一个进去,第一个出来
FILO属于第一个进去,最后一个出来

而这次是希望输入ABC输出ABC,所以用FIFO输出方式.

更新:int.c

struct KEYBUF {
    unsigned char data[32];                     /*缓冲区大小设置*/
    int next;
};
void inthandler21(int *esp)
{
    unsigned char data;
    io_out8(PIC0_OCW2, 0x61); /* 通知PIC IRQ-01已经受理完毕 */
    data = io_in8(PORT_KEYDAT);
    if (keybuf.next < 32) {
        keybuf.data[keybuf.next] = data;
        keybuf.next++;
    }
    return;
}

更新:bootpack.c

void HariMain(void)
{
	....脑补代码

	for (;;) {
		io_cli();
		if (keybuf.len == 0) {
			io_stihlt();
		} else {
			i = keybuf.data[keybuf.next_r];
			keybuf.len--;
			keybuf.next_r++;
			if (keybuf.next_r == 32) {
				keybuf.next_r = 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);
		}
	}
}
  • 如果在禁止中断的期间里做数据移送处理会出现问题。
  • 如果在数据移送处理前,允许中断的话,会搞乱处理的数据。

那该怎么办才好呢?

第07天,FIFO + 鼠标控制《30天自制操作系统学习笔记》

优化FIFO缓冲区

能不能开发一个不需要数据移送操作的FIFO型缓冲区呢?
答案是可以的

原理如下:
数据读出位置追上数据写入位置的时候,就相当于缓冲区为空,没有数据
要维护下一个要写入数据的位置,
还要维护下一个要读出数据的位置。

更新:bootpack.c

struct KEYBUF {
  unsigned char data[32];
  int next_r ,next_w;
  int len;                            /*缓冲区能记录多少字节的数据*/   
};

更新:int.c

void inthandler21(int *esp)
{
    unsigned char data;
    io_out8(PIC0_OCW2, 0x61); /* 通知 IRQ-01已经受理完毕 */
    data = io_in8(PORT_KEYDAT);
    if (keybuf.len < 32) {
        keybuf.data[keybuf.next_w] = data;
        keybuf.len++;
        keybuf.next_w++;
        if (keybuf.next_w == 32) {
        		keybuf.next_w = 0;	
        }
    }
    return;
}

这样,FIFO缓冲区设置完毕

整理FIFO缓冲区

鼠标每次移动就会连续发送3个字节的数据。
我们已经掌握了键盘发送2个字节的方法,所以发送3个字节也不在话下。

FIFO缓冲区结构可以移植到鼠标

第07天,FIFO + 鼠标控制《30天自制操作系统学习笔记》

更新:bootpack.h,增加内容

struct FIFO8 {
	unsigned char *buf;
	int p, q, size, free, flags;
};

新建:fifo.c,初始化fifo

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;
}

更新:fifo.c ,增加put功能(缓冲区存储信息)

.....代码省略

#define FLAGS_OVERRUN 0x0001

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;
}

更新:fifo.c ,增加get功能(缓冲区读取信息)

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;
}

更新:fifo.c ,增加status功能(缓冲区状态查询)

int fifo8_status(struct FIFO8 *fifo)
/* 报告一下到底积攒了多少数据 */
{
				return fifo->size - fifo->free;
}

功能写好了,想要使用,先放入int.c

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;
}

最后再放入bootpack.c

char s[40], mcursor[256], keybuf[32];
fifo8_init(&keyfifo, 32, keybuf);
for (;;) {
    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);
    }
}
第07天,FIFO + 鼠标控制《30天自制操作系统学习笔记》

折腾了这么久,鼠标还是不能动!!!

鼠标

想让鼠标移动?
先让控制电路有效
再让鼠标事件有效

鼠标控制电路包含在键盘控制电路里,
如果键盘控制电路的初始化正常完成,
鼠标电路控制器的激活也就完成了。

更新:bootpack.c

#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;
}

wait_KBC_sendready = 让键盘控制电路做好准备动作

init_keyboard = 一边确认可否往键盘控制电路传送信息,一边发送模式设定指令(0x60)

更新:bootpack.c

#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)*/
}

测试:打开cmd,输入make run

第07天,FIFO + 鼠标控制《30天自制操作系统学习笔记》

鼠标事件触发了,显示了设定的文字

但是,鼠标还是不能移动

从鼠标接收数据

现在取出中断数据

更新:int.c

struct FIFO8 mousefifo;
void inthandler2c(int *esp)
/* 来自PS/2鼠标的中断 */
{
    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;
}

更新:bootpack.c,鼠标数据取得方法

fifo8_init(&mousefifo, 128, mousebuf);
for (;;) {
    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);
        }
    }
}

测试:打开cmd,make run

第07天,FIFO + 鼠标控制《30天自制操作系统学习笔记》

随着鼠标的移动,变量一直在变化!

鼠标还是不能移动!

硬件交互难度很大,细品!

今天就到此,明天继续!

第07天,FIFO + 鼠标控制《30天自制操作系统学习笔记》

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多