Anda di halaman 1dari 7

Komunikasi Port Serial

Oleh Dhanny Dhuzell

Membuat Komunikasi Serial Port adalah gampang-gampang susah. Karena Delphi tidak memuat kemampuan ini secara explisit. Sehingga kita harus membuat sendiri dengan menggunakan rutin-rutin dalam "Windows.pas", yang yang biasa dikenal dengan Windows API. SubTopic : - Teori - Memulai dengan COM - Mengubah Setting pada COM - Mengirim data pada COM - Membaca COM - Membaca COM tanpa Beku - Selesai dengan COM Teori Windows API Win32 telah membungkus kemampuan komunikasi Serial tersebut ke dalam format standar penggunaan File. Atau dengan kata lain, pengguna dapat menikmati komunikasi serial semudah operasi file. Sehingga kita hanya perlu membuka sebuah File dengan nama "COM1", "COM2", dan seterusnya. Lalu kemudian kita dapat membaca dan menulis file tersebut sebagai mana layaknya sebuah file. Sebuah proses yang jelas sangat memudahkan kita. Hal pertama yang harus dilakukan adalah melakukan "Assignfile", dalam hal ini menggunakan metoda "CreateFile" milik windows. Kemudian Windows sudah membuatkan 2 buah rutin khusus yang berkaitan dengan komunikasi serial ini. Yakni "GetCommState" dan "SetCommState". Yang disebut pertama adalah untuk membaca konfigurasi komunikasi serial, dan yang kedua adalah untuk mengatur konfigurasi yang baru. Struktur konfigurasi ini, di-representasi-kan oleh struktur TDCB. Selanjutnya transfer data dapat dilakukan seperti menggunakan sebuah file biasa. Yakni dengan metoda "WriteFile" dan "ReadFile". Yang disebut pertama adalah untuk menuliskan data pada peralatan serial, atau mengirimkan data dari PC ke peralatan semacam modem. Dan yang disebut ke 2 adalah untuk membaca data dari peralatan serial seperti modem menuju ke arah PC. Semudah itukah ?!?! yah memang ... dan semuanya akan dijelaskan sedikit nanti.

Memulai dengan COM Hal pertama yang dilakukan adalah membuat membuat file virtual dengan menggunakan instruksi CreateFile. Parameter penting dari instruksi yang kita gunakan adalah nama File yang harus sesuai dengan nama comm-nya, misalnya commport-1 dengan nama "COM1". Dan kemudian pada parameter "dwCreationDistribution" harus kita isikan dengan "OPEN_EXISTING". Jika instruksi ini sukses maka akan menghasilkan sebuah handle baru untuk File yang kita buat.

Langsung saja, kita buat project baru. Tambahkan 3 buah Button dan 1 buah Label. Dobel-klik Button1 dan isikan seperti dibawah ini. Oh ya variable "hSerialPort" tempatkan pada scope global.

var hSerialPort: hFile ; ... procedure TForm1.Button1Click(Sender: TObject); begin hSerialPort := CreateFile('COM1', GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, longint(0)); if hSerialPort = INVALID_HANDLE_VALUE then begin Label1.Caption := 'Com1 tidak bisa diaktifkan'; ... end else begin Label1.Caption := 'Com1 sudah diaktifkan'; ... // di sini untuk mengubah setting TDCB ... end; end;

Kemudian kita menginjak pada mengubah setting TDCB. Hal ini perlu agar kita dapat menjalankan komunikasi serial seperti yang kita inginkan.

Mengubah Setting pada COM Setelah kita mendapatkan Handle dari COM, sebelum digunakan hal yang perlu kemudian dilakukan adalah mengatur-atur setting pada COM agar sesuai dengan yang kita mau. Misalnya baud rate, jumlah bit , stop bit, dan lain-lain. Kita dapat menggunakan fungsi "GetCommState" untuk mendapatkan setting sebelumnya. Fungsi tersebut adalah memindahkan setting COM yang sudah diatur sebelumnya, pada variabel struktur "TDCB". Kita dapat mengubah sedikit atau keseluruhan, terserah anda. Tentu saja harus disesuaikan dengan peralatan apa yang hendak dihubungkan pada COM. Setelah puas mengubah-ubah, maka tugas selanjutnya adalah mengembalikan nilai pada variable tersebut kembali pada COM, yakni dengan menggunakan fungsi "SetCommState". Misal, untuk downloader C51 biasanya adalah baud rate 57600, untuk Bootloader 38400, MIDI 31250, untuk yang lain biasanya standar 9600.

var TheDCB: TDCB ; ... procedure TForm1.Button1Click(Sender: TObject);

begin ... Label1.Caption := 'Com1 sudah diaktifkan'; // di sini untuk mengubah setting TDCB GetCommState(hSerialPort, TheDCB); TheDCB.BaudRate := CBR_57600; TheDCB.ByteSize := 8; TheDCB.Parity := NOPARITY; TheDCB.StopBits := ONESTOPBIT; TheDCB.Flags := 1; // kode-kode lain untuk mengubah bagian lain dari TheDCB ... SetCommState(hSerialPort, TheDCB); //tambah ini jika menggunakan DT51 atau Simulator lainnya EscapeCommFunction(hSerialPort,CLRDTR); //SETDTR= true //CLRDTR =false EscapeCommFunction(hSerialPort,SETDTR); //SETDTR= true //CLRDTR =false ...

