?? ceseries.cpp
字號:
// CESeries.cpp: implementation of the CCESeries class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "SeriesSample.h"
#include "CESeries.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//定義向?qū)懢€程發(fā)送的消息常量
const CM_THREADCOMMWRITE = WM_USER+110;
//類CCESeries構(gòu)造函數(shù)
CCESeries::CCESeries()
{
m_hComm = INVALID_HANDLE_VALUE;
}
//類CCESeries析構(gòu)函數(shù)
CCESeries::~CCESeries()
{
}
BOOL CCESeries::ClearRxTxBuffer(BYTE Flag)
{
PurgeComm(m_hComm,PURGE_TXCLEAR|PURGE_RXCLEAR);
return TRUE;
}
BOOL CCESeries::SetClearBreak(BYTE Flag)
{
if(Flag==1)
{
SetCommBreak(m_hComm);
}
else
{
ClearCommBreak(m_hComm);
}
return TRUE;
}
#define IOCTL_OPERATE_SEND 0x807
BOOL CCESeries::OperateSerialSend(VOID)
{
HANDLE hComm=NULL;
hComm = CreateFile(_T("KPT1:"),GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
DeviceIoControl(hComm,IOCTL_OPERATE_SEND,NULL,0,NULL,0,0,NULL);
CloseHandle(hComm);
return TRUE;
}
/*
*函數(shù)介紹:打開串口
*入口參數(shù):pPortOwner :使用此串口類的窗體句柄
portNo :串口號
baud :波特率
parity :奇偶校驗
databits :數(shù)據(jù)位
stopbits :停止位
*出口參數(shù):(無)
*返回值:TRUE:成功打開串口;FALSE:打開串口失敗
*/
BOOL CCESeries::OpenPort(CWnd* pPortOwner, /*使用串口類,窗體句柄*/
UINT portNo , /*串口號*/
UINT baud , /*波特率*/
UINT parity , /*奇偶校驗*/
UINT databits , /*數(shù)據(jù)位*/
UINT stopbits /*停止位*/
)
{
DCB commParam;
TCHAR szPort[15];
// 已經(jīng)打開的話,直接返回
if (m_hComm != INVALID_HANDLE_VALUE)
{
return TRUE;
}
ASSERT(pPortOwner != NULL);
ASSERT(portNo > 0 && portNo < 5);
//設(shè)置串口名
wsprintf(szPort, L"COM%d:", portNo);
//打開串口
m_hComm = CreateFile(
szPort,
GENERIC_READ | GENERIC_WRITE, //允許讀和寫
0, //獨占方式(共享模式)
NULL,
OPEN_EXISTING, //打開而不是創(chuàng)建(創(chuàng)建方式)
0,
NULL
);
if (m_hComm == INVALID_HANDLE_VALUE)
{
// 無效句柄,返回。
TRACE(_T("CreateFile 返回?zé)o效句柄"));
return FALSE;
}
// 得到打開串口的當(dāng)前屬性參數(shù),修改后再重新設(shè)置串口。
// 設(shè)置串口的超時特性為立即返回。
if (!GetCommState(m_hComm,&commParam))
{
return FALSE;
}
commParam.BaudRate = baud; // 設(shè)置波特率
commParam.fBinary = TRUE; // 設(shè)置二進制模式,此處必須設(shè)置TRUE
commParam.fParity = TRUE; // 支持奇偶校驗
commParam.ByteSize = databits; // 數(shù)據(jù)位,范圍:4-8
commParam.Parity = parity; // 校驗?zāi)J? commParam.StopBits = stopbits; // 停止位
commParam.fOutxCtsFlow = FALSE; // No CTS output flow control
commParam.fOutxDsrFlow = FALSE; // No DSR output flow control
commParam.fDtrControl = DTR_CONTROL_ENABLE;
// DTR flow control type
commParam.fDsrSensitivity = FALSE; // DSR sensitivity
commParam.fTXContinueOnXoff = TRUE; // XOFF continues Tx
commParam.fOutX = FALSE; // No XON/XOFF out flow control
commParam.fInX = FALSE; // No XON/XOFF in flow control
commParam.fErrorChar = FALSE; // Disable error replacement
commParam.fNull = FALSE; // Disable null stripping
commParam.fRtsControl = RTS_CONTROL_ENABLE;
// RTS flow control
commParam.fAbortOnError = FALSE; // 當(dāng)串口發(fā)生錯誤,并不終止串口讀寫
if (!SetCommState(m_hComm, &commParam))
{
TRACE(_T("SetCommState error"));
return FALSE;
}
//設(shè)置串口讀寫時間
COMMTIMEOUTS CommTimeOuts;
GetCommTimeouts (m_hComm, &CommTimeOuts);
CommTimeOuts.ReadIntervalTimeout = MAXDWORD;
CommTimeOuts.ReadTotalTimeoutMultiplier = 10;
CommTimeOuts.ReadTotalTimeoutConstant = 10;
CommTimeOuts.WriteTotalTimeoutMultiplier = 10;
CommTimeOuts.WriteTotalTimeoutConstant = 1000;
if(!SetCommTimeouts( m_hComm, &CommTimeOuts ))
{
TRACE( _T("SetCommTimeouts 返回錯誤") );
return FALSE;
}
m_pPortOwner = pPortOwner;
//指定端口監(jiān)測的事件集
SetCommMask (m_hComm, EV_RXCHAR);
//分配設(shè)備緩沖區(qū)
SetupComm(m_hComm,512,512);
//初始化緩沖區(qū)中的信息
PurgeComm(m_hComm,PURGE_TXCLEAR|PURGE_RXCLEAR);
m_hReadCloseEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
m_hWriteCloseEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
//創(chuàng)建讀串口線程
m_hReadThread = CreateThread(NULL,0,ReadThreadFunc,this,0,&m_dwReadThreadID);
//創(chuàng)建寫串口線程
m_hWriteThread = CreateThread(NULL,0,WriteThreadFunc,this,0,&m_dwWriteThreadID);
TRACE(_T("串口打開成功"));
return TRUE;
}
/*
*函數(shù)介紹:關(guān)閉串口
*入口參數(shù):(無)
*出口參數(shù):(無)
*返回值: (無)
*/
void CCESeries::ClosePort()
{
//表示串口還沒有打開
if (m_hComm == INVALID_HANDLE_VALUE)
{
return ;
}
//關(guān)閉讀線程
CloseReadThread();
//關(guān)閉寫線程
CloseWriteThread();
//關(guān)閉串口
if (!CloseHandle (m_hComm))
{
m_hComm = INVALID_HANDLE_VALUE;
return ;
}
}
/*
*函數(shù)介紹:向串口發(fā)送數(shù)據(jù)
*入口參數(shù):buf : 將要往串口寫入的數(shù)據(jù)的緩沖區(qū)
bufLen : 將要往串口寫入的數(shù)據(jù)的緩沖區(qū)長度
*出口參數(shù):(無)
*返回值:TRUE:表示成功地將要發(fā)送的數(shù)據(jù)傳遞到寫線程消息隊列。
FALSE:表示將要發(fā)送的數(shù)據(jù)傳遞到寫線程消息隊列失敗。
注視:此處的TRUE,不直接代表數(shù)據(jù)一定成功寫入到串口了。
*/
BOOL CCESeries::WritePort(const BYTE *buf,DWORD bufLen)
{
//將要發(fā)送的數(shù)據(jù)傳遞到寫線程消息隊列
if (PostThreadMessage(m_dwWriteThreadID,CM_THREADCOMMWRITE,
WPARAM(bufLen), LPARAM(buf)))
{
return TRUE;
}
return FALSE;
}
/*
*函數(shù)介紹:設(shè)置串口讀取、寫入超時
*入口參數(shù):CommTimeOuts : 指向COMMTIMEOUTS結(jié)構(gòu)
*出口參數(shù):(無)
*返回值:TRUE:設(shè)置成功;FALSE:設(shè)置失敗
*/
BOOL CCESeries::SetSeriesTimeouts(COMMTIMEOUTS CommTimeOuts)
{
ASSERT(m_hComm != INVALID_HANDLE_VALUE);
return SetCommTimeouts(m_hComm,&CommTimeOuts);
}
//串口讀線程函數(shù)
DWORD CCESeries::ReadThreadFunc(LPVOID lparam)
{
CCESeries *ceSeries = (CCESeries*)lparam;
DWORD evtMask;
BYTE * readBuf = NULL;//讀取的字節(jié)
DWORD actualReadLen=0;//實際讀取的字節(jié)數(shù)
DWORD willReadLen;
DWORD dwReadErrors;
COMSTAT cmState;
// 清空緩沖,并檢查串口是否打開。
ASSERT(ceSeries->m_hComm !=INVALID_HANDLE_VALUE);
//清空串口
PurgeComm(ceSeries->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR );
SetCommMask (ceSeries->m_hComm, EV_RXCHAR | EV_CTS | EV_DSR );
while (TRUE)
{
if (WaitCommEvent(ceSeries->m_hComm,&evtMask,0))
{
SetCommMask (ceSeries->m_hComm, EV_RXCHAR | EV_CTS | EV_DSR );
//表示串口收到字符
if (evtMask & EV_RXCHAR)
{
ClearCommError(ceSeries->m_hComm,&dwReadErrors,&cmState);
willReadLen = cmState.cbInQue ;
if (willReadLen <= 0)
{
continue;
}
readBuf = new BYTE[willReadLen];
ReadFile(ceSeries->m_hComm, readBuf, willReadLen, &actualReadLen,0);
//如果讀取的數(shù)據(jù)大于0,
if (actualReadLen>0)
{
//觸發(fā)讀取回調(diào)函數(shù)
ceSeries->m_OnSeriesRead(ceSeries->m_pPortOwner,readBuf,actualReadLen);
}
}
}
//如果收到讀線程退出信號,則退出線程
if (WaitForSingleObject(ceSeries->m_hReadCloseEvent, 0) == WAIT_OBJECT_0)
{
break;
}
}
return 0;
}
//串口寫線程函數(shù)
DWORD CCESeries::WriteThreadFunc(LPVOID lparam)
{
CCESeries *ceSeries = (CCESeries*)lparam;
MSG msg;
DWORD dwWriteLen = 0;
BYTE * buf = NULL;
while (TRUE)
{
//如果捕捉到線程消息
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
if (msg.hwnd != 0 )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
continue;
}
if (msg.message == CM_THREADCOMMWRITE)
{
//向串口寫
buf = (BYTE*)msg.lParam;
dwWriteLen = msg.wParam;
//向串口寫
WritePort(ceSeries->m_hComm,buf,dwWriteLen);
//刪除動態(tài)分配的內(nèi)存
delete[] buf;
}
}
//如果收到寫線程退出信號,則退出線程
if (WaitForSingleObject(ceSeries->m_hWriteCloseEvent,500) == WAIT_OBJECT_0)
{
break;
}
ceSeries->m_hWriteThread = NULL;
}
return 0;
}
//私用方法,用于向串口寫數(shù)據(jù),被寫線程調(diào)用
BOOL CCESeries::WritePort(HANDLE hComm,const BYTE *buf,DWORD bufLen)
{
DWORD dwNumBytesWritten;
DWORD dwHaveNumWritten =0 ; //已經(jīng)寫入多少
ASSERT(hComm != INVALID_HANDLE_VALUE);
do
{
if (WriteFile (hComm, //串口句柄
buf+dwHaveNumWritten, //被寫數(shù)據(jù)緩沖區(qū)
bufLen - dwHaveNumWritten, //被寫數(shù)據(jù)緩沖區(qū)大小
&dwNumBytesWritten, //函數(shù)執(zhí)行成功后,返回實際向串口寫的個數(shù)
NULL)) //此處必須設(shè)置NULL
{
dwHaveNumWritten = dwHaveNumWritten + dwNumBytesWritten;
//寫入完成
if (dwHaveNumWritten == bufLen)
{
break;
}
Sleep(10);
}
else
{
return FALSE;
}
}while (TRUE);
return TRUE;
}
//關(guān)閉讀線程
void CCESeries::CloseReadThread()
{
SetEvent(m_hReadCloseEvent);
//設(shè)置所有事件無效無效
SetCommMask(m_hComm, 0);
//清空所有將要讀的數(shù)據(jù)
PurgeComm( m_hComm, PURGE_RXCLEAR );
//等待10秒,如果讀線程沒有退出,則強制退出
if (WaitForSingleObject(m_hReadThread,10000) == WAIT_TIMEOUT)
{
TerminateThread(m_hReadThread,0);
}
m_hReadThread = NULL;
}
//關(guān)閉寫線程
void CCESeries::CloseWriteThread()
{
SetEvent(m_hWriteCloseEvent);
//清空所有將要寫的數(shù)據(jù)
PurgeComm( m_hComm, PURGE_TXCLEAR );
//等待10秒,如果讀線程沒有退出,則強制退出
if (WaitForSingleObject(m_hWriteThread,10000) == WAIT_TIMEOUT)
{
TerminateThread(m_hWriteThread,0);
}
m_hWriteThread = NULL;
}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -