作業系統實驗第七天:從滑鼠接受資料

HNU.小白發表於2020-11-19

一、實驗主要內容
內容1:獲取按鍵編碼
在這裡插入圖片描述

將目光轉移到“io_out8(PIC0_OCW2,0x61)”,這句話上,這句話用來通知PIC“已經知道IRQ1中斷”。如果是IRQ3,則寫成0x63。執行這句話後,PIC繼續時刻監視IRQ1中斷是否發生。
在執行之後,按下鍵盤上任意一個按鍵,都會有對應的數字編碼顯示出來。比如A就會顯示出1E。
內容2:加快中斷處理
字元顯示的內容被放在了中斷處理程式中。所謂中斷處理,基本上就是打斷CPU本來的工作,加塞要求進行處理。所以應該完成的乾淨利落。這樣子會不連貫。
另一方面,字元顯示是要花大塊的時間來進行的處理。這期間誰也不知道其它中斷會在哪個瞬間到來。很可能在鍵盤輸入的同時,就有資料正在從網上下載,而PIC還在等待鍵盤中斷處理的結束。
先將按鍵的編碼接收下來,儲存到變數。然後讓Harimain偶爾去檢視這個變數。如果發現有資料,就把它顯示出來。
程式碼部分如下:
在這裡插入圖片描述

考慮到鍵盤輸入時需要緩衝區,我們定義了一個構造體,命名為keybuf。其中的flag變數用於表示這個緩衝區是否為空。如果flag為0,表示緩衝區為空;如果flag為1,則表示緩衝區中存有資料。那麼,如果緩衝區中存有資料,而這時候又來了一箇中斷,應該怎麼辦?在此先不做任何處理,先就當作扔了這個資料。
Harimain函式如下:
在這裡插入圖片描述

用io_cli指令遮蔽中斷,為防止在執行其後的處理時,如果有中斷進來,那可就亂套了。
如果flag==0,說明鍵還沒有被按下,keybuf.data沒有值被儲存下來。因為已經執行了遮蔽中斷,如果之後無事可做執行HLT的花,程式就不再會有任何反應。所以執行了io_stihlt,這樣的話,收到PIC通知後,CPU就可以被喚醒了。
進行測試了之後,可以發現可以順利執行,但是在按下右ctrl時,不管按下還是鬆開,螢幕上顯示的都是E0,正常應該是按下去顯示1D,鬆開時顯示9D。
查詢資料得知,當按下右ctrl時,會產生兩個位元組的鍵碼值“E0,1D”鬆開時是“E0,9D”。所以一次按鍵就會有兩次中斷。在收到E0之前,又收到前一次按鍵產生的1D或者9D,而這個位元組被捨棄了。
內容3:製作FIFO緩衝區
上面會出現錯誤,是因為之前只能接收一箇中斷髮來的資料,所以中斷髮生的太快,有超過一個位元組的資料就會被忽略,所以如下這樣做:
增加變數
在這裡插入圖片描述

data用陣列儲存


顯然,用陣列更方便一些,我們在使用這些緩衝資料時,要採取FIFO策略,也就是先入先出策略,程式實現:
在這裡插入圖片描述

for迴圈中相當於把資料存放位置全部都向前移送一個位置。如果不移送的話,下一次就不能從data[0]讀入資料了。
在這裡插入圖片描述

執行之後可以發現按下右Ctrl鍵執行正常,但並沒有OK,有些地方還不盡如人意。就是這樣的移送資料在資料過多的時候,還是挺麻煩的。
內容4:改善FIFO緩衝區
既維護下一個要寫入資料的位置,也維護下一個要讀出資料的位置
在這裡插入圖片描述

但是當下一個資料寫入位置到達緩衝區終點時,資料讀出位置也恰好到達緩衝區的終點,也就是說緩衝區正好變空。我們只要將下一個資料寫入位置和下一個資料讀出位置都再置0即可,就像從頭再來一樣。但是還是會有資料讀出位置沒有追上寫入位置的情況,就還要資料移送,我們還是想盡量避免。
當下一個資料寫入位置到達緩衝區最末尾時,緩衝區開頭部分應該變空了。因此如果下一個資料寫入位置到了32之後,就強制性將之設定為0,這樣一來,下一個資料寫入位置就跑到了下一個資料讀出位置的後面,讓人覺得怪怪的。但不會有什麼問題。
在這裡插入圖片描述

程式如下:

在這裡插入圖片描述

讀出資料程式如下:
在這裡插入圖片描述

