蜂鳴發聲器
目前制作的作業系統還不能發聲呢,由于呼叫聲卡的程序比較復雜,這里我們就先實作蜂鳴器發聲好了,蜂鳴器發出的聲音,是那種嗶嗶嗶嗶的,聽起來有些奇怪,這里設定聲音的頻率隨著時間以100Hz的速度降低,當聲音頻率降到20Hz以下或鍵盤按下任意鍵時結束,
beepdown.c
void HariMain(void)
{
int i, timer;
timer = api_alloctimer();
api_inittimer(timer, 128);
for (i = 20000000; i >= 20000; i -= 100000) {
/* 20KHz~20Hz : 人類可以聽到的聲音范圍 */
api_beep(i);
api_settimer(timer, 1);
if (api_getkey(1) != 128) {
break;
}
}
api_beep(0);
api_end();
}
這里沒有呼叫聲卡,所以虛擬機里不用設定聲卡也可以聽到聲音,
make run 一下——

將 i 改為遞增的,以 i %的速度遞增則會聽到聲音頻率升高的聲音,發出的聲音要比之前感覺起來好多了,
beepup.c
void api_end(void);
int api_getkey(int mode);
int api_alloctimer(void);
void api_inittimer(int timer, int data);
void api_settimer(int timer, int time);
void api_beep(int tone);
void HariMain(void)
{
int i, timer;
timer = api_alloctimer();
api_inittimer(timer, 128);
for (i = 20000; i <= 20000000; i += i / 100) {
api_beep(i);
api_settimer(timer, 1);
if (api_getkey(1) != 128) {
break;
}
}
api_beep(0);
api_end();
}
make run一下——

顯示多種顏色
現在來實作可以顯示多種顏色的應用程式,將光的三原色RGB(紅、綠、藍)中每個顏色賦予6個色階,這樣可以定義出6×6×6=216種顏色,
graphic.c節選:
void init_palette(void)
{
static unsigned char table_rgb[16 * 3] = {
(略)
};
unsigned char table2[216 * 3];
int r, g, b;
set_palette(0, 15, table_rgb);
for (b = 0; b < 6; b++) {
for (g = 0; g < 6; g++) {
for (r = 0; r < 6; r++) {
table2[(r + g * 6 + b * 36) * 3 + 0] = r * 51;
table2[(r + g * 6 + b * 36) * 3 + 1] = g * 51;
table2[(r + g * 6 + b * 36) * 3 + 2] = b * 51;
}
}
}
set_palette(16, 231, table2);
return;
}
這里RGB顏色與色號的對應關系為:色號 = 16 + r * 1 + g * 6 + b * 36 ,
實作顯示多種顏色的應用程式color,這里將紅色通道關閉,僅顯示綠色和藍色的色階變化,
color.c節選
void HariMain(void)
{
char *buf;
int win, x, y, r, g, b;
api_initmalloc();
buf = api_malloc(144 * 164);
win = api_openwin(buf, 144, 164, -1, "color");
for (y = 0; y < 128; y++) {
for (x = 0; x < 128; x++) {
r = 0;
g = x * 2;
b = y * 2;
buf[(x + 8) + (y + 28) * 144] = 16 + (r / 43) + (g / 43) * 6 + (b / 43) * 36;
}
}
api_refreshwin(win, 8, 28, 136, 156);
api_getkey(1);
api_end();
}
make run——

讓色彩更加豐富,可以用兩種顏色交替排列,看上去就像是這兩種顏色混合在一起一樣,純色中間可以產生3個中間色,這樣6級色階能夠可以顯示出21級色階,(6 + 5 × 3 = 21)
color2.hrb節選:
unsigned char rgb2pal(int r, int g, int b, int x, int y);
void HariMain(void)
{
char *buf;
int win, x, y;
api_initmalloc();
buf = api_malloc(144 * 164);
win = api_openwin(buf, 144, 164, -1, "color2");
for (y = 0; y < 128; y++) {
for (x = 0; x < 128; x++) {
buf[(x + 8) + (y + 28) * 144] = rgb2pal(0, x * 2, y * 2, x, y);
}
}
api_refreshwin(win, 8, 28, 136, 156);
api_getkey(1);
api_end();
}
unsigned char rgb2pal(int r, int g, int b, int x, int y)
{
static int table[4] = { 3, 1, 0, 2 };
int i;
x &= 1; /* 判斷是偶數還是奇數 */
y &= 1;
i = table[x + y * 2]; /* 用來生成中間色的常量 */
r = (r * 21) / 256; /* r為0~20 */
g = (g * 21) / 256;
b = (b * 21) / 256;
r = (r + i) / 4; /* r為0~5 */
g = (g + i) / 4;
b = (b + i) / 4;
return 16 + r + g * 6 + b * 36;
}
執行make run,有點漸變色效果——

增加命令列視窗
我們熟知的作業系統都是可以同時運行多個應用程式的,目前制作的作業系統只有一個命令列視窗,且命令列視窗只能執行一個應用程式,我們想要同時運行兩個應用程式,最簡單的方法就是同時啟動兩個命令列視窗,
實作這個功能,需要修改的地方包括:
1.將與命令列視窗相關的變數定義為陣列,通過回圈進行相同的處理,這樣不管增加多少個命令列視窗都很方便,
2.將用于判斷向哪個命令列視窗輸出字符的變數cons,保存到每個任務各自的TASK結構中,這樣就可以由不同的任務讀取不同的值了,
bootpack.h節選:
struct TASK {
int sel, flags; /* sel代表GDT編號 */
int level, priority;
struct FIFO32 fifo;
struct TSS32 tss;
struct CONSOLE *cons; /* 變數cons保存到這里 */
int ds_base;
};
3.在啟動應用程式時,指定了段號,當啟動下一個應用程式時,之前的使用的段會被覆寫,比如color.hrb 指定了1003號 和 1004號,當運行color2.hrb時,這兩個段會被覆寫,因此需要為color.hrb和color2.hrb分配編號不同的段,
console.c節選:
(略)
set_segmdesc(gdt + task->sel / 8 + 1000, finfo->size - 1, (int) p, AR_CODE32_ER + 0x60);
set_segmdesc(gdt + task->sel / 8 + 2000, segsiz - 1, (int) q, AR_DATA32_RW + 0x60);
(略)
start_app(0x1b, task->sel + 1000 * 8, esp, task->sel + 2000 * 8, &(task->tss.esp0));
(略)
4.實作正常關閉視窗,當使用Shift +F1 鍵盤強制結束 和用滑鼠點擊 × 按鈕會以當前點擊的視窗為物件,
bootpack.c節選,添加鍵盤強制結束代碼:
if (i == 256 + 0x3b && key_shift != 0) {
task = key_win->task;
if (task != 0 && task->tss.ss0 != 0) { /* Shift+F1 */
cons_putstr0(task->cons, "\nBreak(key) :\n");
io_cli(); /* 強制結束處理時,禁止任務切換 */
task->tss.eax = (int) &(task->tss.esp0);
task->tss.eip = (int) asm_end_app;
io_sti();
}
}
bootpack.c節選,添加滑鼠點擊×按鈕結束代碼:
if (sht->bxsize - 21 <= x && x < sht->bxsize - 5 && 5 <= y && y < 19) {
/* 點擊“×”按鈕 */
if ((sht->flags & 0x10) != 0) { /* 是否為應用程式視窗 */
task = sht->task;
cons_putstr0(task->cons, "\nBreak(mouse) :\n");
io_cli(); /* 強制結束處理時,禁止任務切換 */
task->tss.eax = (int) &(task->tss.esp0);
task->tss.eip = (int) asm_end_app;
io_sti();
}
}
task_a視窗不是應用程式,而是作業系統的一部分,放在這里有些礙眼了,把它洗掉掉,
洗掉相關代碼后,執行一下make run——

注:本文參照《30天自制作業系統》制作,感謝各位的持續關注,原著原始碼鏈接見第十九篇,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/310576.html
標籤:其他
上一篇:C++入門篇(3)之類和物件上
