Tải bản đầy đủ (.doc) (17 trang)

Đề tài Ngắt và xử lý ngắt trong C – Chương trình thường trú

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (306.16 KB, 17 trang )

Lời cảm ơn
Từ trước tới nay, chúng ta luôn luôn làm việc với các
chương trình tuần tự. Điều đó có nghĩa là lệnh nọ nối sau
lệnh kia theo một trật tự cố định. Để thực sự sử dụng sức
mạnh của máy tính, tạo ra những ứng dụng có khả năng chạy
thường trú và xử lý đa tuyến, nhiều công việc đan xen nhau,
chúng ta cần tìm hiểu lập trình ở mức độ ngắt.
Nhóm 12 tham gia nghiên cứu Đề tài “Ngắt và xử lý ngắt
trong C – Chương trình thường trú” nhằm nắm được phần
nào dạng lập trình phức tạp này và xây dựng chương trình
thường trú hiển thị Đồng hồ thời gian thực trong DOS.
Hiện nay, tài liệu về Lập trình hệ thống không nhiều, tài liệu
từ Internet đa phần viết bằng tiếng Anh nên nhóm cũng gặp
một vài khó khăn nhất định. Trong quá trình tham gia nghiên
cứu, Nhóm 12 xin chân thành cảm ơn
thầy Nguyễn Trần Thi Văn đã nhiệt tình hướng dẫn, tạo điều
kiện thuận lợi về tài liệu và giúp đỡ nhóm hoàn thành đề tài.
Dù đã rất cố gắng nhưng chắc chắn Nhóm vẫn còn nhiều
thiếu sót. Rất mong nhận được ý kiến đóng góp của Thầy và
các bạn.
Tp. Hồ Chí Minh, tháng 12/2008
Nhóm 12
Tp.Hồ Chí Minh - 12/2008
Ngắt và xử lý ngắt trong C – Chương trình thường trú
Mục lục: Trang
A.Tổng quan 3
B.Nội dung 3
1. NGẮT VÀ XỬ LÝ NGẮT 3
1.1 Ngắt là gì? 3
1.2 Thủ tục ngắt 3
1.3 Bảng vector ngắt (chủ yếu ngắt chính): 4


1.4 Các hàm hỗ trợ gọi ngắt của dos.h: 6
2. CHƯƠNG TRÌNH THƯỜNG TRÚ 10
2.1 Cấu trúc, phân loại và cách xây dựng 10
2.2 Chế độ biên dịch bằng dòng lệnh 13
2.3 Hàm keep() 15
2.4 Tóm tắt các lệnh cần dùng để thường trú chương trình 16
2.5 Ví dụ về chương trình thường trú 16
C.Chương trình 17
D.Kết luận 17
Bài tập lớn môn Cơ sở lập trình 2
2
Ngắt và xử lý ngắt trong C – Chương trình thường trú
A.TỔNG QUAN
DOS là một hệ điều hành phổ biến trong quá khứ và hiện nay nó vẫn còn được ứng
dụng rộng rãi. Thực chất DOS là một hệ điều hành đơn nhiệm (tại một thời điểm chỉ chạy
được một chương trình ứng dụng), nhưng chúng ta vẫn có phương pháp làm cho các ứng dụng
nhỏ chạy song song với chương trình chính, ứng dụng nhỏ đó gọi là chương trình xử lý ngắt
thường trú (hay còn gọi là chương trình thường trú). Do đó, để viết chương trình thường trú
chúng ta cần phải tìm hiểu về ngắt và xử lý ngắt trong DOS.
B. NỘI DUNG
1. NGẮT VÀ XỬ LÝ NGẮT
1.1 Ngắt là gì?
Mỗi khi một thiết bị phần cứng hay một chương trình cần sự giúp đỡ của CPU, nó
gởi một tín hiệu hoặc lệnh đến CPU, gọi là ngắt, chỉ định một công việc cụ thể mà nó
cần CPU thực hiện. Khi CPU nhận được tín hiệu ngắt, nó tạm ngưng tất cả các hoạt
động khác và kích hoạt một chương trình con đang có trong bộ nhớ, gọi là chương trình
xử lí ngắt, tương ứng với số hiệu ngắt cụ thể. Sau khi chương trình xử lí ngắt làm xong
nhiệm vụ, các hoạt động của máy tính sẽ tiếp tục lại từ nơi đã bị tạm dừng lúc xảy ra
ngắt.
• Có hai loại ngắt: ngắt cứng và ngắt mềm. Chúng có cấu trúc tương tự

nhau, chia nhau bảng vectơ ngắt nhưng lại có những khác nhau cơ bản.
• Ngắt cứng xuất hiện khi các thiết bị ngoại vi cần được phục vụ. Ví dụ:
cắm USB, ấn phím, ….
• Ngắt mềm xuất hiện khi chương trình thực hiện một lệnh ngắt.
1.2 Thủ tục ngắt
1.2.1 Thủ tục ngắt là gì?
Khi xuất hiện ngắt cứng có số hiệu N thì chương trình tạm thời gác lại, CPU sẽ
tìm địa chỉ thủ tục ngắt N trong bảng vector ngắt để thực hiện. Nếu ta thay địa chỉ thủ
tục ngắt N bằng địa chỉ của một thủ tục do chúng ta lập ra, thì thủ tục của chúng ta sẽ
được thực hiện mỗi khi xảy ra ngắt N. Thủ tục được xây theo cách này gọi là thủ tục
xử lí ngắt.
1.2.2 Cấu trúc chung và cú pháp.
1.2.2.1 Cú pháp:
void interrupt <tên hàm>([Danh sách các tham số])
{ các_lệnh}
Bài tập lớn môn Cơ sở lập trình 2
3
Ngắt và xử lý ngắt trong C – Chương trình thường trú
Từ khóa interrupt dùng để khai báo hàm xử lý ngắt. Khi gặp từ khai báo
interrupt thì một mã đặc biệt được sinh ra để cất tất cả các thanh ghi và cờ.
1.2.2.2 Tham số:
Trong hàm xử lý ngắt có thể dựa vào các đối. Việc trao đổi thông thông tin giữa
chương trình và hàm được thực hiện thông qua các đối.
Các tham số phải tuân theo các qui tắc sau:
- Các đối sẽ nhận giá trị của các thanh ghi ở thời điểm xảy ra ngắt ( khi ngắt bắt đầu
thực hiện).
- Giá trị của các đối có thể thay đổi bằng câu lệnh trong hàm(nên thận trọng).
- Khi thoát khỏi hàm, giá trị của các đối sẽ gán trả lại cho các thanh ghi.
Đối số của hàm xử lý ngắt cần được khai báo theo mẫu sau:
void interrupt <tên_hàm>(int bp, int di, int si, int ds, int es, int dx, int cx, int bx, int

ax, int ip, int cs, int flags);
Lưu ý: để tránh các cảnh báo khó chịu do không sử dụng hết đối số, ta dùng các
lệnh tiền xử lý sau:
#pragma warn-par //tắt kiểm tra tham số
#pragma warn.par //bật kiểm tra tham số
1.2.2.3 Thân hàm:
i. Không được sử dụng các dịch vụ của DOS (như các hàm vào ra).
ii. Không được sử dụng các phép tính dấu chấm động.
iii. Chỉ nên dùng các phép gán, phép tính trên số nguyên, kí tự và các phép logic.
1.3 Bảng vector ngắt (chủ yếu ngắt chính):
Số hiệu ngắt(hex) Địa chỉ(hex) Công dụng
0 0000 được tạo bởi CPU khi phải chia cho 0.
1 0004 cho phép thực hiện chương trình từng lệnh một.
2 0008 ngắt không bị che (NMI)
3 000C dùng để đặt điểm dừng (break-point) trong chương
trình
4 0010 được tạo ra khi kết quả số học bị tràn
5 0014 gọi chương trình phục vụ BIOS để in trang màn hình
8 0020 được tạo bởi nhịp đồng hồ phần cứng
9 0024 được tạo ra khi có tác động vào phím bất kì
Bài tập lớn môn Cơ sở lập trình 2
4
Ngắt và xử lý ngắt trong C – Chương trình thường trú
D 0034 được tạo ra khi có hồi dọc trên màn hình, dùng để điều
khiển video
E 0038 được tạo ra bởi bộ điều khiển đĩa mềm để báo đang tìm
kiềm trên đĩa
F 003C dùng để điều khiển máy in(song song)
10 0040 gọi các chương trình phục vụ BIOS về màn hình
11 0044 gọi phục vụ BIOS đọc danh sách thiết bị

12 0048 gọi phục vụ BIOS thông báo kích thước bộ nhớ
13 004C gọi các chương trình phục vụ BIOS về vào/ra đĩa (HDD
và FDD)
14 0050 gọi các chương trình phục vụ BIOS cho truyền tin qua
cổng nối tiếp
15 0054 gọi các chương trình phục vụ BIOS cho cassette và các
phục vụ mở rộng
16 0058 gọi các chương trình phục vụ BIOS cho bàn phím
chuẩn
17 005C gọi các chương trình phục vụ BIOS cho máy in
18 0060 kích hoạt ngôn ngữ ROM-BASIC, hoặc cái thay thế
ngôn ngữ này
19 0064 gọi các chương trình khởi động boot-strap
1A 0068 gọi các chương trình phục vụ BIOS về giờ và ngày
tháng
1B 006C được tạo ra (dưới BIOS) bởi các tổ hợp phím thoát Ctrl-
Break, Ctrl-C)
1C 0070 được tạo ra bởi mổi nhịp đồng hồ, do chính ngắt 8 gọi
1D 0074 trỏ tới bảng tham số điều khiển video
1E 0078 trỏ tới bảng tham số cơ sở đĩa
1F 007C trỏ tới các kí tự đồ thị cao
20 0080 gọi phục vụ DOS để kết thúc chương trình
21 0084 gọi tất cả các hàm phục vụ của DOS
22 0088 trỏ đến địa chỉ cần chuyển điều khiển đến khi chương
trình kết thúc dưới DOS
Bài tập lớn môn Cơ sở lập trình 2
5
Ngắt và xử lý ngắt trong C – Chương trình thường trú
23 008C trỏ đến địa chỉ cần chuyển điều khiển đến khi gặp tổ
hợp phím thoát (Ctrl-Break hay Ctrl-C) dưới DOS

24 0090 trỏ đến địa chỉ cần chuyển điều khiển đến khi gặp lỗi
nghiêm trọng dưới DOS
25 0094 gọi phục vụ DOS để đọc đĩa tuyệt đối
26 0098 gọi phục vụ DOS để ghi đĩa tuyệt đối
27 009C kết thúc chương trình và cho thường trú trong bộ nhớ
dưới DOS
44 0110 trỏ đến các kí tự đồ thị thấp (chỉ dùng cho EAG)
49 0124 trỏ đến bảng chuyển đổi cho thiết bị phụ của bàn phím
1.4 Các hàm hỗ trợ gọi ngắt của dos.h:
Gồm: geninterrupt(), int86(), segread(), int86x(), setvect(),
getvect(), disable(), enable(), …
1.4.1 Tìm hiểu về cách gọi một thủ tục ngắt mềm:
Để gọi một ngắt mềm ta phải tiến hành các bước sau:
• Đặt ngắt vào thanh ghi AH.
• Xác định tham số đầu vào và đưa chúng vào các thanh ghi theo yêu cầu của
mỗi ngắt.
• Thực hiện câu lệnh gọi ngắt theo số hiệu ngắt.
• Lấy kết quả do ngắt sinh ra từ thanh ghi(tham số đầu ra).
1.4.2 Các giả thanh ghi, union và struct dùng trong các hàm của
dos.h:
1.4.2.1 Giả thanh ghi:
_AX , _AH, _AL
_BX , _BH, _BL
_CX , _CH, _CL
_DX , _DH, _AL
_CS, _DS, _ES, _SS
_SP, _BP, _SI, _DI
_FLAGS
Các giả thanh ghi tự động biến đổi theo các thanh ghi, vì vậy không thể dùng chúng
với mục đích lưu trữ.

Bài tập lớn môn Cơ sở lập trình 2
6
Ngắt và xử lý ngắt trong C – Chương trình thường trú
1.4.2.2 union và struct:
struct WORDREGS /*thanh ghi chung 16 bit*/
{
unsigned int ax, bx, cx, dx, si, di, cflag, flags;
};
struct WORDREGS /*thanh ghi chung 8 bit*/
{
unsigned int al, ah, bl, bh, cl, ch, dl, dh;
};
struct SREGS /*Các thanh ghi đoạn*/
{
unsigned int es, cs, ss, ds;
};
union REGS /*hợp giữa các thanh ghi 16bit và 8bit*/
{
struct WORDREGS x;
struct BYTEREGS h;
};
1.4.2.3 Chuyển đổi địa chỉ (cần thiết cho các ngắt):
Để chuyển từ địa chỉ thực sang địa chỉ phân đoạn ta dùng các macro sau:
unsigned FP_SEG(địa_chỉ_thực); /*trả về địa chỉ segment*/
unsigned FP_OFF(địa_địa_thực); /*trả về địa chỉ offset*/
Để chuyển ngược lại ta dùng macro: void far *MK_FP(segment, offset);
1.4.2 Chức năng các hàm ngắt mềm:
1.4.2.1 Hàm: geninterrupt(int sh_ngat):
Hàm thực hiện ngắt mềm, sh_ngat là số hiệu ngắt. Hàm này có sử dụng các giả thanh
ghi ở 1.4.2.1.

Ví dụ: Để thực hiện ngắt (0x21, 6) (đưa một kí tự lên màn hình) ta thực hiện như sau:
_AH=6; /*đưa số hiệu chức năng vào thanh ghi AH*/
_AL=65;/*đưa mã kí tự (chữ A) vào thanh ghi AL*/
geninterrupt(0x21); /*gọi ngắt 0x21*/
Trước khi gán giá trị vào giả thanh ghi, ta nên lưu trữ tình trạng hiện thời của nó vào
một biến để sau này khôi phục lại. Nếu không làm như vậy có thể dẫn tới treo máy.
1.4.2.2 Hàm: int int86(int sh_ngat, union REGS *v, union REGS *r):
Hàm thực hiện ngắt mềm sh_ngat. Các tham số đầu vào được nạp vào các thanh ghi
thông qua “union v”. Tham số đầu ra nhận được từ “union r”.
Ví dụ: ở ví dụ 1.4.4.1 ta sử dụng hàm geninterrupt() để thực hiện ngắt (0x21, 6), sau
đây là ví dụ minh họa cho hàm int86() thực hiện ngắt tương tự.
union REGS v, r; /*biến v dùng đề chứa tham số đầu vào, r dùng để chứa tham số
đầu ra*/
Bài tập lớn môn Cơ sở lập trình 2
7
Ngắt và xử lý ngắt trong C – Chương trình thường trú
v.h.ah=6; /*đưa số hiệu chức năng vào thanh ghi AH*/
v.h.al=65; /*đưa mã kí tự (chữ A) vào thanh ghi AL*/
int86(0x21, &v, &r); /*gọi ngắt 0x21*/
Hàm: void segread(struct SREGS *s):
Hàm đặt nội dung các thanh ghi đoạn vào cấu trúc s. Hàm này được dùng để chuẩn
bị cho hàm int86x().
1.4.2.3 Hàm: int int86x(int sh_ngat, union REGS *v, union REGS
*r, struct SREGS *s):
Hàm có tác dụng như hàm int86() nhưng tham số đầu vào được xác định thông qua
“union v” và “struct s”, kết quả nhận từ “union r” và “struct s”.
1.4.3 Các hàm hỗ trợ xử lý ngắt cứng:
1.4.3.1 Hàm disable() và enable():
Có những đoạn mã (đoạn chương trình) đòi hỏi điều kiện nghiêm ngặt sau: trong thời
gian thực hiện đoạn mã không cho phép xuất hiện ngắt cứng. Ta gọi là các đoạn mã

tới hạn. Việc xảy ra ngắt trong đoạn mã tới hạn có thể làm chương trình hoạt động
rối loạn hay thiếu chính xác. Để viết các đoạn mã tới hạn ta cần dùng hai hàm sau:
disable(); //dùng để tắt hệ thống ngắt cứng.
//các câu lệnh
enable(); //dùng để bật trở lại hệ thống ngắt cứng.
Các ngắt chỉ nên tắt trong khoảng thời gian rất ngắn. Mọi ngắt xuất hiện khi hệ thống
ngắt bị tắt, nó sẽ phải chờ cho đến khi được bật trở lại.
1.4.3.2 Hàm getvect() và setvect():
Để chương trình gọi tới một hàm xử lý ngắt, trước đó cần đặt địa chỉ của nó đè
lên địa chỉ của thủ tục dịch vụ ngắt chuẩn tương ứng. Điều này được thực hiện nhờ
hai hàm sau:
void interrupt (*getvect(int sh_ngat))();
Bài tập lớn môn Cơ sở lập trình 2
8
Ngắt và xử lý ngắt trong C – Chương trình thường trú
void setvect(int sh_ngat, void interrupt (*con_tro_ham)());
Hàm getvect() dùng để nhận địa chỉ của một thủ tục dịch vụ ngắt chuẩn với
mục đích khôi phục sau này.
Hàm setvect() dùng để đặt địa chỉ của hàm xử lý ngắt đè lên địa chỉ của thủ tục
dịch vụ ngắt chuẩn có số hiệu sh_ngat.
1.4.3.3 Cấu trúc của một chương trình xử lý ngắt:
/* khai báo con trỏ hàm để lưu địa chỉ thủ tục ngắt chuẩn*/
void interrupt (*dos_int)();
/* khai báo hàm xử lý ngắt*/
void interrupt (*user_int)();
main()
{
/*lưu địa chỉ củ thủ tục ngắt chuẩn*/
dos_int=getvect(8);
/*cài đặt địa chỉ mới*/

disable();
setvect(8, user_int);
enable();
/*thực hiện hàm xử lý ngắt*/
/*khôi phục địa chỉ*/
disable()
setvect(8, dos_int);
enable();
}
Bài tập lớn môn Cơ sở lập trình 2
9
Ngắt và xử lý ngắt trong C – Chương trình thường trú
2. CHƯƠNG TRÌNH THƯỜNG TRÚ
2.1 Cấu trúc, phân loại và cách xây dựng
2.1.1 Khái niệm:
Chương trình xử lý ngắt thường trú hay gọi gọn là Chương trình thường trú (kết
thúc và thường trú – Terminate and stay Resident- TSR) là chương trình mà các
ngắt chuẩn bị sẽ chiếm dụng vĩnh viễn(chỉ khi khởi động lại máy mới khôi phục
được).
Khi thực hiện chương trình thường trú thì chương trình thường trú sẽ được thực
hiện (trong bất kỳ môi trường nào) mỗi khi xuất hiện ngắt chuẩn (đang bị chiếm dụng
bởi chương trình).

Ví dụ: Nếu dùng ngắt 8 (đồng hồ) thì cứ sau mỗi tích tắc (khoảng 1/18 giây) chương
trình lại được kích hoạt. Nếu dung ngắt 0x15(bàn phím) thì chương trình được kích
hoạt mỗi khi gõ phím.
Trong chương trình không thường trú, hàm ngắt thường dùng để lấy thông từ từ các
thanh ghi chứa vào các biến ngoài để cho hàm main xử lý.
trong hàm TSR, hàm ngắt phải làm tất cả mọi việc. Hàm main chỉ làm nhiệm vụ chiếm
dụng ngắt và thường trú.

