串口VC编程步骤及程序
更新时间:2024-01-19 09:09:01 阅读量: 教育文库 文档下载
- vc编程实例教程推荐度:
- 相关推荐
1.添加C++类 CCESeries
下面是CCESeries.h 文件的内容: #pragma once
//定义串口接收数据函数类型
//这是一个回调函数,执行该函数时,表示串口接收到了数据。
typedef void (CALLBACK* ONSERIESREAD)(void * pOwner /*父对象指针*/ ,BYTE* buf /*接收到的缓冲区*/
,DWORD dwBufLen /*接收到的缓冲区长度*/); class CCESeries {
public:
CCESeries(void); //CCESeries类的构造函数 ~CCESeries(void); //CCESeries类的析构函数 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; //串口读取回调函数 HANDLE m_hComm; };
2.下面是CCESeries.cpp文件的内容: #include \#include \
//构造函数,将m_hComm初始化为无效的句柄 CCESeries::CCESeries() {
//初始化内部变量
m_hComm = INVALID_HANDLE_VALUE; m_OnSeriesRead = NULL; m_bOpened = 0; }
//析构函数,检测如果串口是打开的,则关闭串口 CCESeries::~CCESeries() {
if (m_bOpened) {
//关闭串口 ClosePort(); } }
//串口读线程函数,该线程用于异步接收串口数据。大家应仔细理解该线程的具体实现过程, //该线程通过循环调用WaitCommEvent函数来检测串口状态,当发现有数据时,调用//ReadFile函数读取数据,并触发回调函数,由此实现串口数据的实时异步读取。 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\//打开串口
m_hComm = CreateFile( szPort,
GENERIC_READ | GENERIC_WRITE, //允许读和写 0, //独占方式(共享模式) NULL,
OPEN_EXISTING, //打开而不是创建(创建方式) 0, NULL );
if (m_hComm == INVALID_HANDLE_VALUE) {
// 无效句柄,返回。
TRACE(_T(\返回无效句柄\\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(\//关闭串口
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(\返回错误\//关闭串口
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\
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; }
3.添加对话框MFC类:DlgParams
接下来为CDlgParams 类添加一些变量,用来保存设置好的串口通讯参数。找到 public:
UINT m_portNo; //串口号 UINT m_baud; //波特率 UINT m_parity; //奇偶校验 UINT m_databits; //数据位 UINT m_stopbits; //停止位
4.串口参数设置的对话框上我们添加了5个用来选择串口通讯参数的组合框,那么我们在 类的源文件中重载OnInitDialog虚函数,在这个函数中初始化组合框的内容。
做到这一步,我们先来编译了一下工程,0 错误,两警告,没有什么问题,继续。在 DlgParams.cpp文件中加入如下函数代码: BOOL CDlgParams::OnInitDialog() {
CDialog::OnInitDialog(); //
//初始化串口参数下拉框,下拉列表 CString strItem = 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 (int i=0; i < 10; i++) {
strItem.Format(L\,i+1); pCmbComNo->AddString(strItem); }
pCmbComNo->SetCurSel(0);// com1: //波特率
pCmbComBaud->ResetContent(); pCmbComBaud->AddString(L\); pCmbComBaud->AddString(L\); pCmbComBaud->AddString(L\); pCmbComBaud->AddString(L\); pCmbComBaud->AddString(L\); pCmbComBaud->AddString(L\); pCmbComBaud->AddString(L\); pCmbComBaud->AddString(L\);
pCmbComBaud->AddString(L\); pCmbComBaud->AddString(L\); pCmbComBaud->AddString(L\); pCmbComBaud->AddString(L\); pCmbComBaud->SetCurSel(5) ; //9600 //奇偶校验
pCmbComParity->ResetContent(); pCmbComParity->AddString(L\); pCmbComParity->AddString(L\); pCmbComParity->AddString(L\); pCmbComParity->SetCurSel(0); // None //数据位
pCmbComDatabits->ResetContent(); pCmbComDatabits->AddString(L\); pCmbComDatabits->AddString(L\); pCmbComDatabits->AddString(L\); pCmbComDatabits->SetCurSel(0); //8 //停止位
pCmbComStopbits->ResetContent(); pCmbComStopbits->AddString(L\); pCmbComStopbits->AddString(L\); pCmbComStopbits->AddString(L\); pCmbComStopbits->SetCurSel(0); //1 return TRUE; }
6.保存,编译。程序出错了。错误类型如下:
error C2509: 'OnInitDialog' : member function not declared in 'CDlgParams' 这个函数我们没有去声明。在Dlgparams.h 文件中声明该函数,如下图所示: 重新编译,错误没有了。
7.接下来完成“连接”按钮的单击响应函数。双击“连接”按钮,添加代码如下: void CDlgParams::OnBnClickedOk() {
// TODO: 在此添加控件通知处理程序代码 //单击按钮事件 CString strTmp;
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); pCmbComBaud->GetWindowTextW(strTmp);
m_portNo = pCmbComNo->GetCurSel() + 1; //串口号 m_baud = _wtoi(strTmp); //波特率
正在阅读:
串口VC编程步骤及程序01-19
美国的水资源概况及水管理体制03-19
Android手机游戏开发课程设计12-24
第五章 练习题06-27
人类行为与社会环境1-1109-28
外国文学史 - 文艺复兴05-23
挖方、捡底合同(终版)06-28
《商业银行外包风险管理指引》分析及意义12-28
地理教学论,大学知识点复习资料10-16
酱香型白酒项目可行性研究报告08-14
- exercise2
- 铅锌矿详查地质设计 - 图文
- 厨余垃圾、餐厨垃圾堆肥系统设计方案
- 陈明珠开题报告
- 化工原理精选例题
- 政府形象宣传册营销案例
- 小学一至三年级语文阅读专项练习题
- 2014.民诉 期末考试 复习题
- 巅峰智业 - 做好顶层设计对建设城市的重要意义
- (三起)冀教版三年级英语上册Unit4 Lesson24练习题及答案
- 2017年实心轮胎现状及发展趋势分析(目录)
- 基于GIS的农用地定级技术研究定稿
- 2017-2022年中国医疗保健市场调查与市场前景预测报告(目录) - 图文
- 作业
- OFDM技术仿真(MATLAB代码) - 图文
- Android工程师笔试题及答案
- 生命密码联合密码
- 空间地上权若干法律问题探究
- 江苏学业水平测试《机械基础》模拟试题
- 选课走班实施方案
- 串口
- 步骤
- 编程
- 程序
- 高三第一学期地理午后训练(14) - 图文
- 浅析小说《时时刻刻》与《达洛卫夫人》的互文性(论文正文)
- 机械制图 讲义 情境8
- 温州医科大学关于印发科研业绩奖励办法的通知
- 平面向量习题精选精讲
- 商住用地商业和住宅各占多少比例
- 2019年整理--大学生暑期社会实践报告-问卷调查
- 河南监理员继续教育试题02
- 14-15大连大学模电期末考试卷(A卷)
- 九年级下学期英语备课组工作计划 - 图文
- 用MATLAB绘制一元函数和二元函数的图象
- 如何有效提升绩效管理能力
- 数电题目
- 巴玉雅鲁藏布江三线大桥墩身施工专项方案(2017.6.27)
- 江苏三基试题及答案(康复科)
- 2014-2015学年第一学期对口单招联考期中调研测试卷(单二英语)
- 2018北师大版语文一年级上册全册精品教案
- 电视教材与编导试题题库用
- 中心组学习、考勤、通报、发言制度
- CNC2001&3000应用软件介绍NUMROTO plus 2