⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 csdn_文档中心_用vc 6_0实现串行通信的三种方法.htm

📁 csdn10年中间经典帖子
💻 HTM
📖 第 1 页 / 共 2 页
字号:
            <P><FONT color=#ffffff>----</FONT> 
            在ClassWizard中为新创建的通信控件定义成员对象(CMSComm 
            m_Serial),通过该对象便可以对串口属性进行设置,MSComm 控件共有27个属性,这里只介绍其中几个常用属性: 
            <P><FONT color=#ffffff>----</FONT> CommPort 设置并返回通讯端口号,缺省为COM1。 
            <P><FONT color=#ffffff>----</FONT> Settings 
            以字符串的形式设置并返回波特率、奇偶校验、数据位、停止位。 
            <P><FONT color=#ffffff>----</FONT> PortOpen 设置并返回通讯端口的状态,也可以打开和关闭端口。 

            <P><FONT color=#ffffff>----</FONT> Input 从接收缓冲区返回和删除字符。 
            <P><FONT color=#ffffff>----</FONT> Output 向发送缓冲区写一个字符串。 
            <P><FONT color=#ffffff>----</FONT> InputLen 
            设置每次Input读入的字符个数,缺省值为0,表明读取接收缓冲 区中的全部内容。 
            <P><FONT color=#ffffff>----</FONT> InBufferCount 
            返回接收缓冲区中已接收到的字符数,将其置0可以清除接收缓 冲区。 
            <P><FONT color=#ffffff>----</FONT> InputMode 
            定义Input属性获取数据的方式(为0:文本方式;为1:二进制方式)。 
            <P><FONT color=#ffffff>----</FONT> RThreshold 和 SThreshold 属性,表示在 
            OnComm 事件发生之前,接收缓冲区或发送缓冲区中可以接收的字符数。 
            <P><FONT color=#ffffff>----</FONT> 以下是通过设置控件属性对串口进行初始化的实例: <PRE>BOOL    CSampleDlg:: PortOpen()
{
BOOL   m_Opened;
 ......
 m_Serial.SetCommPort(2);          //  指定串口号
 m_Serial.SetSettings("4800,N,8,1");   //  通信参数设置
 m_Serial.SetInBufferSize(1024);      //  指定接收缓冲区大小
 m_Serial.SetInBufferCount(0);        //  清空接收缓冲区
 m_Serial.InputMode(1);             //  设置数据获取方式
 m_Serial.SetInputLen(0);            //  设置读取方式
 m_Opened=m_Serail.SetPortOpen(1);           //   打开指定的串口
       return  m_Opened;
   }
</PRE>
            <P><FONT color=#ffffff>----</FONT> 
            打开所需串口后,需要考虑串口通信的时机。在接收或发送数据过程中,可能需要监视并响应一些事件和错误,所以事件驱动是处理串行端口交互作用的一种非常有效的方法。使用 
            OnComm 事件和 CommEvent 属性捕捉并检查通讯事件和错误的值。发生通讯事件或错误时,将触发 OnComm 
            事件,CommEvent 属性的值将被改变,应用程序检查 CommEvent 
            属性值并作出相应的反应。在程序中用ClassWizard为CMSComm控件添加OnComm消息处理函数: <PRE>void  CSampleDlg::OnComm()
{
  ......
  switch(m_Serial.GetCommEvent())
  {
     case  2:
       //  串行口数据接收,处理;
   }
}
</PRE>
            <P><FONT color=#ffffff>----</FONT> <FONT 
            color=#cc3300>方法二</FONT>:在单线程中实现自定义的串口通信类 
            <P><FONT color=#ffffff>----</FONT> 
            控件简单易用,但由于必须拿到对话框中使用,在一些需要在线程中实现通信的应用场合,控件的使用显得捉襟见肘。此时,若能够按不同需要定制灵活的串口通信类将弥补控件的不足,以下将介绍如何在单线程中建立自定义的通信类。 

            <P><FONT color=#ffffff>----</FONT> 
            该通信类CSimpleComm需手动加入头文件与源文件,其基类为CObject,大致建立步骤如下: 
            <P><FONT color=#ffffff>----</FONT> (1) 打开串口,获取串口资源句柄 
            <P><FONT color=#ffffff>----</FONT> 
            通信程序从CreateFile处指定串口设备及相关的操作属性。再返回一个句柄,该句柄将被用于后续的通信操作,并贯穿整个通信过程。CreateFile()函数中有几个值得注意的参数设置:串口共享方式应设为0,串口为不可共享设备;创建方式必须为OPEN_EXISTING,即打开已有的串口。对于dwFlagAndAttribute参数,对串口有意义的值是FILE_FLAG_OVERLAPPED,该标志表明串口采用异步通信模式,可进行重叠操作;若值为NULL,则为同步通信方式,在同步方式下,应用程序将始终控制程序流,直到程序结束,若遭遇通信故障等因素,将导致应用程序的永久等待,所以一般多采用异步通信。 

            <P><FONT color=#ffffff>----</FONT> (2)串口设置 
            <P><FONT color=#ffffff>----</FONT> 
            串口打开后,其属性被设置为默认值,根据具体需要,通过调用GetCommState(hComm,&amp;dcb)读取当前串口设备控制块DCB(Device 
            Control 
            Block)设置,修改后通过SetCommState(hComm,&amp;dcb)将其写入。再需注意异步读写的超时控制设置, 
            通过COMMTIMEOUTS结构设置超时,调用SetCommTimeouts(hComm,&amp;timeouts)将结果写入。以下是温度监控程序中串口初始化成员函数: 
