lập trình giao tiếp nối tiếp
Trang 1Chương 8
LẬP TRÌNH GIAO TIẾP NỐI TIẾP
8.1 LẬP TRÌNH TRONG DOS:
Ngôn ngữ QBASIC
Lệnh khởi động cổng COM n:
OPEN “COM n, [Baud], [Parity], [Data], [Stop]” for RANDOM
as #m trong đó n = 1, 2, 3, 4; m = 1 ÷ 255
Ví dụ: OPEN “COM 2, 9600, E, 7, 2” FOR RANDOM AS #1
Lệnh xuất ra một chuỗi S $
PRINT #1 , S $
Lệnh đọc vào một chuỗi R $
INPUT # 1, R $
Ngoài ra còn các lệnh truy xuất thanh ghi của vi mạch UART
Ngôn ngữ Pascal và C
Dùng các lệnh truy xuất thanh ghi như ở chương 7
Trong MS DOS ở dòng lệnh đánh
MODE COM n : 96, E, 7, 1 sẽ mở COM n
8.2 LẬP TRÌNH NGÔN NGỮ VISUAL BASIC 6.0
Ngôn ngữ Visual Basic có module phần mềm MSCOMM.OCX phục vụ cho truyền thông, với Visual Basic 4.0 là MSCOMM16.OCX còn với Visual Basic 6.0 là MSCOMM32.OCX
Muốn cài trình đơn truyền thông vào thanh công cụ ta vào Project- Components – Controls chọn Microsoft Comm Control 6.0/ OK (Hình 8.1), biểu tượng hình điện thoại sẽ hiện trên thanh công cụ Có thể nhắp chuột kép để đưa vào form của chương trình Các bước trên có thể làm tắt bằng phím Ctrl T Thành phần Comm khi mới đưa vào form thường được gán tên MSComm1
Trang 2Các tính chất chính của trình đơn là Commport, DTREnable,
EOFEnable, Handshaking, InBuffersize, InputLen, InputMode,
NullDiscard, OutBuffersize, ParityReplace, Rthreshold, RTSEnable,
Settmgs, Sthreshold… được đặt khi viết chương trình, có thể thay
đổi khi chạy chương trình bằng các lệnh điều khiển
Tính chất CommPort
Đặt cổng com được sử dụng
Object.CommPort [= Value]
Value = 1 đến 16, mặc định là 1 khi khởi động Visual Basic
Tính chất này phải đặt trước khi mở cổng, nếu biểu thức
trong ngoặc không có thì trả về số cổng com đang hoạt động
Trang 3Đặt cấu hình cổng
Object.Settings [= Value]
Value = “BBBB, P, D, S”
Gía trị mặc định là “9600, N, 8, 1” Trong trường hợp đặt sai giá
trị sẽ báo sự cố
Sau đây là các giá trị cho phép:
• Baud rate: 110, 300, 600, 1200, 2400, 9600 (Default), 14400,
Trang 4Mở cổng
Object.PortOpen [= True/ False]
Value = True : mở cổng
Value = False : đóng cổng và xóa bộ đệm truyền thu,
Cổng tự động đóng khi kết thúc chương trình áp dụng
Nhập dữ liệu
String$= Object.Input
Dữ liệu chuỗi ở bộ đệm thu được đọc vào biến String$ Liên
quan đến đọc dữ liệu có các lệnh sau:
Object.InputLen [= numByte%]
InputLen: qui định số ký tự đọc bởi Input Chọn InputLen =
0 sẽ cho đọc toàn bộ vùng bộ đệm
Object.InbufferSize = [numbyte%]
InBufferSize đặt và trả về kích thước theo byte của đệm thu,
mặc định là 1024
Object.InbufferCount [= Count%]
InbufferCount: cho biết số ký hiệu có trong bộ đệm nhận Xóa
bộ đệm bằng cách cho InbufferCount = 0
Dim Buffer as Variant
Dim Arr() as Byte
Trang 5Arr = Buffer
Xuất dữ liệu
Object.Output [= value]
Xuất chuỗi ký tự hay chuỗi nhị phân ra cổng COM
Giống như nhập dữ liệu ta có các lệnh hỗ trợ
OutBufferSize: đặt và trả lại kích thước bộ đệm truyền
OutBufferCount: trả lại số ký tự trong bộ đệm truyền
Ví dụ: gởi ký tự nhấn phím
Private Sub Form_KeyPress (KeyAscii As Integer)
Dim Buffer as Variant
‘ gởi chuỗi ký tự
MsComm1.Output = "This is a text string”
‘ gởi số nhị phân
Dim Out( ) As Byte
MsComm1.Output = Out
Gởi tín hiệu Break
object.Break [= True/False]
Đọc chân DCD
inCD= object CDHolding
nếu inCD True thì DCD ở mức cao, nếu False DCD ở mức
thấp
Đặt thời gian chờ sóng mang
object CDTimeout [= milliseconds]
Chờ khoảng thời gian cho DCD ở mức cao, nếu hết thời gian
mà CDHolding = false thì tạo sự kiện onComm CDTO (carrier
detect Timeout Error)
Đọc CTS
Trang 6object CTS Holding
True: mức 1, False: mức 0
Đặt thời gian chờ CTS
Khi DTE gởi RTS thì modem phải gởi trả lại CTS, tính chất
object CTSTimeout định thời gian chờ, nếu quá thời gian đó mà
không có CTS thì tạo sự kiện CTSTO
object DTREnable [=True/False] nếu True thì DTR mức 1 khi
mở cổng và mức 0 khi đóng cổng, nếu False thì DTR ở mức 0
Điều khiển RTS
object RTSEnable [ =True/False]
Khi True RTS sẽ ở mức 1 khi mở cổng và mức 0 khi đóng
cổng
Sthreshold: đặt số byte có trong bộ đệm truyền để báo sự kiện
Nếu Sthreshold = 1 thì sẽ gọi onComm khi bộ đệm truyền
rỗng
Nếu Sthreshold = 0 thì không gọi
Đặt số byte của bộ đệm thu tối thiểu để báo sự kiện
object Rthreshold [= value]
Nếu đặt bằng 1 thì sẽ gọi onComm khi nhận được 1 ký tự
Nếu đặt bằng 0 thì không gọi
Giao thức bắt tay
object.Handshaking [= value]
Value = 0 không bắt tay
Value = 1 bắt tay theo RTS/CTS
= 2 XON/XOFF
= 3 RTS/XON/XOFF
Ví dụ:
Private Sub Form_Load ( )
Dim Buffer$ as string
Trang 7‘ Dùng COM 1, 9600 baud, không parity, 8 bit data, 1 bit stop
MSComm1 Comport = 1
MSComm1 Settings = “9600, N, 8, 1”
‘ Đọc toàn bộ bộ đệm
MSComm1 Inputlen = 0
‘ Mở cổng và gởi lệnh đến modem chế độ trả lời bằng chữ
MSComm1 PortOpen = True
MSComm1 Output = “ATV1Q0” & Chr$(13)
‘ Chờ trả lời “OK”, nếu có OK thì đóng cổng
Do
DoEvents
Buffer$ = Buffer$ & MSComm1 Input
Loop Until InStr (Buffer$, “OK” & vbCrLf)
MSComm1 PortOpen = False
End Sub
Chương trình trên dùng kỹ thuật hỏi vòng Ta có thể dùng kỹ
thuật sự kiện object.CommEvent Khi có sự kiện xảy ra chương
trình cho cổng object_OnComm () sẽ được gọi để xử lý các sự kiện
hay các lỗi
Ví dụ:
Private Sub MSComm1_OnComm ( )
Select Case MSComm1 CommEvent
‘ Xử lý sự kiện hay lỗi bằng cách đặt lệnh dưới mỗi phát biểu Case
‘ Lỗi
Case ComEventBreak ‘Nhận Break
Case ComEventFrame ‘Sai frame
Case ComEventOverrun ‘Mất dữ liệu
Case ComEventRXOver ‘Đệm thu tràn
Case ComEventRXParity ‘Sai Parity
Case ComEventTXFull ‘Đệm phát đầy
Case ComEventDCB ‘Sai khi đọc DCB
‘ Sự kiện
Case ComEvCD ‘Đường CD thay đổi
Case ComEvCTS ‘CTS thay đổi
Case ComEvDSR ‘DSR thay đổi từ 1 xuống 0
Case ComEvRing ‘RI thay đổi
Case ComEvReceive ‘Số byte đệm thu đạt mức Rthreshold
Case ComEvSend ‘Số byte đệm phát ít hơn Sthreshold
Trang 8Case ComEvEOF ‘Nhận ký tự EOF kết thúc file (mã ASCII 26) trong chuỗi nhập
End Select
End Sub
Các lỗi khi sử dụng MSComm trình bày trong bảng sau
8001 Gía trị Timeout phải lớn hơn 0
8003 Thuộc tính chỉ có khi chương trình chạy
8004 Thuộc tính chỉ đọc khi chương trình chạy
8006 Số nhận dạng thiết bị không phù hợp
8007 Vận tốc truyền không phù hợp
8008 Số byte đã đặt không giá tri
8010 Thiết bị không có sẵn
8013 Thiết bị đã mở
comSetCommStateFailed 8015 Không thể đặt trạng thái truyền thông
8016 Không thể đạt mặt nạ che
8019 Thiết bị bận
Ví dụ: chương trình quay số điện thoại qua modem
Option Explicit
' Variable names beginning with A through Z default to Integer
DefInt A-Z
Trang 9Dim CancelFlag, Default$
Private Sub CancelButton_Click()
' CancelFlag tells the Dial procedure to exit
CancelFlag = True
CancelButton.Enabled = False
End Sub
Private Sub Dial(Number$)
Dim DialString$, FromModem$, dummy, i As Double
i = 0
DialString$ = "ATDT" + Number$ + vbCr
' Dial the number
FromModem$ = FromModem$ + MSComm1.Input
' Check for "OK"
If InStr(FromModem$, "OK") Then
' Notify the user to pick up the phone
Trang 10MSComm1.Output = "ATH" + vbCr
End Sub
Private Sub DialButton_Click()
Dim Number$, Temp$
DialButton.Enabled = False
QuitButton.Enabled = False
CancelButton.Enabled = True
' Get the number to dial
Number$ = InputBox$("Enter phone number:", , Default$)
Status = "Dialing - " + Number$
' Dial the selected phone number
Trang 11' Close the port
Trang 12LED3: CJNE A,#33H,NEXT
Trang 13Private Sub Command8_Click() ‘ Communication Setting
On Error GoTo Errlabel
Trang 14Private Sub Command2_Click()
Private Sub MSComm1_OnComm()
Select Case MSComm1.CommEvent
Trang 15Command9.Caption = "ON ALL"
Trang 168.3 LẬP TRÌNH DÙNG DELPHI 5.0 VÀ VISUAL C++6.0
MSComm có thể cài trong Delphi theo các bước sau:
Vào menu Component – Import ActiveX Control Microft
Comm Control 6.0 – Install để cài MSComm vào ActiveX Sau đó
vào toolbar ActiveX tìm icon điện thoại để kéo vào Form
Các lệnh MSComm trong Delphi tương tự trong Visual Basic
Đối với Visual C thì lập trình MSComm phức tạp hơn, sau
đây là ví dụ cài đặt MSComm trong Visual C
Trang 17Cài đặt MSCOMM trong Visual C
Nếu muốn thêm component truyền thông nối tiếp vào project
bạn vào menu Project- Add to Project- Components and Controls
Gallery
Chọn mục Registered ActiveX Controls – Microsoft Communication
Controls, version 6.0- Insert Hình biểu tượng điện thoại xuất
hiện trên thanh Control
Lập trình MSCOMM trong Visual C++ phức tạp hơn lập trình
trong Visual Basic và Delphi, các hàm của lớp CMScomm được
định nghĩa trong mscomm.h, sau đây là một đoạn trong file này
cần tham khảo để gọi hàm cho đúng
void SetCDHolding(BOOL bNewValue);
Trang 19Ví dụ muốn truyền chuỗi what ta dùng đoạn lệnh sau
CString strOutput = "What";
UCHAR myData = 0x00;
strOutput += myData;
m_Comm.SetPortOpen(true); // mở cổng
m_Comm.SetOutput(COleVariant(strOutput));
Sau đây trình bày phần chính của chương trình serialDlg.cpp
giao tiếp qua cổng Com, mời các bạn phân tích ý nghĩa các dòng
lệnh, đề nghị tham khảo thêm hướng dẫn của VC++
// serialDlg.cpp : implementation file
BOOL CSerialDlg::OnInitDialog()
{
CDialog::OnInitDialog();
Trang 20BSTR bstr = SysAllocStringLen(0,i); //dành chỗ cho chuỗi Unicode bstr
MultiByteToWideChar(CP_ACP,0,pstr,i+1,bstr,i+1); //đổi sang mã Unicode
Trang 21Ngoài cách sử dụng công cụ MSComm còn có thể dùng các
hàm của WinAPI 32
Do tính chất phức tạp của các hàm và giới hạn của giáo
trình, xin trình bày vắn tắt để áp dụng vào chương trình trong
Delphi và VC Chi tiết có thể đọc trong Win 32 Program
Reference Sau đây là các hàm
- Createfile, mở cổng COM hàm này trả về một biến
(handle) Nếu không mở cổng được, biến trả về là –1, đóng cổng
dùng lệnh closehandle, biến trả về là khác zero, nếu trả về zero
là có lỗi
- Get Commstate: lấy cấu hình hiện tại của cổng cất vào khối
DCB (device control block)
- Set Commstate: đặt cấu hình cổng theo nội dung của DCB
- Purge Comm: xóa bộ đệm vào ra, chấm dứt đọc, viết
- Writefile: viết data (xuất ra cổng Com)
- Readfile: đọc cổng
- EscapeCommFunction đặt: và xóa RTS hay DTR
Unit modem: // chương trình minh họa các lệnh điều khiển
modem dùng winapi và delphi 6.0
Send: array [1 50] of char;
Receive: array [1 100] of char;
i, sobyte: integer;
Trang 22stri: string;
Procedure Close_Com;
Procedure Open_Com (nCom: byte);
Procedure Set_Com (baud:Dword; Prt:byte; Stpbits:byte; dtbits: byte);
Procedure Gan_chuoi (Str: string);
Procedure Dial (phone: string);
Procedure Hang_up;
Procedure Flush_Com;
Function Send_Com (send_str: string; dWByte: Dword): Boolean;
Function Get_Com_Buffer: longint;
Function Receive_Com (dwByte: Dword): Boolean;
Procedure doi_chuoi (ch: byte);
Procedure Open_Com (nCom : byte);
var sCom: string;
begin
sCom := ‘COM’ + IntToStr (nCom);
if hPort <> –1 then Close Com;
hPort := CreateFile (Pchar (sCom), GENERIC_READ OR
GENERIC_WRITE, 0, NIL, OPEN_EXISTING;
FILE_ATTRIBUTE_NORMAL, longint (0));
end;
Procedure Set_Com(baud: Dword, Prt: byte; Stpbits:byte;dtbits: byte);
var dcbPort:TDCB; // khai bao kieu DCB
dcbPort Bytesize: = dtBits;
dcbPort Parity : = prt;
dcbPort.StopBits : = DtpBits;
dcbPort Elags : = dcbport.flags
Trang 23SetCommState (hPort, dcbPort);
Function Send_Com (send_str: string; dwByte: Dword): Boolean;
var dwWritten: Dword;
WriteFile (hPort, send, dwByte, dwWritten, nil);
if dwWritten <>dwByte then begin
// Loai bo cac ky tu trong in/out buffer
PurgeComm (hPort, PURGE_RXABORT OR PURGE_TXABORT OR
Trang 24s := ‘ATDT’ + Phone+#13;
Flush_Com;
Send_Com (s, length (s));
end;
Function Get_Com_Buffer : longint;
var statPort : TCOMSTAT;
begin
Result := 0;
if hPort <> –1 then begin
bao loi
Result := statPort CbInQue; // lay so byte trong in buffer end;
end;
Function Receive_Com (dwByte : Dword) : Boolean;
Var dwRead : Dword;
begin
begin
ReadFile (hPort, Receive, dwByte, dwRead, nil);
if dwRead <> dwByte then begin
Trang 25Bài tập gợi ý
Viết chương trình giao tiếp PLC OMRON và SIEMENS