龙空技术网

30天自制操作系统day08:对键盘进行响应

老师明明可以靠颜值 592

前言:

眼前姐妹们对“c语言的中断函数怎么写”都比较看重,各位老铁们都需要知道一些“c语言的中断函数怎么写”的相关内容。那么小编在网摘上网罗了一些有关“c语言的中断函数怎么写””的相关内容,希望小伙伴们能喜欢,各位老铁们一起来学习一下吧!

在第7天的教程中,我们在第6天编写的中断函数的基础上,继续编写了FIFO数组,以及对鼠标返回的长度为4的顺序数组进行了接收,完成了对鼠标数据的解码

第7天的教程在:

那么今天,我们的目标是:对键盘进行响应,即:键被按下或者弹起后,我们把其对应的键值显示出来。

演示视频:

视频加载中...

当我们完成对键盘和鼠标的响应后,就可以开发内存管理模块,多线程模块,有了内存管理,多线程模块的加持,操作系统就可以实现更加复杂的功能:比如开发出游戏,开发出文档显示软件等,如下视频:

[视频地址]:

视频加载中...

但是要想完成以上功能,必须先实现键盘响应,内存管理,多线程等模块的编写。

今天day08的主要内容是键盘响应部分, day09就开始做内存管理。

其实做完鼠标的响应,已经学完了键盘响应所需要的所有的知识点。

所以,今天的键盘响应,是对之前所学知识点的一个综合性应用。

今天的内容这样安排:

获取键值内容先入先出FIFO数据结构复习获取键值前,需对键盘初始化中断功能的打开与关闭键盘响应程序出现在 操作系统主程序的循环中总结获取键值的过程

keyfifo,是我们模仿对鼠标数据的保存方式mousefifo,也写了一个对键盘数据的快速有效的保存方式keyfifo,实现在对键的按下与抬起两个动作的数据的保存,并且数据是先保存的,就会先被取出。保证按下与抬起两个动作对应的键值按顺取地读取出来。

