串口VC编程步骤及程序.docx
- 文档编号:23799310
- 上传时间:2023-05-20
- 格式:DOCX
- 页数:22
- 大小:21.28KB
串口VC编程步骤及程序.docx
《串口VC编程步骤及程序.docx》由会员分享,可在线阅读,更多相关《串口VC编程步骤及程序.docx(22页珍藏版)》请在冰豆网上搜索。
串口VC编程步骤及程序
1.添加C++类CCESeries
下面是CCESeries.h文件的内容:
#pragmaonce
//定义串口接收数据函数类型
//这是一个回调函数,执行该函数时,表示串口接收到了数据。
typedefvoid(CALLBACK*ONSERIESREAD)(void*pOwner/*父对象指针*/
BYTE*buf/*接收到的缓冲区*/
DWORDdwBufLen/*接收到的缓冲区长度*/);
classCCESeries
{
public:
CCESeries(void);//CCESeries类的构造函数
~CCESeries(void);//CCESeries类的析构函数
public:
//打开串口
BOOLOpenPort(void*pOwner,/*指向父指针*/
UINTportNo=1,/*串口号*/
UINTbaud=9600,/*波特率*/
UINTparity=NOPARITY,/*奇偶校验*/
UINTdatabits=8,/*数据位*/
UINTstopbits=0/*停止位*/
);
//关闭串口
voidClosePort();
//同步写入数据
BOOLWriteSyncPort(constBYTE*buf,DWORDbufLen);
//设置串口读取、写入超时
BOOLSetSeriesTimeouts(COMMTIMEOUTSCommTimeOuts);
//得到串口是否打开
BOOLGetComOpened();
private:
//串口读线程函数,该函数被定义成私有静态。
staticDWORDWINAPIReadThreadFunc(LPVOIDlparam);
private:
//关闭读线程,当使用完串口后,便调用这个函数退出串口数据接收线程。
voidCloseReadThread();
private:
//已打开的串口句柄
//HANDLEm_hComm;
//读线程句柄
HANDLEm_hReadThread;
//读线程ID标识
DWORDm_dwReadThreadID;
//读线程退出事件
HANDLEm_hReadCloseEvent;
BOOLm_bOpened;//串口是否打开
void*m_pOwner;//指定父对象指针
public:
ONSERIESREADm_OnSeriesRead;//串口读取回调函数
HANDLEm_hComm;
};
2.下面是CCESeries.cpp文件的内容:
#include"StdAfx.h"
#include"CESeries.h"
//构造函数,将m_hComm初始化为无效的句柄
CCESeries:
:
CCESeries()
{
//初始化内部变量
m_hComm=INVALID_HANDLE_VALUE;
m_OnSeriesRead=NULL;
m_bOpened=0;
}
//析构函数,检测如果串口是打开的,则关闭串口
CCESeries:
:
~CCESeries()
{
if(m_bOpened)
{
//关闭串口
ClosePort();
}
}
//串口读线程函数,该线程用于异步接收串口数据。
大家应仔细理解该线程的具体实现过程,
//该线程通过循环调用WaitCommEvent函数来检测串口状态,当发现有数据时,调用//ReadFile函数读取数据,并触发回调函数,由此实现串口数据的实时异步读取。
DWORDCCESeries:
:
ReadThreadFunc(LPVOIDlparam)
{
CCESeries*ceSeries=(CCESeries*)lparam;
DWORDevtMask;
BYTE*readBuf=NULL;//读取的字节
DWORDactualReadLen=0;//实际读取的字节数
DWORDwillReadLen;
DWORDdwReadErrors;
COMSTATcmState;
//清空缓冲,并检查串口是否打开。
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=newBYTE[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;
}
}
return0;
}
//关闭读线程
voidCCESeries:
:
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:
打开串口失败
*/
//供外部调用此方法打开串口,该函数将根据制定的参数打开串口,并创建此串口的读线程,
以实现串口数据实时异步读操作。
BOOLCCESeries:
:
OpenPort(void*pOwner,
UINTportNo,/*串口号*/
UINTbaud,/*波特率*/
UINTparity,/*奇偶校验*/
UINTdatabits,/*数据位*/
UINTstopbits/*停止位*/
)
{
DCBcommParam;
TCHARszPort[15];
ASSERT(pOwner!
=NULL);
m_pOwner=pOwner;
//已经打开的话,直接返回
if(m_hComm!
=INVALID_HANDLE_VALUE)
{
returnTRUE;
}
//设置串口名
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"));
returnFALSE;
}
//得到打开串口的当前属性参数,修改后再重新设置串口。
if(!
GetCommState(m_hComm,&commParam))
{
//关闭串口
CloseHandle(m_hComm);
m_hComm=INVALID_HANDLE_VALUE;
returnFALSE;
}
//设置串口参数
commParam.BaudRate=baud;//设置波特率
commParam.fBinary=TRUE;//设置二进制模式,此处必须设置
TRUE
commParam.fParity=TRUE;//支持奇偶校验
commParam.ByteSize=databits;//数据位,范围:
4-8
commParam.Parity=parity;//校验模式
commParam.StopBits=stopbits;//停止位
commParam.fOutxCtsFlow=FALSE;//NoCTSoutputflowcontrol
commParam.fOutxDsrFlow=FALSE;//NoDSRoutputflowcontrol
commParam.fDtrControl=DTR_CONTROL_ENABLE;
//DTRflowcontroltype
commParam.fDsrSensitivity=FALSE;//DSRsensitivity
commParam.fTXContinueOnXoff=TRUE;//XOFFcontinuesTx
commParam.fOutX=FALSE;//NoXON/XOFFoutflowcontrol
commParam.fInX=FALSE;//NoXON/XOFFinflowcontrol
commParam.fErrorChar=FALSE;//Disableerrorreplacement
commParam.fNull=FALSE;//Disablenullstripping
commParam.fRtsControl=RTS_CONTROL_ENABLE;
//RTSflowcontrol
commParam.fAbortOnError=FALSE;//当串口发生错误,并不终止串口
读写
//设置串口参数
if(!
SetCommState(m_hComm,&commParam))
{
TRACE(_T("SetCommStateerror"));
//关闭串口
CloseHandle(m_hComm);
m_hComm=INVALID_HANDLE_VALUE;
returnFALSE;
}
//设置串口读写时间
COMMTIMEOUTSCommTimeOuts;
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;
returnFALSE;
}
//指定端口监测的事件集
SetCommMask(m_hComm,EV_RXCHAR);
//分配串口设备缓冲区
SetupComm(m_hComm,512,512);
//初始化缓冲区中的信息
PurgeComm(m_hComm,PURGE_TXCLEAR|PURGE_RXCLEAR);
CStringstrEvent;
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;
returnTRUE;
}
/*
*函数介绍:
关闭串口
*入口参数:
(无)
*出口参数:
(无)
*返回值:
(无)
*/
//该函数将退出串口读线程,并关闭串口句柄。
voidCCESeries:
:
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:
设置失败
*/
//供外部调用来向串口发送数据。
BOOLCCESeries:
:
WriteSyncPort(constBYTE*buf,DWORDbufLen)
{
DWORDdwNumBytesWritten;
DWORDdwHaveNumWritten=0;//已经写入多少
intiInc=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)
{
returnFALSE;
}
Sleep(10);
}
else
{
returnFALSE;
}
}while(TRUE);
returnTRUE;
}
/*
*函数介绍:
设置串口读取、写入超时
*入口参数:
CommTimeOuts:
指向COMMTIMEOUTS结构
*出口参数:
(无)
*返回值:
TRUE:
设置成功;FALSE:
设置失败
*/
//供外部调用来设置串口读取,写入超时。
BOOLCCESeries:
:
SetSeriesTimeouts(COMMTIMEOUTSCommTimeOuts)
{
ASSERT(m_hComm!
=INVALID_HANDLE_VALUE);
returnSetCommTimeouts(m_hComm,&CommTimeOuts);
}
//得到串口是否打开
BOOLCCESeries:
:
GetComOpened()
{
returnm_bOpened;
}
3.添加对话框MFC类:
DlgParams
接下来为CDlgParams类添加一些变量,用来保存设置好的串口通讯参数。
找到
public:
UINTm_portNo;//串口号
UINTm_baud;//波特率
UINTm_parity;//奇偶校验
UINTm_databits;//数据位
UINTm_stopbits;//停止位
4.串口参数设置的对话框上我们添加了5个用来选择串口通讯参数的组合框,那么我们在
类的源文件中重载OnInitDialog虚函数,在这个函数中初始化组合框的内容。
做到这一步,我们先来编译了一下工程,0错误,两警告,没有什么问题,继续。
在
DlgParams.cpp文件中加入如下函数代码:
BOOLCDlgParams:
:
OnInitDialog()
{
CDialog:
:
OnInitDialog();
//
//初始化串口参数下拉框,下拉列表
CStringstrItem=L"";
CComboBox*pCmbComNo=(CComboBox*)GetDlgItem(IDC_CMB_NUM);
CComboBox*pCmbComBaud=(CComboBox*)GetDlgItem(IDC_CMB_BAUD);
CComboBox*pCmbComParity=(CComboBox*)GetDlgItem(IDC_CMB_PTY);
CComboBox*pCmbComDatabits=(CComboBox*)GetDlgItem(IDC_CMB_DAT);
CComboBox*pCmbComStopbits=(CComboBox*)GetDlgItem(IDC_CMB_STOP);
//初始化数据
//串口号
pCmbComNo->ResetContent();
for(inti=0;i<10;i++)
{
strItem.Format(L"%d",i+1);
pCmbComNo->AddString(strItem);
}
pCmbComNo->SetCurSel(0);//com1:
//波特率
pCmbComBaud->ResetContent();
pCmbComBaud->AddString(L"300");
pCmbComBaud->AddString(L"600");
pCmbComBaud->AddString(L"1200");
pCmbComBaud->AddString(L"2400");
pCmbComBaud->AddString(L"4800");
pCmbComBaud->AddString(L"9600");
pCmbComBaud->AddString(L"19200");
pCmbComBaud->AddString(L"38400");
pCmbComBaud->AddString(L"43000");
pCmbComBaud->AddString(L"56000");
pCmbComBaud->AddString(L"57600");
pCmbComBaud->AddString(L"115200");
pCmbComBaud->SetCurSel(5);//9600
//奇偶校验
pCmbComParity->ResetContent();
pCmbComParity->AddString(L"None");
pCmbComParity->AddString(L"Odd");
pCmbComParity->AddString(L"Even");
pCmbComParity->SetCurSel(0);//None
//数据位
pCmbComDatabits->ResetContent();
pCmbComDatabits->AddString(L"8");
pCmbComDatabits->AddString(L"7");
pCmbComDatabits->AddString(L"6");
pCmbComDatabits->SetCurSel(0);//8
//停止位
pCmbComStopbits->ResetContent();
pCmbComStopbits->AddString(L"1");
pCmbComStopbits->AddString(L"1.5");
pCmbComStopbits->AddString(L"2");
pCmbComStopbits->SetCurSel(0);//1
returnTRUE;
}
6.保存,编译。
程序出错了。
错误类型如下:
errorC2509:
'OnInitDialog':
memberfunctionnotdeclaredin'CDlgParams'
这个函数我们没有去声明。
在Dlgparams.h文件中声明该函数,如下图所示:
重新编译,错误没有了。
7.接下来完成“连接”按钮的单击响应函数。
双击“连接”按钮,添加代码如下:
voidCDlgParams:
:
OnBnClickedOk()
{
//TODO:
在此添加控件通知处理程序代码
//单击按钮事件
CStringstrTmp;
CComboBox*pCmbComNo=(CComboBox*)GetDlgItem(IDC_CMB_NUM);
CComboBox*pCmbComBaud=(CComboBox*)GetDlgItem(
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 串口 VC 编程 步骤 程序