MFC串口通信编程详解解析
MFC串口通信
用MFC写串口
API串口编程资料(1)在用ReadFile 和WriteFile读写串行口时,需要考虑超时问题。
如果在指定时间内没有读出或写入指定数量的字节,那么ReadFile或WriteFIle的操作就会结束。
要查询当前的超时设置应调用GetCommTimeouts函数,该函数会填充一个COMMTIMEOUTS结构。
调用SetCommTimeouts函数可以用某一个COMMTIMEOUTS结构的内容来设置超时。
typedef struct _COMMTIMEOUTS (DWORD ReadIntervalTimeout; //读时间间隔超时DWORD ReadTotalTimeoutMultiplier; //读时间系数DWORD ReadTotalTimeoutConstant; //读时间常数DWORD WriteTotalTimeoutMultiplier; //写时间系数DWORD WriteTotalTimeoutConstant; //写时间常量) COMMTIMEOUTS,*LPCOMMTIMEOUTS;(1)CreateFile打开串口:HANDLE hCom;DWORD dwError;hCom=CreateFile("COM1",GENERIC_READ|GENERIC_WRITE, //允许读和写0, //独占方式NULLOPEN_EXITSTING, //FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, //重叠方式 NULL)if(hCom==INVALID_HANDLE_VALUE){dwError=GetLastError(); //得到错误信息//。
//处理错误}//重叠I/O操作就是异步操作或非阻塞操作,即在执行一项操作时,若系统有别的操作请求,可以立即返回执行其他任务,这样程序就不会类似死机一样停在那里。
而NomOverLapped方式则正好相反,程序应该在于同步方式下如果有一个API函数在操作中,另一个会阻塞直到上一个操作完成,所以当读数据的线程停留在WaitCommEvent的时候,写操作WriteFile 就停在原地等待。
利用MFC实现串行通信
利用 MFC 实现串行通信吉林大学尚金瑞01-7-30 上午 11:51:21--------------------------------------------------------------------------------在微软公司推出的Visual C++中,不仅可以利用串行通信控件或调用Windows API来进行串行通信,而且可以利用MFC CFile类来实现串行通讯。
这种通信方式与访问磁盘普通文件没有太大不同。
较简单的实现方式是利用VC++中的MFC向导建立一个支持MFC的工作台工程,添入如下相关代码即可。
1)打开一个串口需使用:CFile file;CFileException e;file.Open (portName, //example "COM1","COM2"CFile::modeReadWrite,&e);2)关闭一个串口需使用:file.Close();3)从端口进行读操作,需使用:char m_ReadBuff[UINTn];UINT nByte=file.Read (&m_ReadBuff, //buffer to store byteUINT nCount //number of bytes to read);4)从端口进行写操作,需使用:char m_WriteBuff[UINTn];file.Write (&m_WriteBuff, //buffer to store byteUINT nCount //number of bytes to write);5)配置串口串行端口创建时,必须对其进行设置以匹配与其对话的设备。
虽然可以通过操作系统设置这些参数,但也可以用Windows API 中的SetCommState()函数来设置它们。
一般地,可用如下程序设置它们:DCB dcb;::GetCommState( (HANDLE)file.m_hFile, &dcb );dcb.BaudRate = 1200,…;dcb.ByteSize = 7 or 8;dcb.StopBits = 0,1,2=0,1.5,2;dcb.Parity = 0-4=no,odd,even,mark,space;::SetCommState((HANDLE)file.m_hFile, &dcb );为了更好地控制端口可以利用SetCommTimeouts()函数打开或关闭超时功能,具体程序如下:COMMTIMEOUTS cto;::GetCommTimeouts((HANDLE)file.m_hFile , &cto );cto.ReadIntervalTimeout =0;cto.ReadTotalTimeoutMultiplier =0;cto.ReadTotalTimeoutConstant =0;cto.WriteTotalTimeoutMultiplier=0;cto.WriteTotalTimeoutConstant =0;::SetCommTimeouts((HANDLE)file.m_hFile , &cto );采用上面的程序,利用MFC CFile类进行串行通信,代码简单、编程量小,可应用于在线监测、自动化控制等许多方面,对科研、生产有着广泛的实用价值。
mfc串口类使用方法
mfc串口类使用方法MFC串口类使用方法一、引言MFC(Microsoft Foundation Classes)是微软公司为Windows操作系统开发的一套C++类库,提供了一系列的类和函数,简化了Windows程序的开发。
MFC串口类是其中的一个重要组成部分,用于实现在Windows平台下对串口进行读写操作。
本文将介绍MFC串口类的使用方法,帮助读者快速上手并实现串口通信功能。
二、MFC串口类的基本介绍MFC提供了一个名为CSerialPort的串口类,通过该类可以方便地进行串口的打开、关闭、读写等操作。
在使用MFC串口类之前,需要在代码中包含相应的头文件:#include "afxwin.h"三、打开串口在使用串口之前,首先需要打开串口。
打开串口的函数原型如下:BOOL CSerialPort::Open(int nPort, int nBaud, char nParity, int nDatabits, int nStopbits, DWORD dwCommEvents, UINT nBufferSize = 512);参数说明:nPort:串口号,例如1代表COM1;nBaud:波特率,例如9600;nParity:奇偶校验位,可以选择'N'(无校验)、'E'(偶校验)或'O'(奇校验);nDatabits:数据位,可以选择5、6、7或8;nStopbits:停止位,可以选择1或2;dwCommEvents:串口事件,可以选择EV_RXCHAR(接收到字符时触发)或EV_RXFLAG(接收到指定标志位时触发);nBufferSize:缓冲区大小,默认为512。
示例代码如下:CSerialPort serial;if (serial.Open(1, 9600, 'N', 8, 1, EV_RXCHAR)){// 串口打开成功}else{// 串口打开失败}四、关闭串口在使用完串口后,需要关闭串口。
mfc获取插入串口的详细描述
一、介绍MFC及其作用MFC(Microsoft Foundation Class)是微软公司提供的用于Windows应用程序开发的类库,它为C++程序员提供了一套面向对象的编程接口,使得开发Windows应用程序变得更加简单和高效。
MFC可以用来创建图形用户界面(GUI)、处理消息和事件、管理窗口和控件等,是Windows下开发桌面应用程序的重要工具之一。
其中,串口通信在许多实际应用中具有重要的作用,而MFC提供了方便的类库来实现串口通信。
二、串口通信的基本概念1. 串口通信是指通过串行端口进行数据交换的一种通信方式,主要包括RS-232、RS-485、USB串口等。
2. 串口通信中,数据是按照一定的位序列依次传输的,通常包括起始位、数据位、校验位和停止位。
3. 串口通信分为同步串口和异步串口两种,其中异步串口通信最为常见,其数据传输不需要时钟信号。
4. 串口通信常用于嵌入式系统、传感器、工业自动化等领域,以及一些老旧设备上。
三、在MFC中获取插入串口的详细描述1. MFC提供了CSerialPort类来实现串口通信,其中获取插入串口的详细描述是一个重要的功能。
2. 获取插入串口的详细描述可以包括串口的端口号、设备名称、设备描述等信息。
3. 在MFC中,可以通过遍历系统中的串口端口来获取插入串口的详细描述信息。
四、具体步骤1. 需要包含头文件,引入CSerialPort类的定义和相关函数。
2. 通过查询注册表或WMI(Windows Management Instrumentation)来获取系统中已插入的串口端口信息。
3. 每个串口端口在注册表中都有对应的注册表项,可以通过遍历注册表的方式来获取插入串口的详细描述信息。
4. 对于WMI,可以调用相关接口来获取串口设备的详细信息。
五、代码示例下面是一个简单的代码示例,展示了如何在MFC中获取插入串口的详细描述信息:```C++void CMyDlg::EnumSerialPorts(){CString str;HKEY hKey;LONG lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,_T("HARDWARE\\DEVICEMAP\\SERIALCOMM"), 0, KEY_READ,hKey);if(lResult != ERROR_SUCCESS){AfxMessageBox(_T("Error opening SerialComm Key!"));return;}TCHAR lpValueName[256];DWORD dwValueNameSize = 256;BYTE lpData[256];DWORD dwDataSize = 256;DWORD dwIndex = 0;lResult = RegEnumValue(hKey, dwIndex, lpValueName, dwValueNameSize, NULL, NULL, lpData, dwDataSize);while(lResult == ERROR_SUCCESS){CString strPortName(reinterpret_cast<LPCTSTR>(lpData)); str.Format(_T("s - s"), lpValueName, strPortName);m_lbPorts.AddString(str);dwValueNameSize = 256;dwDataSize = 256;dwIndex++;lResult = RegEnumValue(hKey, dwIndex, lpValueName, dwValueNameSize, NULL, NULL, lpData, dwDataSize);}RegCloseKey(hKey);}```六、总结通过上述步骤和代码示例,我们可以在MFC中轻松获取插入串口的详细描述信息,这对于进行串口通信或者设备监控等应用非常有用。
MFC串口通信程序(基于Vc++及Serialport类)
编程步骤
编写按钮控件消息响应处理函数-发送
以同样的方法打开“发送”按钮的消息函数,插入下面语句
void C串口通信程序Dlg::OnBnClickedButton3() { if(!m_bPortOpen) //检测串口是否打开 return ; //如果关闭,则结束函数 else //如果打开,则执行下面语句 UpdateData(TRUE); //读入编辑框的数据(把编辑框中的字符写入变量) m_SerialPort.WriteToPort((LPCTSTR)m_strTxMsg); //调用函数发送数据 }
m_strPairty
Control型变量
m_strTxMsg
m_strRxMsg
Value型变量
编程步骤
对写好的对话框进行一个初始化 在初始化函数OnInitDialog()中添加如下语句:
BOOL C串口通信程序Dlg::OnInitDialog() { CDialogEx::OnInitDialog(); m_ctrlComPort.SetCurSel(0);//设置默认的索引值 m_ctrlBaudRate.SetCurSel(0); m_ctrlPairty.SetCurSel(0); m_ctrlDataBits.SetCurSel(3); m_ctrlStopBits.SetCurSel(0); GetDlgItem(IDC_BUTTON1)->EnableWindow(TRUE); //把窗口中的“打开串口”置为活动的可操作状态 GetDlgItem(IDC_BUTTON2)->EnableWindow(FALSE); //把窗口中的“关闭串口”置为灰色的不可操作状态
编程步骤
• • 在对话框c文件中声明串口类对象 定义一个布尔变量 CSerialPort m_SerialPort BOOL m_bPortOpen //用来表示标志串口是否打开
MFC串口通信编程详解
DWORD ReadIntervalTimeout;//读间隔超时 DWORD ReadTotalTimeoutMultiplier;//读时间系数 DWORD ReadTotalTimeoutConstant;//读时间常量 DWORD WriteTotalTimeoutMultiplier;//写时间系数 DWORD WriteTotalTimeoutConstant;//写时间常量 } COMMTIMEOUTS,*LPCOMMTIMEOUTS; COMMTIMEOUTS 结构的成员都以毫秒为单位.总超时的计算公式是: 总超时=时间系数×要求读/写的字符数+时间常量 例如要读入 10 个字符,那么读操作的总超时的计算公式为: 读总超时=ReadTotalTimeoutMultiplier×10+ReadTotalTimeoutConstant 可以看出:间隔超时和总超时的设置是不相关的,这可以方便通信程序灵活地设置 各种超时. 如果所有写超时参数均为 0,那么就不使用写超时.如果 ReadIntervalTimeout 为 0,那么就不使用读间隔超时.如果 ReadTotalTimeoutMultiplier 和 ReadTotalTimeoutConstant 都为 0,则不使用读总超时.如果读间隔超时被设置成 MAXDWORD 并且读时间系数和读时间常量都为 0,那么在读一次输入缓冲区的内容后 读操作就立即返回,而不管是否读入了要求的字符. 在用重叠方式读写串口时,虽然 ReadFile 和 WriteFile 在完成操作以前就可能返 回,但超时仍然是起作用的.在这种情况下,超时规定的是操作的完成时间,而不是 ReadFile 和 WriteFile 的返回时间.
MFC串口通信
本文详细介绍了串行通信的基本原理,以及在Windows NT、Win98环境下用MFC实现串口(COM)通信的方法:使用ActiveX控件或Win API.并给出用Visual C++6.0编写的相应MFC32位应用程序。
关键词:串行通信、VC++6.0、ActiveX控件、Win API、MFC32位应用程序、事件驱动、非阻塞通信、多线程.在Windows应用程序的开发中,我们常常需要面临与外围数据源设备通信的问题。
计算机和单片机(如MCS-51)都具有串行通信口,可以设计相应的串口通信程序,完成二者之间的数据通信任务。
实际工作中利用串口完成通信任务的时候非常之多。
已有一些文章介绍串口编程的文章在计算机杂志上发表。
但总的感觉说来不太全面,特别是介绍32位下编程的更少,且很不详细。
笔者在实际工作中积累了较多经验,结合硬件、软件,重点提及比较新的技术,及需要注意的要点作一番探讨。
希望对各位需要编写串口通信程序的朋友有一些帮助。
一.串行通信的基本原理回到页顶串行端口的本质功能是作为CPU和串行设备间的编码转换器。
当数据从CPU经过串行端口发送出去时,字节数据转换为串行的位。
在接收数据时,串行的位被转换为字节数据。
在Windows环境(Windows NT、Win98、Windows2000)下,串口是系统资源的一部分。
应用程序要使用串口进行通信,必须在使用之前向操作系统提出资源申请要求(打开串口),通信完成后必须释放资源(关闭串口)。
二.串口信号线的接法回到页顶一个完整的RS-232C接口有22根线,采用标准的25芯插头座(或者9芯插头座)。
25芯和9芯的主要信号线相同。
以下的介绍是以25芯的RS-232C为例。
①主要信号线定义:2脚:发送数据TXD;3脚:接收数据RXD;4脚:请求发送RTS;5脚:清除发送CTS;6脚:数据设备就绪DSR;20脚:数据终端就绪DTR;8脚:数据载波检测DCD;1脚:保护地;7脚:信号地。
mfc 2010 串口 例程
mfc 2010 串口例程摘要:1.MFC 2010 简介2.串口通信基本概念3.串口通信例程介绍4.例程功能及应用场景5.总结与展望正文:MFC(Microsoft Foundation Class)2010 是微软提供的一款用于开发Windows 应用程序的类库。
它可以帮助开发者更轻松地创建高质量的Windows 应用程序。
在众多功能中,MFC 2010 也提供了串口通信相关的类和方法,以便开发者能够方便地进行串口通信。
串口通信(Serial Communication)是一种在两个设备之间传输数据的方式。
它通过串行传输数据,即将数据位逐个传输,而非并行传输。
串口通信在电子设备、计算机外设、通信设备等领域有着广泛的应用。
MFC 2010 提供了丰富的串口通信例程,可以帮助开发者轻松实现串口通信功能。
这些例程包括了串口配置、数据发送与接收、异常处理等功能。
通过这些例程,开发者可以快速地搭建起一个串口通信程序,并对其进行调试和优化。
以下是使用MFC 2010 串口例程的一个简单示例:首先,需要创建一个串口对象,并配置串口参数,如波特率、数据位、停止位等。
接着,可以通过打开或关闭串口对象来开启或关闭串口通信。
在通信过程中,可以使用发送和接收数据的方法,将数据从串口发送到其他设备,或从其他设备接收数据。
同时,需要对串口通信过程中的异常情况进行处理,以保证程序的稳定性和可靠性。
MFC 2010 串口例程广泛应用于各种需要进行串口通信的场合,如工业自动化、数据采集、通信设备等。
通过使用这些例程,开发者可以节省大量的开发时间,专注于实现应用程序的核心功能。
总结来说,MFC 2010 提供了强大的串口通信功能,通过例程的方式,帮助开发者快速实现串口通信功能。
vc++mfc串口通信
Vc++串口通信(加密解密以及反馈协议)一.主要功能:实现两台计算机通过串口进行数据通信。
二.软件特色:与本软件传输协议不同的串口信息接收到之后不做显示,发送过程中经过数据包加首部尾部来确定数据是否为同一个协议,之后再经过加密发送,接受时先解密,然后经过除去首部跟尾部来得到本来的数据。
三.加密原理:发送时先加首部跟尾部,然后再将所有字符串转换成字符数组,进而对数组中的每个字符进行处理,具体方法是首先获得本次发送的数据总长度,单个字符减去本次字符串总长度的数字,再将数组转换成字符串发送出去,解码时先将受到的字符串转换成字符数组,再将每个字符加上本次接收到的字符串总长度,然后除去首部跟尾部,得到实际有用的数据。
四.协议原理:在每次收到数据之后进行判断,是否为预先设定的反馈数据,如果是,则不做处理,如果不是,则进行发送反馈数据操作。
每次发送完数据对话框有提示“数据已发送“,当收到反馈数据时,提示”数据已成功接收“。
五.主要问题:单次发送的数据不能大于33个字符,否则会接收不正常。
波特率已加到程序里面固定为“115200“,如果太小了可能会出现接收不到信息或者接收速度慢等情况。
六.界面图示:1.发送完数据,但是对方未收到。
2.发送完数据,对方已经成功接收。
七.部分代码界面设计类向导中的函数设计“serilDlg.cpp”文件内部代码#include "stdafx.h"#include "seril.h"#include "serilDlg.h"#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endifint comseril;///////////////////////////////////////////////////////////////////////////// // CAboutDlg dialog used for App Aboutclass CAboutDlg : public CDialog{public:CAboutDlg();// Dialog Data//{{AFX_DATA(CAboutDlg)enum { IDD = IDD_ABOUTBOX };//}}AFX_DATA// ClassWizard generated virtual function overrides//{{AFX_VIRTUAL(CAboutDlg)protected:virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL// Implementationprotected://{{AFX_MSG(CAboutDlg)//}}AFX_MSGDECLARE_MESSAGE_MAP()};CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD){//{{AFX_DATA_INIT(CAboutDlg)//}}AFX_DATA_INIT}void CAboutDlg::DoDataExchange(CDataExchange* pDX){CDialog::DoDataExchange(pDX);//{{AFX_DATA_MAP(CAboutDlg)//}}AFX_DATA_MAP}BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)//{{AFX_MSG_MAP(CAboutDlg)// No message handlers//}}AFX_MSG_MAPEND_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////// CSerilDlg dialogCSerilDlg::CSerilDlg(CWnd* pParent /*=NULL*/): CDialog(CSerilDlg::IDD, pParent){//{{AFX_DATA_INIT(CSerilDlg)m_strRXData = _T("");m_strTXData = _T("");m_TestFlag = _T("");//}}AFX_DATA_INIT// Note that LoadIcon does not require a subsequent DestroyIcon in Win32 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);}void CSerilDlg::DoDataExchange(CDataExchange* pDX){CDialog::DoDataExchange(pDX);//{{AFX_DATA_MAP(CSerilDlg)DDX_Control(pDX, IDC_OPENSERIL, m_Opensril);DDX_Control(pDX, IDC_COM, m_serilcom);DDX_Text(pDX, IDC_EDIT_RXDATA, m_strRXData);DDX_Text(pDX, IDC_EDIT_TXDATA, m_strTXData);DDX_Control(pDX, IDC_MSCOMM1, m_ctrlComm);DDX_Text(pDX, IDC_TESTFLAG, m_TestFlag);//}}AFX_DATA_MAP}BEGIN_MESSAGE_MAP(CSerilDlg, CDialog)//{{AFX_MSG_MAP(CSerilDlg)ON_WM_SYSCOMMAND()ON_WM_PAINT()ON_WM_QUERYDRAGICON()ON_BN_CLICKED(IDC_CLEAR, OnClear)ON_BN_CLICKED(IDC_CLEARSEND, OnClearsend)ON_CBN_CLOSEUP(IDC_COM, OnCloseupCom)ON_BN_CLICKED(IDC_FASONG, OnFasong)ON_BN_CLICKED(IDC_OPENSERIL, OnOpenseril)//}}AFX_MSG_MAPEND_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////// CSerilDlg message handlersBOOL CSerilDlg::OnInitDialog(){CDialog::OnInitDialog();// Add "About..." menu item to system menu.// IDM_ABOUTBOX must be in the system command range.ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);ASSERT(IDM_ABOUTBOX < 0xF000);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);}}// Set the icon for this dialog. The framework does this automatically// when the application's main window is not a dialogSetIcon(m_hIcon, TRUE); // Set big iconSetIcon(m_hIcon, FALSE); // Set small icon// TODO: Add extra initialization herereturn TRUE; // return TRUE unless you set the focus to a control}void CSerilDlg::OnSysCommand(UINT nID, LPARAM lParam){if ((nID & 0xFFF0) == IDM_ABOUTBOX){CAboutDlg dlgAbout;dlgAbout.DoModal();}else{CDialog::OnSysCommand(nID, lParam);}}// If you add a minimize button to your dialog, you will need the code below// to draw the icon. For MFC applications using the document/view model,// this is automatically done for you by the framework.void CSerilDlg::OnPaint(){if (IsIconic()){CPaintDC dc(this); // device context for paintingSendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);// Center icon in client rectangleint 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;// Draw the icondc.DrawIcon(x, y, m_hIcon);}else{CDialog::OnPaint();}}// The system calls this to obtain the cursor to display while the user drags// the minimized window.HCURSOR CSerilDlg::OnQueryDragIcon(){return (HCURSOR) m_hIcon;}BEGIN_EVENTSINK_MAP(CSerilDlg, CDialog)//{{AFX_EVENTSINK_MAP(CSerilDlg)ON_EVENT(CSerilDlg, IDC_MSCOMM1, 1 /* OnComm */, OnComm, VTS_NONE)//}}AFX_EVENTSINK_MAPEND_EVENTSINK_MAP()void CSerilDlg::OnComm(){// TODO: Add your control notification handler code hereVARIANT variant_inp;COleSafeArray safearray_inp;LONG len,k;BYTE rxdata[20480],rxtemp[20480]={0},top[20480],down[20480],jm[20480],jm1[20480]; //设置BYTE数组An 8-bit integerthat is not signed.CString strtemp,test,test1;if (m_ctrlComm.GetCommEvent() == 2) //事件值为2表示接收缓冲区内有字符{ // CString rw="rw";////////以下你可以根据自己的通信协议加入处理代码variant_inp = m_ctrlComm.GetInput(); //读缓冲区safearray_inp = variant_inp; //VARIANT型变量转换为ColeSafeArray型变量len = safearray_inp.GetOneDimSize(); //得到有效数据长度for(k = 0;k < len;k++){safearray_inp.GetElement(&k,rxdata+k);//转换为BYTE型数组}if(rxdata[0] == 'r'&&rxdata[1] == 'e'&&rxdata[2] == 'c'&&rxdata[3] == 'i'&&rxdata[4] == 'v'&&rxdata[5] == 'e'){m_TestFlag = "已被成功接收";}else{m_ctrlComm.SetOutput(COleVariant("recive"));}for (k=0;k<5;k++){top[k]=rxdata[k];}for(k=0;k<4;k++){down[k]=rxdata[len-4+k];}if(top[0] == 'b' && top[1] == 'e' && top[2] == 'g' && top[3] == 'i' && top[4] == 'n' && down[0] == 'o' && down[1] == 'v' && down[2] == 'e' && down[3] == 'r'){for(k=0;k<len-9;k++){rxtemp[k] = rxdata[k+5];}for(k=0;k<len-9;k++){jm1[k] = (rxtemp[k] -len+9);}for(k = 0;k < len-9;k++) //将数组转换为Cstring型变量{BYTE bt = *(char*)(jm1+k); //字符型strtemp.Format("%c",bt); //将字符送入临时变量strtemp存放m_strRXData += strtemp;}}}UpdateData(FALSE); //更新编辑框内容(主要是接收编辑框中的)}void CSerilDlg::OnFasong(){long siz,k;CString SendAll,sendal;UpdateData(TRUE); //读取编辑框内容siz = strlen( m_strTXData) ;char cha[20480] ;char cha1[20480];char cha2[20480];strcpy(cha, m_strTXData);for (k=0;k<siz;k++){cha1[k] = cha[k] +siz ;}CString str(cha1,siz);SendAll = "begin" + str + "over";m_ctrlComm.SetOutput(COleVariant(SendAll)); //发送数据m_TestFlag = "数据已发送";UpdateData(FALSE); //读取编辑框内容}void CSerilDlg::OnOpenseril(){// TODO: Add your control notification handler code herem_ctrlComm.SetCommPort(comseril); //选择com口if ( m_ctrlComm.GetPortOpen() ){m_ctrlComm.SetPortOpen(FALSE);// 关闭串口// AfxMessageBox("cannot open serial port");AfxMessageBox("串口已关闭");}else{m_ctrlComm.SetPortOpen(TRUE);//打开串口AfxMessageBox("串口打开成功");SetDlgItemText(IDC_OPENSERIL,"关闭串口"); //显示串口已经关闭m_ctrlComm.SetSettings("115200,n,8,1"); //波特率9600,无校验,8个数据位,1个停止位m_ctrlComm.SetInputMode(1); //1:表示以二进制方式检取数据m_ctrlComm.SetRThreshold(1); //参数1表示每当串口接收缓冲区中有多于或等于1个字符时将引发一个接收数据的OnComm事件m_ctrlComm.SetInputLen(0); //设置当前接收区数据长度为0m_ctrlComm.GetInput(); //先预读缓冲区以清除残留数据// m_TestFlag = "未测试";UpdateData(FALSE);}}void CSerilDlg::OnCloseupCom(){comseril = m_serilcom.GetCurSel();}void CSerilDlg::OnClear(){m_strRXData = "";UpdateData(FALSE); //更新编辑框内容// TODO: Add your control notification handler code here}void CSerilDlg::OnClearsend(){// TODO: Add your control notification handler code herem_strTXData = "";UpdateData(FALSE);}、Seril.h内代码// serilDlg.h : header file////{{AFX_INCLUDES()#include "mscomm.h"//}}AFX_INCLUDES#if !defined(AFX_SERILDLG_H__1B7176B4_DDC7_45B3_B636_2597E461F275__INCLUDED_) #define AFX_SERILDLG_H__1B7176B4_DDC7_45B3_B636_2597E461F275__INCLUDED_#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000/////////////////////////////////////////////////////////////////////////////// CSerilDlg dialogclass CSerilDlg : public CDialog{// Constructionpublic:CSerilDlg(CWnd* pParent = NULL); // standard constructor// Dialog Data//{{AFX_DATA(CSerilDlg)enum { IDD = IDD_SERIL_DIALOG };CButton m_Opensril;CComboBox m_serilcom;CString m_strRXData;CString m_strTXData;CMSComm m_ctrlComm;CString m_TestFlag;//}}AFX_DATA// ClassWizard generated virtual function overrides//{{AFX_VIRTUAL(CSerilDlg)protected:virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support//}}AFX_VIRTUAL// Implementationprotected:HICON m_hIcon;// Generated message map functions//{{AFX_MSG(CSerilDlg)virtual BOOL OnInitDialog();afx_msg void OnSysCommand(UINT nID, LPARAM lParam);afx_msg void OnPaint();afx_msg HCURSOR OnQueryDragIcon();afx_msg void OnClear();afx_msg void OnClearsend();afx_msg void OnCloseupCom();afx_msg void OnFasong();afx_msg void OnComm();afx_msg void OnOpenseril();DECLARE_EVENTSINK_MAP()//}}AFX_MSGDECLARE_MESSAGE_MAP()};//{{AFX_INSERT_LOCATION}}// Microsoft Visual C++ will insert additional declarations immediately before the previous line.#endif// !defined(AFX_SERILDLG_H__1B7176B4_DDC7_45B3_B636_2597E461F275__INCLUDED_)日期:2013-4-10。
【免费下载】用MFC实现串口编程
2 脚:发送数据 TXD; 3 脚:接收数据 RXD; 4 脚:请求发送 RTS; 5 脚:清除 发送 CTS;
6 脚:数据设备就绪 D脚:信号地。
②电气特性:
数据传输速率最大可到 20K bps,最大距离仅 15m.
注:看了微软的 MSDN 6.0,其 Windows API 中关于串行通讯设备(不一定都是串口 RS232C 或 RS-422 或 RS-449)速率的设置,最大可支持到 RS_256000,即 256K bps! 也不知道 到底是什么串行通讯设备?但不管怎样,一般主机和单片机的串口通讯大多都在 9600 bps, 可以满足通讯需求。
用 MFC 实现串口编程 (作者:付杰 2000 年 08 月 04 日 11:28)
本文详细介绍了串行通信的基本原理,以及在 Windows NT、Win98 环境下用 MFC 实现串 口(COM)通信的方法:使用 ActiveX 控件或 Win API.并给出用 Visual C++6.0 编写的相应 MFC32 位应用程序。关键词:串行通信、VC++6.0、ActiveX 控件、Win API、MFC32 位应用 程序、事件驱动、非阻塞通信、多线程.
8 脚:数据载波检测
CloseComm() 关闭串口; 例:int idComDev; idComDev = OpenComm("COM1", 1024, 128); CloseComm(idComDev); ② BuildCommDCB() 、setCommState()填写设备控制块 DCB,然后对已打开的串口进行参数 配置; 例:DCB dcb; BuildCommDCB("COM1:2400,n,8,1", &dcb); SetCommState(&dcb); ③ ReadComm 、WriteComm()对串口进行读写操作,即数据的接收和发送. 例:char *m_pRecieve; int count; ReadComm(idComDev,m_pRecieve,count); Char wr[30]; int count2; WriteComm(idComDev,wr,count2); 16 位下的串口通信程序最大的特点就在于:串口等外部设备的操作有自己特有的 API 函数; 而 32 位程序则把串口操作(以及并口等)和文件操作统一起来了,使用类似的操作。 四.在 MFC 下的 32 位串口应用程序 32 位下串口通信程序可以用两种方法实现:利用 ActiveX 控件;使用 API 通信函数。 使用 ActiveX 控件,程序实现非常简单,结构清晰,缺点是欠灵活;使用 API 通信函数的 优缺点则基本上相反。 以下介绍的都是在单文档(SDI)应用程序中加入串口通信能力的程序。
MFC串口通信编程详解
MFC 串口通信编程介绍主要介绍了用CreateFile函数和WriteFile函数读写串口的实例以及设置串口属性的实例. 在工业控制中工控机一般都基于Windows 平台经常需要与智能仪表通过串口进行通信.串口通信方便易行应用广泛. 一般情况下工控机和各智能仪表通过RS485 总线进行通信.RS485 的通信方式是半双工的只能由作为主节点的工控PC 机依次轮询网络上的各智能控制单元子节点.每次通信都是由PC 机通过串口向智能控制单元发布命令智能控制单元在接收到正确的命令后作出应答. 在Win32 下可以使用两种编程方式实现串口通信其一是使用ActiveX 控件这种方法程序简单但欠灵活.其二是调用Windows 的API函数这种方法可以清楚地掌握串口通信的机制并且自由灵活.下面只介绍API 串口通信部分. 串口的操作可以有两种操作方式:同步操作方式和重叠操作方式又称为异步操作方式.同步操作时API 函数会阻塞直到操作完成以后才能返回在多线程方式中虽然不会阻塞主线程但是仍然会阻塞监听线程而重叠操作方式API 函数会立即返回操作在后台进行避免线程的阻塞. 无论哪种操作方式一般都通过四个步骤来完成: 1打开串口2配置串口3读写串口4关闭串口一打开串口Win32 系统把文件的概念进行了扩展.无论是文件、通信设备、命名管道、邮件槽、磁盘、还是控制台都是用API 函数CreateFile 来打开或创建的.该函数的原型为: HANDLE CreateFile LPCTSTR lpFileName DWORD dwDesiredAccess DWORD dwShareMode LPSECURITY_ATTRIBUTES lpSecurityAttributes DWORD dwCreationDistribution DWORD dwFlagsAndAttributes HANDLE hTemplateFile lpFileName:将要打开的串口逻辑名如“COM1” dwDesiredAccess:指定串口访问的类型可以是读取、写入或二者并列dwShareMode:指定共享属性由于串口不能共享该参数必须置为0 lpSecurityAttributes:引用安全性属性结构缺省值为NULL dwCreationDistribution:创建标志对串口操作该参数必须置为OPEN_EXISTING dwFlagsAndAttributes:属性描述用于指定该串口是否进行异步操作该值为FILE_FLAG_OVERLAPPED表示使用异步的I/O该值为0表示同步I/O 操作hTemplateFile:对串口而言该参数必须置为NULL同步I/O 方式打开串口的示例:HANDLE hCom//全局变量串口句柄hComCreateFilequotCOM1quot//串口名称GENERIC_READGENERIC_WRITE//允许读和写0//独占方式NULL OPEN_EXISTING//打开而不是创建0//同步方式NULLifhComHANDLE-1 MessageBoxquot?蚩?COM 失败quot return FALSEreturn TRUE重叠I/O 打开串口的示例:HANDLE hCom//全局变量串口句柄hCom CreateFilequotCOM1quot//串口名称GENERIC_READGENERIC_WRITE//允许读和写0//独占方式NULL OPEN_EXISTING//打开而不是创建FILE_ATTRIBUTE_NORMALFILE_FLAG_OVERLAPPED//重叠方式NULLifhComINVALID_HANDLE_VALUE MessageBoxquot打开COM 失败quot return FALSEreturn TRUE二配置串口在打开通讯设备句柄后常需要对串口进行一些初始化配置工作.这需要通过一个DCB 结构来进行.DCB 结构包含了诸如波特率、数据位数、奇偶校验和停止位数等信息.在查询或配置串口的属性时都要用DCB 结构来作为缓冲区. 一般用CreateFile 打开串口后可以调用GetCommState 函数来获取串口的初始配置.要修改串口的配置应该先修改DCB 结构然后再调用SetCommState 函数设置串口. DCB 结构包含了串口的各项参数设置下面仅介绍几个该结构常用的变量: typedef struct _DCB ……… //波特率指定通信设备的传输速率.这个成员可以是实际波特率值或者下面的常量值之一: DWORDBaudRate//CBR_110CBR_300CBR_600CBR_1200CBR_2400CBR_4800CBR_9600CB R_19200//CBR_38400//CBR_56000CBR_57600CBR_115200CBR_128000CBR_25600 0CBR_14400 DWORD fParity//指定奇偶校验使能.若此成员为1允许奇偶校验检查… BYTE ByteSize//通信字节位数4—8 BYTE Parity//指定奇偶校验方法.此成员可以有下列值: //EVENPARITY 偶校验NOPARITY 无校验//MARKPARITY 标记校验ODDPARITY 奇校验BYTE StopBits//指定停止位的位数.此成员可以有下列值: //ONESTOPBIT 1 位停止位TWOSTOPBITS 2 位停止位//ONE5STOPBITS 1.5 位停止位……… DCB 在winbase.h 文件中定义了以上用到的常量.如下所示: define NOPARITY 0 define ODDPARITY 1 define EVENPARITY 2 define ONESTOPBIT 0 define ONE5STOPBITS 1 define TWOSTOPBITS 2 define CBR_110 110 define CBR_300 300 define CBR_600 600 define CBR_1200 1200 defineCBR_2400 2400 define CBR_4800 4800 define CBR_9600 9600 define CBR_14400 14400 define CBR_19200 19200 define CBR_38400 38400 define CBR_56000 56000 define CBR_57600 57600 define CBR_115200 115200 define CBR_128000 128000 define CBR_256000 256000 GetCommState 函数可以获得COM 口的设备控制块从而获得相关参数: BOOL GetCommState HANDLE hFile //标识通讯端口的句柄LPDCB lpDCB //指向一个设备控制块DCB 结构的指针SetCommState 函数设置COM 口的设备控制块: BOOL SetCommState HANDLE hFile LPDCB lpDCB 除了在BCD 中的设置外程序一般还需要设置I/O 缓冲区的大小和超时.Windows用I/O 缓冲区来暂存串口输入和输出的数据.如果通信的速率较高则应该设置较大的缓冲区.调用SetupComm 函数可以设置串行口的输入和输出缓冲区的大小. BOOL SetupComm HANDLE hFile // 通信设备的句柄DWORD dwInQueue // 输入缓冲区的大小字节数DWORD dwOutQueue // 输出缓冲区的大小字节数在用ReadFile 和WriteFile 读写串行口时需要考虑超时问题.超时的作用是在指定的时间内没有读入或发送指定数量的字符ReadFile 或WriteFile 的操作仍然会结束. 要查询当前的超时设置应调用GetCommTimeouts 函数该函数会填充一个COMMTIMEOUTS 结构.调用SetCommTimeouts 可以用某一个COMMTIMEOUTS 结构的内容来设置超时. 读写串口的超时有两种:间隔超时和总超时.间隔超时是指在接收时两个字符之间的最大时延.总超时是指读写操作总共花费的最大时间.写操作只支持总超时而读操作两种超时均支持.用COMMTIMEOUTS 结构可以规定读写操作的超时. COMMTIMEOUTS 结构的定义为: typedef struct _COMMTIMEOUTS DWORD ReadIntervalTimeout//读间隔超时DWORD ReadTotalTimeoutMultiplier//读时间系数DWORD ReadTotalTimeoutConstant//读时间常量DWORD WriteTotalTimeoutMultiplier//写时间系数DWORD WriteTotalTimeoutConstant//写时间常量COMMTIMEOUTSLPCOMMTIMEOUTS COMMTIMEOUTS 结构的成员都以毫秒为单位.总超时的计算公式是:总超时=时间系数×要求读/写的字符数+时间常量例如要读入10 个字符那么读操作的总超时的计算公式为:读总超时=ReadTotalTimeoutMultiplier×10+ReadTotalTimeoutConstant 可以看出:间隔超时和总超时的设置是不相关的这可以方便通信程序灵活地设置各种超时. 如果所有写超时参数均为0那么就不使用写超时.如果ReadIntervalTimeout 为0那么就不使用读间隔超时.如果ReadTotalTimeoutMultiplier 和ReadTotalTimeoutConstant 都为0则不使用读总超时.如果读间隔超时被设置成MAXDWORD 并且读时间系数和读时间常量都为0那么在读一次输入缓冲区的内容后读操作就立即返回而不管是否读入了要求的字符. 在用重叠方式读写串口时虽然ReadFile 和WriteFile 在完成操作以前就可能返回但超时仍然是起作用的.在这种情况下超时规定的是操作的完成时间而不是ReadFile 和WriteFile 的返回时间.配置串口的示例:SetupCommhCom10241024//输入缓冲区和输出缓冲区的大小都是1024 COMMTIMEOUTS TimeOuts //设定读超时TimeOuts.ReadIntervalTimeout1000 TimeOuts.ReadTotalTimeoutMultiplier500 TimeOuts.ReadTotalTimeoutConstant5000 //设定写超时TimeOuts.WriteTotalTimeoutMultiplier500TimeOuts.WriteTotalTimeoutConstant2000 SetCommTimeoutshComampTimeOuts//设置超时DCB dcb GetCommStatehComampdcb dcb.BaudRate9600//波特率为9600 dcb.ByteSize8//每个字节有8 位dcb.ParityNOPARITY//无奇偶校验位dcb.StopBitsTWOSTOPBITS//两个停止位SetCommStatehComampdcb PurgeCommhComPURGE_TXCLEARPURGE_RXCLEAR 在读写串口之前还要用PurgeComm函数清空缓冲区该函数原型: BOOL PurgeComm HANDLE hFile//串口句柄DWORD dwFlags//需要完成的操作参数dwFlags 指定要完成的操作可以是下列值的组合: PURGE_TXABORT 中断所有写操作并立即返回即使写操作还没有完成. PURGE_RXABORT 中断所有读操作并立即返回即使读操作还没有完成. PURGE_TXCLEAR 清除输出缓冲区PURGE_RXCLEAR 清除输入缓冲区三读写串口使用ReadFile 和WriteFile 读写串口下面是两个函数的声明: BOOL ReadFile HANDLE hFile//串口的句柄//读入的数据存储的地址//即读入的数据将存储在以该指针的值为首地址的一片内存区LPVOID lpBuffer DWORD nNumberOfBytesToRead //要读入的数据的字节数//指向一个DWORD 数值该数值返回读操作实际读入的字节数LPDWORD lpNumberOfBytesRead //重叠操作时该参数指向一个OVERLAPPED 结构同步操作时该参数为NULL. LPOVERLAPPED lpOverlapped BOOL WriteFile HANDLE hFile//串口的句柄//写入的数据存储的地址//即以该指针的值为首地址的nNumberOfBytesToWrite //个字节的数据将要写入串口的发送数据缓冲区. LPCVOID lpBuffer DWORD nNumberOfBytesToWrite//要写入的数据的字节数//指向指向一个DWORD 数值该数值返回实际写入的字节数LPDWORD lpNumberOfBytesWritten //重叠操作时该参数指向一个OVERLAPPED 结构//同步操作时该参数为NULL. LPOVERLAPPED lpOverlapped 在用ReadFile 和WriteFile 读写串口时既可以同步执行也可以重叠执行.在同步执行时函数直到操作完成后才返回.这意味着同步执行时线程会被阻塞从而导致效率下降.在重叠执行时即使操作还未完成这两个函数也会立即返回费时的I/O 操作在后台进行. ReadFile 和WriteFile 函数是同步还是异步由CreateFile 函数决定如果在调用CreateFile 创建句柄时指定了FILE_FLAG_OVERLAPPED 标志那么调用ReadFile 和WriteFile 对该句柄进行的操作就应该是重叠的如果未指定重叠标志则读写操作应该是同步的.ReadFile 和WriteFile 函数的同步或者异步应该和CreateFile 函数相一致. ReadFile 函数只要在串口输入缓冲区中读入指定数量的字符就算完成操作.而WriteFile 函数不但要把指定数量的字符拷入到输出缓冲区而且要等这些字符从串行口送出去后才算完成操作. 如果操作成功这两个函数都返回TRUE.需要注意的是当ReadFile 和WriteFile返回FALSE 时不一定就是操作失败线程应该调用GetLastError 函数分析返回的结果.例如在重叠操作时如果操作还未完成函数就返回那么函数就返回FALSE而且GetLastError 函数返回ERROR_IO_PENDING.这说明重叠操作还未完成.下面是同步方式读写串口的示例://同步读串口charstr100DWORD wCount//读取的字节数BOOL bReadStatbReadStatReadFilehComstr100ampwCountNULLifbReadStat MessageBoxquot读串口失败quot return FALSEreturn TRUE//同步写串口char lpOutBuffer100DWORD dwBytesWrite100COMSTAT ComStatDWORD dwErrorFlagsBOOL bWriteStatClearCommErrorhComampdwErrorFlagsampComStatbWriteStatWriteFilehC omlpOutBufferdwBytesWriteamp dwBytesWriteNULLifbWriteStat MessageBoxquot写串口失败quotPurgeCommhComPURGE_TXABORTPURGE_RXABORTPURGE_TXCLEARPURGE_RXCLEAR 在重叠操作时操作还未完成函数就返回. 重叠I/O 非常灵活它也可以实现阻塞例如我们可以设置一定要读取到一个数据才能进行到下一步操作.有两种方法可以等待操作完成:一种方法是用象WaitForSingleObject 这样的等待函数来等待OVERLAPPED 结构的hEvent 成员另一种方法是调用GetOverlappedResult 函数等待后面将演示说明. 下面先简单介绍一下OVERLAPPED 结构和GetOverlappedResult 函数: OVERLAPPED 结构OVERLAPPED 结构包含了重叠I/O 的一些信息定义如下: typedef struct _OVERLAPPED DWORD Internal DWORD InternalHigh DWORD Offset DWORD OffsetHigh HANDLE hEvent OVERLAPPED 在使用ReadFile 和WriteFile 重叠操作时线程需要创建OVERLAPPED 结构以供这两个函数使用.线程通过OVERLAPPED 结构获得当前的操作状态该结构最重要的成员是hEvent.hEvent 是读写事件.当串口使用异步通讯时函数返回时操作可能还没有完成程序可以通过检查该事件得知是否读写完毕. 当调用ReadFile WriteFile 函数的时候该成员会自动被置为无信号状态当重叠操作完成后该成员变量会自动被置为有信号状态. GetOverlappedResult 函数BOOL GetOverlappedResult HANDLE hFile//串口的句柄//指向重叠操作开始时指定的OVERLAPPED 结构LPOVERLAPPED lpOverlapped //指向一个32 位变量该变量的值返回实际读写操作传输的字节数. LPDWORD lpNumberOfBytesTransferred //该参数用于指定函数是否一直等到重叠操作结束. //如果该参数为TRUE函数直到操作结束才返回. //如果该参数为FALSE函数直接返回这时如果操作没有完成//通过调用GetLastError函数会返回ERROR_IO_INCOMPLETE. BOOL bWait 该函数返回重叠操作的结果用来判断异步操作是否完成它是通过判断OVERLAPPED 结构中的hEvent 是否被置位来实现的.异步读串口的示例:char lpInBuffer1024DWORD dwBytesRead1024COMSTAT ComStatDWORD dwErrorFlagsOVERLAPPEDm_osReadmemsetampm_osRead0sizeofOVERLAPPEDm_osRead.hEventCreateEventN ULLTRUEFALSENULLClearCommErrorhComampdwErrorFlagsampComStatdwBytes ReadmindwBytesReadDWORDComStat.cbInQueifdwBytesReadreturn FALSEBOOL bReadStatusbReadStatusReadFilehComlpInBufferdwBytesReadampdwBytesReadampm _osReadifbReadStatus//如果ReadFile 函数返回FALSE ifGetLastErrorERROR_IO_PENDING //GetLastError函数返回ERROR_IO_PENDING表明串口正在进行读操作WaitForSingleObjectm_osRead.hEvent2000 //使用WaitForSingleObject 函数等待直到读操作完成或延时已达到2 秒钟//当串口读操作进行完毕后m_osRead 的hEvent 事件会变为有信号PurgeCommhCom PURGE_TXABORTPURGE_RXABORTPURGE_TXCLEARPURGE_RXCLEAR return dwBytesRead return 0PurgeCommhComPURGE_TXABORTPURGE_RXABORTPURGE_TXCLEARPURGE_RXCLEARreturn dwBytesRead 对以上代码再作简要说明:在使用ReadFile 函数进行读操作前应先使用ClearCommError 函数清除错误.ClearCommError 函数的原型如下: BOOL ClearCommError HANDLE hFile//串口句柄LPDWORD lpErrors//指向接收错误码的变量LPCOMSTAT lpStat//指向通讯状态缓冲区该函数获得通信错误并报告串口的当前状态同时该函数清除串口的错误标志以便继续输入、输出操作. 参数lpStat 指向一个COMSTAT 结构该结构返回串口状态信息.COMSTAT 结构COMSTAT 结构包含串口的信息结构定义如下: typedef struct _COMSTAT//cst DWORD fCtsHold : 1//Tx waiting for CTS signal DWORD fDsrHold : 1//Tx waiting for DSR signal DWORD fRlsdHold : 1//Tx waiting for RLSD signal DWORD fXoffHold : 1//Tx waitingXOFF char recd DWORD fXoffSent : 1//Tx waiting XOFF char sent DWORD fEof : 1//EOF character sent DWORD fTxim : 1//character waiting for Tx DWORD fReserved : 25//reserved DWORD cbInQue//bytes in input buffer DWORD cbOutQue//bytes in output buffer COMSTAT LPCOMSTAT 这里只用到了cbInQue 成员变量该成员变量的值代表输入缓冲区的字节数. 最后用PurgeComm 函数清空串口的输入输出缓冲区. 这段代码用WaitForSingleObject 函数来等待OVERLAPPED 结构的hEvent 成员.下面是调用GetOverlappedResult 函数等待的异步读串口示例:char lpInBuffer1024DWORD dwBytesRead1024BOOL bReadStatusDWORD dwErrorFlagsCOMSTAT ComStatOVERLAPPEDm_osReadClearCommErrorhComampdwErrorFlagsampComStatifComStat.cbInQue return0dwBytesReadmindwBytesReadDWORDComStat.cbInQuebReadStatusReadFilehCom lpInBufferdwBytesRead ampdwBytesReadampm_osReadifbReadStatus//如果ReadFile 函数返回FALSE ifGetLastErrorERROR_IO_PENDING GetOverlappedResulthComampm_osReadampdwBytesReadTRUE//GetOverlappedResult 函数的最后一个参数设为TRUE //函数会一直等待直到读操作完成或由于错误而返回. return dwBytesRead return 0return dwBytesRead异步写串口的示例:char buffer1024DWORD dwBytesWritten1024DWORD dwErrorFlagsCOMSTAT ComStatOVERLAPPED m_osWriteBOOL bWriteStatbWriteStatWriteFilehCombufferdwBytesWritten ampdwBytesWrittenampm_OsWriteifbWriteStat ifGetLastErrorERROR_IO_PENDING WaitForSingleObjectm_osWrite.hEvent1000 return dwBytesWritten return 0return dwBytesWritten四关闭串口利用API 函数关闭串口非常简单只需使用CreateFile 函数返回的句柄作为参数调用CloseHandle 即可: BOOL CloseHandle HANDLE hObject//handle to object to close 为了更好地理解串口编程下面分别编写两个实例这两个实例都实现了工控机与百特显示仪表通过RS485 接口进行的串口通信.其中第一个实例采用同步串口操作第二个实例采用异步串口操作.实例 1 打开VC6.0新建基于对话框的工程RS485Comm在主对话框窗口.。
【最新资料】MFC实现对串口通信的编写
在Windows应用程序的开发中,我们常常需要面临与外围数据源设备通信的问题。
计算机和单片机(如MCS-51)都具有串行通信口,可以设计相应的串口通信程序,完成二者之间的数据通信任务。
实际工作中利用串口完成通信任务的时候非常之多。
已有一些文章介绍串口编程的文章在计算机杂志上发表。
但总的感觉说来不太全面,特别是介绍32位下编程的更少,且很不详细。
笔者在实际工作中积累了较多经验,结合硬件、软件,重点提及比较新的技术,及需要注意的要点作一番探讨。
希望对各位需要编写串口通信程序的朋友有一些帮助一.串行通信的基本原理串行端口的本质功能是作为CPU和串行设备间的编码转换器。
当数据从 CPU经过串行端口发送出去时,字节数据转换为串行的位。
在接收数据时,串行的位被转换为字节数据。
在Windows环境(Windows NT、Win98、Windows2000)下,串口是系统资源的一部分。
应用程序要使用串口进行通信,必须在使用之前向操作系统提出资源申请要求(打开串口),通信完成后必须释放资源(关闭串口)。
串口通信程序的流程如下图:二.串口信号线的接法一个完整的RS-232C接口有22根线,采用标准的25芯插头座(或者9芯插头座)。
25芯和9芯的主要信号线相同。
以下的介绍是以25芯的RS-232C为例。
①主要信号线定义:2脚:发送数据TXD; 3脚:接收数据RXD; 4脚:请求发送RTS; 5脚:清除发送CTS;6脚:数据设备就绪DSR;20脚:数据终端就绪DTR;8脚:数据载波检测DCD;1脚:保护地; 7脚:信号地。
②电气特性:数据传输速率最大可到20K bps,最大距离仅15m.注:看了微软的MSDN 6.0,其Windows API中关于串行通讯设备(不一定都是串口RS-232C或RS-422或RS-449)速率的设置,最大可支持到RS_256000,即256K bps! 也不知道到底是什么串行通讯设备?但不管怎样,一般主机和单片机的串口通讯大多都在9600 bps,可以满足通讯需求。
用MFC实现串口编程
建议你用多线程,至少两个线程,数据接受和处理一个线程,数据显示一个线程;这样至少界面不会卡住的现象。
如果数据接收和处理计算量比较大,这两个还可以分两个线程。
数据接收直接调用串口驱动或则从网上下载一个关于串口数据读取封装类就可以了。
数据处理根据发送数据的情况对串口数据包进行解读,从数据包中解读出你想要的数据。
将解读好的数据放在一块共享内存中,通知界面线程来拿就可以了。
界面显示运用MFC的Timer和Draw函数进行刷新和绘制就可以了。
用MFC实现串口编程<作者:付杰本文详细介绍了串行通信的基本原理,以及在Windows NT、Win98环境下用MFC实现串口<COM)通信的方法:使用ActiveX控件或Win API.并给出用Visual C++6.0编写的相应MFC32位应用程序。
关键词:串行通信、VC++6.0、ActiveX控件、Win API、MFC32位应用程序、事件驱动、非阻塞通信、多线程. 在Windows应用程序的开发中,我们常常需要面临与外围数据源设备通信的问题。
计算机和单片机<如MCS-51)都具有串行通信口,可以设计相应的串口通信程序,完成二者之间的数据通信任务。
实际工作中利用串口完成通信任务的时候非常之多。
已有一些文章介绍串口编程的文章在计算机杂志上发表。
但总的感觉说来不太全面,特别是介绍32位下编程的更少,且很不详细。
笔者在实际工作中积累了较多经验,结合硬件、软件,重点提及比较新的技术,及需要注意的要点作一番探讨。
希望对各位需要编写串口通信程序的朋友有一些帮助。
一.串行通信的基本原理串行端口的本质功能是作为CPU和串行设备间的编码转换器。
当数据从 CPU经过串行端口发送出去时,字节数据转换为串行的位。
在接收数据时,串行的位被转换为字节数据。
在Windows环境<Windows NT、Win98、Windows2000)下,串口是系统资源的一部分。
应用程序要使用串口进行通信,必须在使用之前向操作系统提出资源申请要求<打开串口),通信完成后必须释放资源<关闭串口)。
用MFC编写简单串口
1.建立项目:打开VC++6.0,建立一个基于对话框的MFC应用程序SCommTest(与我源代码一致,等会你会方便一点);2.在项目中插入MSComm控件选择Project菜单下Add To Project子菜单中的Components and Controls…选项,在弹出的对话框中双击Registered ActiveX Controls项(稍等一会,这个过程较慢),则所有注册过的ActiveX控件出现在列表框中。
选择Microsoft Communications Control, version 6.0,,单击Insert按钮将它插入到我们的Project中来,接受缺省的选项。
(如果你在控件列表中看不到Microsoft Communications Control, version 6.0,那可能是你在安装VC6时没有把ActiveX一项选上,重新安装VC6,选上ActiveX 就可以了),这时在ClassView视窗中就可以看到CMSComm类了,(注意:此类在ClassWizard中看不到,重构clw文件也一样),并且在控件工具栏Controls中出现了电话图标(如图1所示),现在要做的是用鼠标将此图标拖到对话框中,程序运行后,这个图标是看不到的。
3.利用ClassWizard定义CMSComm类控制对象打开ClassWizard->Member Viariables选项卡,选择CSCommTestDlg类,为IDC_MSCOMM1添加控制变量:m_ctrlComm,这时你可以看一看,在对话框头文件中自动加入了//{{AFX_INCLUDES() #i nclude "mscomm.h" //}}AFX_INCLUDES (这时运行程序,如果有错,那就再从头开始)。
4.在对话框中添加控件向主对话框中添加两个编辑框,一个用于接收显示数据ID为IDC_EDIT_RXDATA,另一个用于输入发送数据,ID为IDC_EDIT_TXDATA,再添加一个按钮,功能是按一次就把发送编辑框中的内容发送一次,将其ID 设为IDC_BUTTON_MANUALSEND。
mfc串口通信发送16进制数据的方法
mfc串口通信发送16进制数据的方法MFC(Microsoft Foundation Class)提供了许多串口通信的功能来发送和接收数据。
在MFC中,我们可以使用CSerialPort类来完成串口通信,并且可以通过该类发送16进制数据。
以下是在MFC中进行串口通信并发送16进制数据的方法:1.创建一个MFC应用程序项目:首先,我们需要创建一个MFC应用程序项目。
打开Visual Studio,选择“创建新项目”,然后选择MFC应用程序向导。
按照向导的指示进行项目的设置,最后创建一个新的MFC应用程序项目。
2.添加CSerialPort类到项目中:在刚创建的MFC应用程序项目中,右击项目名称,选择“添加”->“类”,在弹出的对话框中选择“MFC类”。
在“MFC类向导”中,选择“添加到一个MFC最后调用的类中”,然后点击“完成”按钮。
现在,CSerialPort类将被添加到项目中。
3.初始化串口设置:打开您的对话框类(例如CMyDialog),在头文件中添加头文件#include "SerialPort.h"。
在对话框类的OnInitDialog()函数中,添加以下代码来初始化串口设置:```cppCSerialPort serialPort;if (serialPort.InitPort(1, 9600, 'N', 8, 1)){//初始化串口成功}else{//初始化串口失败}```InitPort()函数用于初始化串口参数,参数分别为:串口号,波特率,奇偶校验位,数据位,停止位。
以上代码中的示例将串口号设置为1,波特率为9600,无奇偶校验位,数据位为8,停止位为1。
4.发送16进制数据:在需要发送数据的地方,我们可以使用以下代码来发送16进制数据:```cppunsigned char hexData[] = { 0x01, 0x02, 0x03 };int dataSize = sizeof(hexData) / sizeof(hexData[0]);serialPort.SendData(hexData, dataSize);```SendData()函数用于发送数据,第一个参数为待发送数据的指针,第二个参数为待发送数据的大小。
VC6.0MFC串口通信编写全过程(推荐文档)
其于MFC 的串口调试助手编辑过程一、新建打开VC6.0 文件 新建 工程 MFC AppWiard(exe)位置(选择保存工程位置) 工程名称(输入工程名XXXX )确定 选择基本对话框 下一步 下一步 下一步 选择(CXXXXDlg ) 完成 确定 在生成的基本对话框内将不需要按钮及提示框(自动生成的“确定”“取消” 及提示框)删除或修改使用,至此基本框架完成如下图:二、往生成的基本框架中添加控件1、因为控件列表框内没有串口通信用到的通信控件,所以要先添加到控件列表框内再将控件添加到基本框内使用,步骤如下:菜单栏 工程 添加到工程 Components and controls … Registered ActiveX Controls 选择“Microsoft Communications Control, version 6.0” Insert 确定 OK 关闭此子窗口完成添加操作标志如上图所示。
2、将刚才添加添加到控件列表框内的串口控件添加到基本框架内 点击控件列表框内的串口控件,此时光标变为“十”形,在基本框架内随意划取一矩形区域,即可以添加串口控件,不需要修改此控件的大小及位置,因为程编译运行后此控件是看不到的,步骤结果如下图:3、继续往基本框架内添加用于编辑发送数据的输入编辑框及输出编辑框,同理选择控件列表框内的“编辑框控件”,以相同的操作即可添加两个编辑窗口及一个按纽控件如下图所示:这两个窗口需要修改大小及位置,因为程序运行后将会显示而串口通信控件则不显示,上图是运行后的效果。
4、对以上四个控件编程步骤如下:a 、右击串口通信控件 建立类向导Member variables Control IDS 中选择IDC_MSCOMM1 add variable … Member variable name 中输入控件变量名m_ctrlComm (变量名可以随意选取,但程序中应与所取变量名一致) OK 确定b、右击编辑框、属性、常规、ID:中输入ID号,此编辑框用于接收显示数据的其ID 号为IDC_EDIT_RXDATA(可以随意选取,但程序中应与所取ID号一致),再在此窗口的样式中勾选”多行”,同时将“自动水平滚动(T)”勾选去掉,再勾选“垂直滚动(V)”,此勾选操作是用于垂直多行显示的,按回车后即可输入;同理右击另一编辑框输入ID号为IDC_EDIT_TXDATA此编辑框用于编辑发送数据的,同样也选上用于垂直多行显示,发送框可以不用垂直多行显示;再为按钮控件添加ID号,为IDC_BUTTON_MANUALSEND,并将标题中的“Button1”改为“发送”,功能是按一次就把发送编辑框中的内容发送一次。
VS2021之MFC串口通信的编写教程
VS2021之MFC串口通信教程说明:本人也是方才入门MFC,参照一些资料和源代码就实验做了这么一个串口通信工具!资料来源要紧有鸡啄米博客网站,里面有详细的学习教程!网上的VS2021源代码都比较少,建议大伙儿先明白得一个源代码的构架和结构再深切学习!本文档能够一步一步教你从成立工程到实验调试,是一个超级完整的教程!超级适合新手练习!——贺州学院大学生创新基地实验室在制作串口通信所碰着的问题:编辑框的转动条可不能随着数据的更新维持在最后一行!接下来咱们开始讲解MFC串口通信的制作:一、打开VS2021软件,然后新建一个项目,如以下图所示;咱们要用到确实是对话框模块,因此选择如以下图所示最大化框最好别选,因为本人此刻也没弄出来;点击完成绩新建好一个工程了,等资源就绪以后咱们就可以够够进行制作了;咱们能够看到就绪以后的界面如以下图所示,依照步骤把原先的静态文本框和确信按钮、取消按钮删掉;二、为咱们的对话框添加控件添加两个组合边框,并放置好位置;修改组合边框显示的名称;在组合边框里面添加编辑文本框;在这一步必然要警戒选择右边的属性;这一步是把串口控件添加到对话框中来;选择咱们需要的串口控件如以下图所示;三、为编辑框,Combox框,串口控件添加变量;四、为按钮和串口控件添加程序函数void C串口V2Dlg::OnBnClickedButtonOpen()//打开串口按钮程序{// TODO: 在此添加控件通知处置程序代码?CString str,str1,n; //概念字符串GetDlgItemText(IDC_BUTTON_OPEN,str);CWnd *h1;h1=GetDlgItem(IDC_BUTTON_OPEN); //指向控件的captionif(!m_mscom.get_PortOpen()){m_comb2.GetLBText(m_comb2.GetCurSel(),str1);//取得所选的字符串,并寄放在str1里面str1=str1+','+'n'+','+'8'+','+'1'; //这句话很关键m_mscom.put_CommPort((m_comb1.GetCurSel()+1)); //选择串口m_mscom.put_InputMode(1); //设置输入方式为二进制方式m_mscom.put_Settings(str1); //波特率为(波特率组Á合框)无校验,8数据位,1个停止位m_mscom.put_InputLen(1024); //设置当前接收区数据长度为1024m_mscom.put_RThreshold(1); //缓冲区一个字符引发事件m_mscom.put_RTSEnable(1); //设置RT许诺m_mscom.put_PortOpen(true); //打开串口if(m_mscom.get_PortOpen()){str=_T("关闭串口");UpdateData(true);h1->SetWindowText(str); //改变按钮名称为‘’关闭串口”}}else{m_mscom.put_PortOpen(false);if(str!=_T("打开串口)){str=_T("打开串口");UpdateData(true);h1->SetWindowText(str); //改变按钮名称为打开串口}}}void C串口V2Dlg::OnBnClickedButtonSend()//发送数据按钮程{// TODO: 在此添加控件通知处置程序代码?UpdateData(true); //更新控件数据m_mscom.put_Output(COleVariant(m_Editsend));//把发送编辑框的数据发送出去}void C串口V2Dlg::OnBnClickedButtonClean()//清除数据按钮程序{// TODO: 在此添加控件通知处置程序代码m_EditReceive=_T(""); //给接收编辑框发送空格符UpdateData(false); //更新数据}void C串口V2Dlg::OnBnClickedButtonClose()//退出按钮程序{// TODO: 在此添加控件通知处置程序代码if(m_mscom.get_PortOpen())m_mscom.put_PortOpen(false);CDialogEx::OnCancel();}void C串口V2Dlg::OnCommMscomm1()//串口控件程序{// TODO: 在此处添加消息处置程序代码if(m_mscom.get_CommEvent()==2){char str[1024]={0};long k;VARIANT InputData=m_mscom.get_Input(); //读缓冲区COleSafeArray fs;fs=InputData; //VARIANT型变À量转换为COleSafeArray型变量for(k=0;k<fs.GetOneDimSize();k++)fs.GetElement(&k,str+k); //转换为BYTE型数组m_EditReceive+=str; // 接收到编辑框里面//SetTimer(1,10,NULL); //延时10msUpdateData(false);}}// 串口选择组合框CString str;int i;for(i=0;i<15;i++){str.Format(_T("com %d"),i+1);m_comb1.InsertString(i,str); }m_comb1.SetCurSel(0);//预置COM口//波特率选择组合框CString str1[]={_T("300"),_T("600"),_T("1200"),_T("2400"),_T("4800"),_T("9600"), _T("19200"),_T("38400"),_T("43000"),_T("56000"),_T("57600"),_T("115200")};for(int i=0;i<12;i++){int judge_tf=m_comb2.AddString(str1[i]);if((judge_tf==CB_ERR)||(judge_tf==CB_ERRSPACE))MessageBox(_T("build baud error!"));}m_comb2.SetCurSel(5);//预置波特率为"9600"写完以后编译程序五、调试咱们写好的串口工具咱们下面用51单片机调试一下,结果也是成功的;m_Edit.SetSel(-1, -1);this->SetDlgItemTextW(IDC_EDIT1,m_EditReceive);//将m_EditReceive内容显示到ID为IDC_EDIT1的编辑框的最后位置m_Edit.LineScroll(m_Edit.GetLineCount()-1,0);//将垂直转动条转动到最后一修改一下接收编辑框的属性,发送编辑框不用做修改;再调试一下觉察问题解决了!六、修改图标和软件信息咱们去到项目所在的文件夹中,如以下图所示;The End!刘小二2021年5月2日礼拜五。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
串口的操作可以有两种操作方式:同步操作方式和重叠操作方式(又称为异步操作方式.同步操作时,API函数会阻塞直到操作完成以后才能返回(在多线程方式中,
}
return TRUE;
二配置串口
在打开通讯设备句柄后,常需要对串口进行一些初始化配置工作.这需要通过一个DCB结构来进行.DCB结构包含了诸如波特率、数据位数、奇偶校验和停止位数等信息.在查询或配置串口的属性时,都要用DCB结构来作为缓冲区.
一般用CreateFile打开串口后,可以调用GetCommState函数来获取串口的初始配置.要修改串口的配置,应该先修改DCB结构,然后再调用SetCommState函数设置串口.
//EVENPARITY偶校验NOPARITY无校验
//MARKPARITY标记校验ODDPARITY奇校验
BYTE StopBits;//指定停止位的位数.此成员可以有下列值:
//ONESTOPBIT 1位停止位TWOSTOPBITS 2位停止位
//ONE5STOPBITS 1.5位停止位
………
} DCB;
0,//同步方式
NULL;
if(hCom==(HANDLE-1
{
MessageBox("打开COM失败!";
return FALSE;
}
return TRUE;
重叠I/O打开串口的示例:
HANDLE hCom;//全局变量,串口句柄
hCom =CreateFile("COM1",//串口名称
GENERIC_READ|GENERIC_WRITE,//允许读和写
//CBR_56000,CBR_57600,CBR_115200,CBR_128000,CBR_256000,CBR_14400
DWORD fParity;//指定奇偶校验使能.若此成员为1,允许奇偶校验检查
…
BYTE ByteSize;//通信字节位数,4—8
BYTE Parity;//指定奇偶校验方法.此成员可以有下列值:
•lpSecurityAttributes:引用安全性属性结构,缺省值为NULL;
•dwCreationDistribution:创建标志,对串口操作该参数必须置为OPEN_EXISTING;
•dwFlagsAndAttributes:属性描述,用于指定该串口是否进行异步操作,该值为FILE_FLAG_OVERLAPPED,表示使用异步的I/O;该值为0,表示同步I/O操
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile;
•lpFileName:将要打开的串口逻辑名,如“COM1”;
•dwDesiredAccess:指定串口访问的类型,可以是读取、写入或二者并列;
•dwShareMode:指定共享属性,由于串口不能共享,该参数必须置为0;
0,//独占方式
NULL,
OPEN_EXISTING,//打开而不是创建
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,//重叠方式NULL;
if(hCom==INVALID_HANDLE_VALUE
{
MessageBox("打开COM失败!";
return FALSE;
DCB结构包含了串口的各项参数设置,下面仅介绍几个该结构常用的变量: typedef struct _DCB{
………
//波特率,指定通信设备的传输速率.这个成员可以是实际波特率值或者下面的常量值之一:
DWORD BaudRate;
//CBR_110,CBR_300,CBR_600,CBR_1200,CBR_2400,CBR_4800,CBR_9600,CBR_19200, //CBR_38400,
HANDLE CreateFile( LPCTSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDistribution,
虽然不会阻塞主线程,但是仍然会阻塞监听线程;而重叠操作方式,API函数会立即返回,操作在后台进行,避免线程的阻塞.
无论哪种操作方式,一般都通过四个步骤来完成:
(1打开串口
(2配置串口
(3读写串口
(4关闭串口
一打开串口
Win32系统把文件的概念进行了扩展.无论是文件、通信设备、命名管道、邮件槽、磁盘、还是控制台,都是用API函数CreateFile来打开或创建的.该函数的原型为:
在winbase.h文Biblioteka 中定义了以上用到的常量.如下所示:
#define NOPARITY 0
#define ODDPARITY 1
#define EVENPARITY 2
#define ONESTOPBIT 0
#define ONE5STOPBITS 1
#define TWOSTOPBITS 2
作;
•hTemplateFile:对串口而言该参数必须置为NULL;
同步I/O方式打开串口的示例:
HANDLE hCom;//全局变量,串口句柄
hCom=CreateFile("COM1",//串口名称
GENERIC_READ|GENERIC_WRITE,//允许读和写
0,//独占方式
NULL,
OPEN_EXISTING,//打开而不是创建
MFC串口通信编程介绍
主要介绍了用CreateFile(函数和WriteFile(函数读写串口的实例,以及设置串口属性的实例.
在工业控制中,工控机(一般都基于Windows平台经常需要与智能仪表通过串口
进行通信.串口通信方便易行,应用广泛.
一般情况下,工控机和各智能仪表通过RS485总线进行通信.RS485的通信方式是半双工的,只能由作为主节点的工控PC机依次轮询网络上的各智能控制单元子节点.每次通信都是由PC机通过串口向智能控制单元发布命令,智能控制单元在接收到正确的命令后作出应答.