Untuk lebih jelas baca tentang record TDCB di "Win32 SDK Helps". Lalu untuk EscapeCommFunction" dan parameter SETDTR dapat diganti dengan CLRSTR jika anda mengalami masalah, karena beberapa simulator ternyata memiliki rangkaian Reset berbeda. Selanjutnya adalah menginjak kepada Read Write file alias serial port. Siap ?!?!

Mengirim data pada COM (Write) Tentu saja setelah Handle COM sudah didapat, dan COM sesuai dengan kebutuhan kita, maka kita dapat segera menggunakan COM tersebut untuk berkomunikasi. Yakni mengirimkan data (Menulis Port), atau yang lain yakni menerima data (Membaca Port). Menulis COM maksudnya adalah mengrimkan data dari PC ke luar melalui COM port, misalnya menuju modem. Dapat kita lihat ternyata semudah menulis sebuah File. Kita tinggal menentukan apa yang hendak dikirimkan dan seberapa banyak datanya. Data yang dikirimkan bisa berupa data biner byte per byte, maupun string karakter per karakter. Namun banyak orang menyarankan untuk Mode Assynchronous seperti komunikasi dengan Microkontroller, agar diutamakan untuk menggunakan karakter (misalnya diubah menjadi Intel Hex untuk mengirim data biner). Kalaupun datanya berupa biner maka data tersebut harus diubah menjadi karakter heksa desimal. Seperti pula pada karakter ASCII, bahwa ada beberapa karakter khusus yang digunakan sebagai karakter kontrol. Dalam beberapa hal cara yang seperti itu lebih banyak manfaatnya pada kita... Praktek ... Dobel klik Button2, dan isikan kode di bawah ini.

procedure TForm1.Button2Click(Sender: TObject); var sData : String;

BytesWritten : DWord; begin //mulai mengirimkan data pada COMM sData := 'G'#13; WriteFile(hSerialPort, PChar(sData)^ , Length(sData), BytesWritten, nil); //Tambahkan ini jika hendak langsung membacanya. end;

Dalam contoh di atas ditunjukkan adalah proses pengiriman data. Kebetulan kita hanya mengirimkan 2 buah karakter yakni huruf "G" dan "Enter". Jika anda memasangkan dengan peralatan downloader serial yang saya buat, maka 2 karakter itu menjadi ada artinya. Di samping itu, anda bisa mengganti dengan string semau anda suka. Usahakan string tidak melebihi buffer yang telah ditentukan dalam TDCB, biasanya default adalah 1024 bytes saja. Ubah buffer jika anda memaksakan pengiriman dalam jumlah besar dalam sekali kirim. Jika tidak begitu, maka anda harus memecah string dan mengirimnya beberapa kali. Tentu kita harus mempertimbangkan "EndOfChar" dalam TDCB, yang biasanya adalah "#13". Sehingga sesi transfer akan dianggap selesai jika menemukan karakter EndOfChar ini. Sehingga setiap string harusnya diimbuhi dengan "#13". WriteFile sebenarnya adalah fungsi, yang akan berakhir dengan false jika ternyata proses penulisan ternyata terdapat error. Tentu saja anda harus membuat kalang "If WriteFile Then". Untuk lebih jelas error apakah yang terjadi, maka anda harus menggunakan "GetLastError" dan "SysErrorMessage". Nah... ternyata mudah bukan ?!?!. Di bawah ini adalah rutin yang lebih dilengkapi.

procedure TForm1.Button2Click(Sender: TObject); var sData : String; BytesWritten : DWord; begin //mulai mengirimkan data pada COMM sData := 'G'#13; WriteFile(hSerialPort, PChar(sData)^ , Length(sData), BytesWritten, nil); //Tambahkan ini jika hendak langsung membaca port. PurgeComm(hSerialPort, PURGE_TXABORT or PURGE_RXABORT or PURGE_TXCLEAR or PURGE_RXCLEAR); Button3.Click; end;

Instruksi "PurgeComm" adalah untuk membersihkan buffer dari sisa-sisa data yang sudah digunakan sebelumnya. Agar buffer benar-benar fresh dan kosong.

Membaca COM (Read) Membaca COM, maksudnya adalah menerima data dari luar ke PC seperti modem, melalui COM port menuju PC. Dan di dalam contoh di bawah ini adalah sebuah contoh yang paling sederhana. Kita menggunakan instruksi "ReadFile" yang nanti datanya ditempatkan pada variabel sData, dan jumlah data adalah sebanyak 100 karakter.

procedure TForm1.Button3Click(Sender: TObject); var sData : String; BytesRead: DWORD; begin //mulai mengirimkan data pada COMM SetLength(sData , 100); ReadFile(hSerialPort, PChar(sData )^ , 100, BytesRead, nil); SetLength(sData , BytesRead); end;

Namun kelemahan dari metoda seperti di atas adalah program akan nampak hang dan freeze jika ternyata modem (atau device yang terhubung pada COM) tidak mengirimkan data yang diminta. Atau tidak cukup seperti yang diminta, dalam hal seperti contoh adalah 100 karakter. Jika datanya adalah 99 saja, rutin akan setia menunggu 1 karakter yang kurang tersebut, sehingga program akan beku. Masalah seperti ini tidak terjadi pada operasi file yang sebenarnya. Dan suka muncul pada virtual file seperti COMM ini. Berikutnya adalah contoh untuk proses pembacaan port COMM yang lebih baik untuk menghindari kebekuan program.

Membaca COM tanpa Beku Anda juga bisa mengatur Timeout sendiri dengan menggunakan instruksi "GetCommTimeouts" dan "SetCommTimeouts", lalu anda gunakan pada "ReadFile". Sehingga ReadFile akan segera berhenti, setelah waktu Timeout tercapai, yakni dengan return false. Hal ini bisa diketahui pasti dengan menggunakan GetLastError. Dalam Mode ini jumlah karakter yang hendak diterima umumnya tidak tetap. Jumlahnya bisa 1 karakter, 2 atau sebaris karakter. Hal ini akan membuat program tidak bisa memrediksikan kapan sebenarnya data dikirim dan seberapa besar datanya. Sehingga kita harus menghindarkan diri dari segala masalah yang mungkin terjadi. Yakni dengan mengukur berapa karakter dalalam buffer yang telah diterima. Selanjutnya kita membaca file dalam jumlah sebanyak dalam buffer tersebut, untuk menghindarkan diri dari kebekuan program. Cukup menggunakan isntruksi "ClearCommError".

procedure TForm1.Button3Click(Sender: TObject);

var StartTime , TimedOutTime :Cardinal; sData, sResult : String; FoundEndChar : boolean; BytesToRead, BytesRead : DWORD; fTimeOut : boolean; statPort: TCOMSTAT; dwErrorCode: DWord; begin //======================================= TimedOutTime := 3000; // 3000 mS = 3 Detik SResult := ''; StartTime := GetTickCount; repeat ClearCommError(hSerialPort, dwErrorCode, @statPort); BytesToRead := statPort.cbInQue; if BytesToRead > 0 then begin if BytesToRead >= DWORD(Length(sData)) then SetLength(sData, BytesToRead ); ReadFile(hSerialPort, PChar(sData)^, BytesToRead, BytesRead, nil); SResult := SResult + Copy(sData, 0, BytesRead); end; FoundEndChar := Pos(#13, SResult) <> 0; //karakter #13 sebagai akhir karakter fTimeOut := GetTickCount > StartTime + TimedOutTime; until FoundEndChar or fTimeOut; //======================================= if fTimeOut then ShowMessage('Read Timeout') else Label1.Caption := SResult; end;

Ada 2 Bagian terpenting dalam rutin di atas. Yakni adanya timeout yang di atur dalam waktu 3 detik. Yang cukup menggunakan instruksi "GetTickCount", serta dibuatnya kalang "Repeat Until" yang program akan terus di dalam kalang sampai ada 2 kondisi. Yakni ditemukannya karakter "#13" yang berarti akhir dari rangkaian data, dan atau dicapainya waktu tunggu 3 detik. Dengan membuat rutin seperti di atas kita akan terbebas dari masalah hang atau freeze saat kita ingin menunggu data yang hendak dikirimkan.

Selesai dengan COM Saat kita selesai dengan COM maka tentu tindakan bijaksana adalah membersikan memory yang digunakan oleh COM. Yakni cukup dengan menjalankan isntruksi

CloseHandle. Walaupun sebenarnya Windows akan membersikan seleuruh memory yang digunakaan program saat Windows menutup program tersebut, tetap kita harus membiasakan diri untuk bertanggung jawab atas apa yang telah kita lakukan.

CloseHandle(hSerialPort);

Tempatkan kode di atas pada event FormClose. Beberapa penjelasan tentang fungsi Window API yang digunakan tidak semuanya dituliskan. Saya hanya mencontohkan yang penting-penting saja. Sementara penjelasan lebih lengkap dapat anda dapatkan sendiri pada "Win32 SDK Helps". Jadi rasanya tidak perlu dijelaskan di sini, bukan ?!?!

Event OnComm Recieved Waduh keren betul namanya. Kalau sebelumnya kita membaca data setelah sebelumnya mengirim data. Atau bisa disebut dengan Echo (pantul). Seperti yang biasa terjadi pada modem. Tapi saat COMM, kita hubungkan dengan sensor pendeteksi/penghitung jumlah kendaraan. Pasti kita kebingungan bagaimana caraya ?! Saya sendiri rada bingung. Tapi InsyaAlloh swt yang ini bisa membantu. Membuat COMM dengan Event.