2.1.2 Cấu trúc:
/* khai báo con trỏ hàm để lưu địa chỉ thủ tục ngắt
void interrupt(*dos_int)(void);
/*khai báo hàm xử lý ngắt*/
void interrupt(*user_int)(void);
/*xây dựng hàm xử lý ngắt*/
unsigned int_stklen=1024,_heaplen=2;
main()
{
unsigned int size=_SS-_psp+_SP/16+50;
/*lưu địa chỉ của thủ tục ngắt chuẩn*/
dos_int=getvect(8);
/*cài đặt địa chỉ mới*/
disable();
setvect(8,user_int);
enable();
/*thực hiện hàm xử lý ngắt*/
/*khôi phục địa chỉ*/
disable();
setvect(8,dos_int);
enable();
/*kết thúc chương trình thường trú*
Bài tập lớn môn Cơ sở lập trình 2
10
Ngắt và xử lý ngắt trong C – Chương trình thường trú
keep(0,size);
}
Câu lệnh:
unsigned int _stklen=1024,_heaplen=2;
Chương trình thường trú chiếm dụng lâu dài vùng nhớ vì vậy trước khi đặt vào bộ

nhớ ta cần làm giảm độ lớn cho nó, biến _stklen dùng để quy đình kích thước vùng
ngăn xếp. Còn biến _heaplen dùng để quy định kích thước vùng heap. Độ lớn mặc định
của ngăn xếp là 4K byte của heap là toàn bộ vùng nhớ có thể cung cấp (ứng với heap
=0). Ta nên đặt vùng nhớ tối thiểu cho ngăn xếp là 1K byte và heap là 1 word (2 byte).
câu lệnh:
unsigned int size=_SS-_psp+_SP/16+50;
Xem thêm phần hàm Keep() (Mục 2.4)
2.2.3 Phân loại:
2.2.4 Cách xây dựng:
Chúng ta hãy tham khảo ví dụ sau:
Chương trình thay đổi chức năng các phím :
Ta nêu trường hợp cần thay đổi chức năng các phím. Giả sử phím 1( mã quét
0x02) bị hỏng trong khi đó ta thường xuyên phải dùng đến nó, ta hãy chọn một phím
như phím ~ ( mã quét 0x29, ở bên trái phím 1) và đổi chức năng để nó trở thành 1. Nói
cách khác khi bấm phím ~ thì trên màn hình xuất hiện số 1. Muốn vậy ta lập hàm xử lý
ngắt 15 để nhận giá trị các thanh ghi AH, AL và biến đổi theo quy tắc sau: nếu AH =
0x29 ( bấm phím ~) thì đổi AL =0x02 (phím 1).
- Hàm này được viết đơn giản như sau:
#pragma warn – par
void interrupt new_keyboard(INTERRUPT_REGS)
{
if((ax>>8)==KBD_ FUNCTION&&(ax&0xFF)==MA_NGA)
ax=ax&0xFF00|MA_1;
}
#pragma warn.par
// dưới đây là chương trình:
#include”dos.h”
#include”conio.h”
#include”stdio.h”
#include”stdlib.h”

#define MA_NGA 0x29
#define MA_1 0x02
#define KBD_INT 0x15
#define KBD_FUNCTION 0x4F
#define u_int unsigned int
Bài tập lớn môn Cơ sở lập trình 2
11
Ngắt và xử lý ngắt trong C – Chương trình thường trú
#define INTERRUP_REGS u_int bp, u_int di, u_int si, u_int ds,\
u_int es, u_int dx, u_int cx, u_int bx, u_int ax, u_int ip,\
u_int cs, u_int flags
#define INTERRUP_PARAM bp, di, si, ds, es, dx, cx, bx, ax, ip, cs, flags
void interrupt new_keyboard(INTERRUPT_REGS);
void interrupt (*old_keyboard)(INTERRUPT_REGS);
unsigned int_stklen=1024, _heaplen=2;
#pragma warn – par /*tắt kiểm tra tham số*/
void interrupt new_keyboard(INTERRUPT_REGS)
{
if((ax>>8)==KBD_ FUNCTION&&(ax&0xFF)==MA_NGA)
ax=ax&0xFF00|MA_1;
}
#pragma warn.par
/*bật kiểm tra tham số*/
void main(void)
{
unsigned int size = _SS-_psp+_SP/16+50;
disable();
/*tắt hệ thống ngắt cứng*/
setvect(KBD_INT, new_keyboard);
enable();

/*bật hệ thống ngắt cứng*/
keep(0,size);
/*kết thúc chương trình thường trú*/
}
Cách xây dựng chương trình thường trú về cơ bản giống như một chương trình
xử lý ngắt, ta chỉ sử dụng thêm các câu lệnh sau:
unsigned int_stklen=1024,_heaplen=2;
unsigned int size=_SS-_psp+_SP/16+50;
keep(0,size);
trong đó:
• Lệnh thứ nhất đặt trên( bên ngoài) hàm main();
• Lệnh thứ hai đặt ở đầu( bên trong) hàm main();
• Lệnh thứ ba đặt ở cuối( bên trong hàm main();
2.2 CHẾ ĐỘ BIÊN DỊCH BẰNG DÒNG LỆNH TCC
2.2.1 Khái niệm:
Trình biên dịch TCC thực hiện ở mức DOS cho phép dịch các chương trình lớn
gồm nhiều module trên nhiều tệp dạng nguồn (*.C) và dạng đích (*.OBJ). TCC làm
việc theo hai bước:
• Dịch một cách độc lập các module nguồn.
• Liên kết các module vừa dịch , các module dạng đích (đã dịch từ trước) và các
module thư viện (*.LIB) để tạo thành tệp module thực thi (*.EXE).
Bài tập lớn môn Cơ sở lập trình 2
12
Ngắt và xử lý ngắt trong C – Chương trình thường trú
2.2.2 Cấu trúc:
tcc [tùy chọn, ] tên_tệp [tên tệp, ]
2.2.3 Cách viết:
Giữa tcc các tùy chọn và tên tệp phải cách nhau ít nhất một khoảng trắng. Các tùy
chọn bắt đầu bằng dấu gạch ngang. (Ví dụ: -ml)
2.2.4 Quy ước về tên tệp:

• ten_tep hoặc ten_tep.C là tệp nguồn cần dịch.
• ten_tep.OBJ là tệp được ghép vào tệp chính khi liên kết
• ten_tep.LIB là tệp được ghép vào tệp chính như tệp thư viện
• ten_tep.ASM gọi MASM để dịch thành OBJ và liên kết
2.2.5 Tên tệp chương trình thực thi:
Thông thường, trình biên dịch đặt tên tệp chương trình thực thi (*.EXE) là tên tệp gốc
hoặc tệp đích đầu tiên trong dòng lệnh.
Nếu muốn dùng tên khác đặt cho tệp thực thi cần dùng tùy chọn:
-etên_tệp_thực_thi đặt trước mọi tên tệp khác.
2.2.6 Các tùy chọn thường dùng:
2.2.6.1 Tùy chọn mô hình bộ nhớ:
• mc: compact
• mh: huge
• ml: large
• mm: medium
• ms: small
• mt: tiny
Bài tập lớn môn Cơ sở lập trình 2
13
Ngắt và xử lý ngắt trong C – Chương trình thường trú
2.2.6.2 Tùy chọn xử lý chương trình gốc:
-A: Tạo ra chương trình tương thích với ANSI, mọi từ khóa mở rộng đều bị bỏ qua
và có thể dùng như tên gọi. Một số từ khóa như:
near far huge codecl asm pascal interrupt
_es_ds_cs_ss và các biến giả thanh ghi như _AX_BX

-C: Cho phép các lời chú thích được lồng nhau.
-K: Xử lý mọi khai báo là unsigned char (ngầm định char là signed char)
2.2.6.3 Tùy chọn mội trường:
-Itm: Tìm các tệp tiêu đề trong thư mục tm (đường dẫn đầy đủ).

-Ltm: Tìm các tệp thư viện trong thư mục tm (đường dẫn đầy đủ).
2.2.6.4 Tùy chọn kết quả
-eten_tep: Tệp thực hiện có tên là ten_tep.exe
-oten_tep: Dịch tệp ten_tep.C thành tệp đích ten_tep.OBJ
2.2.7 Ví dụ:
Dòng lệnh: “tcc –Id:\tc\include –Ld:\tc\lib –ekq tt1.c tv.obj tt2" có ý nghĩa
như sau:
• Thư mục chứa các tệp tiêu đề: d:\tc\include
• Thư mục chứa các thư viện: d:\tc\lib
• Tên tệp chương trình thực thi: kq.EXE
• Tệp tt1.C, tt2.C là tệp nguồn
• Tệp tv.OBJ cần được ghép vào khi liên kết
2.3 Hàm keep()
2.3.1 Cú pháp:
Để kết thúc và thường trú chương trình, ta dùng hàm
#include <dos.h>
void keep(unsigned char status, unsigned size)
Hàm này có hai đối là mã kết thúc và kích thước chương trình tính theo 16 byte. Ta
dùng mã 0 để kết thúc (kết thúc bình thường).
2.3.2 Kích thước chương trình
Xét bản đồ bộ nhớ, ta thấy đoạn ngăn xếp là ở cuối. Vì vùng đó là không dùng đến
trong các chương trình thường trú nên đoạn ngăn xếp là đoạn cần dùng cuối cùng:
Địa chỉ thấp
_psp
Bài tập lớn môn Cơ sở lập trình 2
14
Ngắt và xử lý ngắt trong C – Chương trình thường trú
_SS Đoạn ngăn xếp
Ngăn xếp _SP Con trỏ ngăn xếp
Địa chỉ cao


Biến _psp chỉ đến tiền tố đoạn chương trình (program segment prefix – PSP) của
chương trình này. Đó chính là địa chỉ đầu của chương trình. Vậy cần trữ từ chỗ
_psp:0000 đến _SP:_SS cộng với một giá trị nào đó để chắc chắn là đủ chỗ cho chương
trình. Tham số size (tính theo 16 byte) của hàm keep có thể tính như sau:
size=_SS - _psp + _SP/16 +50;
Công thức này đúng với mọi mô hình bộ nhớ.
2.4 Tóm tắt các lệnh cần dùng để thường trú chương trình:
Để một chương trình xử lý ngắt trở thành một chương trình thường trú, ta dùng các
lệnh:
unsigned int _stklen=1024, _heaplen=2; //đặt lại ngăn xếp
unsigned int size=_SS - _psp + _SP/16 +50;//kích thước c.trình
keep(0,size); //giữ thường trú
2.5 Ví dụ về chương trình thường trú:
/*Chương trình thường trú thay đổi mã bàn phím, từ “~” -> “1”
Sử dụng ngắt 0x15 để phát hiện phím đã nhấn, so mã với phím
cần chuyển, nếu khớp thì thay đổi mã quét thành phím mới*/
#include “dos.h”
#include “conio.h”
#include “stdio.h”
#include “stdlib.h”
#define MA_NGA 0x29
#define MAX_1 0x02
#define KBD_INT 0x15
#define KBD_FUNCTION 0x4F
#define u_int unsigned int
#define INTERRUPT_REGS u_int bp,u_int di,u_int si,u_int ds,\
u_int es, u_int dx, u_int cx, u_int bx, u_int ax, u_int ip,\
Bài tập lớn môn Cơ sở lập trình 2
15

Ngắt và xử lý ngắt trong C – Chương trình thường trú
u_int cs, u_int flags
#define INTERRUPT_PARA bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags
void interrupt new_keyboard(INTERRUPT_REGS)
void interrupt (*old_keyboard)(INTERRUPT_REGS)
unsigned int _stklen=1024, _heaplen=2;
#pragma warn – par
void interrupt new_keyborad(INTERRUPT_REGS) {
if ((ax>>8)==KBD_FUNCTION && (ax&0xFF)==MA_NGA)
ax==ax&0xff00|MA_1;
}
#pragma warn.par
void main() {
unsigned int size=_SS - _psp + _SP/16 +50;
disable();
setvect(KBD_INT,new_keyboard);
enable();
keep(0,size);
}
C.CHƯƠNG TRÌNH
Chương trình là một ứng dụng nhỏ thường trú trong DOS, hiển thị thời gian của hệ
thống và có thể chạy song song với bất cứ ứng dụng của DOS.
D. KẾT LUẬN
Đây là một chương trình nhỏ gọn, tốn ít bộ nhớ, có thể cho nó chạy thường trú trong
DOS để làm đồng hồ xem thời gian.
Bài tập lớn môn Cơ sở lập trình 2
16
Ngắt và xử lý ngắt trong C – Chương trình thường trú
Tài liệu tham khảo:
1. Kỹ thuật lập trình C cơ sở và nâng cao – Phạm Văn Ất – Nhà xuất bản giao thông vận

tải.
2. Cẩm namg lập trình – Nguyễn Minh San và Hoàng Đức Hải – Nhà xuất bản lao động-
xã hội.
3. Lập trình C nâng cao – The Peter Norton Computing Group – Trung tâm khoa học tự
nhiên và công nghệ quốc gia Hà Nội.
Bảng phân công công việc:
Công việc Người thực hiện
Tìm hiểu về ngắt và thủ tục ngắt trong C Khương Hải Châu
Lê Nhật Linh
Tìm hiểu về chương trình thường trú Phạm Thanh Hải
Hồ Nguyên Hãn
Hà Tuấn Quốc
Bài tập lớn môn Cơ sở lập trình 2
17

×