VS2010之MFC串口通信的编写教程
- 格式:doc
- 大小:5.86 MB
- 文档页数:32
利用 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类进行串行通信,代码简单、编程量小,可应用于在线监测、自动化控制等许多方面,对科研、生产有着广泛的实用价值。
首先,打开VS2010,新建一个MFC 工程,我们命名为SCommT est。
删掉原来的两个按钮和一个静态文本,在标题栏上右键属性,然后更改标题名:串口通信助手1.0 beta。
画程序的界面首先画两个组框,分别为显示区和发送区。
然后在显示区内部画一个编辑框,ID 改为IDC_EDIT_RECV。
样式更改如下:在发送区内画一个编辑框,ID 改为IDC_EDIT_SEND,样式更改如下:最后画一个发送按钮就大功告成啦!按钮ID 改为IDC_BUTTON_SEND。
插入MSComm类添加一个MScomm 控件,就是这个控件为我们完成串口通信的功能。
右键添加变量接下来添加函数首先为MSComm 控件添加一个函数OnComm,主要用于接收串口发送来的消息然后为发送按钮添加一个函数OnButtonSend,主要用于给串口发送消息。
添加的方式是双击控件,修改函数名称,确认即可。
如下两图:首先,要记住,工程中有好几个CPP 文件和H 头文件,但是我们要添加的代码,都是写在SCommT estDlg.CPP 文件中的。
//---------------------------------------------------------------------------//添加的对串口的初始化语句if(m_cComm.get_PortOpen()) //如果发现串口本来是打开的,则关闭串口m_cComm.put_PortOpen(FALSE);m_cComm.put_CommPort(1); //选择COM1端口m_cComm.put_InputMode(1); //输入方式为二进制方式m_cComm.put_InBufferSize(1024); //设置输入缓冲区m_cComm.put_OutBufferSize(512); //设置输出缓冲区m_cComm.put_Settings(TEXT("9600,n,8,1"));//波特率9600,无校验,8个数据位,1个停止位m_cComm.put_Settings(_T("9600,n,8,1"));if(!m_cComm.get_PortOpen()){m_cComm.put_PortOpen(TRUE); //打开串口m_cComm.put_RThreshold(1); //每当接收缓冲区有1个字符则接收串口数据m_cComm.put_InputLen(0); //设置当前缓冲区长度为0m_cComm.get_Input(); //预读缓冲区以清除残留数据}elseAfxMessageBox(TEXT("打开端口失败!"),MB_ICONSTOP,0);AfxMessageBox(_T("打开端口失败!"),MB_ICONSTOP,0);//---------------------------------------------------------------------------void CSCommT estDlg::OnComm(){// TODO: 在此添加命令处理程序代码//---------------------------------------------------------------------------//从串口接收数据并显示在编辑框中VARIANT variant_inp;COleSafeArray safearray_inp;long len,k;byte rxdata[512]; //设置BYTE数组CString strtemp;if(m_cComm.get_CommEvent()==2) //值为2表示接收缓冲区内有字符{variant_inp=m_cComm.get_Input(); //读缓冲区消息safearray_inp=variant_inp; ///变量转换len=safearray_inp.GetOneDimSize(); //得到有效的数据长度for(k=0;k<len;k++)safearray_inp.GetElement(&k,rxdata+k);for(k=0;k<len;k++) //将数组转换为CString型变量{char bt=*(char*)(rxdata+k); //字符型strtemp.Format(TEXT("%c"),bt); //将字符送入临时变量strtemp存放strtemp.Format(_T("%c"),bt);m_strRecvData+=strtemp; //加入接收编辑框对应字符串}}CString temp=(TEXT("\r\n")); //显示完成后要自动换行m_strRecvData+=temp;UpdateData(FALSE); //更新编辑框内容//--------------------------------------------------------------------------- }void CSCommT estDlg::OnButtonSend(){// TODO: 在此添加控件通知处理程序代码//---------------------------------------------------------------------------//单击发送按钮的操作UpdateData(true); //读取编辑框内容m_cComm.put_Output(COleVariant(m_strSendData));//发送数据m_strSendData.Empty(); //发送后清空输入框UpdateData(false); //更新编辑框内容//对发送的数据进行强制类型转换,由CString 字符串数据转换为VARIANT 类型。
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 提供了强大的串口通信功能,通过例程的方式,帮助开发者快速实现串口通信功能。
VS2010/MFC编程入门之三(VS2010应用程序工程中文件的组成结构)这里将以前面的生成应用程序HelloWorld的文件结构为例,讲解VS2010应用程序工程中文件的组成结构。
用应用程序向导生成框架程序后,我们可以在之前设置的Location下看到以解决方案名命名的文件夹,此文件夹中包含了几个文件和一个以工程名命名的子文件夹,这个子文件夹中又包含了若干个文件和一个res文件夹,创建工程时的选项不同,工程文件夹下的文件可能也会有所不同。
如果已经以Debug方式编译链接过程序,则会在解决方案文件夹下和工程子文件夹下各有一个名为“Debug”的文件夹,而如果是Release方式编译则会有名为“Release”的文件夹。
这两种编译方式将产生两种不同版本的可执行程序:Debug版本和Release 版本。
Debug版本的可执行文件中包含了用于调试的信息和代码,而Release版本则没有调试信息,不能进行调试,但可执行文件比较小。
将所有文件分为6个部分:解决方案相关文件、工程相关文件、应用程序头文件和源文件、资源文件、预编译头文件和编译链接生成文件。
1.解决方案相关文件解决方案相关文件包括解决方案文件夹下的.sdf文件、.sln文件、.suo文件和ipch文件夹。
.sdf文件和ipch目录一般占用空间比较大,几十兆甚至上百兆,与智能提示、错误提示、代码恢复和团队本地仓库等相关。
如果你觉得不需要则可以设置不生成它们,方法是点击菜单栏Tools->Options,弹出Options对话框,选择左侧面板中Text Editor->C/C++->Advanced,右侧列表中第一项Disable Database由False改为True就可以了,最后关闭VS2010再删除.sdf文件和ipch目录以后就不会再产生了。
但关闭此选项以后也会有很多不便,例如写程序时的智能提示没有了。
.sln文件和.suo文件为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在主对话框窗口.。
VS2010/MFC编程入门之前言鸡啄米的C++编程入门系列给大家讲了C++的编程入门知识,大家对C++语言在语法和设计思想上应该有了一定的了解了。
但是教程中讲的例子只是一个个简单的例程,并没有可视化窗口。
鸡啄米在这套VS2010/MFC编程入门教程中将会给大家讲解怎样使用VS2010进行可视化编程,也就是基于窗口的程序。
C++编程入门系列主要偏重于理论方面的知识,目的是让大家打好底子,练好内功,在使用VC++编程时不至于丈二和尚摸不着头脑。
本套教程也会涉及到VC++的原理性的东西,同样更重视实用性,让大家学完本套教程以后,基本的界面程序都能很容易编写出来。
VC++简介VC++全称是Visual C++,是由微软提供的C++开发工具,它与C++的根本区别就在于,C++是语言,而VC++是用C++语言编写程序的工具平台。
VC++不仅是一个编译器更是一个集成开发环境,包括编辑器、调试器和编译器等,一般它包含在Visual Studio中。
Visual Studio包含了VB、VC++、C#等编译环境。
当然我们在使用VC++ 6.0的时候为了轻便,总是只单独安装VC++ 6.0。
但自微软2002年发布Visual 以来,微软建立了在.NET框架上的代码托管机制,一个项目可以支持多种语言开发的组件,VC++同样被扩展为支持代码托管机制的开发环境,所以.NET Framework是必须的,也就不再有VC++的独立安装程序,不过可以在安装Visual Studio时只选择VC++进行安装。
VC++版本的选择:VS2010因为VC++ 6.0以后的版本不再有独立的安装程序,所以鸡啄米在教程中将不会称VC++ 6.0以后的版本为VC++ 7.0等等,而是用VC++所属的Visual Studio的版本名称代替,比如VS2003。
近些年VC++主要的版本包括:VC++ 6.0、VS2003、VS2005、VS2008和VS2010。
在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,可以满足通讯需求。
VS2010/MFC编程入门之二(利用MFC向导生成单文档应用程序框架)这里给大家一个简单的例子,演示如何生成单文档应用程序框架。
解决方案与工程在VS2010的使用介绍中已经讲了解决方案与工程的概念,这里再重提一下。
每个应用程序都作为一个工程来处理,它包含了头文件、源文件和资源文件等,这些文件通过工程集中管理。
在VS2010中,工程都是在解决方案管理之下的。
一个解决方案可以管理多个工程,可以把解决方案理解为多个有关系或者没有关系的工程的集合。
VS2010提供了一个Solution Explorer解决方案浏览器视图,可以显示当前解决方案的内容,当新建一个工程时可以选择新建一个解决方案还是加入当前解决方案。
下图左侧面板中正在显示的视图就是Solution Explorer,视图中有一个解决方案-HelloWorld,此解决方案下有一个同名的工程-HelloWorld。
在应用程序向导生成应用程序后,VS2010会在用户设置的路径下,以解决方案名为名称建立一个目录,里面存放自动生成的文件。
使用VS2010应用程序向导生成单文档应用程序框架这里简略演示下怎样生成单文档应用程序框架,让大家先有个直观的了解,有不理解的地方可以留着以后回来再看。
下面按照操作步骤一步步讲解:1.点菜单栏File->New->Project,弹出New Project对话框,我们可以选择工程类型。
如果安装完VS2010以后第一启动时已经设置为VC++,则Installed Templates->Visual C++项会默认展开,而如果没有设置VC++,则可以展开到Installed Templates->Other Languages->Visual C++项。
因为我们要生成的是MFC程序,所以在“Visual C++”下选择“MFC”,对话框中间区域会出现三个选项:MFC ActiveX Control、MFC Application和MFC DLL。
visualbasic串口通信及编程实例Visual Basic串口通信及编程实例在实际的工业控制、机器人控制、智能家居等领域中,使用串口通信是一种非常广泛的方式。
Visual Basic (VB) 是一种微软公司开发的高级编程语言,它不仅易于学习,而且拥有丰富的图形界面设计和数据处理功能。
在本篇文章中,我们将深入介绍如何使用VB实现串口通信。
1. 建立串口通信首先,我们需要在VB中创建一个新的窗口(Form),然后打开工具箱,从中拖拽出一个SerialPort(串口)控件。
在控件属性中,我们需要为其指定相关的参数,例如串口名称、波特率、数据位、停止位、校验位等。
通常情况下,这些参数需要根据硬件设备的配置来进行调整。
在VB中实现串口通信的核心部分是对于SerialPort控件的事件监控。
具体来讲,当SerialPort收到一个数据包时,它会触发一个DataReceived事件。
对于这个事件,我们可以在程序中编写回调函数进行处理。
例如:Private Sub SerialPort1_DataReceived(ByVal sender As System.Object, ByVal e AsSystem.IO.Ports.SerialDataReceivedEventArgs) HandlesSerialPort1.DataReceived'在这里实现对于数据包的解析和处理End Sub2. 数据读取和发送在SerialPort控件中,有几种方法可以实现数据的读取和发送。
下面我们将介绍其中两种方法:(1) ReadExisting这个方法可以从串口中读取所有现有的数据,例如:Dim data As String = SerialPort1.ReadExisting()(2) Write这个方法可以向串口发送数据,例如:SerialPort1.Write("Hello World")注意,这个函数只能发送字符串数据。
基于vs2010-mfc简易串口数据波形显示软件(入门篇)软件版本vs2010旗舰版文件—新建—项目选择基本对话框语言—美国英语,若选择中国汉语,可能这版本没破解好,会有些问题。
后面就一直下一步,直到完成。
在右边工具箱中,添加下面需要用到的控件。
如下图右击类向导---项目com 类名CcomDlg。
点击成员变量,分别给他们添加变量名。
添加完如下图:添加串口控件。
右击插入Active控件(X),找到如下确定。
界面出现串口控件(小电话一样的东东)点击串口控件(小电话)右键添加变量,输入变量名m_mscomm ,同时下方出现mscomm1.h 和mscomm1.cpp,点击确定,坐标目录生成该两个文件点击菜单栏工具---选择工具箱项(X)--点击COM组件,浏览找到TeeChart8.ocx,可由网上下载。
然后添加如下之后再工具箱中最下面便可看到该控件接下来拉出图形界面。
进入类向导,点击右上角 添加类(C)—>类型库中的MFC类(T)…添加这5个类这里有很多这里有很多这里有很多在comDlg.cpp文件中添加头文件#include"CTChart.h"#include"CAxis.h"#include"CAxes.h"#include"CScroll.h"#include"CSeries.h"双击teechart,添加曲线Add这里模板很丰富,这里我们选择FastLine标题命名、初值点设置Data中、左轴底轴显示设置在Axis中,以及其他功能到此,基本框架已经搭好了 后面添加程序 双击打开串口按钮添加代码如下:void CcomDlg::OnBnClickedButtonOpen(){// TODO: 在此添加控件通知处理程序代码if( !m_mscomm.get_PortOpen()){m_mscomm.put_PortOpen(true);SetDlgItemText(IDC_BUTTON_OPEN,_T("关闭串口"));AfxMessageBox(_T("串口打开成功"));}else{m_mscomm.put_PortOpen(FALSE);SetDlgItemText(IDC_BUTTON_OPEN,_T("打开串口"));}}双击发送按钮。
VS2010/MFC编程入门教程之目录第一部分:VS2010/MFC开发环境VS2010/MFC编程入门之前言VS2010/MFC编程入门之一(VS2010与MSDN安装过程图解)第二部分:VS2010/MFC应用程序框架VS2010/MFC编程入门之二(利用MFC向导生成单文档应用程序框架)VS2010/MFC编程入门之三(VS2010应用程序工程中文件的组成结构)VS2010/MFC编程入门之四(MFC应用程序框架分析)VS2010/MFC编程入门之五(MFC消息映射机制概述)第三部分:对话框VS2010/MFC编程入门之六(对话框:创建对话框模板和修改对话框属性)VS2010/MFC编程入门之七(对话框:为对话框添加控件)VS2010/MFC编程入门之八(对话框:创建对话框类和添加控件变量)VS2010/MFC编程入门之九(对话框:为控件添加消息处理函数)VS2010/MFC编程入门之十(对话框:设置对话框控件的Tab顺序)VS2010/MFC编程入门之十一(对话框:模态对话框及其弹出过程)VS2010/MFC编程入门之十二(对话框:非模态对话框的创建及显示)VS2010/MFC编程入门之十三(对话框:属性页对话框及相关类的介绍)VS2010/MFC编程入门之十四(对话框:向导对话框的创建及显示)VS2010/MFC编程入门之十五(对话框:一般属性页对话框的创建及显示)VS2010/MFC编程入门之十六(对话框:消息对话框)VS2010/MFC编程入门之十七(对话框:文件对话框)VS2010/MFC编程入门之十八(对话框:字体对话框)VS2010/MFC编程入门之十九(对话框:颜色对话框)第四部分:常用控件VS2010/MFC编程入门之二十(常用控件:静态文本框)VS2010/MFC编程入门之二十一(常用控件:编辑框Edit Control)VS2010/MFC编程入门之二十二(常用控件:按钮控件Button、Radio Button和Check Box)VS2010/MFC编程入门之二十三(常用控件:按钮控件的编程实例)VS2010/MFC编程入门之二十四(常用控件:列表框控件ListBox)VS2010/MFC编程入门之二十五(常用控件:组合框控件Combo Box)VS2010/MFC编程入门之二十六(常用控件:滚动条控件Scroll Bar)VS2010/MFC编程入门之二十七(常用控件:图片控件Picture Control)VS2010/MFC编程入门之二十八(常用控件:列表视图控件List Control 上)VS2010/MFC编程入门之二十九(常用控件:列表视图控件List Control 下)VS2010/MFC编程入门之三十(常用控件:树形控件Tree Control 上)VS2010/MFC编程入门之三十一(常用控件:树形控件Tree Control 下)VS2010/MFC编程入门之三十二(常用控件:标签控件Tab Control 上)VS2010/MFC编程入门之三十三(常用控件:标签控件Tab Control 下)第五部分:菜单、工具栏与状态栏VS2010/MFC编程入门之三十四(菜单:VS2010菜单资源详解)VS2010/MFC编程入门之三十五(菜单:菜单及CMenu类的使用)VS2010/MFC编程入门之三十六(工具栏:工具栏资源及CToolBar类)VS2010/MFC编程入门之三十七(工具栏:工具栏的创建、停靠与使用)VS2010/MFC编程入门之三十八(状态栏的使用详解)第六部分:文档、视图和框架VS2010/MFC编程入门之三十九(文档、视图和框架:概述)VS2010/MFC编程入门之四十(文档、视图和框架:各对象之间的关系)VS2010/MFC编程入门之四十一(文档、视图和框架:分割窗口)第七部分:MFC常用类VS2010/MFC编程入门之四十二(MFC常用类:CString类)VS2010/MFC编程入门之四十三(MFC常用类:CTime类和CTimeSpan类)VS2010/MFC编程入门之四十四(MFC常用类:定时器Timer)VS2010/MFC编程入门之四十五(MFC常用类:CFile文件操作类)VS2010/MFC编程入门之四十六(MFC常用类:MFC异常处理)第八部分:字体和文本输出VS2010/MFC编程入门之四十七(字体和文本输出:CFont字体类)VS2010/MFC编程入门之四十八(字体和文本输出:文本输出)第九部分:图形图像VS2010/MFC编程入门之四十九(图形图像:CDC类及其屏幕绘图函数)VS2010/MFC编程入门之五十(图形图像:GDI对象之画笔CPen)VS2010/MFC编程入门之五十一(图形图像:GDI对象之画刷CBrush)第十部分:Ribbon界面开发VS2010/MFC编程入门之五十二(Ribbon界面开发:创建Ribbon样式的应用程序框架)VS2010/MFC编程入门之五十三(Ribbon界面开发:为Ribbon Bar添加控件)VS2010/MFC编程入门之五十四(Ribbon界面开发:使用更多控件并为控件添加消息处理函数)VS2010/MFC编程入门之前言鸡啄米的C++编程入门系列给大家讲了C++的编程入门知识,大家对C++语言在语法和设计思想上应该有了一定的了解了。
VS2010之MFC串口通信教程
说明:本人也是刚刚入门MFC,参照一些资料和源代码就实验做了这么一个串口通信工具!资料来源主要有鸡啄米博客网站,里面有详细的学习教程!网上的VS2010源代码都比较少,建议大家先理解一个源代码的构架和结构再深入学习!本文档可以一步一步教你从建立工程到实验调试,是一个非常完整的教程!非常适合新手练习!
——贺州学院大学生创新基地实验室
在制作串口通信所遇到的问题:编辑框的滚动条不会随着数据的更新保持在最后一行!
接下来我们开始讲解MFC串口通信的制作:
一、打开VS2010软件,然后新建一个项目,如下图所示;
我们要用到就是对话框模块,所以选择如下图所示
最大化框最好别选,因为本人现在也没搞出来;
点击完成就新建好一个工程了,等资源就绪之后我们就可以进行制作了;
我们可以看到就绪之后的界面如下图所示,按照步骤把原来的静态文本框和确定按钮、取消按钮删掉;
二、为我们的对话框添加控件添加两个组合边框,并放置好位置;
修改组合边框显示的名称;
在组合边框里面添加编辑文本框;
在这一步一定要小心选择右边的属性;
这一步是把串口控件添加到对话框中来;选择我们需要的串口控件如下图所示;
三、为编辑框,Combox框,串口控件添加变量;
四、为按钮和串口控件添加程序函数
void C串口V2Dlg::OnBnClickedButtonOpen()//打开串口按钮程序
{
// TODO: 在此添加控件通知处理程序代码?
CString str,str1,n; //定义字符串
GetDlgItemText(IDC_BUTTON_OPEN,str);
CWnd *h1;
h1=GetDlgItem(IDC_BUTTON_OPEN); //指向控件的caption
if(!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); //设置当前接收区数据长度为1024
m_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); //延时10ms
UpdateData(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!
作者:刘小二
2014年5月2日星期五。