VC串口通讯实例

时间:2023.12.1

在VC++中有两种方法可以进行串口通讯。一种是利用Microsoft公司提供的ActiveX控件 Microsoft Communications Control。另一种是直接用VC++访问串口。下面将简述这两种方法。

一、Microsoft Communications Control

Microsoft公司在WINDOWS中提供了一个串口通讯控件,用它,我们可以很简单的利用串口进行通讯。在使用它之前,应将控件加在应用程序的对话框上。然后再用ClassWizard 生成相应的对象。现在我们可以使用它了。

该控件有很多自己的属性,你可以通过它的属性窗口来设置,也可以用程序设置。我推荐用程序设置,这样更灵活。

SetCommPort:指定使用的串口。

GetCommPort:得到当前使用的串口。

SetSettings:指定串口的参数。一般设为默认参数"9600,N,8,1"。这样方便与其他串口进行通讯。

GetSettings:取得串口参数。

SetPortOpen:打开或关闭串口,当一个程序打开串口时,另外的程序将无法使用该串口。

GetPortOpen:取得串口状态。

GetInBufferCount:输入缓冲区中接受到的字符数。

SetInPutLen:一次读取输入缓冲区的字符数。设置为0时,程序将读取缓冲区的全部字符。

GetInPut:读取输入缓冲区。

GetOutBufferCount:输出缓冲区中待发送的字符数。

SetOutPut:写入输出缓冲区。

一般而言,使用上述函数和属性就可以进行串口通讯了。以下是一个范例。

#define MESSAGELENGTH 100

class CMyDialog : public CDialog

{

protected:

VARIANT InBuffer;

VARIANT OutBuffer;

CMSComm m_Com;

public:

......

}

BOOL CMyDiaLog::OnInitDialog()

{

CDialog::OnInitDialog();

m_Com.SetCommPort(1);

if (!m_Com.GetPortOpen()) {

m_Com.SetSettings("57600,N,8,1");

m_Com.SetPortOpen(true);

m_Com.SetInBufferCount(0);

SetTimer(1,10,NULL);

InBuffer.bstrVal=new unsigned short[MESSAGELENGTH]; OutBuffer.bstrVal=new unsigned short[MESSAGELENGTH]; OutBuffer.vt=VT_BSTR;

}

return true;

}

void CMyDiaLog::OnTimer(UINT nIDEvent)

{

if (m_Com.GetInBufferCount()>=MESSAGELENGTH) { InBuffer=m_Com.GetInput();

// handle the InBuffer.

// Fill the OutBuffer.

m_Com.SetOutput(OutBuffer);

}

CDialog::OnTimer(nIDEvent);

}

用该控件传输的数据是UNICODE格式。关于UNICODE和ANSI的关系和转换请参看MSDN。

关于该控件的其他详细资料请查看MSDN关于COMM CONTROL部分。

二、直接用VC++访问串口。

在VC++中,串口和磁盘文件可以统一的方式来简单读写。这两者几乎没有什么不同,只是在WINDOWS 9X下磁盘文件只能做同步访问,而串口只能做异步访问。

CreateFile:用指定的方式打开指定的串口。通常的方式为

m_hCom = CreateFile( "COM1", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL );

m_hCom为文件句柄。GENERIC_READ | GENERIC_WRITE指定可以对串口进行读写操作。第三个参数0表示串口为独占打开。OPEN_EXISTING表示当指定串口不存在时,程序将返回失败。 FILE_ATTRIBUTE_NORMAL |

FILE_FLAG_OVERLAPPED则表示文件属性。当打开串口时,必须指定

FILE_FLAG_OVERLAPPED,它表示文件或设备不会维护访问指针,则在读写时,必须使用OVERLAPPED 结构指定访问的文件偏移量。

ReadFile:读取串口数据。

WriteFile:向串口写数据。

CloseHandle:关闭串口。

COMMTIMEOUTS:COMMTIMEOUTS主要用于串口超时参数设置。