<PRE>BOOL  CSimpleComm::Open( )
     {
	  DCB dcb;

m_hIDComDev=CreateFile( "COM2", 
GENERIC_READ | GENERIC_WRITE,
0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_
NORMAL|FILE_FLAG_OVE    RLAPPED, NULL );        
//  打开串口,异步操作
if( m_hIDComDev == NULL ) return( FALSE );

dcb.DCBlength = sizeof( DCB );
GetCommState( m_hIDComDev, &amp;dcb );  //  获得端口默认设置
dcb.BaudRate=CBR_4800;
dcb.ByteSize=8;
dcb.Parity= NOPARITY;
dcb.StopBits=(BYTE) ONESTOPBIT;
       ...... }
</PRE>
            <P><FONT color=#ffffff>----</FONT> (3)串口读写操作 
            <P><FONT color=#ffffff>----</FONT> 
            主要运用ReadFile()与WriteFile()API函数,若为异步通信方式,两函数中最后一个参数为指向OVERLAPPED结构的非空指针,在读写函数返回值为FALSE的情况下,调用GetLastError()函数,返回值为ERROR_IO_PENDING,表明I/O操作悬挂,即操作转入后台继续执行。此时,可以用WaitForSingleObject()来等待结束信号并设置最长等待时间,举例如下: 
<PRE>BOOL   bReadStatus;
    bReadStatus = ReadFile( m_hIDComDev, buffer, 
	dwBytesRead, &amp;dwBytesRead,    &amp;m_OverlappedRead );
    if(!bReadStatus)
	 {
	    if(GetLastError()==ERROR_IO_PENDING)
		{
       WaitForSingleObject(m_OverlappedRead.hEvent,1000);
			return ((int)dwBytesRead);
		}
		return(0);
	 }
	 return ((int)dwBytesRead);
</PRE>
            <P><FONT color=#ffffff>----</FONT> 
            定义全局变量m_Serial作为新建通信类CSimpleComm的对象,通过调用类的成员函数即可实现所需串行通信功能。与方法一相比,方法二赋予串行通信程序设计较大的灵活性,端口的读写可选择较简单的查询式,或通过设置与外设数据发送时间间隔TimeCycle相同的定时器:SetTimer(1,TimeCycle,NULL),进行定时读取或发送。 
