0x07_自制操作系统My-OS实现键盘输出字符到屏幕
接上一课class04,这是他的运行结果
收到了键盘的中断,现在想的当然是怎么把输入的文字显示到屏幕上,做成一个最简单的IO
这是class04的目录结构,现在我们把他换成class05
我们现在要读取键盘的数据,然后显示在屏幕上面
interrupt.c
#include "include/head.h" void inthandler21(int *esp) /* 来自PS/2键盘的中断 */ { unsigned char data,s[256]; io_set8(PIC0_OCW2, 0x61); /* 通知PIC,说IRQ-01的受理已经完成 */ data = io_get8(PORT_KEYDAT); struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO; boxfill8(binfo->vram, binfo->scrnx, 0,0,0,binfo->scrnx, binfo->scrny); sprintf(s, "key = %d", data); putfonts8_asc(binfo->vram, binfo->scrnx, 8, 8, 7, s); return; }
直接修改中断函数里面的代码即可,主要就是获取data然后输出
head.h
/*interrupt.c*/ #define PORT_KEYDAT 0x0060
这个是数据的地址,你要修改一下head.h,刚刚的那个函数要用的
运行:
cd class05 ..\z_tools\make.exe run
如果你发现你的键盘按一下就没用了可能是现在的键盘有点新,你可以把大写锁定打开,如果你不想这么麻烦,你可以自己买老键盘,最好2010之前的也可以买罗技k120这个型号的我就是这个试着没问题
还有我把main.c的输出那几句删了避免显示重叠
今天还没完呢,我还得讲一下fifo,first in first out,这个东西是用来缓存数据的,我刚刚给你们的键盘输入是不是还行,但是这个有个问题就是你按键盘的时候pic完全为键盘+屏幕输出服务,比如你用pic搞计时器,计时器会受影响,屏幕输出要花时间的pic等不起,或许你看不出来但是这对pic影响很大,所以我们要先把数据保存下来然后慢慢的输出,这时候pic就只负责保存数据到内存,不要显示。
fifo.c
#include "include/head.h" void 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; }
代码给你们直接用就是,我解释也解释不清,我乃cv工程师不需要知道原理
/*fifo.c*/ struct FIFO8 { unsigned char *buf; int p, q, size, free, flags; }; #define FLAGS_OVERRUN 0x0001 void fifo8_init(struct FIFO8 *fifo, int size, unsigned char *buf); int fifo8_put(struct FIFO8 *fifo, unsigned char data); int fifo8_get(struct FIFO8 *fifo); int fifo8_status(struct FIFO8 *fifo);
这个添加到head.h里面去都是fifo要用的
/*naskfunc.asm*/ void io_stihlt(); void io_hlt(void); void io_cli(void); void io_sti(void); int io_get8(int port); void io_set8(int port, int data); void write_mem8(int addr, int data); int io_load_eflags(void); void io_store_eflags(int eflags); void load_gdtr(int limit, int addr); void load_idtr(int limit, int addr); void asm_inthandler21(void); /* asmhead.nas */ struct BOOTINFO { /* 0x0ff0-0x0fff */ char cyls; /* 启动区读磁盘读到此为止 */ char leds; /* 启动时键盘的LED的状态 */ char vmode; /* 显卡模式为多少位彩色 */ char reserve; short scrnx, scrny; /* 画面分辨率 */ char *vram; }; #define ADR_BOOTINFO 0x00000ff0 /*graphic.c*/ void init_palette(void); void set_palette(int start, int end, unsigned char *rgb); void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1); void putfont8(char *vram, int xsize, int x, int y, char c, char *font); void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s); /*font*/ extern char font[4096]; /* dsctbl.c */ struct SEGMENT_DESCRIPTOR { short limit_low, base_low; char base_mid, access_right; char limit_high, base_high; }; struct GATE_DESCRIPTOR { short offset_low, selector; char dw_count, access_right; short offset_high; }; void init_gdtidt(void); void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar); void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar); #define ADR_IDT 0x0026f800 #define LIMIT_IDT 0x000007ff #define ADR_GDT 0x00270000 #define LIMIT_GDT 0x0000ffff #define ADR_BOTPAK 0x00280000 #define LIMIT_BOTPAK 0x0007ffff #define AR_DATA32_RW 0x4092 #define AR_CODE32_ER 0x409a #define AR_INTGATE32 0x008e /* pic.c */ void init_pic(void); #define PIC0_ICW1 0x0020 #define PIC0_OCW2 0x0020 #define PIC0_IMR 0x0021 #define PIC0_ICW2 0x0021 #define PIC0_ICW3 0x0021 #define PIC0_ICW4 0x0021 #define PIC1_ICW1 0x00a0 #define PIC1_OCW2 0x00a0 #define PIC1_IMR 0x00a1 #define PIC1_ICW2 0x00a1 #define PIC1_ICW3 0x00a1 #define PIC1_ICW4 0x00a1 /*interrupt.c*/ #define PORT_KEYDAT 0x0060 void inthandler21(int *esp); /*fifo.c*/ struct FIFO8 { unsigned char *buf; int p, q, size, free, flags; }; #define FLAGS_OVERRUN 0x0001 void fifo8_init(struct FIFO8 *fifo, int size, unsigned char *buf); int fifo8_put(struct FIFO8 *fifo, unsigned char data); int fifo8_get(struct FIFO8 *fifo); int fifo8_status(struct FIFO8 *fifo);
加粗你懂吧,都是新加的,上面单独这句也要,之前说了,是键盘接收数据的地址
修改interrupt.c
#include "include/head.h" struct FIFO8 keyfifo; void inthandler21(int *esp) /* 来自PS/2键盘的中断 */ { unsigned char data; io_set8(PIC0_OCW2, 0x61); /* 通知PIC,说IRQ-01的受理已经完成 */ data = io_get8(PORT_KEYDAT); fifo8_put(&keyfifo, data); return; }
就是保存数据了,fifo还要初始化,我们在main里面初始化,在main的死循环里面读取
main.c
#include "include/head.h" #include <string.h> struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO; extern struct FIFO8 keyfifo; void Main(void){ int i;char s[256]; char keybuf[256]; init_gdtidt(); init_pic(); io_sti(); fifo8_init(&keyfifo, 32, keybuf); init_palette(); io_set8(PIC0_IMR, 0xf9); /* 开放PIC1和键盘中断(11111001) */ for (;;) { io_hlt(); if (fifo8_status(&keyfifo)== 0) { io_stihlt(); } else { int i = fifo8_get(&keyfifo); io_sti(); if(i<129) { boxfill8(binfo->vram, binfo->scrnx, 0,0,0,binfo->scrnx, binfo->scrny); sprintf(s, "key = %d", i); putfonts8_asc(binfo->vram, binfo->scrnx, 8, 8, 7, s); }else{ boxfill8(binfo->vram, binfo->scrnx, 0,0,0,binfo->scrnx, binfo->scrny); sprintf(s, "key = -"); putfonts8_asc(binfo->vram, binfo->scrnx, 8, 8, 7, s); } } } }
加粗懂我意思吧,最后修改Makefile就可以编译运行了
运行:
cd class05 ..\z_tools\make.exe run
自制操作系统合集
原文地址:https://www.cnblogs.com/Frank-dev-blog/category/2249116.html
项目github地址rick521/My-OS (github.com)给我点颗star