COMMTIMEOUTS结构如下: typedef struct _COMMTIMEOUTS {

DWORD ReadIntervalTimeout;

DWORD ReadTotalTimeoutMultiplier;

DWORD ReadTotalTimeoutConstant;

DWORD WriteTotalTimeoutMultiplier;

DWORD WriteTotalTimeoutConstant;

} COMMTIMEOUTS,*LPCOMMTIMEOUTS;

ReadIntervalTimeout:两字符之间最大的延时,当读取串口数据时,一旦两个字符传输的时间差超过该时间,读取函数将返回现有的数据。设置为0表示该参数不起作用。

ReadTotalTimeoutMultiplier:读取每字符间的超时。

ReadTotalTimeoutConstant:一次读取串口数据的固定超时。所以在一次读取串口的操作中,其超时为ReadTotalTimeoutMultiplier乘以读取的字节数再加上

ReadTotalTimeoutConstant。将ReadIntervalTimeout设置为MAXDWORD,并将ReadTotalTimeoutMultiplier 和ReadTotalTimeoutConstant设置为0,表示读取操作将立即返回存放在输入缓冲区的字符。

WriteTotalTimeoutMultiplier:写入每字符间的超时。

WriteTotalTimeoutConstant:一次写入串口数据的固定超时。所以在一次写入串口的操作中,其超时为WriteTotalTimeoutMultiplier乘以写入的字节数再加上 WriteTotalTimeoutConstant。

SetCommTimeouts函数可以设置某设备句柄的超时参数,要得到某设备句柄的超时参数可以用GetCommTimeouts函数。

DCB:DCB结构主要用于串口参数设置。该结构太庞大,这里就不一一讲述了,有兴趣者可查看MSDN关于DCB的描述。其中下面两个是比较重要的属性。

BaudRate:串口的通讯速度。一般设置为9600。

ByteSize:字节位数。一般设置为8。

DCB结构可以用SetCommState函数来设置,并可以用GetCommState来得到现有串口的属性。

SetupComm:设置串口输入、输出缓冲区。

OVERLAPPED:保存串口异步通讯的信息。具体结构如下: typedef struct _OVERLAPPED {

DWORD Internal;

DWORD InternalHigh;

DWORD Offset;

DWORD OffsetHigh;

HANDLE hEvent;

} OVERLAPPED;

Internal,InternalHigh是保留给系统使用的,用户不需要设置。

Offset,OffsetHigh是读写串口的偏移量,一般设置OffsetHigh为NULL,可以支持2GB数据。

hEvent读写事件,因为串口是异步通讯,操作可能被其他进程堵塞,程序可以通过检查该时间来得知是否读写完毕。事件将在读写完成后,自动设置为有效。

通过以上这些函数和结构,我们就可以通过串口进行通讯了,现在我们具体看下面的实例:

BOOL CSerial::Open( int nPort, int nBaud )

{

if( m_bOpened ) return( TRUE );

char szPort[15];

DCB dcb;

wsprintf( szPort, "COM%d", nPort );

m_hComDev = CreateFile( szPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL |

FILE_FLAG_OVERLAPPED, NULL );

if( m_hComDev == NULL ) return( FALSE );

memset( &m_OverlappedRead, 0, sizeof( OVERLAPPED ) );

memset( &m_OverlappedWrite, 0, sizeof( OVERLAPPED ) );

COMMTIMEOUTS CommTimeOuts;

CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF;

CommTimeOuts.ReadTotalTimeoutMultiplier = 0;

CommTimeOuts.ReadTotalTimeoutConstant = 0;

CommTimeOuts.WriteTotalTimeoutMultiplier = 0;

CommTimeOuts.WriteTotalTimeoutConstant = 5000;

SetCommTimeouts( m_hComDev, &CommTimeOuts );

m_OverlappedRead.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); m_OverlappedWrite.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );

dcb.DCBlength = sizeof( DCB );

GetCommState( m_hComDev, &dcb );

dcb.BaudRate = nBaud;

dcb.ByteSize = 8;