<PRE>CSampleView:: OnTimer(UINT nIDEvent)
     {
       char  InputData[30];
       m_Serial.ReadData(InputData,30);
       // 数据处理
     } </PRE>
            <P><FONT color=#ffffff>----</FONT> 
            若对端口数据的响应时间要求较严格,可采用事件驱动I/O读写,Windows定义了9种串口通信事件,较常用的有: 
            <P><FONT color=#ffffff>----</FONT> EV_RXCHAR: 接收到一个字节,并放入输入缓冲区。 
            <P><FONT color=#ffffff>----</FONT> EV_TXEMPTY: 输出缓冲区中的最后一个字符发送出去。 
            <P><FONT color=#ffffff>----</FONT> EV_RXFLAG: 
            接收到事件字符(DCB结构中EvtChar成员),放入输入缓冲区。 
            <P><FONT color=#ffffff>----</FONT> 
            在用SetCommMask()指定了有用的事件后,应用程序可调用WaitCommEvent()来等待事件的发生。SetCommMask(hComm,0)可使WaitCommEvent()中止。 

            <P><FONT color=#ffffff>----</FONT> <FONT color=#cc3300>方法三</FONT> 
            多线程下实现串行通信 
            <P><FONT color=#ffffff>----</FONT> 
            方法一,二适用于单线程通信。在很多工业控制系统中,常通过扩展串口连接多个外设,各外设发送数据的重复频率不同,要求后台实时无差错捕捉,采集,处理,记录各端口数据,这就需要在自定义的串行通信类中创建端口监视线程,以便在指定的事件发生时向相关的窗口发送通知消息。 

            <P><FONT color=#ffffff>----</FONT> 
            线程的基本概念可详见VC++参考书目,Windows内部的抢先调度程序在活动的线程之间分配CPU时间,Win 32 
            区分两种不同类型的线程,一种是用户界面线程UI(User Interface 
            Thread),它包含消息循环或消息泵,用于处理接收到的消息;另一种是工作线程(Work 
            Thread),它没有消息循环,用于执行后台任务。用于监视串口事件的线程即为工作线程。 
            <P><FONT color=#ffffff>----</FONT> 
            多线程通信类的编写在端口的配置,连接部分与单线程通信类相同,在端口配置完毕后,最重要的是根据实际情况,建立多线程之间的同步对象,如信号灯,临界区,事件等,相关细节可参考VC++ 
            中的同步类。 
            <P><FONT color=#ffffff>----</FONT> 一切就绪后即可启动工作线程: <PRE>CWinThrea *CommThread = AfxBegin
Thread(CommWatchThread,  // 线程函数名
 (LPVOID) m_pTTYInfo,                       // 传递的参数
 THREAD_PRIORITY_ABOVE_NORMAL,       // 设置线程优先级
  (UINT) 0,                                  //  最大堆栈大小
  (DWORD) CREATE_SUSPENDED ,           //  创建标志
 (LPSECURITY_ATTRIBUTES) NULL);         //  安全性标志
 </PRE>
            <P><FONT color=#ffffff>----</FONT> 同时,在串口事件监视线程中: <PRE>if(WaitCommEvent(pTTYInfo-&gt;idComDev,&amp;dwEvtMask,NULL))
		{
	if((dwEvtMask  &amp; pTTYInfo-&gt;dwEvtMask )== pTTYInfo-&gt;dwEvtMask)
	{
	 WaitForSingleObject(pTTYInfo-&gt;hPostEvent,0xFFFFFFFF);
      ResetEvent(pTTYInfo-&gt;hPostEvent);    // 置同步事件对象为非信号态
	   ::PostMessage(CSampleView,ID_COM1_DATA,0,0);  // 发送通知消息
			}
		}</PRE>
            <P><FONT color=#ffffff>----</FONT> 
            用PostMessage()向指定窗口的消息队列发送通知消息,相应地,需要在该窗口建立消息与成员函数间的映射,用ON_MESSAGE将消息与成员函数名关联。 
<PRE>BEGIN_MESSAGE_MAP(CSampleView, CView)
 //{{AFX_MSG_MAP(CSampleView)
ON_MESSAGE(ID_COM1_DATA, OnProcessCom1Data)  
	ON_MESSAGE(ID_COM2_DATA, OnProcessCom2Data)  