if (fifo8_status(&keyfifo) != 0) { // 使用fifo8_status函数,检查有没有新的键值存入				i = fifo8_get(&keyfifo);// 如果有,保存键值到i中				io_sti();// 操作完fifo类型的数据keyfifo了,要打开中断,允许新的键值存入keyfifo中				sprintf(s, "%02X", i);// 将键值保存到s中        // 在屏幕上绘制出一个矩形框				boxfill8(binfo->vram, binfo->scrnx, COL8_008484,  0, 16, 15, 31);				// 在屏幕上绘制出字符串s,完成键值的绘制        putfonts8_asc(binfo->vram, binfo->scrnx, 0, 16, COL8_FFFFFF, s);			} // 把以上代码放入主函数的for循环中,就可以实现对键值的连续绘制

以上代码中的keyfifo是什么?keyfifo中的数据为什么就是键值了?

keyfifo是一个先入先出类型数组结构FIFO8

keyfifo的值是在键盘的中断函数inthandler21中获取的。

我们看一下相关代码:

char keybuf[32]; // 声明keybuf数组,用来保存键值struct FIFO8 keyfifo; // 声明先入先出结构体 FIFO8 keyfifofifo8_init(&keyfifo, 32, keybuf);// 把keybuf交给keyfifo来管理,实现数组很方便的先入先出#define PORT_KEYDAT 0x0060 // 键盘数据的读取端口号void inthandler21(int *esp){unsigned char data;io_out8(PIC0_OCW2, 0x61); // 通知中断控制器,0x61代表的中断已经处理完毕,可以响应新的中断了data = io_in8(PORT_KEYDAT); // 从端口号读取数据到data中fifo8_put(&keyfifo, data); // 将data放入键值数组keyfifo中return;}

这个汇编代码要放在汇编文件nas中进行编译

在这个汇编写的中断函数中,调用了inthanler21函数

也就是说,用C语言是无法直接写中断函数的,

但是C语言写程序效率高,怎样才能用C语言写中断函数呢?

用C语言写一个函数 xxx

然后在汇编函数里调用 xxx

我们这里就是采用的这种办法

_asm_inthandler21:PUSH ESPUSH DSPUSHADMOV EAX,ESPPUSH EAXMOV AX,SSMOV DS,AXMOV ES,AXCALL _inthandler21POP EAXPOPADPOP DSPOP ESIRETD

那么为什么写了_asm_inthandler21这样的函数,它就是中断函数了呢?

键盘有动作时,为什么它就能被执行呢?

因为我们把这个函数的地址放在了中断记录表IDT里,用的是这个语句

set_gatedesc(idt + 0x21, (int) asm_inthandler21, 2 * 8, AR_INTGATE32);

中断记录表IDT记录了中断函数的地址,当硬件上发生中断时,cpu就会跳转到IDT中查询一个地址,然后去这个地址开始执行

所以为什么keyinfo中的数据就是键盘的键值了呢?

因为键盘当有键按下->产生中断信号0x21->执行0x21对应的中断函数asm_inthandler21

->执行inthandler21 -> 从端口号0x60读数据到keyinfo中

先入先出FIFO数据结构复习

FIFO8的初始化函数,添加数据函数,读出数据函数,以及判断有无数据函数

带注释版本的可看这里:

#define FLAGS_OVERRUN		0x0001void fifo8_init(struct FIFO8 *fifo, int size, unsigned char *buf){	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){	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){	int data;	if (fifo->free == fifo->size) {		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;}

获取键值前,需对键盘初始化

键盘的初始化与鼠标的初始化很相似,

KBC是keyboard controller ,键盘控制器。

对键盘的初始化,就是通过设置KBC完成的。这是一个设置硬件的步骤,所以会牵涉到往某些端口写数据等操作。

基本逻辑是等待KBC可以与CPU交互后,

CPU 就给KBC发送命令KEYCMD_WRITE_MODE,让KBC处于可被设置的状态

然后CPU再次等待KBD准备好后,给KBC发送KBC_MODE=0x47,表示键盘工作在键盘+鼠标的模式。如果KBC_MODE=0x60,那么就是工作在键盘模式,对鼠标无法识别的。

所以,如果你想玩玩,可以写个程序,把你自己电脑的KBC的工作模式设置为0x60,那么cpu将忽略鼠标的存在。

#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 0x47void init_keyboard(void){wait_KBC_sendready();io_out8(PORT_KEYCMD, KEYCMD_WRITE_MODE); //设置KBC为可写,硬件操作wait_KBC_sendready();io_out8(PORT_KEYDAT, KBC_MODE); //设置KBC对鼠标的识别,硬件操作return;}_io_in8: ; int io_in8(int port); //汇编实现读端口port的数据MOV EDX,[ESP+4] ; portMOV EAX,0IN AL,DXRET_io_out8: ; void io_out8(int port, int data); //汇编实现对port写数据dataMOV EDX,[ESP+4] ; portMOV AL,[ESP+8] ; dataOUT DX,ALRET

中断功能的打开与关闭

在对数据进行读取时,不希望中断发生,要关闭中断功能。

取完数据,希望中断发生,要打开中断。

中断要不断的被打开和关闭,并且是在C语言中操作

这就用到了如下函数:

; 写在汇编文件中,导出给C语言使用io_sti:	; void io_sti(void);		STI ;允许中断发生		RET ;返回_io_cli:	; void io_cli(void);		CLI ;禁止中断发生		RET ;返回_io_stihlt:	; void io_stihlt(void);		STI ;允许中断发生		HLT ;cpu停止一个时钟周期		RET ;返回                      
键盘响应程序出现在 操作系统主程序的循环中,

具体如下:

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();				if (mouse_decode(&mdec, i) != 0) {									sprintf(s, "[lcr %4d %4d]", mdec.x, mdec.y);					if ((mdec.btn & 0x01) != 0) {						s[1] = 'L';					}					if ((mdec.btn & 0x02) != 0) {						s[3] = 'R';					}					if ((mdec.btn & 0x04) != 0) {						s[2] = 'C';					}					boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 32, 16, 32 + 15 * 8 - 1, 31);					putfonts8_asc(binfo->vram, binfo->scrnx, 32, 16, COL8_FFFFFF, s);									boxfill8(binfo->vram, binfo->scrnx, COL8_008484, mx, my, mx + 15, my + 15); /* ƒ}ƒEƒXÁ‚· */					mx += mdec.x;					my += mdec.y;					if (mx < 0) {						mx = 0;					}					if (my < 0) {						my = 0;					}					if (mx > binfo->scrnx - 16) {						mx = binfo->scrnx - 16;					}					if (my > binfo->scrny - 16) {						my = binfo->scrny - 16;					}					sprintf(s, "(%3d, %3d)", mx, my);					boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 0, 0, 79, 15); /* À•WÁ‚· */					putfonts8_asc(binfo->vram, binfo->scrnx, 0, 0, COL8_FFFFFF, s); /* À•W‘‚­ */					putblock8_8(binfo->vram, binfo->scrnx, 16, 16, mx, my, mcursor, 16); /* ƒ}ƒEƒX•`‚­ */				}			}		}	}
总结获取键值内容先入先出FIFO数据结构复习获取键值前,需对键盘初始化中断功能的打开与关闭键盘响应程序出现在 操作系统主程序的循环中

本节课我们复习的知识点有FIFO数据结构、中断函数、中断函数记录表、

我们利用这些知识点,完成了对键盘的初始化,使键盘按下时,CPU去执行中断函数,将键值保存到FIFO的keyinfo中,最后,我们把keyinfo中保存的键值通过操作系统主程序的for训练,显示到屏幕上。

如下视频所示:

视频地址:

视频加载中...

内存管理,将在day_09的教程中讲解。

标签: #c语言的中断函数怎么写 #c语言的中断函数怎么写出来 #win10键盘无响应