if( !SetCommState( m_hComDev, &dcb ) ||

!SetupComm( m_hComDev, 10000, 10000 ) ||

m_OverlappedRead.hEvent == NULL ||

m_OverlappedWrite.hEvent == NULL ){

DWORD dwError = GetLastError();

if( m_OverlappedRead.hEvent != NULL )

CloseHandle( m_OverlappedRead.hEvent );

if( m_OverlappedWrite.hEvent != NULL )

CloseHandle( m_OverlappedWrite.hEvent );

CloseHandle( m_hComDev );

return FALSE;

}

m_bOpened = TRUE;

return m_bOpened;

}

int CSerial::InBufferCount( void )

{

if( !m_bOpened || m_hComDev == NULL ) return( 0 );

DWORD dwErrorFlags;

COMSTAT ComStat;

ClearCommError( m_hIDComDev, &dwErrorFlags, &ComStat );

return (int)ComStat.cbInQue;

}

DWORD CSerial::ReadData( void *buffer, DWORD dwBytesRead)

{

if( !m_bOpened || m_hComDev == NULL ) return 0;

BOOL bReadStatus;

DWORD dwErrorFlags;

COMSTAT ComStat;

ClearCommError( m_hComDev, &dwErrorFlags, &ComStat );

if( !ComStat.cbInQue ) return 0;

dwBytesRead = min(dwBytesRead,(DWORD) ComStat.cbInQue);

bReadStatus = ReadFile( m_hComDev, buffer, dwBytesRead, &dwBytesRead, &m_OverlappedRead );

if( !bReadStatus ){

if( GetLastError() == ERROR_IO_PENDING ){

WaitForSingleObject( m_OverlappedRead.hEvent, 2000 );

return dwBytesRead;

}

return 0;

}

return dwBytesRead;

}

DWORD CSerial::SendData( const char *buffer, DWORD dwBytesWritten) {

if( !m_bOpened || m_hComDev == NULL ) return( 0 );

BOOL bWriteStat;

bWriteStat = WriteFile( m_hComDev, buffer, dwBytesWritten, &dwBytesWritten, &m_OverlappedWrite );

if( !bWriteStat){

if ( GetLastError() == ERROR_IO_PENDING ) {

WaitForSingleObject( m_OverlappedWrite.hEvent, 1000 );

return dwBytesWritten;

}

return 0;

}

return dwBytesWritten;

}

上述函数基本实现串口的打开,读写操作。本文章略去该串口类的说明和关闭函数。读者应该能将这些内容写完。接下来,你就可以在你的程序中调用该串口类了。关于本文有任何疑问,请与作者联系。


第二篇:VC++串口通讯设计与分析


VC++串口通讯设计与分析

许朋举

2009-9-4

最近在做一个关于串口通讯控制的软件,在不断学习和总结的过程中,对于计算机串口通讯的设计有了一定的了解,现在把的学习心得与大家分享,水平有限,不足之处敬请谅解。为了便于读者理解,我们这里只介绍了最基本的串口通讯处理程序的设计和编写,如需加深了解,请查阅msdn有关内容。

1. 单线程串口处理程序。

基本步骤:

a) 打开串口:串口也是被windows当做文件设备来处理的,可以使用API函数

CreateFile打开指定串口,进行串口数据收发。

示例:

HANDLE hComm=CreateFile((LPCTSTR)strPort, //串口号字符串

GENERIC_READ|GENERIC_WRITE,

NULL,

NULL,

OPEN_EXISTING,

//指定打开已存在设备 //必须设置文件为异步读写 FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED //设置读写模式

,NULL);

b) 设置串口属性:涉及到两个数据结构:DCB,COMMTIMEOUTS,和几个API函数,

GetCommState(HANDLE hComm,LPDCB lpDCB)获得串口属性数据,

SetCommState(HANDLE hComm,LPDCB lpDCB),设置串口属性数据

SetupComm(HANDLE hComm,DWORD dwInQueue,DWORD dwOutQueeu)设置串口输入输出缓冲区大小。

SetCommMask(HANDLE hfile,DWORD dwEvtMask)设置串口屏蔽事件字。

SetCommTimeouts(HANDLE hfile,LPCOMMTIMEOUTS lpCommTimeouts)设置串口通讯超时。

