以下是我初学串口写的一个串口程序示例,内有详细注释
BOOL CMyTestCommDlg::OnInitDialog()
... {
CDialog::OnInitDialog();
// TODO: Add extra initialization here
DCB dcb;
DWORD dwError;
COMMTIMEOUTS CommTimeOuts;
hCom=CreateFile("COM1",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,NULL);//打开串口
if(hCom==(HANDLE)0xFFFFFFFF)//INVALID_HANDLE_VALUE==0xFFFFFFFF
...{
dwError=GetLastError();
ATLTRACE("打开串口:dwError=%d ",dwError);
return FALSE;
}
SetupComm(hCom,1024,512);//设置输入、输出缓冲区大小
PurgeComm(hCom,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR );//中止后台读写操作,清空发送、接收缓冲区
CommTimeOuts.ReadIntervalTimeout=20;//设置超时参数
CommTimeOuts.ReadTotalTimeoutMultiplier=10;
CommTimeOuts.ReadTotalTimeoutConstant=100;
CommTimeOuts.WriteTotalTimeoutMultiplier=10;
CommTimeOuts.WriteTotalTimeoutConstant=100;
if(!SetCommTimeouts(hCom,&CommTimeOuts))
...{
dwError=GetLastError();
ATLTRACE("超时:dwError=%d ",dwError);
}
GetCommState(hCom,&dcb);//获取串口参数
dcb.BaudRate=9600;
dcb.Parity=NOPARITY;
dcb.ByteSize=8;
dcb.StopBits=1;
SetCommMask(hCom,EV_ERR|EV_RXCHAR);//设置事件掩码
SetCommState(hCom,&dcb);//设置串口参数
memset(&osRead,0,sizeof(OVERLAPPED));
osRead.Offset=0;
osRead.OffsetHigh=0;
osRead.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
AfxBeginThread((AFX_THREADPROC)CommWatchProc,(LPVOID)this);//创建事件监控线程
return TRUE; // return TRUE unless you set the focus to a control
}
void CMyTestCommDlg::OnBnClickedButtonSend()
... {
// TODO: 在此添加控件通知处理程序代码
UpdateData(true);
DWORD wCount = 0;
PurgeComm(hCom,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
BOOL bwritestate=WriteFile(hCom, m_sendstr.GetBuffer(0), m_sendstr.GetLength(), &wCount, NULL);//&overlapped);//发送数据
if(!bwritestate||m_sendstr.GetLength()!=wCount)
...{
MessageBox("error:数据发送失败!");
return;
}
MessageBox("数据发送成功!");
}
UINT CommWatchProc(LPVOID pParam)
... {
ATLTRACE("thread start ");
DWORD dwEventMask;//=0;
CMyTestCommDlg* tempcom=(CMyTestCommDlg*)pParam;
SetCommMask(hCom,EV_ERR|EV_RXCHAR|EV_TXEMPTY|EV_RXFLAG);//设置事件掩码
PurgeComm(hCom,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR );
LPOVERLAPPED os=&osRead;
OVERLAPPED olRead=osRead;//注意:等待事件和读写时的异步标志参数标志都是返回的,不要混用,因为可能不同值
int count1=0;//限制循环次数
DWORD count;
while(count1<5000)
...{
count1++;
ATLTRACE("***%d***: ",count1);
BOOL statetem=0;
//SetCommMask(hCom,EV_ERR|EV_RXCHAR|EV_TXEMPTY|EV_RXFLAG);
if(!(statetem=WaitCommEvent(hCom,&dwEventMask,os)))
...{
DWORD error=GetLastError();
ATLTRACE("error1=%d ",error);
if(error==ERROR_IO_PENDING)//异步I/O操作进行中
...{
GetOverlappedResult(hCom,os,&count,TRUE);//参数4为true表示等待标志,异步操作完成才返回
ATLTRACE("GetOverlappedResult:123456 count=%d ",count);
}
else
continue;
}
if(dwEventMask == 0)
continue;
...{
if ((dwEventMask&EV_RXCHAR)==EV_RXCHAR)//接收事件
...{
COMSTAT comstat;
DWORD dwLength;
DWORD dwErrorFlags;
ClearCommError(hCom,&dwErrorFlags,&comstat);//获取缓冲区字符长度
dwLength=comstat.cbInQue;
if(dwLength>0)
...{
BOOL fReadStat;
char str[512]="";
DWORD count;
DWORD dwBytesRead,dwBytetoRead=100;
dwBytesRead=(dwLength<dwBytetoRead)?dwLength:dwBytetoRead;//比较缓冲区字符长度与可以读的字符长度,得到要求读字符长度
ATLTRACE("比较:dwLength=%d dwBytetoRead=%d => dwBytesRead=%d ",dwLength,dwBytetoRead,dwBytesRead);
fReadStat = ReadFile(hCom,&str,dwBytesRead,&count,&olRead);//读缓冲区数据
if(fReadStat==FALSE)//读写失败则
...{
if(GetLastError() != ERROR_IO_PENDING)
...{
continue;
}
if(GetOverlappedResult(hCom,&olRead,&count,TRUE) == FALSE)//??
...{
str[count]=0;
}
if(count == 0)
...{
continue;
}
}
str[count]=0;//置字符串以结束字符标志
ATLTRACE("str=%s, count=%d, fReadStat=%d, ",str,count,fReadStat);
if(count>0)
::PostMessage(tempcom->m_hWnd,COM_RECVDATA,(WPARAM) str,count);//接收到字符事件后,可以将此消息登记到由pParam指定的窗口类中进行处理
}
}
if((dwEventMask&EV_ERR)==EV_ERR)//出错事件
...{
DWORD error=GetLastError();
//ATLTRACE("EV_ERR:error=%d ",error);//发生错误时的处理
}
}
ATLTRACE("***一次事件结束*** ");
}
return 0;
}
LRESULT CMyTestCommDlg::OnRecvData(WPARAM wParam, LPARAM lParam)
... {
char str[201];
CString recvStr((char *)wParam);
m_receivestr+=recvStr+"-- ";//+"-- ";
ATLTRACE("m_receivestr=%s ",m_receivestr);
SetDlgItemText(IDC_RECE,m_receivestr);
return TRUE;
}
void CMyTestCommDlg::OnClose()
... {
// TODO: 在此添加消息处理程序代码和/或调用默认值
CloseComm();
CDialog::OnClose();
}
void CMyTestCommDlg::CloseComm()
... {
SetCommMask(hCom,0);//结束WaitCommEvent的等待,即停止事件监控
PurgeComm(hCom,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);//中止后台读写操作,清空发送、接收缓冲区
CloseHandle(hCom);//关闭句柄
}
... {
CDialog::OnInitDialog();
// TODO: Add extra initialization here
DCB dcb;
DWORD dwError;
COMMTIMEOUTS CommTimeOuts;
hCom=CreateFile("COM1",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,NULL);//打开串口
if(hCom==(HANDLE)0xFFFFFFFF)//INVALID_HANDLE_VALUE==0xFFFFFFFF
...{
dwError=GetLastError();
ATLTRACE("打开串口:dwError=%d ",dwError);
return FALSE;
}
SetupComm(hCom,1024,512);//设置输入、输出缓冲区大小
PurgeComm(hCom,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR );//中止后台读写操作,清空发送、接收缓冲区
CommTimeOuts.ReadIntervalTimeout=20;//设置超时参数
CommTimeOuts.ReadTotalTimeoutMultiplier=10;
CommTimeOuts.ReadTotalTimeoutConstant=100;
CommTimeOuts.WriteTotalTimeoutMultiplier=10;
CommTimeOuts.WriteTotalTimeoutConstant=100;
if(!SetCommTimeouts(hCom,&CommTimeOuts))
...{
dwError=GetLastError();
ATLTRACE("超时:dwError=%d ",dwError);
}
GetCommState(hCom,&dcb);//获取串口参数
dcb.BaudRate=9600;
dcb.Parity=NOPARITY;
dcb.ByteSize=8;
dcb.StopBits=1;
SetCommMask(hCom,EV_ERR|EV_RXCHAR);//设置事件掩码
SetCommState(hCom,&dcb);//设置串口参数
memset(&osRead,0,sizeof(OVERLAPPED));
osRead.Offset=0;
osRead.OffsetHigh=0;
osRead.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
AfxBeginThread((AFX_THREADPROC)CommWatchProc,(LPVOID)this);//创建事件监控线程
return TRUE; // return TRUE unless you set the focus to a control
}
void CMyTestCommDlg::OnBnClickedButtonSend()
... {
// TODO: 在此添加控件通知处理程序代码
UpdateData(true);
DWORD wCount = 0;
PurgeComm(hCom,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
BOOL bwritestate=WriteFile(hCom, m_sendstr.GetBuffer(0), m_sendstr.GetLength(), &wCount, NULL);//&overlapped);//发送数据
if(!bwritestate||m_sendstr.GetLength()!=wCount)
...{
MessageBox("error:数据发送失败!");
return;
}
MessageBox("数据发送成功!");
}
UINT CommWatchProc(LPVOID pParam)
... {
ATLTRACE("thread start ");
DWORD dwEventMask;//=0;
CMyTestCommDlg* tempcom=(CMyTestCommDlg*)pParam;
SetCommMask(hCom,EV_ERR|EV_RXCHAR|EV_TXEMPTY|EV_RXFLAG);//设置事件掩码
PurgeComm(hCom,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR );
LPOVERLAPPED os=&osRead;
OVERLAPPED olRead=osRead;//注意:等待事件和读写时的异步标志参数标志都是返回的,不要混用,因为可能不同值
int count1=0;//限制循环次数
DWORD count;
while(count1<5000)
...{
count1++;
ATLTRACE("***%d***: ",count1);
BOOL statetem=0;
//SetCommMask(hCom,EV_ERR|EV_RXCHAR|EV_TXEMPTY|EV_RXFLAG);
if(!(statetem=WaitCommEvent(hCom,&dwEventMask,os)))
...{
DWORD error=GetLastError();
ATLTRACE("error1=%d ",error);
if(error==ERROR_IO_PENDING)//异步I/O操作进行中
...{
GetOverlappedResult(hCom,os,&count,TRUE);//参数4为true表示等待标志,异步操作完成才返回
ATLTRACE("GetOverlappedResult:123456 count=%d ",count);
}
else
continue;
}
if(dwEventMask == 0)
continue;
...{
if ((dwEventMask&EV_RXCHAR)==EV_RXCHAR)//接收事件
...{
COMSTAT comstat;
DWORD dwLength;
DWORD dwErrorFlags;
ClearCommError(hCom,&dwErrorFlags,&comstat);//获取缓冲区字符长度
dwLength=comstat.cbInQue;
if(dwLength>0)
...{
BOOL fReadStat;
char str[512]="";
DWORD count;
DWORD dwBytesRead,dwBytetoRead=100;
dwBytesRead=(dwLength<dwBytetoRead)?dwLength:dwBytetoRead;//比较缓冲区字符长度与可以读的字符长度,得到要求读字符长度
ATLTRACE("比较:dwLength=%d dwBytetoRead=%d => dwBytesRead=%d ",dwLength,dwBytetoRead,dwBytesRead);
fReadStat = ReadFile(hCom,&str,dwBytesRead,&count,&olRead);//读缓冲区数据
if(fReadStat==FALSE)//读写失败则
...{
if(GetLastError() != ERROR_IO_PENDING)
...{
continue;
}
if(GetOverlappedResult(hCom,&olRead,&count,TRUE) == FALSE)//??
...{
str[count]=0;
}
if(count == 0)
...{
continue;
}
}
str[count]=0;//置字符串以结束字符标志
ATLTRACE("str=%s, count=%d, fReadStat=%d, ",str,count,fReadStat);
if(count>0)
::PostMessage(tempcom->m_hWnd,COM_RECVDATA,(WPARAM) str,count);//接收到字符事件后,可以将此消息登记到由pParam指定的窗口类中进行处理
}
}
if((dwEventMask&EV_ERR)==EV_ERR)//出错事件
...{
DWORD error=GetLastError();
//ATLTRACE("EV_ERR:error=%d ",error);//发生错误时的处理
}
}
ATLTRACE("***一次事件结束*** ");
}
return 0;
}
LRESULT CMyTestCommDlg::OnRecvData(WPARAM wParam, LPARAM lParam)
... {
char str[201];
CString recvStr((char *)wParam);
m_receivestr+=recvStr+"-- ";//+"-- ";
ATLTRACE("m_receivestr=%s ",m_receivestr);
SetDlgItemText(IDC_RECE,m_receivestr);
return TRUE;
}
void CMyTestCommDlg::OnClose()
... {
// TODO: 在此添加消息处理程序代码和/或调用默认值
CloseComm();
CDialog::OnClose();
}
void CMyTestCommDlg::CloseComm()
... {
SetCommMask(hCom,0);//结束WaitCommEvent的等待,即停止事件监控
PurgeComm(hCom,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);//中止后台读写操作,清空发送、接收缓冲区
CloseHandle(hCom);//关闭句柄
}