摘要:串口是常用的計算機與外部串行設備之間的數據傳輸通道,由於串行通信方便易行,所以應用廣泛。本文介紹了在C++ Builder中如何利用串行通信控件進行串行通信編程。
一、引言
目前,在用計算機進行數據傳輸時,常用的是串行通信方式。用C++ Builder來編寫串行通信程序時,可以調用Windows API函數,也可以利用VB中的MSComm控件。 利用 API函數編寫實際應用程序時,往往要考慮多線程的問題,這樣編出來的程序不但十分龐大,而且結構比較復雜,繼承性差,維護困難。但是使用串行通信控件就相對簡單一些,而且功能強大,性能安全可靠。本文就簡單的介紹一下在C++ Builder中利用MSComm控件進行編程。
二、MSComm控件的常用屬性和事件
MSComm 控件通過串行端口傳輸和接收數據,為應用程序提供串行通訊功能。具體的來說,它提供了兩種處理通信問題的方法:一是事件驅動(Event-driven)方法,一是查詢法。
事件驅動方式
在使用事件驅動法設計程序時,每當有新字符到達,或端口狀態改變,或發生錯誤時,MSComm控件將解發OnComm事件,而應用程序在捕獲該事件後,通過檢查MSComm控件的CommEvent屬性可以獲知所發生的事件或錯誤,從而采取相應的操作。這種方法的優點是程序響應及時,可靠性高。
查詢方式
查詢方式實質上還是事件驅動,但在有些情況下,這種方式顯得更為便捷。在程序的每個關鍵功能之後,可以通過檢查 CommEvent 屬性的值來查詢事件和錯誤。如果應用程序較小,並且是自保持的,這種方法可能是更可取的。
1.MSComm 控件的常用屬性
CommPort屬性:設置或返回通訊端口號,可以設置為1到16之間的任何值,本系統采用缺省值2;
Settings屬性:以字符串形式設置或返回波特率、奇偶校驗、數據位和停止位,本系統采用缺省值"9600,n,8,1";
PortOpen屬性:設置或返回通訊口的狀態以及打開和關閉端口,可通過把該屬性設置為true或者false來打開或者關閉端口;
InBufferSize和OutBufferSize屬性:分別設置接收和發送緩沖區分配的內存數量,單位為字節,缺省值分別為1024byte和512byte;
InputLen屬性:確定希望從接收緩沖區移出的字符數量,當InputLen=0時,一次把接收緩沖區的字符全部移出;
Input屬性:從接收緩沖區中讀出數據,然後將該數據從緩沖區移走。
OutPut屬性:向發送緩沖區傳遞待發送的數據。
InBufferCount和OutBufferCount屬性:分別確定當前駐留在接收緩沖區等待被取出和發送緩沖區准備發送的字符數量,這兩個屬性設置為0,接收和發送緩沖區的內容將被清除;
InputMode屬性:設置接收傳入數據的格式,設置為0采用文本形式,設置為1采用二進制格式,本系統設置為二進制格式進行發送和接收;
SThreshold屬性:保存一個產生發送OnComm事件的界限值,本系統設置該屬性為0,發送數據時不產生OnComm事件;
RThreshold屬性:設定當接收幾個字符時觸發OnComm事件,本系統設置該屬性為1,每接收一個字符就產生一個OnComm事件;
2.MSComm控件的事件
MSCOMM控件只使用一個事件OnComm,用屬性CommEvent的十七個值來區分不同的觸發時機。主要有以下幾個:
(1)CommEvent=1時:傳輸緩沖區中的字符個數已少於Sthreshold(可設置的屬性值)個。
(2)CommEvent=2時:接收緩沖區中收到Rthreshold(可設置的屬性值)個字符,利用此事件可編寫接收數據的過程。
(3)CommEvent=3時:CTS線發生變化。
(4)CommEvent=4時:DSR線發生變化。
(5)CommEvent=5時:CD線發生變化。
(6)CommEvent=6時:檢測到振鈴信號。
另外十種情況是通信錯誤時產生,即錯誤代碼。
三、程序的實現
1.注冊MSComm控件
眾所周知,C++Builder本身並不提供串行通訊控件MSComm,但我們卻可以通過注冊後直接使用它。啟動C++Builder5.0後,然後選擇C++Builder主菜單中的Component菜單項,單擊Import Active Control命令,彈出Import Active窗口,選擇Microsoft Comm Control6.0,再選擇Install按鈕執行安裝命令,系統將自動進行編譯,編譯完成後即完成MSComm控件在C++Builder中的注冊,系統默認安裝在控件板的Active頁,接下來我們就可以像使用C++Builder本身提供的控件那樣使用新注冊的MSComm控件了。(前提條件是你的機子上安裝了Visual Basic,或者有它的庫)
2.具體實現
新建一個工程Project1,把注冊好的MSComm控件加入到窗體中,然後再加入5個ComboBox用來設置串口的屬性,4個Button分別用來"打開串口" "關閉串口""發送數據""保存數據" ,2個Memo控件分別用來顯示接收到的數據和發送的數據。再加入一個Shape控件用來標明串口是否打開。
ComboBox1用來設置串口號,通過它的Items屬性設置1,2,3,4四個列表項分別表示COM1,COM2,COM3,COM4口。ComboBox2用來設置波特率,ComboBox3用來設置奇偶校驗位,ComboBox4用來設置數據位,ComboBox5用來設置停止位。他們的缺省值分別是9600,n,8,1。
Button1用來打開串口,Button2用來關閉串口,Button3用來發送數據,Button4用來保存數據。Memo1用來顯示發送的數據,Memo2顯示接收的數據。Shape1的Shape屬性設置為stCircle。
下面給出部分源碼:
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
if(MSComm1->PortOpen==true)
{
Button1->Enabled=false;
Button2->Enabled=true;
Button3->Enabled=true;
Button4->Enabled=true;
Shape1->Brush->Color=clGreen;
}
else
{
Button2->Enabled=true;
Button2->Enabled=false;
Button3->Enabled=false;
Button4->Enabled=false;
Shape1->Brush->Color=clRed;
}
}
void __fastcall TForm1::Button1Click(TObject *Sender) / /打開串口
{
if(MSComm1->PortOpen!=true)
{
MSComm1->CommPort=StrToInt(ComboBox1->Text);//選擇串口號
MSComm1->Settings=
ComboBox2->Text+","+
ComboBox3->Text+","+
ComboBox4->Text+","+
ComboBox5->Text; file://設置串口的屬性波特率、奇偶校驗、數據位和、//停止位。
MSComm1->InputMode=0;//設置傳入數據的格式,0表示文本形式
MSComm1->PortOpen=true;//打開串口
Button1->Enabled=false;
Button2->Enabled=true;
Button3->Enabled=true;
Button4->Enabled=true;
Shape1->Brush->Color=clGreen;
}
}
void __fastcall TForm1::Button2Click(TObject *Sender) / /關閉串口
{
if(MSComm1->PortOpen!=false)
{
MSComm1->PortOpen=false;
Button1->Enabled=true;
Button2->Enabled=false;
Button3->Enabled=false;
Button4->Enabled=false;
Shape1->Brush->Color=clRed;
}
else
{
Button1->Enabled=false;
Button2->Enabled=true;
Shape1->Brush->Color=clRed;
}
}
MSComm控件的Input和Output屬性在Object Inspector中是看不到的,而且在C++Builder環境下這兩個屬性已不在是VB、VC中的原類型,而是OleVariant類型,也就是Ole萬能變量,這就需要我們在發送接收數據時要把數據轉換成Ole類型。
void __fastcall TForm1::Button3Click(TObject *Sender) file://發送Memo2中的數據
{
MSComm1->Output=StringToOleStr(Memo2->Text); file://把AnsiString型轉化成//Ole形式。
}
通過OnComm事件接收數據,必須把MSComm的RThreshold屬性設置為大於0,只有這樣在接收到字符時才會產生一個OnComm事件。
void __fastcall TForm1::MSComm1Comm(TObject *Sender)
{
AnsiString str; file://聲明一個AnsiString類型的變量
OleVariant s; file://聲明一個用於接收數據的OleVariant變量。
if(MSComm1->CommEvent==comEvReceive)
// 接收緩沖區中是否收到Rthreshold個字符。
{
if(MSComm1->InBufferCount)// 是否有字符駐留在接收緩沖區等待被取出
{
s=MSComm1->Input;//接收數據
str=s.AsType(varString); file://把接收到的OleVariant變量轉換成AnsiString類型
Memo1->Text=Memo1->Text+str;//把接收到的數據顯示在Memo1中。
}
}
}
要保存數據應該再加入一個SaveDialog模塊
void __fastcall TForm1::Button4Click(TObject *Sender)
file://把Memo1中的數據保存在指定的文件中
{
AnsiString filename1;
SaveDialog1->Filter="Text files (*.txt)|*.txt|All files (*.*)|*.*";//文件類型過濾器
SaveDialog1->FilterIndex=2;
if(SaveDialog1->Execute())
{
filename1=SaveDialog1->FileName;
Memo1->Lines->SaveToFile(filename1);//把收到的數據保存在文件filename1中
}
}
四、結束語
上面給出了C++ Builder中利用MSComm控件進行串行通信編程的實現和部分源碼,有了上面的參照讀者可以根據實際需要編寫出具有發送文件和接收文件功能的程序。