PurgeComm(HANDLE hfile,DWORD dwFlags)清除串口缓冲区的数据或所处异常中断。 i. 设置串口通讯属性:通过填写DCB 结构来对串口通讯模式进行控制。

示例:

DCB dcb;

//获取默认串口DCB 结构的属性 GetCommState(m_hComm,&dcb);

dcb.BaudRate=atoi((LPCTSTR)m_strBaud);//修改串口的波特率,一般为9600等

dcb.ByteSize= atoi((LPCTSTR)m_strDatas);//修改串口的数据帧位长度,一般为8位

dcb.StopBits=m_cboStop.GetCurSel(); //修改串口的数据帧停止位长度,一般为1位

dcb.fParity=TRUE;

dcb.fNull=true; //修改是否采用检验 //设置串口是否传输NULL

dcb.Parity=m_cboParity.GetCurSel(); //修改通讯检验方式,一般为,none,odd,even SetCommState(m_hComm,&dcb);

ii.

iii. 其他DCB结构属性字段可以忽略,如感兴趣请参阅msdn有关介绍。 设置串口通讯缓冲区大小,通过SetupComm函数来实现。 示例:SetupComm(m_hComm,1024,1024);//将输入输出缓冲区大小设置位1024字节。 设置串口屏蔽事件字:可以通过SetCommState函数实现,屏蔽字的作用是用来

iv. 对串口收发数据的事件进行控制,我们这里采用的是“直接发送,监视接收”的通讯方式;故我们在这里可以只监视数据的接收,屏蔽字为 EV_RXCHAR。 etCommMask(m_hComm,EV_RXCHAR);示例:S 设置串口通讯超时:可以通过COMMTIMEOUTS 结构来达到目的,这个结构比较

简单,共有5个字段,一般可以设置为零等待发送,无限制接收,示例: COMMTIMEOUTS commtimeouts;

commtimeouts.ReadIntervalTimeout=0xFFFFFFFF;//设置读取操作数据间隔时间为最大 commtimeouts.ReadTotalTimeoutConstant=0;

commtimeouts.ReadTotalTimeoutMultiplier=0;

commtimeouts.WriteTotalTimeoutConstant=0;

SetCommTimeouts(m_hComm,&commtimeouts);

串口的收发数据的总超时=超时常量+超时的字节倍数*数据字节数。 //读取操作的超时常量时间 //读取操作的超时字节倍数。 //发送操作的超时常量 commtimeouts.WriteTotalTimeoutMultiplier=0; //发送操作的超时字节倍数。

v. 清除缓冲区数据:可以使用PurgeComm函数来实现,目的是清除串口以前操作

的影响,示例:

PurgeComm(m_hComm,PURGE_RXCLEAR|PURGE_TXCLEAR|PURGE_RXABORT|PURGE_TXABORT);

c) 发送串口数据:即可用与文件相关函数WriteFile来实现.不过因为打开的设备文件

要进行异步操作,所以必需使用一个OVERLAPPED 结构来辅助函数实现数据发送到串口。对于这个结构,我们可以只关心我们用到的字段,其中最主要的是hEvent,这个事件句柄,在执行操作以前首先要对它进行创建,用来监视发送操作是否完成。先看下示例代码:

OVERLAPPED wOverlapped;

CString strBuf=strData; DWORD dwBytes; memset(&wOverlapped,0,sizeof(wOverlapped)); wOverlapped.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL); if(!WriteFile(m_hComm,(LPVOID)strData,strBuf.GetLength(),&dwBytes,&wOverlapped)) { } if(GetLastError()==ERROR_IO_PENDING) { } else { } return false; WaitForSingleObject(wOverlapped.hEvent,1000); CloseHandle(wOverlapped.hEvent);

对OVERLAPPED 结构,再使用以前必需进行清空操作,以避免对我们操作的影响。我们这里创建一个人工重置的事件,其实对于我们的简单程序,只需创建一个事件即可,无需关心太多细节。写入操作如果完成WriteFile将返还TRUE,dwBytes返还发送的数据长度;否则返还假,这时我们可以检查一下错误,看是否的io数据未发送完毕,如果是利用WaitForsingleObject函数来等待一秒,否则发送失败。 最后要记得将创建的事件句柄关闭。

d) 接收串口数据:接收数据和发送数据的基本操作结构相似,但是多出来两个检查接

收数据的事件的函数。那我们先看下示例代码:

DWORD dwEvt,dwErr,dwByte=0;

)

{ } else { CloseHandle(rOverlapped.hEvent); strBuf.ReleaseBufferSetLength(0); return false; strBuf.SetAt((int)dwByte,0); m_edtRecv.SetWindowTextA((LPCTSTR)strBuf); CloseHandle(rOverlapped.hEvent); strBuf.ReleaseBufferSetLength(0); } } } { if(GetLastError()==ERROR_IO_PENDING) { } WaitForSingleObject(rOverlapped.hEvent,1000); OVERLAPPED rOverlapped; CString strBuf; strBuf.GetBufferSetLength(1024); memset(&rOverlapped,0,sizeof(rOverlapped)); rOverlapped.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL); WaitCommEvent(m_hComm,&dwEvt,&rOverlapped); if(WaitForSingleObject(rOverlapped.hEvent,100)==WAIT_OBJECT_0) { if(dwEvt==EV_RXCHAR) { COMSTAT comstat; memset(&comstat,0,sizeof(comstat)); ClearCommError(m_hComm,&dwErr,&comstat); if(comstat.cbInQue) { if(!ReadFile(m_hComm,(LPVOID)(LPCTSTR)strBuf,comstat.cbInQue,&dwByte,&rOverlapped) }if(dwByte)

}

这里我们用到了WaitCommEvent函数,它的作用主要是查询我们设置的屏蔽事件字的事件的发生,如果有事件发生,函数返还非零值,dwEvt返还屏蔽事件字,如上述的EV_RXCHAR ,即输入缓冲区接收到数据事件。接下来,我们这里引入了一个COMSTAT 的结构,它是一个用来反映串口状态属性的结构,可以使用

ClearCommError函数来实现得到串口的当前状态属性。对于接收数据来讲,

cbInQue属性反映当前输入缓冲区内数据的字节数。然后我们就可以使用ReadFile函数来读取输入缓冲区内的数据了,同样dwBytes返还读取的数据字节数。

e) 关闭串口:关闭串口比较简单,可以直接利用CloseHandle关闭串口资源句柄即可。 程序源代码:

// SerialPort2Dlg.h : 头文件

//

#pragma once

#include "afxwin.h"

// CSerialPort2Dlg 对话框

class CSerialPort2Dlg : public CDialog

{

// 构造

public:

// 对话框数据

// 实现

protected:

// 生成的消息映射函数 virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP() CComboBox m_cboPort; CComboBox m_cboBaud; HICON m_hIcon; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 enum { IDD = IDD_SERIALPORT2_DIALOG }; CSerialPort2Dlg(CWnd* pParent = NULL); // 标准构造函数 public:

CComboBox m_cboData; CComboBox m_cboStop; CComboBox m_cboParity; CButton m_btnOpen; CButton m_btnSend; CEdit m_edtRecv; CEdit m_edtSend; HANDLE m_hComm; BOOL bOpen;

public:

};

// SerialPort2Dlg.cpp : 实现文件

//

#include "stdafx.h"

#include "SerialPort2.h"

#include "SerialPort2Dlg.h"

#ifdef _DEBUG

#define new DEBUG_NEW

#endif

// 用于应用程序“关于”菜单项的CAboutDlg 对话框

class CAboutDlg : public CDialog

{

public:

// 对话框数据 CAboutDlg(); afx_msg void OnBnClickedButtonOpen(); bool OpenComm(); bool CloseComm(); bool RecvData(); bool SendData(LPCTSTR strData); CString m_strPort; afx_msg void OnBnClickedButtonSend(); CString m_strData; CString m_strBaud; CString m_strDatas;

enum { IDD = IDD_ABOUTBOX }; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持

// 实现

protected:

};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) {

}

void CAboutDlg::DoDataExchange(CDataExchange* pDX) {

}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)

END_MESSAGE_MAP()

// CSerialPort2Dlg 对话框

