Nội dung bài giảng môn Thiết bị ngoại vi và ghép nối nội dung chương 7: Điều khiển thiết bị

Nội dung bài giảng môn Thiết bị ngoại vi và ghép nối nội dung chương 7: Điều khiển thiết bị của Học viện Công nghệ Bưu chính Viễn thông với những kiến thức và thông tin bổ ích giúp sinh viên tham khảo, ôn luyện và phục vụ nhu cầu học tập của mình cụ thể là có định hướng ôn tập, nắm vững kiến thức môn học và làm bài tốt trong những bài kiểm tra, bài tiểu luận, bài tập kết thúc học phần, từ đó học tập tốt và có kết quả cao cũng như có thể vận dụng tốt những kiến thức mình đã học vào thực tiễn cuộc sống. Mời bạn đọc đón xem!

lOMoARcPSD|10435767
CHƯƠNG 7 ĐIỀU KHIN THIT B (DEVICE DRIVERS) LT6
7.1 KHÁI NIỆM
Một “device driver” một chương trình iều khin mt thiết bị cụ thcm vào máy
tính. dụ c “device driver” cho các máy in, các màn hình hin thị, các ĩa CD
ROM, các bọc ĩa …. Khi cài một hiều hành trên y tính, ã rt nhiều “device
driver” ược thiết kế sn bên trong nó. Tuy nhiên, khi sdụng mt thiết bị mi, hay khi
tchế tạo ra mt hthng mạch giao tiếp vi máy tính, hiu hành sẽ chưa hỗ trc
thiết bị y, thì cn i t một “device driver” mới cho chúng. Một “device driver” v
bản cht biến ổi nhiu lnh vào ra chung của hệ iều hành thành c thông iệp mà thiết bị
thhiểu ược.
Mt schương trình chạy trong windows “device driver” o. c chương trình
này giao tiếp vi giao din quản y o của Windows (Windows Virtual Machine
Manager). Mi thết bị phn cng chính trong hthng sẽ một “device driver” o,
dụ như: biều khiển ĩa cng, bàn phím, các cng giao tiếp ni tiếp, song song. Chúng
ược sdụng duy trì trạng thái của mt thiết bị phn cng ththay ổi các thiết lp.
Các “device driver” o sẽ xử lý các ngt mm trong hthng, thay cho vic sdụng các
ngt cng.
Trong hệ iều hành Windows, mt tp tin “device driver” thường có uôi dưi dạng
DLL hoc EXE, còn mt “device driver” o thường có uôi là VXD.
Để viết mt Driver cn hiu biết sâu vphn cng phn mm hthng. Các driver
hoạt ộng môi trường có mức ặc quyn cao, và chúng có thgây nguy him nếu chúng
sai sót. Ngược lại, hàu hết các phn mm mc người s dụng hoạt ng dưới các h
iều hành hiện i, thngng hợat ng không nh hưởng ti c phn còn lại của
hthng. Ngay cả c driver hoạt ng trong chế n người sdụng ng thgây
hỏng hthng nếu chúng ược lp trình sai.
thế vic viết các driver trong thc tế thường ưc các kphần mm trong các
công ty chế tạo phn cng thc hin, do họ có các thông ti tốt hơn vthiết kế phn cng
của họ. Hơn nữa trong thương mại các hãng chế tạo phn cng u mun khách hàng của
mình sử dụng mt cách tối ưu các thiết bị phn cng của họ. Thông thường các logical
device driver (LDD) ược các nhà cung cp hiều hành viết, trong khi ó các physical
device driver (PDD) ược cung cp tc nhà cung cp thiết bị. Nhng năm gần ây một
sc giả không cung cp hiều hành phn cng thiết bị ng thc hin các driver,
chúng chủ yếu thc hin cho các hiều hành mã ngun m. Trong các trường hp này,
quan trọng các nhà sn xut phn cng cn cung cp các thông tin vvic truyn thông
tin trong các thiết bị của họ. Đối vi các kngành iện ty nh, phát trin các
phn cng kết ni vi y tính cn phải thc hin các driver htrcho các thiết bị
này.
lOMoARcPSD|10435767
Hãng phn mềm Microsoft ang cố gng giảm bt skhông ổn nh của hthng do c
driver ược viết không tt bng các tạo ra mt khung mi (new framework) cho vic phát
trin c driver ược gọi WDF (Windows Driver Foundation). bao gm User-Mode
Driver Framework (UMDF) htr người sdụng tphát trin các driver cho các thiết
bị bng cách thc hin mt bgiao thức thông iệp cơ sở (message-based protocol), cho
việc trao i thông tin vi các thiết bị của họ, ging như một driver lp người s
dụng. Nếu các driver này sai chức năng nó sẽ không y nh hưởng ti ổn nh của h
thng. Chế Kernel-Mode Driver Framework (KMDF) cho phép phát trin các driver
trong lp lõi (kernel-mode), nhưng tạm thi cung cp các tiêu chun thc hin của các
chức năng ể xử lý khi xảy ra li bao gm:
bỏ qua hoạt ộng của vào ra, quản lý ngun, cm và chạy các thiết bị.
7.2 PC LAYERS
Hình 7.1: Phân lp phn mm trong máy tính
Hình 7.1 tả sphân lp phn mm trong máy tính nhân, các thiết bị chun cm
vào máy nh như bàn phím, màn hình, con chut, biều khin ĩa, các cng vào ra
song song, ni tiếp, USB … thông thường ưc các phn mm viết sn htr. Các phn
mm y bao gm c chương trình ngt cha trong ROM BIOS cm sn trên bo mạch
chính máy tính, c chương trình htrợ của hiều hành DOS, WINDOWS gọi tt là OS
(Operating system). c chương trình người s dụng lp chương trình ng dụng (Appl.
Prog. Application Program), có ththc hin vic iều khin trc tiếp các thiết bị bng
các lnh vào ra cơ bản, khi biết ược cơ chế trao i thông tin của các thiết bị, hoc có th
gọi các chương trình ã thc hin trong ROM BIOS và trong hiều hành. Tuy nhiên, h
iều hành quản cp phát tài nguyên hthng cho các ng dụng khác nhau thc
lOMoARcPSD|10435767
hin vic bảo vhthng, nênc chương trình lp ng dụng nếu không có các lệnh
thay ổi mức c quyn sẽ không ược phép thc hin các lnh truy cp trc tiếp ti phn
cng hthng.
Trong các chương trình hp ngvic gọi các ngt của BIOS DOS ược thc hin
bng các lnh gọi ngt INT (Interrupt), hthng máy tính có tt cà 256 vector ngắt như
ã tả trong chương 3. Mt sngôn ngcp cao khác ng htrvic gọi các ngt của
hthng bng phn mm.
7.3 DOS DEVICE DRIVERS
7.3.1 Truy cập thiết bị bằng các lệnh vào ra
Như ã cp, thc hin các chương trình iều khin thiết bị “device driver” dưới môi
trường DOS, có ththc hin các lnh truy cp trc tiếp ti vào ra của các ngôn ng
lp trình dưới DOS. Sau ây là ví dụ về các lnh truy cp vào ra trong các ngôn ngữ khác
nhau. Lập trình hợp ng
Xut dliu tbiến data ra cng có a chỉ address:
mov dx, address
mov ax, data
out dx, ax
Ví dụ: mov dx, 300H
mov ax, F0H
out dx, ax
Nhp sliu tcổng ịa chỉ address vào biến data
mov dx, address in ax, dx mov data, ax
data, address là số nhị phân 16 bit. Qbasic
Dùng lnh INP (port%) OUT port%, data% port snguyên t0 ến 65535 chỉ
a chỉ cng data snguyên t0 ÷ 255,&H hiu sHex phía sau , % hiu
biến là s
nguyên
Ví dụ: a% = INP (&H3FC) ‘ ọc sliu cng 3FCH, thanh ghi modem
OUT &H3FC, (a% XOR 1) ‘ ảo bit cui, xut ra cng 3FCH
OUT 768, 160 ‘ xut A0H ra cng 300H
Pascal
Dùng lnh port: xut nhp mt byte, portw: xut nhp mt t
{Xuất ra port ịa chỉ reg:} port[reg]:
= data;
{ọc số liệu ở port ịa chỉ reg vào biến value} .
value: = port [reg];
Ví dụ: data: = port [$378];
lOMoARcPSD|10435767
port [$37A]:= data out; C,
C Builder, Visual C
Dùng lnh inp và outp (hay inportb, outportb, inport,
outport) Control = inp (0X61); outp (0X43, 0Xb6);
Visual C++ 6.0 có các m và thủ tục:
_inp: c byte _outp: xut byte
_inpw: c mt t_outpw: xut t
_inpd: c từ kép _outpd: xut từ kép
dụ: lp trình C
# include <conio.h>
# define dataport 0x378
# define statusport 0x379
int Dummy:
Dummy = _outp(dataport, 0);
Dummy = _inp(statusport);
...
7.3.2 Truy cập các thiết bị chuẩn bằng ngắt mềm
Với các thiết bị chuẩn có thể sử dụng các ngắt của DOS và BIOS ể truy cập thiết bị.
Sau ây là mt số ngắt cơ bản truy cập tới các thiết bị và các cổng chuẩn trên máy tính:
Ngắt 21H:
Hàm 01H ngắt 21H: c mt ký ttừ bàn phím
Mt ký tự sẽ ược ọc vào từ bàn phím và hin lên màn hình. Nếu tại thời iểm gọi hàm
chưa có ký tsn sàng, thì hàm sẽ ợi cho ti khi có phím ược nhn.
Vào: AH = 01
Ra: AL cha mã ASCII của phím nhn
Khi nhận ược các ký tự có mã mrng AL = 0. Lúc này có thể gi hàm mt ln na
ọc ược mã mrng.
Khi ký tự vào là Ctrl C (mã ASCII là 3) ngt 23H sẽ ược gọi trả iều khin vDOS.
Ngoài AL, ni dung các thanh ghi khác không bị thay ổi sau khi gọi hàm.
dụ khi gọi hàm này có thviết:
MOV AH,02
INT 21H
Hàm 02H ngắt 21H: Hin mt ký tlên màn hình.
Hàm này cho phép hin mt ký tlên màn hình
Vào: AH = 02
DL cha mã ASCII của ký tcn hin th.
Ra: không.
Tt cả các thanh ghi không bị thay i sau khi gọi hàm, các mã c biệt như
lOMoARcPSD|10435767
Backspace (xoá ký ttrước), Carriage Return (về ầu hàng) và Line Feed (xung hàng)
sẽ ược ghi trên màn hình dưới dạng lnh.
Hàm 09 ngắt 21H: Hin chui ký tlên màn hình.
Vào: AH = 09
DX chứa ịa chỉ offset của chui cn hin thị.
Ra:không
Chui ký tcần ặt trong bnhdưới dạng mt chui các byte ASCII, kết thúc là ký t
‘$’ (mã ASCII là 36). Các mã ặc biệt như Backspace (xoá ký ttrước), Carriage Return
(vu hàng) Line Feed (xung hàng) sẽ ưc ghi trên màn hình dưới dạng lnh. Chỉ
AL bị thay ổi sau khi gọi hàm.
Hàm 4CH ngắt 21H: kết thúc chương trình loại .EXE.
Hàm y kết thúc chương trình truyn vmt li, chương trình gọi thnhn
ược li y bng cách gọi hàm 4DH, bnhRAM cho chương trình chiếm sẽ ược
giải phóng.
Ngắt 10H của BIOS và chế ộ văn bản trên màn hình màu:
Màn hình màu a chỉ RAM là B800:0000. Trong chế văn bản 80 hàng 25 ct mi
ký tsẽ ược cha bng hai byte trong bnhn hình, byte ầu là ASCII của ký t
byte sau thuc tính của t. Như vậy a chỉ ASCII của mt t trên màn
hình trong bnhớ sẽ là :
Offset(hàng, ct) = hàng x160 + ct x 2.
Hàm 00 ngắt 10H: Đặt chế ộ màn hình.
Hàm này cho phép t lại chế ộ màn hình. Toàn bộ màn hình sẽ bị xoá, vì vy có th
dùng hàm này ể xoá toàn bn hình ngay cả khi không muốn thay ổi chế ộ n
hình.
Vào: AH = 0
AL = chế ộ màn hình:
0: chế ộ 40x25 ký t, en trắng. 1:
chế ộ 40x25 ký t, màu.
2: chế ộ 80x25 ký t, en trắng.
3: chế ộ 80x25 ký t, màu.
4: chế ộ 320x200 iểm ồ thị, 4 màu.
5: chế ộ 320x200 iểm ồ thị, 2 màu.
6: chế ộ 640x200 iểm ồ thị, 2 màu.
7: chế ộ của màn hình mono.
8: chế ộ 160x200 im ồ thị, 16 màu.
9: chế ộ 320x200 iểm ồ thị, 16 màu.
0A: chế ộ 640x200 iểm ồ thị, 4 màu.
0B: chế ộ 640x200 iểm ồ thị, 16 màu.
10H: chế ộ 640x350 iểm ồ thị, 16 màu.
lOMoARcPSD|10435767
11H: chế ộ 640x480 iểm ồ thị, 2 màu.
12H: chế ộ 640x480 iểm ồ thị, 256 màu.
Ra: không
Ni dung các thanh ghi BX, CX, DX, SS, CS, DS không bị thay ổi sau khi gọi hàm.
Các thanh ghi còn lại có thể bị thay ổi.
Hàm 02 ngắt 10H: Đặt vị trí con trỏ.
Hàm này cho phép t con trỏ ti mt vị trí nào ó trên màn hình, sau ó cho phép ưa ra
màn hình bng các hàm khác của BIOS.
Vào: AH = 02
BH = strang màn hình (0 ti 7)
DH = Toạ ộ dòng.
DL = Toạ ộ ct.
Ra: không
Chú ý :
- Con trỏ nhp nháy trên màn hình chỉ bị thay ổi vị trí khi trang màn hình là trang
hin hành.
- Toạ ộ dòng nhn các giá trị t0 ti 24, ct t0 ti 79. Có thể làm con trỏ biến mt
bng cách ặt nó nm ngoài các toạ nêu trên.
- Ni dung các thanh ghi BX, CX, DX, CS, DS và SS không bị thay ổi. Hàm 03
ngắt 10H: Đọc vị trí con trỏ.
Hàm này cho phép c vị trí con trỏ trên mt trang màn hình và kích thước nhp nháy
của nó.
Vào: AH = 03H
BH = strang màn hình.
Ra: DH = toạ ộ dòng, DL = toạ ộ ct.
CH = dòng bắt ầu của con trỏ, CL dòng kết thúc của con trỏ.
Hàm 05 ngắt 10H: Chọn trang màn hình hin hành
Vào : AH = 05
AL = strang.
Ra:không
Khi trang ược chọn nó sẽ hin lên trên màn hình, con trỏ sẽ ly toạ ộ của trang ó, lúc
này có thghi vào trang ang ược kích hoạt.
Hàm 06 ngắt 10H: Cun ca slên.
Cho phép cun mt số dòng văn bản của ca s, hoc xoá toàn bca s.
Vào: AH = 06
AL = số dòng mun cun lên (0 là xoá ca s).
CH = toạ ộ dòng góc cao bên trái.
CL = toạ ộ ct góc cao bên trái.
DH= toạ ộ dòng góc dưới bên phải.
lOMoARcPSD|10435767
DL = toạ ộ ct góc dưới bên phải.
BH = màu thuc tính cho các dòng bị xoá.
Các bit thuc tính của BL bao gm: D7:
nhp nháy (1 cho phép chnhp nháy) D6,
D5, D4: màu nn.
D3 D0: màu ch
Các màu tương ứng vi các giá trị t0 ti 0FH là : Đen, Xanh da tri, Xanh lục, Xanh
dương, Đỏ, Tím, Nâu, Xám nhạt, m sm, Xanh da tri nhạt, Lục nhạt, Xanh dương
nhạt, Hng, Tím nhạt, Vàng, Trng.
Ra: không.
Chú ý : Hàm này chỉ làm vic vi trang màn hình hin hành. Khi AL = 0 ca sổ sẽ ược
xoá iền vào bng các t trng (mã ASCII 32). Ni dung các dòng cun sẽ bị
mt và không thkhôi phục lại.
Hàm 0A ngắt 10H: ghi ký t.
Cho phép ghi ký tự vào vị trí hin hành của con trỏ trong mt trang màn hình.
Vào : AH = 0AH
BH = strang màn hình.
CX = sln lp lại của ký t.
AL = mã ASCII của ký t.
BL = thuc tính của ký t(chỉ có ý nghĩa tả )
Ra: không
Chú ý : Trong chế ộ ồ thị nếu phải lp lại ký tnhiu ln, thì trang màn hình sẽ là hin
hành. Các mã iều khin sẽ ược in ra như các ký tASCII thường.
Hàm 13H ngắt 10H: Ghi chui ký tra màn hình.
Vào : AH = 13H
AL = chế ộ ghi.
AL = 0: Thuc tính trong BL, không thay ổi vị trí con trỏ.
1: Thuc tính trong BL, chuyn con trỏ ti cui chui.
2: Thuc tính trong vùng m, không thay ổi vị trí con trỏ.
3: Thuc tính trong vùng m, chuyn con trỏ ti cui chui.
BL = thuc tính của các ký t.
CX = số ký tcn ghi.
DH = toạ ộ dòng bắt ầu, DL = toạ ộ ct bắt ầu.
BH = strang màn hình.
ES = a chỉ oạn của vùng m; BP = a chỉ offset của vùng m.
Ra: không.
lOMoARcPSD|10435767
Ngắt 14H - Truyền nhận nối tiếp Tác
dụng : Truy xuất các cổng nối tiếp.
Tham s : AX, DX
BIOS của y PC, hỗ trợ lên ên 4 loại cổng nối tiếp khác nhau ( phần cứng thể h
trợ ến 8 loại ). Nhìn chung, hầu hết tất cả các PC ều có một hay hai cổng nối tiếp
(COM1: và COM2:). Ngắt 14H có 4 hàm con, hỗ trợ nhận và chuyển các ký tự, cho biết
tình trạng các cổng ... Các công ược ánh số từ 0 .. 3 trên dx (0=COM1:, 1=COM2:, .v.v.).
Ngắt 14H chờ và nhận lại dữ liệu từ thanh ghi AL hoặc AX.
Hàm 0h - Ngắt 14h
Hàm 0h skhởi tạo một cổng nối tiếp. giúp thiết lập các thông snhư tốc ộ, số
bit chẵn lẻ, số bits stop (number of stop bits ), số bit ã ược truyền qua ường truyền
(hình 7.2).
Hình 7.2: Các tham scho hàm 0 ngắt 14H
Mặc dù các cổng nối tiếp chuẩn hỗ trợ tốc ộ ến 19.200 baud, nhưng các BIOS không
hỗ trợ tốc ộ ó.
Ví dụ : Khởi tạo cổng COM1: 2400 baud, không kiểm tra chẵn lẻ, 8 bit dữ liệu, và 2 bit
stop : mov ah, 0 ;Initialize opcode mov al, 10100111b ;Parameter data. mov dx, 0
;COM1: port. int 14h
Sau khi oạn code trên ược thực thi, tình trng của cổng sẽ ược trả về ở AX.
Hàm 01h ngắt 14H : Chuyển một ký tự ến cổng.
Hàm y tác dụng chuyển một tự chứa trong AL ến cổng, ã ược chọn trước
trong DX (DX = 0,1,2,3). Khi trả về kết quả, nếu AH chứa zero, thì ký tã ược chuyển
thành công. Nếu bit 7 của AH chứa giá trị 1, nghĩa là quá trình chuyển bị lỗi. Bit 7 chứa
tình trạng của tất cả các lỗi ược trả về. Nếu một lỗi ược báo cáo, bạn có thsử dụng hàm
03h ể lấy các giá trị lỗi từ cổng nối tiếp.dụ: Chuyển một ký tự ến cổng COM1 : mov
dx, 0 ;Select COM1:
mov al, ‘a’ ;Character
to transmit mov ah, 1
;Transmit opcode int 14h
lOMoARcPSD|10435767
test ah, 80h ;Check for error
jnz SerialError
Đoạn lệnh trên sẽ chờ cho ến khi cổng nối tiếp hoàn thành công việc "trans" cho ến
khi hết các ký tự ( nếu chuyển nhiều ký tự ),sau ó sẽ lưu ký t vào thanh ghi vận
chuyển (transmit register).
Hàm 02h ngắt 14H : Nhận kí tự từ cổng nối tiếp
Vào : DX : Chứa số hiệu của cổng nối tiêo ( 0 .. 3 )
Ra : AL chứa kí tự ược ọc từ cổng và bit thứ 7 của AH chứa tình trạng lỗi.
Khi gọi hàm y, nó sko trả quyền iều khiển cho ến khi nhận ược một tự từ cổng.
7.3.3 Truy cập các thiết bị bằng ngắt cứng
Khi thiết kế các giao tiếp phần cứng thông qua các khe cắm, (PCI, ISA,…) hoặc qua
các cổng chuẩn của máy tính, các chương trình iều khiển thiết bị có thể sử dụng các ngắt
phần cứng chưa sử dụng, các ngắt cứng ã thiết kế sẵn cho cổng, thậm chí thcấm
ngắt các thiết bị hiện có trong hệ thống ể cấp ngắt cứng cho thiết bị mới.
Các ngắt cứng của tính ược iều khiển bởi hai vi mạch iều khiển ngắt PIC8259,
các vector ngắt của hệ thống ược cho trong bảng 7.1.
Bảng 7.1: Các vector ngắt của máy tính
INT (Hex)
IRQ
Sử dụng
00 - 01
Exception Handlers
Chia cho zero
02
IRQ không che (NMI)
Sai parity
03 - 07
Exception Handlers
Xử lý các ngoại l
08
Ngt cng IRQ0
Timer hệ thống
09
Ngt cng IRQ1
Bàn phím
0A
Ngt cng IRQ2
Chuyển hướng sang IRQ9
0B
Ngt cng IRQ3
Cổng nối tiếp 2, 4
0C
Ngt cng IRQ4
Cổng nối tiếp 1, 3
0D
Ngt cng IRQ5
Card âm thanh
0E
Ngt cng IRQ6
Đĩa mềm
0F
Ngt cng IRQ7
Cổng song song
10 ÷ 6F
Ngt mềm
Ngt do phầnn mềm
70
Ngt cng IRQ8
Đờng hồ thời gian thc
71
Ngt cng IRQ9
Chuyển hướng tIRQ2
72
Ngt cng IRQ10
Dtr
73
Ngt cng IRQ11
Dtr
74
Ngt cng IRQ12
Con chuột PS/2
75
Ngt cng IRQ13
Đồng xử lý
lOMoARcPSD|10435767
76
Ngt cng IRQ14
Đĩa cng
77
Ngt cng IRQ15
Dtr
78 - FF
Ngt mềm
Ngt do phần mềm
Mun sử dụng ngt ta phải viết chương trình phục vụ ngt ISR, ặt ịa chỉ của
chương trình này vào vị trí phù hp trên bảng vector ngt, trước ó cn phải cất ịa chỉ ã
có sn ể sau ó phục hi trở lại. Khi có ngt xảy ra và ISR thc hin xong phải báo
trở lại cho PIC bng cách gi EOI (end of interrupt) ến OCW2, thông thường là byte
20H (cho ngt thường). Vic khởi ộng PIC do ROM BIOS ảm nhim ta không cn
quan tâm ến.
Ví du : Lp trình ngt dùng C
#include <process.h>
#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <conio.h>
void main(void)
{
No_irq = 5; init_isr(No_irq); {
/*Thêm mã*/ }
close_isr(No_irq);
}
/* INIT INTERRUPT SERVICE ROUTINE */ void init_isr (int irq_num)
{ disable(); if ( irq_num) disable();
if ( irq_num<8 ) old_handler1 =
getvect(irq_num+8);
else old_handler1 = getvect(irq_num-
8+0x70); if ( irq_num < 8 )
setvect(irq_num+8, isr);
else setvect(irq_num-8+0x70, isr); if
( irq_num < 8 )
{ int_mask = inportb(0x21)
& ~(0x01<<irq_num); outportb(0x21,
int_mask);
}
else
{
int_mask = inportb(0xa1) & ~(0x01<<(irq_num-8));
outportb(0xa1, int_mask); }
enable( );
}
lOMoARcPSD|10435767
/* CLOSE INTERRUPT SERVICE ROUTINE */ void close_isr(int irq_num) {
int int_mask; disable(); if ( irq_num < 8 )
{ int_mask = inportb(0x21) |
(0x01<<irq_num); outportb(0x21,int_mask);
setvect(irq_num+8,old_handler1);
} else
{
int_mask = inportb(0xa0) | (0x01<<(irq_num-8));
outportb(0xa1,int_mask);
setvect(irq_num-8+0x70,old_handler1);
}
enable();
}
/* INTERRUPT SERVICE ROUTINE */ void interrupt isr(void) {
disable();
{/* thêm mã*/
}
outportb(0x20,0x20);
if ( DDA_irq > 7 ) { outportb(0xa0,0x20);
}
enable();
}
Ví dụ: ếm sln nút nhn tác ộng dùng ngt IRQ3
#include< stdio.h >
#include< stdlib.h >
#include< dos.h > #include<
conio.h > void interrupt
(*oldIrq3)(void); void interrupt
countToggle(void); int i = 0;
long j = 0;
#define IRQ3 0x0B /* IRQ3 address */int main(void)
{
lOMoARcPSD|10435767
window(5,5,50,75);
clrscr(); gotoxy(1,3); cprintf("Do-while loop iteration # ");
oldIrq3 = getvect(IRQ3); /* lưu vectơ ngắt */
setvect(IRQ3, countToggle); /* cài vectơ ngắt mi */
outportb(0x21, ( inportb(0x21) & 0xF7 ) ); /* cho phép IRQ3
*/
/*Vòng lp, khi bm phím thì thoát khỏi chương trình, khi nhn nút thì vào ISR*/
do { j++; gotoxy(27,3); cprintf("%ld\n", j); }
while(!kbhit());
/* Có phím bm, thoát khỏi chương trình chính */ setvect(IRQ3,
oldIrq3); outportb(0x21, (inportb(0x21) | 0x08) ); /*
cm IRQ3 */
/* Sln bm phím*/ printf("\nswitch
presses i = %d\n", i); printf("j =
%ld\n", j); return 0;
} /* end of main */
/* Chương trình phục vụ khi IRQ3 lên mc cao */ void
interrupt countToggle(void)
{ disable(); i++; outportb(0x20, 0x20); /* send
EOI signal */ enable();
}
Ví dụ: Chương trìnhc kết quả chuyển ổi cùa card ADC 8 bit, mỗi khi ổi xong vi
mạch cho tín hiu EOCc ộng lên IRQ3, kết quả chuyển ổi lưu o file văn bản
#include < stdio.h >
#include < stdlib.h >
#include < dos.h >
#include < conio.h >
#define IRQ3 0x0b /* IRQ3 */
#define BASEADDRESS 608 /*Địa chỉ gc */
#define TRUE 1 #define FALSE 0
#define MAXSIZE 5000
/* Ly 5000 mu */ /* globals */
int EOC;
/* Đổi xong */
int readData;
/* Kết quả ổi thp phân */
float i;
/* Sln lp */
float data[MAXSIZE][2];
/* Mảng cha các kết quả chuyển ổi */
FILE* fp;
/*Con trỏ ến file ASCII */
int j;
void interrupt (*oldIrq3)(void);
/* Biến ếm */ /*
prototypes */
lOMoARcPSD|10435767
void interrupt eocTrue(void); int
main(void)
{ clrscr();
/*
fp = fopen("data.txt", "wt");
/* khởi ộng mảng v0.0 */
/* file cha kết quả */
for(j= 0; j < MAXSIZE; j++)
{
data[j][0] = 0.0;
data[j][1] = 0.0;
}; printf("data array
initialized\n"); i = 0.0; oldIrq3
= getvect(IRQ3);
setvect(IRQ3, eocTrue);
outportb(0x21, ( inportb(0x21) & 0xF7 ) );
EOC = FALSE;
do { readData = inportb(BASEADDRESS); /*Kích ồi */
while(EOC == FALSE)
{ /* ChEOC ON */
};
readData = inportb(BASEADDRESS); /* Đọc kết quả*/
EOC = FALSE; /*
Xóa EOC */ data[i][0] = i;
data[i][1] = (float)(readData * 5.0/255.0); /* Đi ra volt */
i++;
}
while(i < MAXSIZE);
printf("Writing to file...\n");
for(j=0; j < MAXSIZE; j++)
{ fprintf(fp, "%f\t%f\n", data[j][0], data[j][1]);
}; printf("done\n"); fclose(fp);
setvect(IRQ3, oldIrq3); outportb(0x21,
(inportb(0x21) | 0x08) );
printf("Bye!\n");return 0;
} /* end of main */
/* Gọi ISR cho EOC ON mi khi IRQ3 múc cao*/ void
interrupt eocTrue(void)
{
#pragma asm pushf;
#pragma asm cli;
EOC = TRUE;
lOMoARcPSD|10435767
outportb(0x20, 0x20);
#pragma asm popf; return;
} /* end of eofTrue */
Ví dụ: lập trình ngắt trong Turbo Pascal
unit ngat; interface uses dos,crt; {$I+}
var
Interrupt9 : procedure ;
Procedure Int9;
interrupt;
Procedure SetInt9;
Procedure ResetInt9;
IMPLEMENTATION { Interrupt subroutine }
Procedure Int9; begin { call
original interrupt }
Interrupt9;
{insert code here}
end;
Procedure SetInt9;
var R : registers;
begin
{ save current IRQ9 }
getintvec($71,@Interrupt9);
{$71: interrupt of IRQ9}
{ load new IRQ9 }
setintvec($71,@ nt9);
end;
Procedure ResetInt9; var
R : registers; begin
{ restore IRQ9 }
setintvec($71,@Interrupt9);
end;
Begin
End.
7.4 WINDOW DEVICE DRIVERS
Việc lập trình iều khiển các thiết bị chạy dưới hệ iều hành Windows có thể sử dụng
các lệnh truy cập trực tiếp phần cứng bằng c ngôn nglập trình Windows, cũng thể
sử dụng các thư viện sẵn của các hãng phần mềm, hoặc tự xây dựng các driver. Trong
lOMoARcPSD|10435767
phần này stả việc lập trình iều khiển bằng các ngôn ngữ khác nhau trong môi trường
Windows.
++
7.4.1 Lập trình xuất nhập dùng Visual C 6.0
Sau khi mVC, bạn vào menu File New Projects chọn mục MFCAppWizard
(exe), sau ó t tên cho project và a chỉ lưu file rồi bm OK.
Khi ca sMFCAppWizard xut hin, chọn option Dialog Based sau ó tiếp tục
bm Next, bước 4 bạn bm Finish ri OK
Sau ó bạn tạo các ối tượng Static Text, Edit Box, Button và Timer, các biến liên
kết vi Edit Box Port In và Port Out ln lượt là m_indata và m_outdata. Cmi 1s do
Timer chương trình ọc dliu Port In 379, xử lý ri xut ra Port Out 378
lOMoARcPSD|10435767
Sau ây là mt phn của chương trình xut nhp cng, các dòng in m là các dòng
bsung thêm // ioportDlg.cpp : implementation file #include "stdafx.h"
#include "ioport.h"
#include "ioportDlg.h"
# include "conio.h" //definition _inp and _outp
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE static char THIS_FILE[ ] = __FILE__;
#endif BOOL
CIoportDlg::OnInitDialog()
{
CDialog::OnInitDialog(); SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, ALSE); // Set small icon
SetTimer(ID_CLOCK_TIMER,1000, NULL);
return TRUE;
}
void CIoportDlg::OnTimer(UINT nIDEvent)
{
UpdateData(TRUE);
m_indata=_inp(0x379);
m_outdata=m_indata ^0x80;
_outp(0x378,m_outdata); UpdateData(FALSE);
lOMoARcPSD|10435767
CDialog::OnTimer(nIDEvent);
} void
CIoportDlg::OnBtnexit()
{
OnOK();
}
7.4.2 Lập trình dùng Delphi
Không có lnh xut nhp mà ta phải dùng hp ng tạo hàm xut nhp.
Functrion Inport (address:
word): byte;
Var data: word;
begin
asm
push dx mov
dx, address in
ax, dx mov
data, ax pop
dx
end; inport: =
data; end;
Procedure Outport (address: word; data: word);
begin asm push dx mov dx,
address mov ax, data out dx, ax
pop dx
end; end;
Ví dụ: Chương trình Delphi xut nhp Port
unit inoutunit;
lOMoARcPSD|10435767
interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls; type
TForm1 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
Label1: TLabel;
Label2: TLabel;
btnIN: TButton;
btnOUT: TButton;
function inport (address:word):byte;
procedure outport (address:word; data:byte);
procedure btnINClick (Sender: TObject);
procedure btnOUTClick (Sender: TObject);
private { Private declarations } public
{ Public declarations } end; var
Form1: TForm1; implementation {$R
*.DFM} function Tform1.inport
(address:word):byte;
var data:byte;
begin asm push dx
mov dx,address in
al,dx mov data, al
pop dx end;
inport:= data;
end;
procedure TForm1.outport (address:word; data:byte);
begin asm push dx mov dx,address mov al,data
out dx,al pop dx end;
end; procedure TForm1.btnINClick Sender:
TObject); begin edit2.text:= inttostr (inport
(strtoint (edit1.text)));
end;
procedure TForm1.btnOUTClick (Sender: TObject);
begin
outport (strtoint (edit1.text), strtoint
(edit2.text)); end; end.
7.4.3 Visual Basic
Ngôn ngữ này không htrxut nhp port, ta phải dùng thư viện liên kết ộng
(dynamic link library)
Viết tập tin liên kết ộng dll
lOMoARcPSD|10435767
File thư viện liên kết ng uôi .dll cha các hàm thường trình các chương
trình chạy trong môi trường Windows như Delphi, Visual Basic, Visual C ths
dụng.
++
Các ngôn nglp trình Visual C, Delphi, Borland C Builder u cho phép viết tp tin
.dll. Hiều hành Windows có sn mt shàm thư viện liên kết ng gọi chung dưới tên
Win API (Applications Programming Interface) tuy nhiên vic sdụng chúng òi hỏi
kinh nghim lp trình.
thly các tp tin dll nhp xut dliu các port máy tính tmạng Internet cài
vào máy tính, hoc có thtviết. Sau ây trình y hai ví dụng Visual C và Delphi
viết tp tin.dll mà Visual Basic sẽ sử dụng.
Dùng Visual C++4.0 (Win 16 bit) Ta viết tập tin thư viện ặt tên là INOUT.dll gm
thường trình xut ra cng ặt tên OUTPORT và thường trình nhp dliu INPORT.
Đầu tiên dùng phn mm soạn văn bản viết hai tp tin INOUT.DEF (define) và tâp
tin INOUT.CPP (chương trình C).
// Inout.def listing
Library inout
Description dll for I/O card
Exports
Outport @ 1
Inport @ 2
ng ầu là tên file INOUT, hàng thhai là chú thích, các hàng sau lit kê tên các
thường trình trong thư viện. Sau tên thường trình là du @ và stht.
// INOUT.CPP Listing
// file ngun .CPP cho dll INOUT.dll
# include <stdio.h>
# include <conio.h> // cha hàm INP và OUTP
Short-stdcall OUTPORT (int PortAddress, int PortData)
{
Short Dummy;
Dummy = (Short) (_outp (PortAddress, PortData)); Return
(Dummy);
};
Short_stdcall INPORT (int PortAddress)
{
Short PortData; PortData = (Short) (_inp (PortAddress));
Return (PortData);
} ;
Sau khi ã soạn xong hai tp tin INOUT.def INOUT.cpp ta ct vào một thư
mục, dụ, C:\port. Vào Visual C chọn File - New -Projects Win32DLL ánh tên INOUT
lOMoARcPSD|10435767
a chỉ C:\port\INOUT ri bm OK. Màn hình INOUT - Microsoft Developper Studio
sẽ xut hin project INOUT classes ưc tạo ra, ta sẽ cng thêm hai file INOUT.def
và INOUT.cpp vào project INOUT ri bm FILE - SAVE ALL.
Sau khi ã tạo project INOUT bm Build chọn Build INOUT.dll, nếu không có gì
sai sót file INOUT.dll sẽ ược tạo ra ct trong C:\port\inout\debug. Sau ó ct file o
thư mục hthng của Windows, dụ, C:\Windows. Vi Visual C 5.0 và 6.0 cách viết
sẽ khác i.
c chương trình viết trên ngôn ngữ khác như Delphi, Visual Basic có thể gọi hàm
INPORT và OUTPORT khi ã khai báo các hàm này và INOUT.dll
dụ, trong Visual Basic ta thêm các dòng y trong phn khai o chương trình
sau phát biu Option Explicit: Option Explicit
Private Declare Function OUTPORT LIB “INOUT.dll” (ByVal PortAddress As
Integer, By Val Port Data as Integer) As Integer.
Private Declare Function INPORT Lib “INOUT.dll” (ByVal PortAddress As Integer)
As Integer
Private cho biết các hàm và thường trình sau Declare là cục b. Sau Declare ta viết
Function nếu trả vgiá trị, còn không thì dùng SUB, sau ó n. TLIB kèm
theo cho biết nơi tìm tp tin dll, thường phải kèm ường dn.
Sau khi ã khai báo có thsử dụng các hàm và chương trình con trong chương
trình..
Ví dụ, mun xut 0 ra ịa chỉ 300H ta viết:
Dummy = OUTPORT (768, 0)
Dummy là biến nguyên ã khai báo (Dim Dummy as Integer;)
Mun nhp mt trị ở cng Control Port vào biến Value ta viết
Value = INPORT (Control Port)
7.4.4 Tạo dll dùng VC++ 6.0 (Win32 bit)
Vào File- New- Projects chọn Wìn32 Dynamic- Link Library, t tên cho project là
inout
lOMoARcPSD|10435767
Sau ó tiếp tục chọn option A Simple DLL Project Khung soạn thảo chương trình xut
hin
Ta bsung thêm các dòng lnh vào inout.cpp
// inout.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#include <stdio.h>
#include <conio.h>
lOMoARcPSD|10435767
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call,
LPVOID lpReserved)
{
return TRUE;
}
int APIENTRY inport(WORD Port)
{
return(_inp(Port));
}
int APIENTRY outport(WORD Port, int ByteData)
{
return(_outp(Port, ByteData));
}
Sau ó vào File New -Files, chọn Text File, bsung vào Project inout file
inout.def //inout.def LIBRARY inout EXPORTS inport @1 outport @2
Vào menu Chọn Build- Build inout.dll, file inout ược lưu o thư mục
d:\inout\Debug, ta chép o tmục c:\Windows Chương trình sdụng file inout. dll
trong Visual Basic 6.0:
lOMoARcPSD|10435767
Private Declare Function inport Lib "inout.dll" (ByVal portaddress As Integer) As
Long
Private Declare Function outport Lib "inout.dll" (ByVal portaddress As Integer,
ByVal_ value As Byte) As Long Private Sub Command1_Click() Timer1.Enabled
= True End Sub Private Sub Command2_Click()
Timer1.Enabled = False
Unload Form1 End Sub Private Sub Form_Load()
Timer1.Interval = 1000
Timer1.Enabled = False End Sub Private Sub Timer1_Timer()
Dim i, port, giatri, dummy port = 768 dummy = outport(port + 1, Val(Text1.Text))
giatri = inport(port) Text2.text=giatri
For i = 0 To 7
If (giatri And (2 ^ i))=2^i
Then Lamp(i).FillColor = QBColor(12)
Else Lamp(i).FillColor = QBColor(10)
End If
Next End Sub
Chương trình Delphi dùng inout.dll: unit
Unit1; interface uses
Windows, Messages, SysUtils, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls; type
TForm1 = class(TForm) Edit1: TEdit;
Button1: TButton; Edit2: TEdit;
procedure Button1Click(Sender: TObject);
private { Private declarations } public
{ Public declarations } end;
Function inport (adr: word): byte; stdcall; external 'inout.dll'
Function outport (adr: word; data:byte): byte; stdcall;
external'inout.dll' var
Form1: TForm1; implementation {$R *.DFM}
procedure TForm1.Button1Click(Sender:
TObject); var data: byte; begin data := outport
lOMoARcPSD|10435767
($378, strtoint ( edit1.text)); edit2.text := inttostr
(inport($379)) end; end.
4.2.3 Tạo DLL dùng Delphi
Chạy Delphi, vào menu File- New, chọn DLL - OK, trên ca s soạn thảo
Project1.dpr xut hiện khung chương trình sau: library Project1; uses SysUtils,
Classes; {$R *.RES} begin
end.
Ta sẽ ổi tên Project1 thành inout và thêm các dòng lnh trước begin end. Ví dụ sau
tạo inout.dll gồm chương trình con outport và hàm inport library inout;
uses SysUtils, Classes;
{$R *.RES}
Procedure outport(adr:word;data:word);
export; stdcall; begin asm
push dx mov
dx,adr mov
ax,data out
dx,ax
pop dx
end;
end;
Function inport(adr:word):word;
export;
stdcall; var
data:word;
begin asm
push dx
mov dx,adr
in ax,dx
mov data, ax
pop dx end;
inport:=data;
end;
lOMoARcPSD|10435767
exports outport index 1,inport index 2; begin
end.
Sau ó vào menu Project- Build inout. File inout.dll ược tạo ra trong thư mục
\Delphi5\Projects cùng vi các file inout.dpr, inout.res, inout.dof, inout.cfg. Ta chép
file inout.dll vào thư mục Windows\System.
Ví dụ: Viết chương trình Visual Basic dùng dll inout do Delphi tạo ra
Private Declare Function inport Lib "inout.dll" (ByVal portaddress As Integer) As
Byte
Private Declare Sub outport Lib "inout.dll" (ByVal portaddress As Integer, ByVal_
value As Byte)
Private Sub Command1_Click()
Timer1.Enabled = True
End Sub
Private Sub Command2_Click()
Timer1.Enabled = False
Unload Form1
End Sub
Private Sub Timer1_Timer()
Dim i, port, giatri port =
768
giatri = inport (port+1)
For i = 0 To 7
If (giatri And (2 ^ i)) and 2^i Then Lamp(i).FillColor = QBColor(12)
Else_
Lamp(i).FillColor =
QBColor(10)
Next
End Sub
lOMoARcPSD|10435767
Ví dụ: viết chương trình Delphi dùng inout.dll do Delphi tạo ra
unit Unit1; interface uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls; type
TForm1 = class(TForm) Edit1: TEdit; Button1: TButton; Edit2: TEdit;
procedure Button1Click(Sender: TObject);
private { Private declarations } public
{ Public declarations }
end;
Function inport (adr: word): word; stdcall;
external 'inout.dll'
Procedure outport (adr: word; data:
word); stdcall; external 'inout.dll' var
Form1: TForm1;
implementation {$R *.DFM} procedure
TForm1.Button1Click (Sender: TObject);
begin outport ($378, strtoint ( edit1.text));
edit2.text:= inttostr((inport($379)) and $ff)
end;
end.
Xuất nhập với Win 2000 và Win NT
Vic xut nhp trong DOS Win 98 thc hin ddàng như ã trình y các mục
trên, tuy nhiên các hiu hành Win 2000 Win NT ngăn cản vic thc hin các lnh
truy cp ngoại vi trc tiếp trong mode người dùng. Mun vượt qua rào cản y ta phải
viết các driver truy cp ngoại vi trong mode kernel sdụng các hàm WinAPI. Viết các
file xut nhp dll dạng y khá phc tạp òì hỏi trình lp trình cao, th o các
trang web download vsử dụng, dụ một ịa chỉ là www.logix4u.net. Một ịa chỉ khác
www.jungo.com htrviết driver cho card ISA, PCI, USB….
| 1/26

