串口操作类
来源:互联网 发布:mysql分区表 编辑:程序博客网 时间:2024/05/21 22:00
一:创建操作串口的串口类
//定义串口接收数据函数类型
typedef void (CALLBACK* ONSERIESREAD)(void * pOwner /*父对象指针*/
,BYTE* buf /*接收到的缓冲区*/
,DWORD dwBufLen /*接收到的缓冲区长度*/);
class CCESeries
{
public:
CCESeries(void);
~CCESeries(void);
public:
//打开串口
BOOL OpenPort(void* pOwner,/*指向父指针*/
UINT portNo = 1, /*串口号*/
UINT baud = 9600, /*波特率*/
UINT parity = NOPARITY, /*奇偶校验*/
UINT databits = 8, /*数据位*/
UINT stopbits = 0 /*停止位*/
);
//关闭串口
void ClosePort();
//同步写入数据
BOOL WriteSyncPort(const BYTE*buf , DWORD bufLen);
//设置串口读取、写入超时
BOOL SetSeriesTimeouts(COMMTIMEOUTS CommTimeOuts);
//得到串口是否打开
BOOL GetComOpened();
private:
//串口读线程函数
static DWORD WINAPI ReadThreadFunc(LPVOID lparam);
private:
//关闭读线程
void CloseReadThread();
private:
//已打开的串口句柄
HANDLE m_hComm;
//读线程句柄
HANDLE m_hReadThread;
//读线程ID标识
DWORD m_dwReadThreadID;
//读线程退出事件
HANDLE m_hReadCloseEvent;
BOOL m_bOpened; //串口是否打开
void * m_pOwner; //指定父对象指针
public:
ONSERIESREAD m_OnSeriesRead; //串口读取回调函数
};
//构造函数
CCESeries::CCESeries()
{
//初始化内部变量
m_hComm = INVALID_HANDLE_VALUE;
m_OnSeriesRead = NULL;
m_bOpened = 0;
}
//析构函数
CCESeries::~CCESeries()
{
if (m_bOpened)
{
//关闭串口
ClosePort();
}
}
//串口读线程函数
DWORD CCESeries::ReadThreadFunc(LPVOID lparam)
{
CCESeries *ceSeries = (CCESeries*)lparam;
DWORD evtMask;
BYTE * readBuf = NULL;//读取的字节
DWORD actualReadLen=0;//实际读取的字节数
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];
ZeroMemory(readBuf,willReadLen);
//读取串口数据
ReadFile(ceSeries->m_hComm, readBuf, willReadLen, &actualReadLen,0);
//如果读取的数据大于,
if (actualReadLen>0)
{
//触发读取回调函数
if (ceSeries->m_OnSeriesRead)
{
ceSeries->m_OnSeriesRead(ceSeries->m_pOwner,readBuf,actualReadLen);
}
}
//释放内存
delete[] readBuf;
readBuf = NULL;
}
}
//如果收到读线程退出信号,则退出线程
if (WaitForSingleObject(ceSeries->m_hReadCloseEvent,500) == WAIT_OBJECT_0)
{
break;
}
}
return 0;
}
//关闭读线程
void CCESeries::CloseReadThread()
{
SetEvent(m_hReadCloseEvent);
//设置所有事件无效无效
SetCommMask(m_hComm, 0);
//清空所有将要读的数据
PurgeComm( m_hComm, PURGE_RXCLEAR );
//等待秒,如果读线程没有退出,则强制退出
if (WaitForSingleObject(m_hReadThread,4000) == WAIT_TIMEOUT)
{
TerminateThread(m_hReadThread,0);
}
m_hReadThread = NULL;
}
/*
*函数介绍:打开串口
*入口参数:pPortOwner :使用此串口类的窗体句柄
portNo :串口号
baud :波特率
parity :奇偶校验
databits :数据位
stopbits :停止位
*出口参数:(无)
*返回值:TRUE:成功打开串口;FALSE:打开串口失败
*/
BOOL CCESeries::OpenPort(void * pOwner,
UINT portNo , /*串口号*/
UINT baud , /*波特率*/
UINT parity , /*奇偶校验*/
UINT databits , /*数据位*/
UINT stopbits /*停止位*/
)
{
DCB commParam;
TCHAR szPort[15];
ASSERT(pOwner!=NULL);
m_pOwner = pOwner;
// 已经打开的话,直接返回
if (m_hComm != INVALID_HANDLE_VALUE)
{
return TRUE;
}
//设置串口名
wsprintf(szPort, L"COM%d:", portNo);
//打开串口
m_hComm = CreateFile(
szPort,
GENERIC_READ | GENERIC_WRITE, //允许读和写
0, //独占方式(共享模式)
NULL,
OPEN_EXISTING, //打开而不是创建(创建方式)
0,
NULL
);
if (m_hComm == INVALID_HANDLE_VALUE)
{
// 无效句柄,返回。
TRACE(_T("CreateFile 返回无效句柄/n"));
return FALSE;
}
// 得到打开串口的当前属性参数,修改后再重新设置串口。
if (!GetCommState(m_hComm,&commParam))
{
//关闭串口
CloseHandle (m_hComm);
m_hComm = INVALID_HANDLE_VALUE;
return FALSE;
}
//设置串口参数
commParam.BaudRate = baud; // 设置波特率
commParam.fBinary = TRUE; // 设置二进制模式,此处必须设置TRUE
commParam.fParity = TRUE; // 支持奇偶校验
commParam.ByteSize = databits; // 数据位,范围:4-8
commParam.Parity = parity; // 校验模式
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; // 当串口发生错误,并不终止串口读写
//设置串口参数
if (!SetCommState(m_hComm, &commParam))
{
TRACE(_T("SetCommState error"));
//关闭串口
CloseHandle (m_hComm);
m_hComm = INVALID_HANDLE_VALUE;
return FALSE;
}
//设置串口读写时间
COMMTIMEOUTS CommTimeOuts;
GetCommTimeouts (m_hComm, &CommTimeOuts);
CommTimeOuts.ReadIntervalTimeout = MAXDWORD;
CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
CommTimeOuts.ReadTotalTimeoutConstant = 0;
CommTimeOuts.WriteTotalTimeoutMultiplier = 10;
CommTimeOuts.WriteTotalTimeoutConstant = 1000;
if(!SetCommTimeouts( m_hComm, &CommTimeOuts ))
{
TRACE( _T("SetCommTimeouts 返回错误") );
//关闭串口
CloseHandle (m_hComm);
m_hComm = INVALID_HANDLE_VALUE;
return FALSE;
}
//指定端口监测的事件集
SetCommMask (m_hComm, EV_RXCHAR);
//分配串口设备缓冲区
SetupComm(m_hComm,512,512);
//初始化缓冲区中的信息
PurgeComm(m_hComm,PURGE_TXCLEAR|PURGE_RXCLEAR);
CString strEvent;
strEvent.Format(L"Com_ReadCloseEvent%d",portNo);
m_hReadCloseEvent = CreateEvent(NULL,TRUE,FALSE,strEvent);
//创建串口读数据监听线程
m_hReadThread = CreateThread(NULL,0,ReadThreadFunc,this,0,&m_dwReadThreadID);
TRACE(_T("串口打开成功"));
m_bOpened = TRUE;
return TRUE;
}
/*
*函数介绍:关闭串口
*入口参数:(无)
*出口参数:(无)
*返回值:(无)
*/
void CCESeries::ClosePort()
{
//表示串口还没有打开
if (m_hComm == INVALID_HANDLE_VALUE)
{
return ;
}
//关闭读线程
CloseReadThread();
//关闭串口
CloseHandle (m_hComm);
//关闭事件
CloseHandle(m_hReadCloseEvent);
m_hComm = INVALID_HANDLE_VALUE;
m_bOpened = FALSE;
}
/*
*函数介绍:往串口写入数据
*入口参数:buf :待写入数据缓冲区
bufLen : 待写入缓冲区长度
*出口参数:(无)
*返回值:TRUE:设置成功;FALSE:设置失败
*/
BOOL CCESeries::WriteSyncPort(const BYTE*buf , DWORD bufLen)
{
DWORD dwNumBytesWritten;
DWORD dwHaveNumWritten =0 ; //已经写入多少
int iInc = 0; //如果次写入不成功,返回FALSE
ASSERT(m_hComm != INVALID_HANDLE_VALUE);
do
{
if (WriteFile (m_hComm, //串口句柄
buf+dwHaveNumWritten, //被写数据缓冲区
bufLen - dwHaveNumWritten, //被写数据缓冲区大小
&dwNumBytesWritten, //函数执行成功后,返回实际向串口写的个数
NULL)) //此处必须设置NULL
{
dwHaveNumWritten = dwHaveNumWritten + dwNumBytesWritten;
//写入完成
if (dwHaveNumWritten == bufLen)
{
break;
}
iInc++;
if (iInc >= 3)
{
return FALSE;
}
Sleep(10);
}
else
{
return FALSE;
}
}while (TRUE);
return TRUE;
}
/*
*函数介绍:设置串口读取、写入超时
*入口参数:CommTimeOuts : 指向COMMTIMEOUTS结构
*出口参数:(无)
*返回值:TRUE:设置成功;FALSE:设置失败
*/
BOOL CCESeries::SetSeriesTimeouts(COMMTIMEOUTS CommTimeOuts)
{
ASSERT(m_hComm != INVALID_HANDLE_VALUE);
return SetCommTimeouts(m_hComm,&CommTimeOuts);
}
//得到串口是否打开
BOOL CCESeries::GetComOpened()
{
return m_bOpened;
}
二:操作串口类
public:
CCESeries *m_pSerial; //串口对象指针
//定义串口接收数据函数类型
static void CALLBACK OnSerialRead(void * pOwner,BYTE* buf,DWORD bufLen);
1:打开串口
//打开串口
void CSerialSampleDlg::OnBnClickedBtnOpen()
{
//判断串口是否已经打开
if (m_pSerial != NULL)
{
m_pSerial->ClosePort();
delete m_pSerial;
m_pSerial = NULL;
}
//串口参数输入对话框
CDlgParams dlgParams;
if (dlgParams.DoModal() == IDOK)
{
//新建串口通讯对象
m_pSerial = new CCESeries();
m_pSerial->m_OnSeriesRead = OnSerialRead; //
//打开串口
if (m_pSerial->OpenPort(this,
dlgParams.m_portNo,
dlgParams.m_baud,
dlgParams.m_parity,
dlgParams.m_databits,
dlgParams.m_stopbits))
{
AfxMessageBox(L"串口打开成功");
}
else
{
AfxMessageBox(L"串口打开失败");
}
}
}
2:关闭串口
//关闭串口
void CSerialSampleDlg::OnBnClickedBtnClose()
{
//
if (m_pSerial != NULL)
{
//关闭串口
m_pSerial->ClosePort();
//释放串口对象
delete m_pSerial;
m_pSerial = NULL;
}
}
3:发送数据
//发送数据
void CSerialSampleDlg::OnBnClickedBtnSend()
{
char * buf =NULL; //定义发送缓冲区
DWORD dwBufLen = 0; //定义发送缓冲区长度
CString strSend = L"";
//得到发送输入框
CEdit *pEdtSendMsg = (CEdit*)GetDlgItem(IDC_EDT_SEND);
ASSERT(pEdtSendMsg != NULL);
//串口如果没有打开,直接返回
if (m_pSerial == NULL)
{
AfxMessageBox(L"串口未打开");
return;
}
//得到待发送的字符串
pEdtSendMsg->GetWindowTextW(strSend);
//将待发送的字符串转换成单字节,进行发送
buf = new char[strSend.GetLength()*2+1];
ZeroMemory(buf,strSend.GetLength()*2+1);
//转换成单字节进行发送
WideCharToMultiByte(CP_ACP,WC_COMPOSITECHECK,strSend.GetBuffer(strSend.GetLength())
,strSend.GetLength(),buf,strSend.GetLength()*2,NULL,NULL);
dwBufLen = strlen(buf) + 1;
//发送字符串
m_pSerial->WriteSyncPort((BYTE*)buf,dwBufLen);
//释放内存
delete[] buf;
buf = NULL;
}
//定义串口接收数据函数类型
void CALLBACK CSerialSampleDlg::OnSerialRead(void * pOwner,BYTE* buf,DWORD bufLen)
{
BYTE *pRecvBuf = NULL; //接收缓冲区
//得到父对象指针
CSerialSampleDlg* pThis = (CSerialSampleDlg*)pOwner;
//将接收的缓冲区拷贝到pRecvBuf种
pRecvBuf = new BYTE[bufLen];
CopyMemory(pRecvBuf,buf,bufLen);
//发送异步消息,表示收到串口数据,消息处理完,应释放内存
pThis->PostMessage(WM_RECV_SERIAL_DATA,WPARAM(pRecvBuf),bufLen);
}
三:关注回调函数的使用
1:定义串口接收数据函数类型
typedef void (CALLBACK* ONSERIESREAD)(void * pOwner /*父对象指针*/
,BYTE* buf /*接收到的缓冲区*/
,DWORD dwBufLen /*接收到的缓冲区长度*/);
ONSERIESREAD m_OnSeriesRead; //串口读取回调函数
2:当线程收到数据时,触发回调函数
if (ceSeries->m_OnSeriesRead)
{
ceSeries->m_OnSeriesRead(ceSeries->m_pOwner,readBuf,actualReadLen);
}
3:在操作类中添加函数
CCESeries *m_pSerial; //串口对象指针
m_pSerial = new CCESeries();
m_pSerial->m_OnSeriesRead = OnSerialRead; //
//定义串口接收数据函数类型
static void CALLBACK OnSerialRead(void * pOwner,BYTE* buf,DWORD bufLen);
//定义串口接收数据函数类型
void CALLBACK CSerialSampleDlg::OnSerialRead(void * pOwner,BYTE* buf,DWORD bufLen)
{
BYTE *pRecvBuf = NULL; //接收缓冲区
//得到父对象指针
CSerialSampleDlg* pThis = (CSerialSampleDlg*)pOwner;
//将接收的缓冲区拷贝到pRecvBuf种
pRecvBuf = new BYTE[bufLen];
CopyMemory(pRecvBuf,buf,bufLen);
//发送异步消息,表示收到串口数据,消息处理完,应释放内存
pThis->PostMessage(WM_RECV_SERIAL_DATA,WPARAM(pRecvBuf),bufLen);
}
4:消息触发收到函数
//定义串口数据接收消息常量
#define WM_RECV_SERIAL_DATA WM_USER + 101
afx_msg LONG OnRecvSerialData(WPARAM wParam,LPARAM lParam);
ON_MESSAGE(WM_RECV_SERIAL_DATA,OnRecvSerialData)
// 串口接收数据处理函数
LONG CSerialSampleDlg::OnRecvSerialData(WPARAM wParam,LPARAM lParam)
{
return 0;
}
- 串口操作类
- 串口操作类
- 串口操作类
- C#串口操作类
- C# 操作串口类
- C#串口操作类
- 一个操作串口的类.
- 【C#】串口操作实用类
- 【C#】串口操作实用类
- 【C#】串口操作实用类
- 【C#】串口操作实用类
- EVC下串口操作类
- API串口操作封装类
- 【C#】串口操作实用类
- 【C#】串口操作实用类
- C#串口操作实用类
- 【C#】串口操作实用类
- C#串口操作类 【转】
- vc 获取屏幕大小
- [MSSQL]游标原理和使用方法
- 字节对齐
- 『安装配置』Oracle 异构服务实践(一)
- 『管理调优』处理Oracle中杀不掉的锁
- 串口操作类
- 『安装配置』Oracle 异构服务实践(二)
- smartforms和function中接口定义
- GPS通讯
- 利用clickstream跟踪用户
- SQL Server 查询
- 怎样用Eclipse生成jar文件
- 『管理调优』Oracle10g的library内存分配告警
- 构师接龙: 王速瑜VS.林昊