CSerialPort2Dlg::CSerialPort2Dlg(CWnd* pParent /*=NULL*/)

{

}

void CSerialPort2Dlg::DoDataExchange(CDataExchange* pDX) {

CDialog::DoDataExchange(pDX); DDX_Control(pDX, IDC_COMBO_PORT, m_cboPort); DDX_Control(pDX, IDC_COMBO_BAUD, m_cboBaud); DDX_Control(pDX, IDC_COMBO_DATA, m_cboData); m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); : CDialog(CSerialPort2Dlg::IDD, pParent) , m_strPort(_T("")) , m_strData(_T("")) , m_strBaud(_T("")) , m_strDatas(_T("")) CDialog::DoDataExchange(pDX); DECLARE_MESSAGE_MAP()

}

DDX_Control(pDX, IDC_COMBO_STOP, m_cboStop); DDX_Control(pDX, IDC_COMBO_PARITY, m_cboParity); DDX_Control(pDX, IDC_BUTTON_OPEN, m_btnOpen); DDX_Control(pDX, IDC_BUTTON_SEND, m_btnSend); DDX_Control(pDX, IDC_EDIT_RECV, m_edtRecv); DDX_Control(pDX, IDC_EDIT_SEND, m_edtSend); DDX_CBString(pDX, IDC_COMBO_PORT, m_strPort); DDX_Text(pDX, IDC_EDIT_SEND, m_strData); DDX_CBString(pDX, IDC_COMBO_BAUD, m_strBaud); DDX_CBString(pDX, IDC_COMBO_DATA, m_strDatas);

BEGIN_MESSAGE_MAP(CSerialPort2Dlg, CDialog)

// CSerialPort2Dlg 消息处理程序

BOOL CSerialPort2Dlg::OnInitDialog() {

CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { CString strAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { } pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); // IDM_ABOUTBOX 必须在系统命令范围内。 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); // 将“关于...”菜单项添加到系统菜单中。 CDialog::OnInitDialog(); ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() //}}AFX_MSG_MAP ON_BN_CLICKED(IDC_BUTTON_OPEN, &CSerialPort2Dlg::OnBnClickedButtonOpen) ON_BN_CLICKED(IDC_BUTTON_SEND, &CSerialPort2Dlg::OnBnClickedButtonSend) END_MESSAGE_MAP()

}

} // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动 // 执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 // 设置小图标 SetIcon(m_hIcon, FALSE); // TODO: 在此添加额外的初始化代码 m_cboPort.SetCurSel(0); m_cboBaud.SetCurSel(3); m_cboData.SetCurSel(3); m_cboStop.SetCurSel(0); m_cboParity.SetCurSel(0); bOpen=FALSE; return TRUE; // 除非将焦点设置到控件,否则返回TRUE

void CSerialPort2Dlg::OnSysCommand(UINT nID, LPARAM lParam) {

}

// 如果向对话框添加最小化按钮,则需要下面的代码

// 来绘制该图标。对于使用文档/视图模型的MFC 应用程序, // 这将由框架自动完成。

void CSerialPort2Dlg::OnPaint()

{

SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); if (IsIconic()) { CPaintDC dc(this); // 用于绘制的设备上下文 if ((nID & 0xFFF0) == IDM_ABOUTBOX) { } else { } CDialog::OnSysCommand(nID, lParam); CAboutDlg dlgAbout; dlgAbout.DoModal();

}

} // 使图标在工作区矩形中居中 int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // 绘制图标 dc.DrawIcon(x, y, m_hIcon); else { } CDialog::OnPaint();

//当用户拖动最小化窗口时系统调用此函数取得光标 //显示。

HCURSOR CSerialPort2Dlg::OnQueryDragIcon() {

}

void CSerialPort2Dlg::OnBnClickedButtonOpen() {

// TODO: 在此添加控件通知处理程序代码 if(bOpen) { } else { if(OpenComm()) { } else { bOpen=FALSE; bOpen=TRUE; m_btnOpen.SetWindowText(_T("断开")); CloseComm(); bOpen=FALSE; m_btnOpen.SetWindowText(_T("连接")); return static_cast<HCURSOR>(m_hIcon);

}

} } m_btnOpen.SetWindowText(_T("连接"));

bool CSerialPort2Dlg::OpenComm() {

PurgeComm(m_hComm,PURGE_RXCLEAR|PURGE_TXCLEAR|PURGE_RXABORT|PURGE_TXABORT); COMMTIMEOUTS commtimeouts; commtimeouts.ReadIntervalTimeout=0xFFFFFFFF; commtimeouts.ReadTotalTimeoutConstant=0; commtimeouts.ReadTotalTimeoutMultiplier=0; commtimeouts.WriteTotalTimeoutConstant=0; commtimeouts.WriteTotalTimeoutMultiplier=100; SetCommTimeouts(m_hComm,&commtimeouts); SetCommMask(m_hComm,EV_RXCHAR); SetupComm(m_hComm,1024,1024); if(bOpen)return false; UpdateData(); m_hComm=CreateFile(m_strPort,GENERIC_READ|GENERIC_WRITE,NULL,NULL,OPEN_EXISTING,FILE_ATif(m_hComm==INVALID_HANDLE_VALUE) { } DCB dcb; GetCommState(m_hComm,&dcb); dcb.BaudRate=atoi((LPCTSTR)m_strBaud); dcb.ByteSize=atoi((LPCTSTR)m_strDatas); dcb.StopBits=m_cboStop.GetCurSel(); dcb.fParity=TRUE; dcb.fNull=true; dcb.Parity=m_cboParity.GetCurSel(); SetCommState(m_hComm,&dcb); MessageBox(_T("打开串口失败!"),_T("提示"),MB_OK); return false; TRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,NULL);

}

bOpen=true; return true;

bool CSerialPort2Dlg::CloseComm() {

}

