-
Thông tin
-
Hỏi đáp
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!
Môn: Thiết bị ngoại vi và ghép nổi
Trường: Học viện Công Nghệ Bưu Chính Viễn Thông
Thông tin:
Tác giả:
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 Ví 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….