Giáo trình Đo lường và điều khiển bằng máy tính - Chương 4: Lập trình cho máy tính điều khiển

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. 
pdf 25 trang xuanthi 24/12/2022 4580
Bạn đang xem 20 trang mẫu của tài liệu "Giáo trình Đo lường và điều khiển bằng máy tính - Chương 4: Lập trình cho máy tính điều khiển", để tải tài liệu gốc về máy hãy click vào nút Download ở trên.

File đính kèm:

  • pdfgiao_trinh_do_luong_va_dieu_khien_bang_may_tinh_chuong_4_lap.pdf

Nội dung text: Giáo trình Đo lường và điều khiển bằng máy tính - Chương 4: Lập trình cho máy tính điều khiển

  1. CHƯƠNG 4: LẬP TRÌNH CHO MÁY TÍNH ĐIỀU KHIỂN Trang 88 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 3- 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]; port [$37A]:= data out; 4- 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); 4.1.2 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.
  2. CHƯƠNG 4: LẬP TRÌNH CHO MÁY TÍNH ĐIỀU KHIỂN Trang 90 Sau đây là một phần của chương trình xuất nhập cổng, các dòng in
  3. CHƯƠNG 4: LẬP TRÌNH CHO MÁY TÍNH ĐIỀU KHIỂN Trang 92 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; 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;
  4. CHƯƠNG 4: LẬP TRÌNH CHO MÁY TÍNH ĐIỀU KHIỂN Trang 94 4.2.1 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 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
  5. CHƯƠNG 4: LẬP TRÌNH CHO MÁY TÍNH ĐIỀU KHIỂN Trang 96 Sau đó tiếp tục chọn option A Simple DLL Project
  6. CHƯƠNG 4: LẬP TRÌNH CHO MÁY TÍNH ĐIỀU KHIỂN Trang 98
  7. CHƯƠNG 4: LẬP TRÌNH CHO MÁY TÍNH ĐIỀU KHIỂN Trang 100 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 ($378, strtoint ( edit1.text)); edit2.text := inttostr (inport($379)) end; end.
  8. CHƯƠNG 4: LẬP TRÌNH CHO MÁY TÍNH ĐIỀU KHIỂN Trang 102 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
  9. CHƯƠNG 4: LẬP TRÌNH CHO MÁY TÍNH ĐIỀU KHIỂN Trang 104 4.4 SỬ DỤNG NGẮT TRONG ĐIỀU KHIỂN Khi đọc dữ liệu từ cổng ngoại vi thường dùng hai phương pháp. Phương pháp thứ nhất là thăm dò bằng cách đọc trạng thái của cổng theo chu kỳ để xem có gì thay đổi không, nếu có sẽ chuyển sang một chương trình phục vụ. Phương pháp này tốn thời gian và làm chậm các quá trình khác. Phương pháp thứ hai là dùng ngắt, vi xử lý thực hiện công việc bình thường, khi ngoại vi có thông tin cần gởi đến sẽ gởi yêu cầu ngắt IRQ (Interrupt Request) đến vi xử lý, lúc đó VXL chấm dứt lệnh đang thực hiện, cất một số thông tin vào ngăn xếp và thực hiện thường trình phục vụ ngắt ISR (Interrupt Service Rovtine) đã định sẵn. Khi đã thực hiện xong ISR, VXL quay trở lại nơi đã rời khỏi. Có tất cả 256 ngắt cho họ VXL 8086, một số ngắt (đa số) không liên quan gì đến ngoại vi, số ít còn lại là ngắt cứng phục vụ cho việc giao tiếp VXL với ngoại vi như ngắt thời gian, bàn phím, con chuột, cổng song song, cổng nối tiếp, đĩa cứng, đĩa mềm, card âm thanh VXL quản lý ngắt qua vector ngắt, vector ngắt cho biết địa chỉ chứa ISR cho mỗi loại ngắt. Bảng các địa chỉ gọi là bảng vector ngắt (bảng 4.1). Mỗi địa chỉ chiếm bốn byte N x 4 Các ngắt ký hiệu INT N có địa chỉ ISR ở trong IP các ô nhớ: gồm địa chỉ đoạn CS và địa chỉ tương đối N x 4 + 1 IP, địa chỉ vật lý CS x 16 + IP N x 4 + 2 CS Các ngắt được xếp ưu tiên từ cao đến thấp như N x 4 + 3 sau: INT0; INTn; NMI; IRQ0; IRQ1; IRQ8 ÷ IRQ15; IRQ3; IRQ4, IRQ5; IRQ6; IRQ7; INT1 INTn là các ngắt mềm và ngắt ngoại lệ. Vi xử lý xử lý ngắt ngoài thông qua vi mạch điều khiển ưu tiên ngắt PIC (Priority Interrupt Controller), các mainboard đời cũ dùng hai PIC 8259A còn các mainboard đời mới tích hợp trong một chip đa năng theo công nghệ ASIC (chip set) PIC có các thanh ghi phục vụ xử lý ngắt PIC 1: ngắt IRQ7, 6, 5, 4, 3, 2, 1, 0 có địa chỉ 20H và 21H
  10. CHƯƠNG 4: LẬP TRÌNH CHO MÁY TÍNH ĐIỀU KHIỂN Trang 106 PIC2: ngắt IRQ15, 14, 13, 12, 11, 10, 9, 8 có địa chỉ tương ứng là A0H và A1H Muốn che một ngắt nào đó ta cho bit tương ứng của nó trong OCW1 bằng 1. Ví dụ, muốn cho phép IRQ3 ta gởi byte F7 đến địa chỉ 21H lúc này các IRQ 0 ÷ 7 trừ IRQ3 sẽ bị cấm. Muốn không ảnh hưởng đến các IRQ khác ta dùng lệnh: Outportb (OX21, (inportb (0X21) & OXF7)); (trong C) Muốn che IRQ3 ta gởi lệnh: Outportb (OX21, (inportb (OX21) ⏐ OX08)); 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 < 8 ) old_handler1 = getvect(irq_num+8);
  11. CHƯƠNG 4: LẬP TRÌNH CHO MÁY TÍNH ĐIỀU KHIỂN Trang 108 { 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 #include #include #include void interrupt (*oldIrq3)(void); void interrupt countToggle(void); int i = 0; long j = 0; #define IRQ3 0x0B /* IRQ3 address */ int main(void) { 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 */
  12. CHƯƠNG 4: LẬP TRÌNH CHO MÁY TÍNH ĐIỀU KHIỂN Trang 110 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); /* Dổ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; 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 ;