bool CSerialPort2Dlg::RecvData() {

} if(dwByte) { } } } DWORD dwEvt,dwErr,dwByte=0; OVERLAPPED rOverlapped; CString strBuf; strBuf.GetBufferSetLength(1024); memset(&rOverlapped,0,sizeof(rOverlapped)); rOverlapped.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL); WaitCommEvent(m_hComm,&dwEvt,&rOverlapped); if(WaitForSingleObject(rOverlapped.hEvent,100)==WAIT_OBJECT_0) { if(dwEvt==EV_RXCHAR) { { if(GetLastError()==ERROR_IO_PENDING) { } WaitForSingleObject(rOverlapped.hEvent,1000); COMSTAT comstat; memset(&comstat,0,sizeof(comstat)); ClearCommError(m_hComm,&dwErr,&comstat); if(comstat.cbInQue) { if(!bOpen)return false; CloseHandle(m_hComm); return true; if(!ReadFile(m_hComm,(LPVOID)(LPCTSTR)strBuf,comstat.cbInQue,&dwByte,&rOverlapped))

}

} strBuf.SetAt((int)dwByte,0); m_edtRecv.SetWindowTextA((LPCTSTR)strBuf); CloseHandle(rOverlapped.hEvent); strBuf.ReleaseBufferSetLength(0); else { } return true; CloseHandle(rOverlapped.hEvent); strBuf.ReleaseBufferSetLength(0); return false;

bool CSerialPort2Dlg::SendData(LPCTSTR strData) {

}

void CSerialPort2Dlg::OnBnClickedButtonSend() {

// TODO: 在此添加控件通知处理程序代码 UpdateData(); if(m_strData.IsEmpty()) return; OVERLAPPED wOverlapped; CString strBuf=strData; DWORD dwBytes; memset(&wOverlapped,0,sizeof(wOverlapped)); wOverlapped.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL); if(!WriteFile(m_hComm,(LPVOID)strData,strBuf.GetLength(),&dwBytes,&wOverlapped)) { } CloseHandle(wOverlapped.hEvent); return true; if(GetLastError()==ERROR_IO_PENDING) { } else { } return false; WaitForSingleObject(wOverlapped.hEvent,1000);

} if(SendData((LPCTSTR)m_strData)) { } else { } Sleep(1000); if(!RecvData()) { } MessageBox("未收到应答!","提示",MB_OK); return;

(未完待续)

2. 双线程串口处理程序。

更多相关推荐:
3.4 通讯

信息技术系辅导员下寝室指导学生工作为了进一步了解学生公寓生活,做好学生公寓卫生安全工作,20xx年x月4号下午,我系xxx,xxx等老师特地来到信息系学生公寓视察学生生活。在信息系生活部几名同学陪同下,xxx,…

通讯稿;把好年关,稳定心弦

把好年关,稳定心弦时处年末,归心似箭,外地务工人员盼望过年。恰逢公司任务紧,工作重,怎样才能正确的安抚好兵心,继续奋战?我通风部在公司的正确指导下以及科长的带头下把好年关,稳定心弦。每个人都想早过年、过好年。过…

建始城乡党组织联争联创谱新曲(通讯)

农村经济基础薄弱;党员主体作用发挥不够;机关党组织活力不足;城乡党建工作整体水平差距较大。怎么办?请看——建始城乡党组织联争联创谱新曲通讯员黄义新汪奉天3年前,建始县围绕建立健全党的基层组织互帮互助机制、推进城…

干部交流会通讯稿

做人做事做学问,尽心尽力尽责任——记我院20xx级优秀毕业研究生干部经验交流会20xx年x月x日下午三点,我院20xx届毕业研究生学生干部与低年级学生干部交流会在学院研究生四教室举行。20xx级优秀研究生干部代…

长河通讯稿

长河九义校通讯稿草池镇场长河九义校召开庆祝教师节暨表彰大会9月x日,草池镇长河九义校召开了简朴而热烈的“庆祝教师节暨表彰会”,对草池镇长河九义校教育战线上涌现出来的先进工作者和十佳教师进行了表彰。大会为20xx…

廉洁文化进校园通讯稿

廉洁文化进校园—提高廉洁修身和自身素养内涵,争做优秀团干20xx年x月x日,湖南交通职业技术学院在院纪检监审处、团委和思政课部组织下,在瞿岳荣老师的主持下,为推进廉洁文化进校园在学术报告厅举办了一场“廉洁文化进…

三八妇女节通讯稿

大庙乡九年一贯制学校喜迎“三八妇女节”阳春三月,春风送暖,在第104个“三八国际妇女节”来临之际,大庙乡九年一贯制学校开展了一系列的节日庆祝活动,为全校女教职员工以及所有女生送去了节日的祝福。从3月x日下午,大…

通讯稿范文六篇

通讯稿范文6篇音乐学院开展学生干部动员大会10月13号中午12点半音乐学院学生干部动员大会在B105教室召开第七届学生会主席团办公室宣传部实践部生卫部女生部学习部文艺部体育部外联部主要成员参加了会议会议中学生会...

新闻稿及通讯稿范文

我校20xx年飞扬梦想唱响青春迎新晚会取得圆满成功年飞扬梦想唱响青春迎新晚会在工大会堂隆重举行校党委书记贺伟机关党委教务处学生处公安处部门负责人和各学院学生工作干部应邀出席晚会迎新晚会是校团委三节一晚会中的重要...

通讯稿范文

小艾向前冲治愈爱无能山东师范大学主题讲座成功举办9月13日下午山东电视台著名主持人大冰著名作家陈岚民谣歌手五哥走进山东师大校园在校本部四号教学楼4201教室举行小艾向前冲治愈爱无能山东师范大学主题讲座山东师大2...

校运会的通讯稿怎么写

校运会的通讯稿怎么写标签校运会通讯稿通讯稿的格式Jane回答2人气23解决时间20xx11202004满意答案好评率71别样的风采高昂的斗志迎面走来的是学校运动员代表队他们正以整齐的步伐以军人的风采展示信息工程...

校园通讯稿范文1

四人四载四枝花一室一生一颗心记人文科协宿舍文化节答辩活动10月23日下午备受期待的宿舍文化节答辩活动在三江楼17楼报告厅如火如荼地展开本次活动由人文科协主办数十个宿舍积极参加了这次温馨之聚随着活动的开展各宿舍竞...

通讯(527篇)