?? com.cpp
字號:
//---------------------------------------------------------------------------
//串口控制類
//基本用WINAPI實現,采用事件響應方式,用一個線程處理各種消息
//用一個線程進行監控串口以接收字符,直接向串口寫字符
//作者:馮華亮
//最后修改日期:2002年5月
#include <vcl.h>
#pragma hdrstop
#include "stdio.h"
#include "Com.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
//---------------------------------------------------------------------------
int g_iSerialPort; //端口號:COM1,COM2,COM3,COM4
//---------------------------------------------------------------------------
//構造函數,初始化,把各數據成員置0
TSerialPort::TSerialPort()
{
hComm =INVALID_HANDLE_VALUE; //串口句柄
ComThread=NULL; //串口監控線程
//異步寫操作中用到的重疊結構中的事件
ov_Write.hEvent=CreateEvent(NULL, true, false, NULL);
}
//----------------------------------------------------------------------
//析構函數
TSerialPort::~TSerialPort()
{
if(ComThread!=NULL)
{
//如果線程掛起則啟動它,只要這樣Terminate()方法才會有效,
//線程才會FreeOnTerminated
while(ComThread->Suspended)
ComThread->Resume();
ComThread->Terminate();
ComThread=NULL;
}
//釋放對象,如果句柄有效,則關閉
if(ov_Write.hEvent!=NULL)
{
CloseHandle(ov_Write.hEvent);
ov_Write.hEvent=NULL;
}
}
//----------------------------------------------------------------------
//串口初始化,可用于串口1到4,參數意義如下:
//pPortOwner-父窗口,uPortNo-串口號,uBaud-波特率,cParity-奇偶校驗,uDatabits-數據位數,
//uStopbits-停止位數,dwCommEvents-需要監控的串口事件
bool TSerialPort::InitPort(HWND Parent ,unsigned uPortNo,unsigned uBaud,
char cParity,unsigned uDataBits,unsigned uStopBits,DWORD dwCommEvents)
{
char sTemp[100];
if(uPortNo<1||uPortNo>4)
{
sprintf(sTemp,"無法打開串口COM%d,串口號只能是COM1、COM2、COM3或COM4中的一個.",
uPortNo);
Application->MessageBox(sTemp,"錯誤",MB_ICONSTOP);
return false;
}
if(Parent==NULL)
{
Application->MessageBox("串口的父窗口無效,串口監控線程無法正常工作.","錯誤",MB_ICONSTOP);
return false;
}
sprintf(sTemp,"COM%d",uPortNo); //合成串口號字符串
//打開串口,獲取串口句柄
hComm = CreateFile(sTemp, //串口號
GENERIC_READ|GENERIC_WRITE,//讀寫方式
0, //通訊設備必須以獨占方式打開
NULL, //無安全屬性
OPEN_EXISTING, //通訊設備已存在
FILE_FLAG_OVERLAPPED, //異步I/O
0); //通訊設備不能用模板打開
if (hComm==INVALID_HANDLE_VALUE) //句柄無效,打開串口失敗
{
sprintf(sTemp,"無法打開串口%d(COM%d),請檢查串口是否正確安裝,或是否被已經被占用.",
uPortNo,uPortNo);
Application->MessageBox(sTemp,"錯誤",MB_ICONSTOP);
return false;
}
//設置超時參數,總時間=Multiplier*字符數+Constant
//Interval為讀入的字符串中任意兩個字符間的最大間隔
CommTimeouts.ReadIntervalTimeout=1000;
CommTimeouts.ReadTotalTimeoutMultiplier=1000;
CommTimeouts.ReadTotalTimeoutConstant=1000;
CommTimeouts.WriteTotalTimeoutMultiplier=1000;
CommTimeouts.WriteTotalTimeoutConstant=1000;
sprintf(sTemp,"baud=%d parity=%c data=%d stop=%d",uBaud,
cParity,uDataBits,uStopBits); //合成串口參數字符串
//配置串口
if (SetCommTimeouts(hComm,&CommTimeouts)) //超時參數
{
if (SetCommMask(hComm,dwCommEvents)) //需要監控的事件
{
if (GetCommState(hComm,&ComDCB)) //獲取原始DCB
{
//禁止硬流控,因為本系統不需要
ComDCB.fOutxCtsFlow=false;
ComDCB.fOutxDsrFlow=false;
ComDCB.fDsrSensitivity=false;
ComDCB.fDtrControl=DTR_CONTROL_DISABLE;
ComDCB.fRtsControl=RTS_CONTROL_DISABLE;
//設置串口設備控制塊(DCB)
if (BuildCommDCB(sTemp,&ComDCB))
{
if (!SetCommState(hComm,&ComDCB))
ProcessErrorMessage("設置串口");
}
else
ProcessErrorMessage("建立串口設備控制塊");
}
else
ProcessErrorMessage("獲取串口狀態");
}
else
ProcessErrorMessage("設置串口事件掩碼");
}
else
ProcessErrorMessage("串口超時參數設置");
//清空串口緩沖區,退出所有相關操作
PurgeComm(hComm,PURGE_RXCLEAR|PURGE_TXCLEAR|PURGE_RXABORT|PURGE_TXABORT);
//創建串口監控線程
ComThread=new TComThread(true,hComm,Parent);
if(ComThread==NULL) //無法創建線程
{
ProcessErrorMessage("創建線程");
return false;
}
return true;
}
//----------------------------------------------------------------------
//啟動串口監控線程
void __fastcall TSerialPort::StartMonitoring()
{
ComThread->Resume();
}
//----------------------------------------------------------------------
//掛起線程
void __fastcall TSerialPort::StopMonitoring()
{
ComThread->Suspend();
}
//----------------------------------------------------------------------
//向串口寫一個字符
bool TSerialPort::WriteToPort(unsigned char ucTxChar)
{
if(hComm==INVALID_HANDLE_VALUE)
{
Application->MessageBox("串口句柄無效,無法發送數據.","錯誤",MB_ICONSTOP);
return false;
}
//初始化重疊結構
ov_Write.Offset=0;
ov_Write.OffsetHigh=0;
//清空串口
PurgeComm(hComm,PURGE_RXCLEAR|PURGE_TXCLEAR|PURGE_RXABORT|PURGE_TXABORT);
//寫串口
DWORD BytesSent=0;
bool bResult = WriteFile(hComm, //串口句柄
&ucTxChar, //輸出緩沖區
1, //每次只發送一個字符
&BytesSent, //實際讀入的字符數
&ov_Write); //重疊結構
if(!bResult) //寫串口失敗
{
DWORD dwError=GetLastError(); //得到失敗原因
switch(dwError)
{
case ERROR_IO_PENDING: //串口操作正在后臺進行
{
BytesSent=0;
//等待重疊結果
bResult=GetOverlappedResult(hComm,
&ov_Write,
&BytesSent, //實際發送字符數
true);
if (!bResult) //重疊操作失敗
return false;
break;
}
default: //失敗
return false;
}
}
//檢查實際發送的字符數是否與要求相符
if (BytesSent!=1)
return false;
return true;
}
//---------------------------------------------------------------------------
//錯誤處理,顯示原因
void __fastcall ProcessErrorMessage(char* ErrorText)
{
char ErrorMsg[400];
LPVOID lpMsgBuf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
NULL,GetLastError(), //獲取錯誤信息標識
MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),//使用系統缺省語言
(LPTSTR)&lpMsgBuf, //消息緩沖區
0,
NULL);
sprintf(ErrorMsg, "\"%s\" 由于以下錯誤而失敗: \n\n%s",ErrorText,lpMsgBuf);
Application->MessageBox(ErrorMsg, "串口錯誤", MB_ICONSTOP);
LocalFree(lpMsgBuf);
}
//----------------------------------------------------------------------
//---------------------------------------------------------------------------
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -