前言:
眼前姐妹们对“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键盘无响应