Preview text:

lOMoARcPSD| 10435767
CHƯƠNG 7 – ĐIỀU KHIỂN THIẾT BỊ (DEVICE DRIVERS) LT6 7.1 KHÁI NIỆM
Một “device driver” là một chương trình iều khiển một thiết bị cụ thể cắm vào máy
tính. Ví dụ các “device driver” cho các máy in, các màn hình hiển thị, các ổ ĩa CD –
ROM, các bộ ọc ĩa …. Khi cài một hệ iều hành trên máy tính, ã có rất nhiều “device
driver” ược thiết kế sẵn bên trong nó. Tuy nhiên, khi sử dụng một thiết bị mới, hay khi
tự chế tạo ra một hệ thống mạch giao tiếp với máy tính, hệ iều hành sẽ chưa hỗ trợ các
thiết bị này, thì cần cài ặt một “device driver” mới cho chúng. Một “device driver” về
bản chất biến ổi nhiều lệnh vào ra chung của hệ iều hành thành các thông iệp mà thiết bị có thể hiểu ược.
Một số chương trình chạy trong windows là “device driver” ảo. Các chương trình
này giao tiếp với giao diện quản lý máy ảo của Windows (Windows Virtual Machine
Manager). Mỗi thết bị phần cứng chính trong hệ thống sẽ có một “device driver” ảo, ví
dụ như: bộ iều khiển ĩa cứng, bàn phím, các cổng giao tiếp nối tiếp, song song. Chúng
ược sử dụng ể duy trì trạng thái của một thiết bị phần cứng có thể thay ổi các thiết lập.
Các “device driver” ảo sẽ xử lý các ngắt mềm trong hệ thống, thay cho việc sử dụng các ngắt cứng.
Trong hệ iều hành Windows, một tập tin “device driver” thường có uôi dưới dạng
DLL hoặc EXE, còn một “device driver” ảo thường có uôi là VXD.
Để viết một Driver cần hiểu biết sâu về phần cứng và phần mềm hệ thống. Các driver
hoạt ộng ở môi trường có mức ặc quyền cao, và chúng có thể gây nguy hiểm nếu chúng
có sai sót. Ngược lại, hàu hết các phần mềm mức người sử dụng hoạt ộng dưới các hệ
iều hành hiện ại, có thể ngừng hợat ộng mà không ảnh hưởng tới các phần còn lại của
hệ thống. Ngay cả các driver hoạt ộng trong chế ộn người sử dụng cũng có thể gây hư
hỏng hệ thống nếu chúng ược lập trình sai.
Vì thế việc viết các driver trong thực tế thường ược các kỹ sư phần mềm trong các
công ty chế tạo phần cứng thực hiện, do họ có các thông ti tốt hơn về thiết kế phần cứng
của họ. Hơn nữa trong thương mại các hãng chế tạo phần cứng ều muốn khách hàng của
mình sử dụng một cách tối ưu các thiết bị phần cứng của họ. Thông thường các logical
device driver (LDD) ược các nhà cung cấp hệ iều hành viết, trong khi ó các physical
device driver (PDD) ược cung cấp từ các nhà cung cấp thiết bị. Những năm gần ây một
số tác giả không cung cấp hệ iều hành và phần cứng thiết bị cũng thực hiện các driver,
chúng chủ yếu thực hiện cho các hệ iều hành mã nguồn mở. Trong các trường hợp này,
quan trọng là các nhà sản xuất phần cứng cần cung cấp các thông tin về việc truyền thông
tin trong các thiết bị của họ. Đối với các kỹ sư ngành iện tử máy tính, ể phát triển các
phần cứng kết nối với máy tính cần phải thực hiện các driver ể hỗ trợ cho các thiết bị này. lOMoARcPSD| 10435767
Hãng phần mềm Microsoft ang cố gắng giảm bớt sự không ổn ịnh của hệ thống do các
driver ược viết không tốt bằng các tạo ra một khung mới (new framework) cho việc phát
triển các driver ược gọi là WDF (Windows Driver Foundation). Nó bao gồm User-Mode
Driver Framework (UMDF) hỗ trợ người sử dụng tự phát triển các driver cho các thiết
bị bằng cách thực hiện một bộ giao thức thông iệp cơ sở (message-based protocol), cho
việc trao ổi thông tin với các thiết bị của họ, nó giống như một driver ở lớp người sử
dụng. Nếu các driver này sai chức năng nó sẽ không gây ảnh hưởng tới ổn ịnh của hệ
thống. Chế ộ Kernel-Mode Driver Framework (KMDF) cho phép phát triển các driver
trong lớp lõi (kernel-mode), nhưng tạm thời cung cấp các tiêu chuẩn thực hiện của các
chức năng ể xử lý khi xảy ra lỗi bao gồm:
bỏ qua hoạt ộng của vào ra, quản lý nguồn, cắm và chạy các thiết bị. 7.2 PC LAYERS
Hình 7.1: Phân lớp phần mềm trong máy tính
Hình 7.1 mô tả sự phân lớp phần mềm trong máy tính cá nhân, các thiết bị chuẩn cắm
vào máy tính như bàn phím, màn hình, con chuột, bộ iều khiển ổ ĩa, các cổng vào ra
song song, nối tiếp, USB … thông thường ược các phần mềm viết sẵn hỗ trợ. Các phần
mềm này bao gồm các chương trình ngắt chứa trong ROM – BIOS cắm sẵn trên bo mạch
chính máy tính, các chương trình hỗ trợ của hệ iều hành DOS, WINDOWS gọi tắt là OS
(Operating system). Các chương trình người sử dụng ở lớp chương trình ứng dụng (Appl.
Prog. – Application Program), có thể thực hiện việc iều khiển trực tiếp các thiết bị bằng
các lệnh vào ra cơ bản, khi biết ược cơ chế trao ổi thông tin của các thiết bị, hoặc có thể
gọi các chương trình ã thực hiện trong ROM BIOS và trong hệ iều hành. Tuy nhiên, hệ
iều hành quản lý và cấp phát tài nguyên hệ thống cho các ứng dụng khác nhau và thực lOMoARcPSD| 10435767
hiện việc bảo vệ hệ thống, nên các chương trình ở lớp ứng dụng nếu không có các lệnh
thay ổi mức ặc quyền sẽ không ược phép thực hiện các lệnh truy cập trực tiếp tới phần cứng hệ thống.
Trong các chương trình hợp ngữ việc gọi các ngắt của BIOS và DOS ược thực hiện
bằng các lệnh gọi ngắt INT (Interrupt), hệ thống máy tính có tất cà 256 vector ngắt như
ã mô tả trong chương 3. Một số ngôn ngữ cấp cao khác cũng hỗ trợ việc gọi các ngắt của
hệ thống bằng phần mềm.
7.3 DOS DEVICE DRIVERS
7.3.1 Truy cập thiết bị bằng các lệnh vào ra
Như ã ề cập, ể thực hiện các chương trình iều khiển thiết bị “device driver” dưới môi
trường DOS, có thể thực hiện các lệnh truy cập trực tiếp tới vào ra của các ngôn ngữ
lập trình dưới DOS. Sau ây là ví dụ về các lệnh truy cập vào ra trong các ngôn ngữ khác
nhau. Lập trình hợp ngữ
Xuất dữ liệu từ biến data ra cổng có ịa chỉ address: mov dx, address mov ax, data out dx, ax Ví dụ: mov dx, 300H mov ax, F0H out dx, ax
Nhập số liệu từ cổng ịa chỉ address vào biến data
mov dx, address in ax, dx mov data, ax
data, address là số nhị phân 16 bit. Qbasic
Dùng lệnh INP (port%) và OUT port%, data% port là số nguyên từ 0 ến 65535 chỉ
ịa chỉ cổng data là số nguyên từ 0 ÷ 255,&H ký hiệu số Hex phía sau , % ký hiệu biến là số nguyên
Ví dụ: a% = INP (&H3FC) ‘ ọc số liệu ở cổng 3FCH, thanh ghi modem
OUT &H3FC, (a% XOR 1) ‘ ảo bit cuối, xuất ra cổng 3FCH
OUT 768, 160 ‘ xuất A0H ra cổng 300H Pascal
Dùng lệnh port: xuất nhập một byte, portw: xuất nhập một từ
{Xuất ra port ịa chỉ reg:} port[reg]: = data;
{ọc số liệu ở port ịa chỉ reg vào biến value} . value: = port [reg];
Ví dụ: data: = port [$378]; lOMoARcPSD| 10435767
port [$37A]:= data out; C, C Builder, Visual C
Dùng lệnh inp và outp (hay inportb, outportb, inport,
outport) Control = inp (0X61); outp (0X43, 0Xb6);
Visual C++ 6.0 có các hàm và thủ tục:
_inp: ọc byte _outp: xuất byte
_inpw: ọc một từ _outpw: xuất từ
_inpd: ọc từ kép _outpd: xuất từ kép dụ: lập trình C # include # define dataport 0x378 # define statusport 0x379 int Dummy: Dummy = _outp(dataport, 0); Dummy = _inp(statusport); ...
7.3.2 Truy cập các thiết bị chuẩn bằng ngắt mềm
Với các thiết bị chuẩn có thể sử dụng các ngắt của DOS và BIOS ể truy cập thiết bị.
Sau ây là một số ngắt cơ bản truy cập tới các thiết bị và các cổng chuẩn trên máy tính: Ngắt 21H:
Hàm 01H ngắt 21H: ọc một ký tự từ bàn phím
Một ký tự sẽ ược ọc vào từ bàn phím và hiện lên màn hình. Nếu tại thời iểm gọi hàm
chưa có ký tự sẵn sàng, thì hàm sẽ ợi cho tới khi có phím ược nhấn. Vào: AH = 01
Ra: AL chứa mã ASCII của phím nhấn
Khi nhận ược các ký tự có mã mở rộng AL = 0. Lúc này có thể gọi hàm một lần nữa ể ọc ược mã mở rộng.
Khi ký tự vào là Ctrl – C (mã ASCII là 3) ngắt 23H sẽ ược gọi trả iều khiển về DOS.
Ngoài AL, nội dung các thanh ghi khác không bị thay ổi sau khi gọi hàm. Ví
dụ khi gọi hàm này có thể viết: MOV AH,02 INT 21H
Hàm 02H ngắt 21H: Hiện một ký tự lên màn hình.
Hàm này cho phép hiện một ký tự lên màn hình Vào: AH = 02
DL chứa mã ASCII của ký tự cần hiển thị. Ra: không.
Tất cả các thanh ghi không bị thay
ổi sau khi gọi hàm, các mã ặc biệt như lOMoARcPSD| 10435767
Backspace (xoá ký tự trước), Carriage Return (về ầu hàng) và Line Feed (xuống hàng)
sẽ ược ghi trên màn hình dưới dạng lệnh.
Hàm 09 ngắt 21H: Hiện chuỗi ký tự lên màn hình. Vào: AH = 09
DX chứa ịa chỉ offset của chuỗi cần hiển thị. Ra:không
Chuỗi ký tự cần ặt trong bộ nhớ dưới dạng một chuỗi các byte ASCII, kết thúc là ký tự
‘$’ (mã ASCII là 36). Các mã ặc biệt như Backspace (xoá ký tự trước), Carriage Return
(về ầu hàng) và Line Feed (xuống hàng) sẽ ược ghi trên màn hình dưới dạng lệnh. Chỉ
có AL bị thay ổi sau khi gọi hàm.
Hàm 4CH ngắt 21H: kết thúc chương trình loại .EXE.
Hàm này kết thúc chương trình và truyền về một mã lỗi, chương trình gọi có thể nhận
ược mã lỗi này bằng cách gọi hàm 4DH, bộ nhớ RAM cho chương trình chiếm sẽ ược giải phóng.
Ngắt 10H của BIOS và chế ộ văn bản trên màn hình màu:
Màn hình màu có ịa chỉ RAM là B800:0000. Trong chế ộ văn bản 80 hàng 25 cột mỗi
ký tự sẽ ược chứa bằng hai byte trong bộ nhớ màn hình, byte ầu là mã ASCII của ký tự
và byte sau là thuộc tính của ký tự. Như vậy ịa chỉ mã ASCII của một ký tự trên màn
hình trong bộ nhớ sẽ là :
Offset(hàng, cột) = hàng x160 + cột x 2.
Hàm 00 ngắt 10H: Đặt chế ộ màn hình.
Hàm này cho phép ặt lại chế ộ màn hình. Toàn bộ màn hình sẽ bị xoá, vì vậy có thể
dùng hàm này ể xoá toàn bộ màn hình ngay cả khi không muốn thay ổi chế ộ màn hình. Vào: AH = 0 AL = chế ộ màn hình:
0: chế ộ 40x25 ký tự, en trắng. 1:
chế ộ 40x25 ký tự, màu.
2: chế ộ 80x25 ký tự, en trắng.
3: chế ộ 80x25 ký tự, màu.
4: chế ộ 320x200 iểm ồ thị, 4 màu.
5: chế ộ 320x200 iểm ồ thị, 2 màu.
6: chế ộ 640x200 iểm ồ thị, 2 màu.
7: chế ộ của màn hình mono.
8: chế ộ 160x200 iểm ồ thị, 16 màu.
9: chế ộ 320x200 iểm ồ thị, 16 màu.
0A: chế ộ 640x200 iểm ồ thị, 4 màu.
0B: chế ộ 640x200 iểm ồ thị, 16 màu.
10H: chế ộ 640x350 iểm ồ thị, 16 màu. lOMoARcPSD| 10435767
11H: chế ộ 640x480 iểm ồ thị, 2 màu.
12H: chế ộ 640x480 iểm ồ thị, 256 màu. Ra: không
Nội dung các thanh ghi BX, CX, DX, SS, CS, DS không bị thay ổi sau khi gọi hàm.
Các thanh ghi còn lại có thể bị thay ổi.
Hàm 02 ngắt 10H: Đặt vị trí con trỏ.
Hàm này cho phép ặt con trỏ tới một vị trí nào ó trên màn hình, ể sau ó cho phép ưa ra
màn hình bằng các hàm khác của BIOS. Vào: AH = 02
BH = số trang màn hình (0 tới 7) DH = Toạ ộ dòng. DL = Toạ ộ cột. Ra: không Chú ý :
- Con trỏ nhấp nháy trên màn hình chỉ bị thay ổi vị trí khi trang màn hình là trang hiện hành.
- Toạ ộ dòng nhận các giá trị từ 0 tới 24, cột từ 0 tới 79. Có thể làm con trỏ biến mất
bằng cách ặt nó nằm ngoài các toạ ộ nêu trên.
- Nội dung các thanh ghi BX, CX, DX, CS, DS và SS không bị thay ổi. Hàm 03
ngắt 10H: Đọc vị trí con trỏ.
Hàm này cho phép ọc vị trí con trỏ trên một trang màn hình và kích thước nhấp nháy của nó. Vào: AH = 03H BH = số trang màn hình.
Ra: DH = toạ ộ dòng, DL = toạ ộ cột.
CH = dòng bắt ầu của con trỏ, CL dòng kết thúc của con trỏ.
Hàm 05 ngắt 10H: Chọn trang màn hình hiện hành Vào : AH = 05 AL = số trang. Ra:không
Khi trang ược chọn nó sẽ hiện lên trên màn hình, con trỏ sẽ lấy toạ ộ của trang ó, lúc
này có thể ghi vào trang ang ược kích hoạt.
Hàm 06 ngắt 10H: Cuốn cửa sổ lên.
Cho phép cuốn một số dòng văn bản của cửa sổ, hoặc xoá toàn bộ cửa sổ. Vào: AH = 06
AL = số dòng muốn cuốn lên (0 là xoá cửa sổ).
CH = toạ ộ dòng góc cao bên trái.
CL = toạ ộ cột góc cao bên trái.
DH= toạ ộ dòng góc dưới bên phải. lOMoARcPSD| 10435767
DL = toạ ộ cột góc dưới bên phải.
BH = màu thuộc tính cho các dòng bị xoá.
Các bit thuộc tính của BL bao gồm: D7:
nhấp nháy (1 cho phép chữ nhấp nháy) D6, D5, D4: màu nền. D3 – D0: màu chữ
Các màu tương ứng với các giá trị từ 0 tới 0FH là : Đen, Xanh da trời, Xanh lục, Xanh
dương, Đỏ, Tím, Nâu, Xám nhạt, Xám sẫm, Xanh da trời nhạt, Lục nhạt, Xanh dương
nhạt, Hồng, Tím nhạt, Vàng, Trắng. Ra: không.
Chú ý : Hàm này chỉ làm việc với trang màn hình hiện hành. Khi AL = 0 cửa sổ sẽ ược
xoá và iền vào bằng các ký tự trắng (mã ASCII là 32). Nội dung các dòng cuốn sẽ bị
mất và không thể khôi phục lại.
Hàm 0A ngắt 10H: ghi ký tự.
Cho phép ghi ký tự vào vị trí hiện hành của con trỏ trong một trang màn hình. Vào : AH = 0AH BH = số trang màn hình.
CX = số lần lặp lại của ký tự.
AL = mã ASCII của ký tự.
BL = thuộc tính của ký tự (chỉ có ý nghĩa mô tả ) Ra: không
Chú ý : Trong chế ộ ồ thị nếu phải lặp lại ký tự nhiều lần, thì trang màn hình sẽ là hiện
hành. Các mã iều khiển sẽ ược in ra như các ký tự ASCII thường.
Hàm 13H ngắt 10H: Ghi chuỗi ký tự ra màn hình. Vào : AH = 13H AL = chế ộ ghi.
AL = 0: Thuộc tính trong BL, không thay ổi vị trí con trỏ.
1: Thuộc tính trong BL, chuyển con trỏ tới cuối chuỗi.
2: Thuộc tính trong vùng ệm, không thay ổi vị trí con trỏ.
3: Thuộc tính trong vùng ệm, chuyển con trỏ tới cuối chuỗi.
BL = thuộc tính của các ký tự.
CX = số ký tự cần ghi.
DH = toạ ộ dòng bắt ầu, DL = toạ ộ cột bắt ầu. BH = số trang màn hình.
ES = ịa chỉ oạn của vùng ệm; BP = ịa chỉ offset của vùng ệm. Ra: không. lOMoARcPSD| 10435767
Ngắt 14H - Truyền nhận nối tiếp Tác
dụng : Truy xuất các cổng nối tiếp.
Tham số : AX, DX
BIOS của máy PC, hỗ trợ lên ên 4 loại cổng nối tiếp khác nhau ( phần cứng có thể hỗ
trợ ến 8 loại ). Nhìn chung, hầu hết tất cả các PC ều có một hay hai cổng nối tiếp
(COM1: và COM2:). Ngắt 14H có 4 hàm con, hỗ trợ nhận và chuyển các ký tự, cho biết
tình trạng các cổng ... Các công ược ánh số từ 0 .. 3 trên dx (0=COM1:, 1=COM2:, .v.v.).
Ngắt 14H chờ và nhận lại dữ liệu từ thanh ghi AL hoặc AX.
Hàm 0h - Ngắt 14h
Hàm 0h sẽ khởi tạo một cổng nối tiếp. Nó giúp thiết lập các thông số như tốc ộ, số
bit chẵn lẻ, số bits stop (number of stop bits ), số bit ã ược truyền qua ường truyền (hình 7.2).
Hình 7.2: Các tham số cho hàm 0 ngắt 14H
Mặc dù các cổng nối tiếp chuẩn hỗ trợ tốc ộ ến 19.200 baud, nhưng các BIOS không hỗ trợ tốc ộ ó.
Ví dụ : Khởi tạo cổng COM1: 2400 baud, không kiểm tra chẵn lẻ, 8 bit dữ liệu, và 2 bit
stop : mov ah, 0 ;Initialize opcode mov al, 10100111b ;Parameter data. mov dx, 0 ;COM1: port. int 14h
Sau khi oạn code trên ược thực thi, tình trạng của cổng sẽ ược trả về ở AX.
Hàm 01h ngắt 14H : Chuyển một ký tự ến cổng.
Hàm này có tác dụng chuyển một ký tự chứa trong AL ến cổng, ã ược chọn trước
trong DX (DX = 0,1,2,3). Khi trả về kết quả, nếu AH chứa zero, thì ký tự ã ược chuyển
thành công. Nếu bit 7 của AH chứa giá trị 1, nghĩa là quá trình chuyển bị lỗi. Bit 7 chứa
tình trạng của tất cả các lỗi ược trả về. Nếu một lỗi ược báo cáo, bạn có thể sử dụng hàm
03h ể lấy các giá trị lỗi từ cổng nối tiếp. Ví dụ: Chuyển một ký tự ến cổng COM1 : mov dx, 0 ;Select COM1: mov al, ‘a’ ;Character to transmit mov ah, 1 ;Transmit opcode int 14h lOMoARcPSD| 10435767 test ah, 80h ;Check for error jnz SerialError
Đoạn lệnh trên sẽ chờ cho ến khi cổng nối tiếp hoàn thành công việc "trans" cho ến
khi hết các ký tự ( nếu chuyển nhiều ký tự ),sau ó sẽ lưu ký tự vào thanh ghi vận chuyển (transmit register).
Hàm 02h ngắt 14H : Nhận kí tự từ cổng nối tiếp
Vào : DX : Chứa số hiệu của cổng nối tiêo ( 0 .. 3 )
Ra : AL chứa kí tự ược ọc từ cổng và bit thứ 7 của AH chứa tình trạng lỗi.
Khi gọi hàm này, nó sẽ ko trả quyền iều khiển cho ến khi nhận ược một kí tự từ cổng.
7.3.3 Truy cập các thiết bị bằng ngắt cứng
Khi thiết kế các giao tiếp phần cứng thông qua các khe cắm, (PCI, ISA,…) hoặc qua
các cổng chuẩn của máy tính, các chương trình iều khiển thiết bị có thể sử dụng các ngắt
phần cứng chưa sử dụng, các ngắt cứng ã thiết kế sẵn cho cổng, thậm chí có thể cấm
ngắt các thiết bị hiện có trong hệ thống ể cấp ngắt cứng cho thiết bị mới.
Các ngắt cứng của má tính ược iều khiển bởi hai vi mạch iều khiển ngắt PIC8259,
các vector ngắt của hệ thống ược cho trong bảng 7.1.
Bảng 7.1: Các vector ngắt của máy tính INT (Hex) IRQ Sử dụng 00 - 01 Exception Handlers Chia cho zero 02
IRQ không che (NMI) Sai parity 03 - 07 Exception Handlers Xử lý các ngoại lệ 08 Ngắt cứng IRQ0 Timer hệ thống 09 Ngắt cứng IRQ1 Bàn phím 0A Ngắt cứng IRQ2 Chuyển hướng sang IRQ9 0B Ngắt cứng IRQ3 Cổng nối tiếp 2, 4 0C Ngắt cứng IRQ4 Cổng nối tiếp 1, 3 0D Ngắt cứng IRQ5 Card âm thanh 0E Ngắt cứng IRQ6 Đĩa mềm 0F Ngắt cứng IRQ7 Cổng song song 10 ÷ 6F Ngắt mềm Ngắt do phầnn mềm 70 Ngắt cứng IRQ8
Đờng hồ thời gian thực 71 Ngắt cứng IRQ9 Chuyển hướng từ IRQ2 72 Ngắt cứng IRQ10 Dự trữ 73 Ngắt cứng IRQ11 Dự trữ 74 Ngắt cứng IRQ12 Con chuột PS/2 75 Ngắt cứng IRQ13 Đồng xử lý lOMoARcPSD| 10435767 76 Ngắt cứng IRQ14 Đĩa cứng 77 Ngắt cứng IRQ15 Dự trữ 78 - FF Ngắt mềm Ngắt do phần mềm
Muốn sử dụng ngắt ta phải viết chương trình phục vụ ngắt ISR, ặt ịa chỉ của
chương trình này vào vị trí phù hợp trên bảng vector ngắt, trước ó cần phải cất ịa chỉ ã
có sẵn ể sau ó phục hồi trở lại. Khi có ngắt xảy ra và ISR thực hiện xong phải báo
trở lại cho PIC bằng cách gởi EOI (end of interrupt) ến OCW2, thông thường là byte
20H (cho ngắt thường). Việc khởi ộng PIC do ROM BIOS ảm nhiệm ta không cần quan tâm ến.
Ví du : Lập trình ngắt dùng C #include #include #include #include #include void main(void) {
No_irq = 5; init_isr(No_irq); { /*Thêm mã*/ } close_isr(No_irq); }
/* INIT INTERRUPT SERVICE ROUTINE */ void init_isr (int irq_num)
{ disable(); if ( irq_num) disable();
if ( irq_num<8 ) old_handler1 = getvect(irq_num+8);
else old_handler1 = getvect(irq_num-
8+0x70); if ( irq_num < 8 ) setvect(irq_num+8, isr);
else setvect(irq_num-8+0x70, isr); if ( irq_num < 8 ) { int_mask = inportb(0x21) & ~(0x01< outportb(0x21, int_mask); } else {
int_mask = inportb(0xa1) & ~(0x01<<(irq_num-8)); outportb(0xa1, int_mask); } enable( ); } lOMoARcPSD| 10435767
/* CLOSE INTERRUPT SERVICE ROUTINE */ void close_isr(int irq_num) {
int int_mask; disable(); if ( irq_num < 8 ) { int_mask = inportb(0x21) |
(0x01<setvect(irq_num+8,old_handler1); } else {
int_mask = inportb(0xa0) | (0x01<<(irq_num-8)); outportb(0xa1,int_mask);
setvect(irq_num-8+0x70,old_handler1); } enable(); }
/* INTERRUPT SERVICE ROUTINE */ void interrupt isr(void) { disable(); {/* thêm mã*/ } outportb(0x20,0x20);
if ( DDA_irq > 7 ) { outportb(0xa0,0x20); } enable(); }
Ví dụ: ếm số lần nút nhấn tác ộng dùng ngắt IRQ3 #include< stdio.h > #include< stdlib.h >
#include< dos.h > #include< conio.h > void interrupt
(*oldIrq3)(void); void interrupt countToggle(void); int i = 0; long j = 0;
#define IRQ3 0x0B /* IRQ3 address */int main(void) { lOMoARcPSD| 10435767 window(5,5,50,75);
clrscr(); gotoxy(1,3); cprintf("Do-while loop iteration # ");
oldIrq3 = getvect(IRQ3); /* lưu vectơ ngắt cũ */
setvect(IRQ3, countToggle); /* cài vectơ ngắt mới */
outportb(0x21, ( inportb(0x21) & 0xF7 ) ); /* cho phép IRQ3 */
/*Vòng lặp, khi bấm phím thì thoát khỏi chương trình, khi nhấn nút thì vào ISR*/
do { j++; gotoxy(27,3); cprintf("%ld\n", j); } while(!kbhit());
/* Có phím bấm, thoát khỏi chương trình chính */ setvect(IRQ3,
oldIrq3); outportb(0x21, (inportb(0x21) | 0x08) ); /* cấm IRQ3 */
/* Số lần bấm phím*/ printf("\nswitch
presses i = %d\n", i); printf("j = %ld\n", j); return 0; } /* end of main */
/* Chương trình phục vụ khi IRQ3 lên mức cao */ void interrupt countToggle(void)
{ disable(); i++; outportb(0x20, 0x20); /* send EOI signal */ enable(); }
Ví dụ: Chương trình ọc kết quả chuyển ổi cùa card ADC 8 bit, mỗi khi ổi xong vi
mạch cho tín hiệu EOC tác ộng lên IRQ3, kết quả chuyển ổi lưu vào file văn bản #include < stdio.h > #include < stdlib.h > #include < dos.h > #include < conio.h > #define IRQ3 0x0b /* IRQ3 */
#define BASEADDRESS 608 /*Địa chỉ gốc */
#define TRUE 1 #define FALSE 0
#define MAXSIZE 5000 /* Lấy 5000 mẫu */ /* globals */ int EOC; /* Đổi xong */ int readData;
/* Kết quả ổi thập phân */
float i; /* Số lần lặp */ float data[MAXSIZE][2];
/* Mảng chứa các kết quả chuyển ổi */ FILE* fp;
/*Con trỏ ến file ASCII */ int j; /* Biến ếm */ /* prototypes */
void interrupt (*oldIrq3)(void); lOMoARcPSD| 10435767 void interrupt eocTrue(void); int /* main(void) { clrscr();
fp = fopen("data.txt", "wt"); /* file chứa kết quả */
/* khởi ộng mảng về 0.0 */
for(j= 0; j < MAXSIZE; j++) { data[j][0] = 0.0; data[j][1] = 0.0; }; printf("data array
initialized\n"); i = 0.0; oldIrq3 = getvect(IRQ3); setvect(IRQ3, eocTrue);
outportb(0x21, ( inportb(0x21) & 0xF7 ) ); EOC = FALSE;
do { readData = inportb(BASEADDRESS); /*Kích ồi */ while(EOC == FALSE) { /* Chờ EOC ON */ };
readData = inportb(BASEADDRESS); /* Đọc kết quả*/ EOC = FALSE; /* Xóa EOC */ data[i][0] = i;
data[i][1] = (float)(readData * 5.0/255.0); /* Đổi ra volt */ i++; } while(i < MAXSIZE);
printf("Writing to file...\n"); for(j=0; j < MAXSIZE; j++)
{ fprintf(fp, "%f\t%f\n", data[j][0], data[j][1]);
}; printf("done\n"); fclose(fp);
setvect(IRQ3, oldIrq3); outportb(0x21, (inportb(0x21) | 0x08) ); printf("Bye!\n");return 0; } /* end of main */
/* Gọi ISR cho EOC ON mỗi khi IRQ3 múc cao*/ void interrupt eocTrue(void) { #pragma asm pushf; #pragma asm cli; EOC = TRUE; lOMoARcPSD| 10435767 outportb(0x20, 0x20); #pragma asm popf; return; } /* end of eofTrue */
Ví dụ: lập trình ngắt trong Turbo Pascal
unit ngat; interface uses dos,crt; {$I+} var Interrupt9 : procedure ; Procedure Int9; interrupt; Procedure SetInt9; Procedure ResetInt9;
IMPLEMENTATION { Interrupt subroutine } Procedure Int9; begin { call original interrupt } Interrupt9; {insert code here} end; Procedure SetInt9; var R : registers; begin { save current IRQ9 } getintvec($71,@Interrupt9); {$71: interrupt of IRQ9} { load new IRQ9 } setintvec($71,@ nt9); end; Procedure ResetInt9; var R : registers; begin { restore IRQ9 } setintvec($71,@Interrupt9); end; Begin End.
7.4 WINDOW DEVICE DRIVERS
Việc lập trình iều khiển các thiết bị chạy dưới hệ iều hành Windows có thể sử dụng
các lệnh truy cập trực tiếp phần cứng bằng các ngôn ngữ lập trình Windows, cũng có thể
sử dụng các thư viện có sẵn của các hãng phần mềm, hoặc tự xây dựng các driver. Trong lOMoARcPSD| 10435767
phần này sẽ mô tả việc lập trình iều khiển bằng các ngôn ngữ khác nhau trong môi trường Windows. ++
7.4.1 Lập trình xuất nhập dùng Visual C 6.0
Sau khi mở VC, bạn vào menu File – New – Projects chọn mục MFCAppWizard
(exe), sau ó ặt tên cho project và ịa chỉ lưu file rồi bấm OK.
Khi cửa sổ MFCAppWizard xuất hiện, chọn option Dialog Based sau ó tiếp tục
bấm Next, ở bước 4 bạn bấm Finish rồi OK
Sau ó bạn tạo các ối tượng Static Text, Edit Box, Button và Timer, các biến liên
kết với Edit Box Port In và Port Out lần lượt là m_indata và m_outdata. Cứ mỗi 1s do
Timer chương trình ọc dữ liệu ở Port In 379, xử lý rồi xuất ra Port Out 378 lOMoARcPSD| 10435767
Sau ây là một phần của chương trình xuất nhập cổng, các dòng in ậm là các dòng
bổ sung thêm // ioportDlg.cpp : implementation file #include "stdafx.h" #include "ioport.h" #include "ioportDlg.h" # include "conio.h" //definition _inp and _outp #ifdef _DEBUG #define new DEBUG_NEW
#undef THIS_FILE static char THIS_FILE[ ] = __FILE__; #endif BOOL CIoportDlg::OnInitDialog() {
CDialog::OnInitDialog(); SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, ALSE); // Set small icon
SetTimer(ID_CLOCK_TIMER,1000, NULL); return TRUE; }
void CIoportDlg::OnTimer(UINT nIDEvent) { UpdateData(TRUE); m_indata=_inp(0x379);
m_outdata=m_indata ^0x80;
_outp(0x378,m_outdata); UpdateData(FALSE); lOMoARcPSD| 10435767 CDialog::OnTimer(nIDEvent); } void CIoportDlg::OnBtnexit() { OnOK(); }
7.4.2 Lập trình dùng Delphi
Không có lệnh xuất nhập mà ta phải dùng hợp ngữ tạo hàm xuất nhập. Functrion Inport (address: word): byte; Var data: word; begin asm push dx mov dx, address in ax, dx mov data, ax pop dx end; inport: = data; end;
Procedure Outport (address: word; data: word); begin asm push dx mov dx,
address mov ax, data out dx, ax pop dx end; end;
Ví dụ: Chương trình Delphi xuất nhập Port unit inoutunit; lOMoARcPSD| 10435767
interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Edit1: TEdit; Edit2: TEdit; Label1: TLabel; Label2: TLabel; btnIN: TButton; btnOUT: TButton; function inport (address:word):byte;
procedure outport (address:word; data:byte);
procedure btnINClick (Sender: TObject);
procedure btnOUTClick (Sender: TObject);
private { Private declarations } public
{ Public declarations } end; var
Form1: TForm1; implementation {$R *.DFM} function Tform1.inport (address:word):byte; var data:byte; begin asm push dx mov dx,address in al,dx mov data, al pop dx end; inport:= data; end;
procedure TForm1.outport (address:word; data:byte);
begin asm push dx mov dx,address mov al,data out dx,al pop dx end;
end; procedure TForm1.btnINClick Sender:
TObject); begin edit2.text:= inttostr (inport (strtoint (edit1.text))); end;
procedure TForm1.btnOUTClick (Sender: TObject); begin
outport (strtoint (edit1.text), strtoint (edit2.text)); end; end. 7.4.3 Visual Basic
Ngôn ngữ này không hỗ trợ xuất nhập port, ta phải dùng thư viện liên kết ộng (dynamic link library)
Viết tập tin liên kết ộng dll lOMoARcPSD| 10435767
File thư viện liên kết ộng có uôi .dll chứa các hàm và thường trình mà các chương
trình chạy trong môi trường Windows như Delphi, Visual Basic, Visual C có thể sử dụng. ++
Các ngôn ngữ lập trình Visual C, Delphi, Borland C Builder ều cho phép viết tập tin
.dll. Hệ iều hành Windows có sẵn một số hàm thư viện liên kết ộng gọi chung dưới tên
Win API (Applications Programming Interface) tuy nhiên việc sử dụng chúng òi hỏi kinh nghiệm lập trình.
Có thể lấy các tập tin dll nhập xuất dữ liệu các port máy tính từ mạng Internet và cài
vào máy tính, hoặc có thể tự viết. Sau ây trình bày hai ví dụ dùng Visual C và Delphi ể
viết tập tin.dll mà Visual Basic sẽ sử dụng.
Dùng Visual C++4.0 (Win 16 bit) Ta viết tập tin thư viện ặt tên là INOUT.dll gồm
thường trình xuất ra cổng ặt tên OUTPORT và thường trình nhập dữ liệu INPORT.
Đầu tiên dùng phần mềm soạn văn bản viết hai tập tin INOUT.DEF (define) và tâp
tin INOUT.CPP (chương trình C). // Inout.def listing Library inout Description dll for I/O card Exports Outport @ 1 Inport @ 2
Hàng ầu là tên file INOUT, hàng thứ hai là chú thích, các hàng sau liệt kê tên các
thường trình trong thư viện. Sau tên thường trình là dấu @ và số thứ tự. // INOUT.CPP Listing
// file nguồn .CPP cho dll INOUT.dll # include
# include // chứa hàm INP và OUTP
Short-stdcall OUTPORT (int PortAddress, int PortData) { Short Dummy;
Dummy = (Short) (_outp (PortAddress, PortData)); Return (Dummy); };
Short_stdcall INPORT (int PortAddress) {
Short PortData; PortData = (Short) (_inp (PortAddress)); Return (PortData); } ;
Sau khi ã soạn xong hai tập tin INOUT.def và và INOUT.cpp ta cất vào một thư
mục, ví dụ, C:\port. Vào Visual C chọn File - New -Projects Win32DLL ánh tên INOUT lOMoARcPSD| 10435767
và ịa chỉ C:\port\INOUT rồi bấm OK. Màn hình INOUT - Microsoft Developper Studio
sẽ xuất hiện và project INOUT classes ược tạo ra, ta sẽ cộng thêm hai file INOUT.def
và INOUT.cpp vào project INOUT rồi bấm FILE - SAVE ALL.
Sau khi ã tạo project INOUT bấm Build và chọn Build INOUT.dll, nếu không có gì
sai sót file INOUT.dll sẽ ược tạo ra và cất trong C:\port\inout\debug. Sau ó cất file vào
thư mục hệ thống của Windows, ví dụ, C:\Windows. Với Visual C 5.0 và 6.0 cách viết sẽ khác i.
Các chương trình viết trên ngôn ngữ khác như Delphi, Visual Basic có thể gọi hàm
INPORT và OUTPORT khi ã khai báo các hàm này và INOUT.dll
Ví dụ, trong Visual Basic ta thêm các dòng này trong phần khai báo chương trình
sau phát biểu Option Explicit: Option Explicit
Private Declare Function OUTPORT LIB “INOUT.dll” (ByVal PortAddress As
Integer, By Val Port Data as Integer) As Integer.
Private Declare Function INPORT Lib “INOUT.dll” (ByVal PortAddress As Integer) As Integer
Private cho biết các hàm và thường trình sau Declare là cục bộ. Sau Declare ta viết
Function nếu có trả về giá trị, còn không thì dùng SUB, sau ó là tên. Từ LIB và kèm
theo cho biết nơi tìm tập tin dll, thường phải kèm ường dẫn.
Sau khi ã khai báo có thể sử dụng các hàm và chương trình con trong chương trình..
Ví dụ, muốn xuất 0 ra ịa chỉ 300H ta viết: Dummy = OUTPORT (768, 0)
Dummy là biến nguyên ã khai báo (Dim Dummy as Integer;)
Muốn nhập một trị ở cổng Control Port vào biến Value ta viết Value = INPORT (Control Port)
7.4.4 Tạo dll dùng VC++ 6.0 (Win32 bit)
Vào File- New- Projects chọn Wìn32 Dynamic- Link Library, ặt tên cho project là inout lOMoARcPSD| 10435767
Sau ó tiếp tục chọn option A Simple DLL Project Khung soạn thảo chương trình xuất hiện
Ta bổ sung thêm các dòng lệnh vào inout.cpp
// inout.cpp : Defines the entry point for the DLL application. #include "stdafx.h" #include #include lOMoARcPSD| 10435767
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { return TRUE; }
int APIENTRY inport(WORD Port) { return(_inp(Port)); }
int APIENTRY outport(WORD Port, int ByteData) {
return(_outp(Port, ByteData)); }
Sau ó vào File – New -Files, chọn Text File, bổ sung vào Project inout file
inout.def //inout.def LIBRARY inout EXPORTS inport @1 outport @2
Vào menu Chọn Build- Build inout.dll, file inout ược lưu vào thư mục
d:\inout\Debug, ta chép vào thư mục c:\Windows Chương trình sử dụng file inout. dll trong Visual Basic 6.0: lOMoARcPSD| 10435767
Private Declare Function inport Lib "inout.dll" (ByVal portaddress As Integer) As Long
Private Declare Function outport Lib "inout.dll" (ByVal portaddress As Integer,
ByVal_ value As Byte) As Long Private Sub Command1_Click() Timer1.Enabled
= True End Sub Private Sub Command2_Click() Timer1.Enabled = False
Unload Form1 End Sub Private Sub Form_Load() Timer1.Interval = 1000
Timer1.Enabled = False End Sub Private Sub Timer1_Timer()
Dim i, port, giatri, dummy port = 768 dummy = outport(port + 1, Val(Text1.Text))
giatri = inport(port) Text2.text=giatri For i = 0 To 7 If (giatri And (2 ^ i))=2^i
Then Lamp(i).FillColor = QBColor(12)
Else Lamp(i).FillColor = QBColor(10) End If Next End Sub
Chương trình Delphi dùng inout.dll: unit Unit1; interface uses
Windows, Messages, SysUtils, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls; type
TForm1 = class(TForm) Edit1: TEdit;
Button1: TButton; Edit2: TEdit;
procedure Button1Click(Sender: TObject);
private { Private declarations } public { Public declarations } end;
Function inport (adr: word): byte; stdcall; external 'inout.dll'
Function outport (adr: word; data:byte): byte; stdcall; external'inout.dll' var
Form1: TForm1; implementation {$R *.DFM}
procedure TForm1.Button1Click(Sender:
TObject); var data: byte; begin data := outport lOMoARcPSD| 10435767
($378, strtoint ( edit1.text)); edit2.text := inttostr (inport($379)) end; end.
4.2.3 Tạo DLL dùng Delphi
Chạy Delphi, vào menu File- New, chọn DLL - OK, trên cửa sổ soạn thảo
Project1.dpr xuất hiện khung chương trình sau: library Project1; uses SysUtils, Classes; {$R *.RES} begin end.
Ta sẽ ổi tên Project1 thành inout và thêm các dòng lệnh trước begin end. Ví dụ sau
tạo inout.dll gồm chương trình con outport và hàm inport library inout; uses SysUtils, Classes; {$R *.RES}
Procedure outport(adr:word;data:word);
export; stdcall; begin asm push dx mov dx,adr mov ax,data out dx,ax pop dx end; end;
Function inport(adr:word):word; export; stdcall; var data:word; begin asm push dx mov dx,adr in ax,dx mov data, ax pop dx end; inport:=data; end; lOMoARcPSD| 10435767
exports outport index 1,inport index 2; begin end.
Sau ó vào menu Project- Build inout. File inout.dll ược tạo ra trong thư mục
\Delphi5\Projects cùng với các file inout.dpr, inout.res, inout.dof, inout.cfg. Ta chép
file inout.dll vào thư mục Windows\System.
Ví dụ: Viết chương trình Visual Basic dùng dll inout do Delphi tạo ra
Private Declare Function inport Lib "inout.dll" (ByVal portaddress As Integer) As Byte
Private Declare Sub outport Lib "inout.dll" (ByVal portaddress As Integer, ByVal_ value As Byte) Private Sub Command1_Click() Timer1.Enabled = True End Sub Private Sub Command2_Click() Timer1.Enabled = False Unload Form1 End Sub Private Sub Timer1_Timer() Dim i, port, giatri port = 768 giatri = inport (port+1) For i = 0 To 7
If (giatri And (2 ^ i)) and 2^i Then Lamp(i).FillColor = QBColor(12) Else_ Lamp(i).FillColor = QBColor(10) Next End Sub lOMoARcPSD| 10435767
Ví dụ: viết chương trình Delphi dùng inout.dll do Delphi tạo ra unit Unit1; interface uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type
TForm1 = class(TForm) Edit1: TEdit; Button1: TButton; Edit2: TEdit;
procedure Button1Click(Sender: TObject);
private { Private declarations } public { Public declarations } end;
Function inport (adr: word): word; stdcall; external 'inout.dll'
Procedure outport (adr: word; data:
word); stdcall; external 'inout.dll' var Form1: TForm1;
implementation {$R *.DFM} procedure
TForm1.Button1Click (Sender: TObject);
begin outport ($378, strtoint ( edit1.text));
edit2.text:= inttostr((inport($379)) and $ff) end; end.
Xuất nhập với Win 2000 và Win NT
Việc xuất nhập trong DOS và Win 98 thực hiện dễ dàng như ã trình bày ở các mục
trên, tuy nhiên các hệ iều hành Win 2000 và Win NT ngăn cản việc thực hiện các lệnh
truy cập ngoại vi trực tiếp trong mode người dùng. Muốn vượt qua rào cản này ta phải
viết các driver truy cập ngoại vi trong mode kernel sử dụng các hàm WinAPI. Viết các
file xuất nhập dll dạng này khá phức tạp và òì hỏi trình ộ lập trình cao, có thể vào các
trang web ể download về sử dụng, ví dụ một ịa chỉ là www.logix4u.net. Một ịa chỉ khác
www.jungo.com hỗ trợ viết driver cho card ISA, PCI, USB….