none
wince 串口问题(对串口感兴趣的同志请进) RRS feed

  • 问题

  • 2台电脑上的2个串口相联,其中接受端的串口没有打开,发送端打开,然后发送端执行发送数据的命令,然后接受端打开串口,为什莫接受端的串口就无法打开(createFile)

    ,如果开始发送端不发送数据,则接受端可以正常打开?

    2008年6月13日 6:07

答案

全部回复

  • 我在讲的详细一点
    电脑1 com1(接受端)
    电脑2 com2(发送端)
    开始: com1打开,com2打开,com2执行发送数据命令,com1正常收到数据
    第2步:com1关闭,com2打开,com2执行发送数据命令,然后打开com1,在打开com1的过程中,执行到createFile时候,程序死掉,不报错

    为什莫?
    2008年6月13日 6:21
  • 再补充
    然后com2再发送,才去执行com1的createFile

    我用了WaitCommEvent事件
    给个解释??

    2008年6月13日 7:50
  • 虽然你进行了补充说明,但是觉得问题还不是很清楚。

    1、主题是wince串口问题,内容却是电脑串口,请确认试验设备是PC还是WINCE系统,操作系统的版本是什么,串口是物理串口,还是USB等转串口设备。

    2、createFile仅仅是打开串口操作,这时候和是否用WaitCommEven没有关系

    3、确认createFile错误返回值是什么,用GetLastError函数看看出现了什么错误。

     

    2008年6月15日 3:13
    版主
  • 回复叶老师
    1 我用的是wince 模拟器,所以实际用的是pc的9孔串口,pc是win XP +sp2
    2 我用了一个线程用于监视串口事件,担心关闭串口却没有真正关闭
    主画面的线程接受事件为

    打开串口
    private void openCom()
    {
    打开串口
    myThread = new Thread(new ThreadStart(receiveData));
                        myThread.Start();
    }

    关闭串口
    {
    if (myThread != null)
                {
                    myThread.Abort();
                    myThread = null;
                }
                rxThreadCancelled = true;
    Close();
    }

      public void Close()
            {
                if (hComm != INVALID_HANDLE_VALUE)
                {
                    CloseHandle(hComm);
                    Opened = false;
                }
            }

    串口接受函数
     private void receiveData()
            {
                 string recvMsg = "";
                while (rxThreadCancelled == false)
                {
                    if (comm.Opened)
                    {
                        comm.setComMask();
                        recvMsg = comm.waitCommEvent();
                        comm.ClearReceiveBuf();
                        if (recvMsg == "")
                        {
                            rxThreadCancelled = true;
    }
                    }
                }
            }


    public bool setComMask()
            {
                if (hComm != INVALID_HANDLE_VALUE)
                {
                    if (!SetCommMask(hComm, EV_RXCHAR | EV_ERR | EV_TXEMPTY | EV_CTS | EV_DSR | EV_BREAK | EV_RLSD | EV_RING))
                        return false;
                    else
                        return true;
                }
                return false;
            }

            public string waitCommEvent()
            {
                string msg="";
                Marshal.WriteInt32(uMask, 0);
                if (hComm != INVALID_HANDLE_VALUE)
                {
                    try
                    {
                        if (!WaitCommEvent(hComm, uMask, unmanagedOv))
                        {
                            if (Marshal.GetLastWin32Error() == ERROR_IO_PENDING)
                            {
                                sg.WaitOne();
                            }
                        }
                        SetCommMask(hComm, EV_RXCHAR);
                        eventMask = (uint)Marshal.ReadInt32(uMask);
                        if ((eventMask & EV_RXCHAR) != 0)
                        {
                            do
                            {
                                gotbytes = 0;
                                ReadFile(hComm, buf, 1024, out gotbytes, unmanagedOv);
                                msg = Encoding.ASCII.GetString(buf, 0, Convert.ToInt32(gotbytes));
                            } while (msg.IndexOf("<EOF>") <= 0);
                        }
                    }
                    catch (Exception e)
                    {
                        if (uMask != IntPtr.Zero)
                            Marshal.FreeHGlobal(uMask);
                        if (unmanagedOv !=
                            IntPtr.Zero) Marshal.FreeHGlobal(unmanagedOv);
                    }
                }
                return msg;

            }
    这是主要代码
    谢谢老师帮我看看

    3 createFile没有错误,等到发送端再发送数据的时候
    createFile才会继续执行,否则它就不执行,停在那里了
    2008年6月15日 23:57
  • 1、最好用实际的wince系统进行测试,如果采用模拟器,问题也许有可能出在它身上。

    2、从代码上看,C#中调用API函数操作串口,用C#的错误捕捉机制,对API函数有可能无效。

    3、不明白你打开串口为什么用线程的方式,对串口来说,打开一次就够了,如果你多个进程要使用同一个串口,你可以使用其它的方法解决,并且我没有看到createFile出现的位置。

    4、我认为串口应用不是一个特别复杂的问题,如有可能可以对上面的代码进行大幅度的简化(实际应用中嵌入式系统下的SetCommMask并不是特别好用),我不建议在C#语法中采用如此复杂的API调用,如有可能,我到是建议直接用EVC编写。

     

    2008年6月16日 0:59
    版主
  • 现在我的要求就是一个端口可以打开然后关闭然后再打开关闭的,并自动接收数据
    public int Open()
            {
                DCB dcb = new DCB();
                COMMTIMEOUTS ctoCommPort = new COMMTIMEOUTS();
                hComm = CreateFile(Port, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
                if (hComm == INVALID_HANDLE_VALUE)
                {
                    return -1;
                }

                setComMask();
                SetupComm(hComm, 1024, 1024);
                ClearReceiveBuf();
                ClearSendBuf();
                GetCommTimeouts(hComm, ref ctoCommPort);
                ctoCommPort.ReadTotalTimeoutConstant = ReadTimeout;
                ctoCommPort.ReadTotalTimeoutMultiplier = 0;
                ctoCommPort.WriteTotalTimeoutMultiplier = 0;
                ctoCommPort.WriteTotalTimeoutConstant = 0;
                SetCommTimeouts(hComm, ref ctoCommPort);
                GetCommState(hComm, ref dcb);
                dcb.DCBlength = Marshal.SizeOf(dcb);
                dcb.BaudRate = BaudRate;
                dcb.flags = 0;
                dcb.ByteSize = (byte)ByteSize;
                dcb.StopBits = StopBits;
                dcb.Parity = (byte)Parity;

                //------------------------------
                SetDcbFlag(0, 1, dcb);           
                SetDcbFlag(1, (Parity == 0) ? 0 : 1, dcb);
                SetDcbFlag(2, 0, dcb);           
                SetDcbFlag(3, 0, dcb);           
                SetDcbFlag(4, 0, dcb);         
                SetDcbFlag(6, 0, dcb);          
                SetDcbFlag(9, 1, dcb);          
                SetDcbFlag(8, 0, dcb);           
                SetDcbFlag(10, 0, dcb);         
                SetDcbFlag(11, 0, dcb);         
                SetDcbFlag(12, 0, dcb);     
                SetDcbFlag(14, 0, dcb);         
                //--------------------------------
                dcb.wReserved = 0;                     
                dcb.XonLim = 0;                        
                dcb.XoffLim = 0;                       
                dcb.XonChar = 0;                       
                dcb.XoffChar = 0;                      
                dcb.ErrorChar = 0;        
                dcb.EofChar = 0;                         
                dcb.EvtChar = 0;                             
                dcb.wReserved1 = 0;                  

                if (!SetCommState(hComm, ref dcb))
                {
                    return -2;
                }
                Opened = true;
                Thread.Sleep(500);
                rxThreadStopped = false;
                return 0;
            }

    现在程序的毛病就是端口打开,可以正常接受数据,关闭以后再发送数据然后打开端口,执行到createFile种停止,现在重新发送,才去执行createfile并继续执行下面程序,不知道为
    2008年6月16日 2:44
  • 1、建议直接用WiNCE设备进行测试,先排除是否模拟器的问题。

    2、如果不成,对串口来说仅打开一次就够了。从目前的代码上看,我不认为逻辑上存在什么问题。

     

    2008年6月16日 4:34
    版主
  • 我用vs2008 中的serialport也会出现这种问题,不知道是程序的问题还是模拟器的问题
    没有ce设备
    真够痛苦 的
    2008年6月16日 5:35
  • 谢谢叶老师
    我用这种方法去解决了,虽然方法很不好,但可以不让他出错了

    当端口关闭的时候,发送消息给另各端口,说他关闭了,此时另各端口不允许写数据了
    嘿嘿
    先解燃煤之急再说
    有什莫好方法谢谢提供阿

    2008年6月16日 7:58
  •  

    我还是没有搞明白 哦
    2008年6月17日 7:49
  • 没明白我的问题?
    2008年6月17日 23:53
  • 还是那个waitcommevet,怎莫让它停止执行?
    因为它在监听串口的时候,如果串口没有信息发送来,他就一直监听,我想关闭串口也要先有个信息发过来才好结束他,
    如何让我执行closeHandler的时候,也直接把监听给结束了?

    2008年6月18日 5:12
  • 我对waitcommevet函数研究不深,针对它的特性不特别了解,我最早用VC做串口开发的时候也喜欢用waitcommevet,最后因为实在不方便也就不用它了。此外据我所知,WINCE的串口仅支持同步操作,所以我建议最好不要用waitcommevet,否者在操作时会因为它的阻塞操作,出现难以预料的问题。下面是我项目中实际的读操作例子。

    windows平台上VC的代码

    Code Snippet

    //读取数据
    long COM_ReadData(IOMDevice *md,BYTE *bytBuffer, long lngSize )
    {  
        try
     {
         if( md->mHandle == NULL ) return( -1 );
         
      DWORD   lngBytesRead=lngSize;
      BOOL    fReadStat;
      DWORD   dwRes=0;

      //读数据
      fReadStat=ReadFile(md->mHandle,bytBuffer,lngSize,&lngBytesRead,&(md->m_OverlappedRead)); 
      //Sleep(1);
      if( !fReadStat )
      {
       if( GetLastError() == ERROR_IO_PENDING )                                   //重叠 I/O 操作在进行中
       {
    //    HANDLE mExitEvent[2];
    //    mExitEvent[0]=md->m_OverlappedRead.hEvent;
    //    mExitEvent[1]=G_IOMRun.m_exitThreadEvent;
    //    dwRes=WaitForMultipleObjects(2,mExitEvent,FALSE,md->Overtime);

        dwRes=WaitForSingleObject(md->m_OverlappedRead.hEvent,md->Overtime);   //等待,直到超时
        switch(dwRes)
        {
        case WAIT_OBJECT_0:   //读完成        
         if(GetOverlappedResult(md->mHandle,&(md->m_OverlappedRead),&lngBytesRead,FALSE)==0)
         {
          //错误
          return -2;
         }    
         break;
        case WAIT_TIMEOUT:    //超时
         return -1;
         break;
        default:              //WaitForSingleObject 错误
         break;
        }
       }
      }

         return lngBytesRead;             
     
     }
     catch(...)
     {
            G_IOMRun.mIOMDevice.ShowMessage(0,2,"读取数据错误","YFIOS.dll[COM_ReadData]");
      return -1;
     }
    }

     

    wince平台上的EVC代码

    Code Snippet

    //读取数据
    long COM_ReadData(IOMDevice *md,BYTE *bytBuffer, long lngSize )
    {
     
        try
     {
         if( md->mHandle == NULL ) return( -1 );
            long lngBytesRead=0;
      
      //清除错误
      COMSTAT   ComStat;  
            DWORD     dwErrorFlags;
            ClearCommError( md->mHandle,&dwErrorFlags,&ComStat);
      //读数据
      ReadFile(md->mHandle, bytBuffer, lngSize,(DWORD *) &lngBytesRead, NULL);

         return lngBytesRead;             
     
     }
     catch(...)
     {
            G_IOMRun.mIOMDevice.ShowMessage(0,2,_T("读取数据错误"),_T("YFIOS.dll[COM_ReadData]"));
      return -1;
     }
    }

     

     

    2008年6月18日 10:19
    版主
  • 那关键是什莫时候开始读取阿?
    除了waitcommevent事件,还有什莫方法可以适时地从端口读取数据的?
    2008年6月18日 23:40
  • 如果是主从通信,你发送命令后,你就会非常清楚从设备什么时候响应命令。

    如果非主从通信,开一个线程,不断地循环去收数据。

     

    2008年6月19日 13:10
    版主

  • 现在我做了个实验
    用SerialPort控件在2台pc上运行

    而且代码也很简捷
    只是利用datareceive事件
    我参考别人的
    ce下写法也是一样
    自己没有添加任何线程
    只是简单的打开关闭接受发送
    一切正常
    不会出现上面的情况
    但是一放到ce模拟器上
    同样的问题就出现
    然后我用另一种方法
    用计时器去读取串口数据
    还是会出现同样的问题
    因为代码实在认为没有问题
    所以斗胆下个结论:是虚拟机的问题
    2008年6月19日 23:41
  • 非常有可能。

    2008年6月20日 2:05
    版主
  • 谢谢叶老师的经常回复
    非常感谢
    因为这个论坛很多人都是吃干饭不下菜的人
    只有你等是可以提供帮助的

    也谢谢其他不给个主意参考的

    2008年6月20日 2:20
  • 老兄,你的DCB结构体在C#里面是怎么表示的,可否把代码发给我看看啊?因为DCB里面有位域,不知道在C#里面该怎么写,多谢,可发到我的邮箱xzhg3@126.com,也可直接回复我的留言

    2008年10月31日 2:14