內容5:整理FIFO緩衝區
將結構做成一下這樣:
在這裡插入圖片描述

如果我們將緩衝區大小固定為32位元組的話,以後改起來就不方便,所以將之定義為可變的,幾個位元組都行。緩衝區的總位元組數儲存在變數size裡。變數free用於儲存緩衝區裡沒有資料的位元組數。緩衝區的地址當然也必須儲存下來。我們將之儲存在變數buf中。p代表下一個資料寫入地址,q代表下一個資料讀出地址。
下面是結構的初始化函式
在這裡插入圖片描述

關於往FIFO緩衝區儲存1位元組資訊的函式如下。
在這裡插入圖片描述

這裡出現的新東西,應該就是return語句後面跟著數字的寫法。如果有人呼叫以上函式,寫出類似於“i=fifo8_put(fifo,data);”這種語句,我們就可以通過這種方式指定賦給i的值。為了能夠簡單明瞭地確認到底有沒有發生溢位,筆者將之設定在-1或0,分別表示有溢位和沒有溢位這兩種情況。
下面是從緩衝區取出1位元組的函式。
在這裡插入圖片描述

調查緩衝區狀態的函式:
在這裡插入圖片描述

執行之後依舊執行正常。
內容6:總算講到滑鼠了
鍵盤控制電路部分:
在這裡插入圖片描述

其中wait_KBC_sendready的作用是讓鍵盤控制電路做好準備動作,等待控制指令的到來。
因為雖然CPU的電路很快,但是鍵盤控制電路卻沒有那麼快。如果CPU不管裝置接收資料的能力,只是傳送指令,那麼有些指令就會得不到執行,從而導致錯誤的結果。如果鍵盤控制電路可以接收CPU指令,CPU從裝置號碼0x0064處所讀取的資料的倒數第二位應該是0。在確定這位是0之前,程式一直通過for語句迴圈查詢。
Break語句是從for迴圈中強制退出的語句,退出以後,只有return語句在哪裡等待執行,因此,將這裡的break語句換寫成return語句,結果也是一樣的。
init_keyboard函式是一邊確認可否往鍵盤控制電路傳送資訊,一般傳送模式設定指令,指令中包含著要設定為何種模式,模式設定的指令是0x60,利用滑鼠模式的模式號碼是0x47。
在這裡插入圖片描述

該函式與init_keyboard函式非常相似,不同點僅在於寫入的資料不同。如果往鍵盤控制電路傳送指令0xd4,下一個資料就會自動傳送給滑鼠。另一方面,當滑鼠收到啟用指令以後,馬上給CPU傳送答覆資訊。這個答覆資訊就是0xfa。
測試之後,可以對滑鼠中斷做出相應。
內容七:FIFO與滑鼠控制
基本與鍵盤的原理和程式差不多。
中斷函式:
在這裡插入圖片描述

資料取得方法,和鍵盤完全相同,如下:
在這裡插入圖片描述

也許是因為鍵盤控制電路中含有滑鼠控制電路,才造成了這種結果。
最後執行之後,發現鍵盤和滑鼠的功能都可以相應。滑鼠的滾動也會相應出對應資料。

二、遇到的問題及解決方法
問題1:
在設計圓的邊界問題的時候,因為在設計的時候涉及到了速度的變化,那麼速度如果不是1的話,在判斷邊界的時候,就有可能越界。解決越界問題的方式如下:
在這裡插入圖片描述

即判斷到下一次移動如果要移出螢幕或者正好到邊界的話,就設定好這次到的位置。然後對這個圓進行列印。這樣的話,不管再怎麼移動,也不會移出螢幕。
問題二:
還是在這個部分,當時驗收的時候,老師看到我在移動到右邊界的時候,左邊界多出來一個畫素點,後來我想了一下,整個螢幕是320200,但是我按的兩個邊界是0-320,也就是321200了,所以實際上是越界了,而整個VGA實際上是一個一維陣列而已,所以自然就顯示到了下一行。修改方式就是定義的位置左移一下就行了:
在這裡插入圖片描述

三、創新點
創新點一:
關於速度的變化,只要每一次改變圓移動的步長,也就改變了速度,所以定義一個變數speed,在按下w或s的時候speed變化就行了。
在這裡插入圖片描述

創新點二:
修改圓的顏色,函式中COL的部分用變數代替,然後再按下對應按鍵的時候更改這個顏色變數即可。
在這裡插入圖片描述

相關文章