.....
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
</PRE>
            <P><FONT color=#ffffff>----</FONT> 
            然后在各成员函数中完成对各串口数据的接收处理,但必须保证在下一次监测到有数据到来之前,能够完成所有的中间处理工作。否则将造成数据的捕捉错误。 

            <P><FONT color=#ffffff>----</FONT> 
            多线程的实现可以使得各端口独立,准确地实现串行通信,使串口通信具有更广泛的灵活性与严格性,且充分利用了CPU时间。但在具体的实时监控系统中如何协调多个线程,线程之间以何种方式实现同步也是在多线程串行通信程序实现的难点。 

            <P><FONT color=#ffffff>----</FONT> 以VC++ 6.0 为工具,实现串行通信的三种方法各有利弊, 
            <P>
            <CENTER><IMG height=114 
            src="CSDN_文档中心_用VC 6_0实现串行通信的三种方法.files/1.jpg" width=501> </CENTER>
            <P><FONT color=#ffffff>----</FONT> 
            根据不同需要,选择合适的方法,将达到事半功倍的效果。在温度监控系统中,笔者采用了方法二,在Window 98 ,Windows 95 
            上运行稳定,取得了良好的效果。 </P>
            <P>&nbsp;</P><BR></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR>
<TABLE align=center bgColor=#006699 border=0 cellPadding=0 cellSpacing=0 
width=770>
  <TBODY>
  <TR bgColor=#006699>
    <TD align=middle bgColor=#006699 id=white><FONT 
    color=#ffffff>对该文的评论</FONT></TD>
    <TD align=middle>
      <SCRIPT src="CSDN_文档中心_用VC 6_0实现串行通信的三种方法.files/readnum.htm"></SCRIPT>
    </TD></TR></TBODY></TABLE>
<TABLE align=center bgColor=#666666 border=0 cellPadding=2 cellSpacing=1 
width=770>
  <TBODY>
  <TR>
    <TD bgColor=#cccccc colSpan=3><SPAN style="COLOR: #cccccc"><IMG height=16 
      hspace=1 src="CSDN_文档中心_用VC 6_0实现串行通信的三种方法.files/ico_pencil.gif" width=16> 
      </SPAN>&nbsp;&nbsp;&nbsp;&nbsp; gn <I>(2001-3-3 22:25:24)</I> </TD></TR>
  <TR>
    <TD bgColor=#ffffff colSpan=3 width=532><BR>我还是用了最后一种方法。:) 
  <BR></TD></TR></TBODY></TABLE><BR>
<DIV align=center>
<TABLE align=center bgColor=#cccccc border=0 cellPadding=2 cellSpacing=1 
width=770>
  <TBODY>
  <TR>
    <TH bgColor=#006699 id=white><FONT 
color=#ffffff>我要评论</FONT></TH></TR></TBODY></TABLE></DIV>
<DIV align=center>
<TABLE border=0 width=770>
  <TBODY>
  <TR>
    <TD>你没有登陆,无法发表评论。 请先<A 
      href="http://www.csdn.net/member/login.asp?from=/Develop/read_article.asp?id=2138">登陆</A> 
      <A 
href="http://www.csdn.net/expert/zc.asp">我要注册</A><BR></TD></TR></TBODY></TABLE></DIV><BR>
<HR noShade SIZE=1 width=770>

<TABLE border=0 cellPadding=0 cellSpacing=0 width=500>
  <TBODY>
  <TR align=middle>
    <TD height=10 vAlign=bottom><A 
      href="http://www.csdn.net/intro/intro.asp?id=2">网站简介</A> - <A 
      href="http://www.csdn.net/intro/intro.asp?id=5">广告服务</A> - <A 
      href="http://www.csdn.net/map/map.shtm">网站地图</A> - <A 
      href="http://www.csdn.net/help/help.asp">帮助信息</A> - <A 
      href="http://www.csdn.net/intro/intro.asp?id=2">联系方式</A> - <A 
      href="http://www.csdn.net/english">English</A> </TD>
    <TD align=middle rowSpan=3><A 
      href="http://www.hd315.gov.cn/beian/view.asp?bianhao=010202001032100010"><IMG 
      border=0 height=48 src="CSDN_文档中心_用VC 6_0实现串行通信的三种方法.files/biaoshi.gif" 
      width=40></A></TD></TR>
  <TR align=middle>
    <TD vAlign=top>百联美达美公司 版权所有 京ICP证020026号</TD></TR>
  <TR align=middle>
    <TD vAlign=top><FONT face=Verdana>Copyright &copy; CSDN.net, Inc. All rights 
      reserved</FONT></TD></TR>
  <TR>
    <TD height=15></TD>
    <TD></TD></TR></TBODY></TABLE></DIV>
<DIV></DIV><!--内容结束//--><!--结束//--></BODY></HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -