奇怪的问题:
同样的软件在两台台式机同时运行,从设备中重复上传数据,每包间隔15ms左右。
设备与电脑USB线连接,USB转串口通讯,波特率设置比较高,921600,
运行时,没有规律出现死机的现象,
两台电脑,有一台运行从昨天15:30左右到今天10:39左右,就自动重启了。
另一台到现在还运行正常。设备和电脑软件都一样。
以前出现死机的现象,现在,还出现了自动重启,真奇怪。

解决方案 »

  1.   

    以下是串口通讯源程序:{
    tzj 2008-02-25
    }
    unit Unit_Comm;interface
    uses
      Windows, SysUtils, StrUtils, Classes, Dialogs, forms;  const
        comBufferSize = 20480;  type
        //监视串口线程 (设备联机工作状态)
        TcomWatchThread = class(TThread)
        private
          searchComId : integer;
          function tryOpenNextCom : boolean;
          procedure onCom_Connecting();   //当串口正在连接
          { Private declarations }
        protected
          procedure comWatch;
          procedure Execute; override;
        public
          procedure onCom_Connect();   //当串口连接
          procedure onCom_Disconnect(); //当串口断开连接
          constructor Create; virtual;
        end;
        TComm = class
        private
          ReceiveAndDealWithDataFlag, SendDataFlag : boolean;      RecvBuff : array[0..comBufferSize] of char;      dcb:_DCB; //DCB结构用于配置串口,程序中涉及各域含义如下:
                    //DWORD DCBlength :DCB结构大小
                    //DWORD BaudRate :  波特率
                    //DWORD fBinary  : 1 二进制模式
                    //DWORD fParity  : 1 进行奇偶校验
                    //BYTE  ByteSize: 字符位数 4~8
                    //BYTE  Parity:   奇偶校验位 0-4分别表示无、奇、偶、传号、空号校验
                    //BYTE  StopBits: 停止位数 0-2分别表示 1、1.5、2个停止位
                    //WORD  XonLim :XON 阈值
                    //WORD  XoffLim  XOFF 阈值
                    //char  XonChar: XON 字符
                    //char  XoffChar: XOFF 字符
                    //char  EvtChar:  事件字符
          comStat:_COMSTAT; //COMSTAT结构用于存放有关通信设备的当前信息
                            //程序中涉及各域含义如下:
                            //cbInQue :接收缓冲区中字符个数
                            //cbOutQue:发送缓冲区中字符个数
          dwErrorFlag:LongWord;
          hCommDev:Thandle;//通信串口句柄和通信监视线程句柄
          comMask,comBuf,comState:BOOL;
          read_os,write_os:_OVERLAPPED;  //OVERLAPPED 结构,用于异步操作的Win32函数中
                                        //程序中涉及各域含义如下:
                                        //DWORD Interval 保留给操作系统使用
                                        //DWORD IntervalHigh 保留给操作系统使用
                                        //DOWD  hEvent 当I/O操作完成时被设置为有信号状态
                                        //的事件;当调用ReadFile和WriteFile函数之前,调
                                        //用进程设置该事件
          postRecvEvent, postSendEvent :Thandle;//发送缓冲区空和接收到字符事件句柄
        public
          toSendList : TStringList;      comNo : integer;//串口号
          comName : String;//串口名
          BaudRate: DWORD; //波特率
          ByteSize: Byte;  //数据长度
          Parity: Byte;    //校验方式
          StopBits: Byte;  //停止位
          EvtChar: CHAR;   //每次接收完成字符      openIni : String;
          timeOutFlag,    //超时标志
          openFlag : boolean;
          SendCommand,RecvCommand:String;//发送和接收到的命令      function comSend : boolean;
          procedure com_init;//初始化
          procedure com_open;  //初始化切换台串口,返回状态字符
          procedure com_close;
          procedure com_abort; //中断串口      procedure CommSendNotifyDealWith;//串口接收到字符事件响应过程
          procedure CommRecvNotifyDealWith; //串口发送缓冲区空事件响应过程      procedure DealWithRecvData;//处理接收的数据      procedure SendCommandStr(cmdStr : String);
          procedure SendNextCommand;  //发送下一个命令      procedure comReceive;
          function comReceive_:boolean;      function strtoByte(Str : String):String;
          function byteToStr(Str : String):String;
        end;var
      lineNumber : integer;
    implementationuses Unit_Communication, Unit_Menu, Unit_publicVar, unit_realDataView,
      Unit_Hint, Unit_DevFileManage, Unit_devUploadData, Unit_Socket;{
    procedure writeLogToFile(Str : String);
    begin
      if not Form_devUploadData.bsSkinGroupBox1.Visible then exit;  try
      if FileExists(appPath + 'log.txt') then
        Form_menu.Memo_log.Lines.LoadFromFile(appPath + 'log.txt')
      else
        Form_menu.Memo_log.Lines.Clear;
        
      Form_menu.Memo_log.Lines.Add(formatdateTime('hh:MM:ss ',now)+Str);
      if Form_menu.Memo_log.Lines.Count > 100 then
        Form_menu.Memo_log.Lines.Delete(0);
      Form_menu.Memo_log.Lines.SaveToFile(appPath + 'log.txt');
      except
      end;
    end;      }function TcomWatchThread.tryOpenNextCom : boolean;
    begin
      findDevFlag := false;  inc(searchComId);
      if searchComId > 256 then searchComId := 1;  onCom_Connecting;  Comm.comNo := searchComId;
      Comm.com_open;  result := Comm.openFlag;
    end;procedure TcomWatchThread.onCom_Connecting;
    const pointCount = 50;
    var
      flagPos : integer;
    begin
      if appQuit then exit;
      flagPos := trunc(searchComId * (pointCount / 256));
      Form_menu.Status_devIni.Caption := '正在寻找' +
                                         stringOfchar('.',flagPos)+
                                         '|' +
                                         stringOfchar('.',pointCount - flagPos);
      Form_realDataView.Status_devIni.Caption := Form_menu.Status_devIni.Caption;
    end;procedure TcomWatchThread.onCom_Connect;
    begin
      outputIni('------111-----');  if appQuit then exit;
      outputIni('---111---222-----');
      Form_Hint.Visible := false;
      SetForegroundWindow( Application.Handle );
      outputIni('------222-----');  receiveDataStr := '';
      lastComStatus := '';  Communication_ECG.resetBtnStatus(true);
      Form_menu.Status_devIni.Caption := '端口:'+Comm.comName+'   SN:'+formatfloat('0-0000-0000-0000',devCodeStr)+'';  Form_realDataView.Status_devIni.Caption := Form_menu.Status_devIni.Caption;  if Form_DevFileManage.Visible then
      begin
       // sleep(100);
        Form_DevFileManage.btn_refreshClick(nil); //刷新文件列表
      end;  if Form_devUploadData.Visible then
      begin
        Form_devUploadData.Timer_timeOut.Enabled := true;
      end;  outputIni('------333-----');  Communication_ECG.send_getDevVer;
       
      if Form_realDataView.Visible then Form_realDataView.init;end;
    procedure TcomWatchThread.onCom_Disconnect;
    begin
      if appQuit then exit;  if findDevFlag then Form_Hint.Show;  Communication_ECG.resetBtnStatus(false);  comStatus := '';  with Form_menu do
      begin
        Status_devIni.Caption := '正在寻找';
        lbl_DevVer.Caption := '硬件版本:_._._._';
      end;  with Form_realDataView do
      if visible then
      begin
        stopReceive;
        Status_devIni.Caption := Form_menu.Status_devIni.Caption;
      end;end;
      

  2.   


    { TcomWatchThread }constructor TcomWatchThread.Create;
    begin
      inherited Create(true);
      FreeOnTerminate := True;
      searchComId := 0;
    end;procedure TcomWatchThread.comWatch;
    var
      dwTransfer,dwEvtMask,dwError:DWORD;
      os:_OVERLAPPED;
      bl:boolean;
    begin
      os.hEvent:=CreateEvent(nil, TRUE, FALSE, NIL);  with comm do
      begin
        while openFlag and (not timeOutFlag) do//串口处于打开状态
        begin
          if appQuit then break;      ClearCommError(hCommDev,dwErrorFlag,@ComStat);      dwEvtMask:=0;
          bl:=WaitCommEvent(hCommDev,dwEvtMask,@os); //查询所监视的通信事件是否
                                                    //已经发生
          if bl=False then
          begin
            dwError:=GetLastError();
            if dwError <> 0 then
              if dwError=ERROR_IO_PENDING then
              begin
                GetOverlappedResult(hCOmmDev,os,dwTransfer,True)//若未监测到通信事件
                                                                //则在此等待事件发生
              end
              else
                break;
          end;      //有事件,进行如下处理
          if (dwEvtMask and EV_RXFLAG)=EV_RXFLAG then //判断是否为接收到 字符事件
          begin
            //self.Synchronize(
            CommRecvNotifyDealWith;
            continue; //处理完接收字符,继续监测通信事件
          end
          else
          if (dwEvtMask and EV_TXEMPTY)=EV_TXEMPTY then //判断是否为发送缓冲区空事件
          begin
            self.Synchronize(commSendNotifyDealWith); //调用发送缓冲区空处理函数
    //        commSendNotifyDealWith; //调用发送缓冲区空处理函数
            continue;//处理完,继续监测通信事件
          end
          else
          if (dwEvtMask and $FFFFFFFF) = 0 then //通讯中断
          begin
            break;
          end;
        end;
      end;
      CloseHandle(os.hEvent);
    end;
    procedure TcomWatchThread.Execute;
    begin
    //*** 注意:不用Synchronize调用执行带窗口操作的过程或函数会造成程序死掉的严重现象 ****//
      repeat
        if tryOpenNextCom then //串口打开成功
        begin
          outputIni('成功');
          receiveDataStr := '';
          Communication_ECG.send_getDevCode; //读取设备编码
          comWatch;//串口监视
          //Form_menu.Memo1.Lines.Add(comm.comName+ ' com_close ');
          self.Synchronize( comm.com_close );//关闭串口
          self.Synchronize( onCom_Disconnect ); //串口断开提示
        end
        else  //串口打开失败
        begin
          application.ProcessMessages;
          sleep(1);
        end;    if appQuit then break;
      until Terminated;
    end;
    ///串口初始化函数
    //该函数主要完成串口初始化设置和通信线程的启动
    //入口参数:串口号
    //返回值;初始化是否成功的状态字符
    procedure TComm.com_open;
    var
      TimeOuts : COMMTIMEOUTS;
    begin
      outputIni('打开串口:'+formatfloat('000',self.comNo));  openFlag := false;
      timeOutFlag := false;  comName := '\\.\COM' + inttostr(comNo);  ///打开串口
      hCommDev:=CreateFile(pchar(comName),   //串口号
                       GENERIC_READ or GENERIC_WRITE,//对串口以读写方式打开
                       0,
                       nil,
                       OPEN_EXISTING,
                       FILE_ATTRIBUTE_NORMAL or FILE_FLAG_OVERLAPPED,//允许重叠操作
                       0
                       );
      if hCommDev=INVALID_HANDLE_VALUE then
      begin
        openIni := '打开串口"'+comName+'"失败.';
        exit;
      end;  comBuf:=SetupComm(hCommDev,comBufferSize,comBufferSize);//设置接收和发送缓冲区大小皆为4096字节  if comBuf=False then
      begin
        openIni := '设置接收和发送缓冲区大小失败.';
        exit;
      end;                  //设置通讯超时
      getCommTimeouts(hCommDev, TimeOuts);
      TimeOuts.ReadIntervalTimeout := MAXDWORD;      // 读间隔超时
      TimeOuts.ReadTotalTimeoutMultiplier := 500;    // 读时间系数
      TimeOuts.ReadTotalTimeoutConstant := 2000;      // 读时间常量
      TimeOuts.WriteTotalTimeoutMultiplier := 500;   // 写时间系数
      TimeOuts.WriteTotalTimeoutConstant := 2000;     // 写时间常量  //COMMTIMEOUTS结构的成员都以毫秒为单位。总超时的计算公式是:
      //总超时=时间系数×要求读/写的字符数 + 时间常量
      //  例如,如果要读入10个字符,那么读操作的总超时的计算公式为:
      //读总超时=ReadTotalTimeoutMultiplier×10 + ReadTotalTimeoutConstant  SetCommTimeouts(hCommDev, TimeOuts); // 设置超时  //清空缓冲区
      PurgeComm(hCommDev,PURGE_TXABORT or PURGE_RXABORT or PURGE_TXCLEAR or PURGE_RXCLEAR ) ;  //以下对串口进行配置
      comState:=GetCommState(hCOmmDev,dcb);  //得到缺省设置
      if  comState=False then
      begin
        openIni := '得到缺省设置失败.';
        exit;
      end;  dcb.DCBlength:=sizeof(_DCB);  dcb.BaudRate := BaudRate;  //波特率 9600
      dcb.ByteSize := ByteSize;  //数据长度7位
      dcb.Parity := Parity;      //校验方式
      dcb.StopBits := StopBits;  //停止位 {dcb.Flags := 0;               // Enable fBinary
      dcb.Flags := dcb.Flags or 2; // Enable parity check
      dcb.XonChar:= chr($00) ;
      dcb.XoffChar:= chr($00) ;
      dcb.XonLim:= 100 ;
      dcb.XoffLim:= 100 ;  }
      dcb.EvtChar := EvtChar;  comState:=SetCommState(hCommDev,dcb);  //设置串口
      if comState=False then
      begin
        openIni := '设置串口失败.';
        exit;
      end;  comMask:=SetCommMask(hCommDev,EV_RXFLAG or EV_TXEMPTY);//设置监视的事件为接
                                                            //收到字符或发送缓冲区空
      if comMask = False then
      begin
        openIni := '设置监视的事件失败';
        exit;
      end;
      openIni := '打开并设置串口"'+comName+'"成功.';  //设置通信接收到字符事件句柄
      postRecvEvent:=CreateEvent(NIL,
                              TRUE,//手工重置事件
                              TRUE, //初始化为有信号状态
                              NIL
                              );  //设置读异步I/O操作事件句柄
      read_os.hEvent:=CreateEvent(NIL,
    //                          TRUE,//手工重置事件
                              False,//自动重置事件
                              FALSE, //初始化为无信号状态
                              NIL
                              );
      //设置发送缓冲区空事件句柄
      postSendEvent := CreateEvent(NIL,
                              TRUE,//手工重置事件
                              TRUE, //初始化为有信号状态
                              NIL);
                                //设置写异步I/O操作事件句柄
      write_os.hEvent:=CreateEvent(NIL,
    //                          TRUE,//手工重置事件
                              False,//自动重置事件
                              FALSE,//初始化为无信号状态
                              NIL);
      //初始化变量
      openFlag := true;//串口已成功打开  toSendList.Clear;
    end;procedure TComm.comReceive;
    var
      receiveResult : Boolean;
    begin
      //writeLogToFile('r-');
      //***** 注意:此处等条件必须为=WAIT_OBJECT_0,否则操作系统会死掉 *****//
      if WaitForSingleObject(postRecvEvent,50) = WAIT_OBJECT_0 then//等待接收事件句柄为有信号状态
      begin
        if ResetEvent(postRecvEvent) then //置接收事件句柄为无信号状态,以免接收缓冲区被覆盖
        begin
          try
            receiveResult := comReceive_;
            if not receiveResult then //如果接收失败
            begin
              outputIni( 'SendCommandStr接收失败---closeComm--');
             // com_abort; //中断串口  //时有发生,不要打开
             // exit;
            end;
          finally
            SetEvent(postRecvEvent); //置接收事件句柄为有信号状态,以便接收新字符
          end;
        end;
      end
      else
        com_abort;
      //writeLogToFile('r*');
    end;procedure TComm.DealWithRecvData;//处理接收的数据
    begin
        //如果接收的数据包不为空,则调用数据包处理过程
        if RecvCommand <> '' then
        begin
          Communication_ECG.onReceiveData(RecvCommand);
          RecvCommand := '';
        end;
    end;procedure TComm.CommRecvNotifyDealWith;
    begin
      if ReceiveAndDealWithDataFlag then exit;  try
        ReceiveAndDealWithDataFlag := true;
        //接收数据
        comReceive;
        
        //处理接收的数据
        comWatchThread.Synchronize(DealWithRecvData);
      finally
        ReceiveAndDealWithDataFlag := false;
      end;  SendNextCommand;  //发送下一个数据包
    end;
      

  3.   

    //-----------------------------------------
    //向串口发送数据
    //-----------------------------------------
    function TComm.comSend : boolean;
    var
     dwWriteByte,TxCount:DWORD;
     dwError, dwR:DWORD;
     WriteBuffer:PChar;
    begin
      try
        result := false;
        ClearCommError(hCommDev,dwErrorFlag,@ComStat);
        {
        if not ClearCommError(hCommDev,dwErrorFlag,@ComStat) then
        begin
          PurgeComm(hCommDev, PURGE_TXABORT or PURGE_TXCLEAR );
          Exit;
        end;     }    TxCount:=Length(SendCommand);
        WriteBuffer := pchar(SendCommand);   // dwWriteByte:=0;    result := WriteFile(hCommDev,Byte(WriteBuffer^),TxCount,dwWriteByte,@write_os);    dwError:=GetLastError();
        if (not result) and (dwError = ERROR_IO_PENDING) then  //正在发送数据
        begin
          result := (WaitForSingleObject(write_os.hEvent,100) = WAIT_OBJECT_0);
      //    result := GetOverLappedResult(hCommDev, write_os, dwWriteByte, False) //**** 注意最后一个参数必须为False,否则程序容易死掉 ****//
        end
        else
        begin
          com_abort; //中断串口
          exit;
        end;    if result then
        begin
          //write_os.Offset := write_os.Offset + TxCount - dwWriteByte;
          if RecCom then Form_Socket.Rec_sendStr(self.byteToStr(SendCommand));
        end;
      except
      end;
    end;
    procedure TComm.SendNextCommand;
      function SendNextCommand_:boolean;
      begin
        result := false;
        if not openFlag then exit;    //writeLogToFile('w-');
        if WaitForSingleObject(postSendEvent,50) = WAIT_OBJECT_0 then//等待发送事件句柄为有信号状态
        begin
          if ResetEvent(postSendEvent) then  //置发送事件句柄为无信号状态,,以免发送缓冲区被覆盖
          begin
            try
              result := comSend;
              if not result then //如果发送失败
              begin
                com_abort; //中断串口
                exit;
              end;
            finally
              setEvent(postSendEvent);//置发送事件有信号状态,以便进行下一次发送
            end;
          end;
        end
        else
          com_abort;    //writeLogToFile('w*');
      end;
    begin
      if SendDataFlag then exit;  try
        SendDataFlag := true;
        if Assigned(toSendList) then
        begin
          if toSendList.Count > 0 then
          begin
            SendCommand := toSendList.Strings[0];
            toSendList.Delete(0);
            SendNextCommand_;
          end;
        end;
      finally
        SendDataFlag := false;
      end;
    end;procedure TComm.SendCommandStr(cmdStr : String);
    begin
      if not openFlag then exit;  if Assigned(toSendList) then
      begin
        if toSendList.Count < 10 then
          toSendList.Add(cmdStr);    comWatchThread.Synchronize( SendNextCommand );
        SendNextCommand;
      end;
    end;
    //发送缓冲区空处理过程
    procedure TComm.CommSendNotifyDealWith;
    begin
      //if not ReceiveAndDealWithDataFlag then //不在接收和处理数据状态
        SendNextCommand; //发送下一个数据包
    end;
    function TComm.comReceive_:boolean;
    var
      RxCount,dwReadByte, toReadByte :DWORD;
      dwError, DwRes:DWORD;
      i : integer;
    begin
      result := false;
      RecvCommand := '';  try
        ClearCommError(hCommDev,dwErrorFlag,@ComStat);
      {
        if not ClearCommError(hCommDev,dwErrorFlag,@ComStat) then
        begin
          PurgeComm(hCommDev, Purge_Rxabort or Purge_Rxclear);
          Exit;
        end;
        }    RxCount:=ComStat.cbInQue; //获取接收缓冲区的字符个数
        if ((comBufferSize-1) < RxCount) then
          toReadByte := comBufferSize-1
        else
          toReadByte := RxCount;    if toReadByte>0 then
        begin
          fillchar(RecvBuff, toReadByte, #0);      result := ReadFile(hCommDev,RecvBuff,toReadByte,dwReadByte,@read_os);
          //需要注意的是如果该函数因为超时而返回,那么返回值是TRUE。参数lpOverlapped在
          //重叠操作时应该指向一个OVERLAPPED结构,如果该参数为NULL,
          //那么函数将进行同步操作,而不管句柄是否是由FILE_FLAG_OVERLAPPED标志建立的。      dwError:=GetLastError();
          if not (result and (dwError = 0)) then
          begin
            result := false;
            com_abort; //中断串口
            exit;
          end;      if dwReadByte > 0 then //临时缓冲区中接收到字符个数大于1
          begin
            //read_os.Offset := read_os.Offset + dwReadByte;
            RecvBuff[dwReadByte] := #0;
            for i:=0 to dwReadByte-1 do
              RecvCommand := RecvCommand + RecvBuff[i];
            if RecCom then Form_Socket.Rec_receiveStr(self.byteToStr(RecvCommand));
          end;    end;
      except
      end;
    end;
    //中断串口
    procedure TComm.com_abort;
    begin
      if openFlag then
      begin
        SetEvent(postRecvEvent);
        SetEvent(postSendEvent);
        PurgeComm(hCommDev,PURGE_TXABORT or PURGE_RXABORT or PURGE_TXCLEAR or PURGE_RXCLEAR ) ;
        SetCommMask(hCommDev,0);
      end;
    end;
      

  4.   

    function TComm.byteToStr(Str: String): String;
    var
      i, len : integer;
    begin
      len := length(Str);
      result := '';
      for i:=1 to len do
        result := result + ' ' + rightStr('00'+inttohex(ord(Str[i]),0),2);
    end;function TComm.strtoByte(Str: String): String;
    var
      i, len : integer;
    begin
      len := length(Str);
      result := '';
      for i:=0 to len div 2 - 1 do
        result := result + char(strtoIntDef('$'+copy(Str,i*2 + 1,2),0));
    end;
    procedure TComm.com_close;
    begin
    //outputIni('关闭串口:'+formatfloat('000',self.comNo));
      Form_menu.receiveTimer.Enabled := false; //停止超时定时器  Form_devUploadData.Timer_timeOut.Enabled := false;
      
      if not openFlag then exit;   //如果已经关闭则退出  openFlag := false;//串口已关闭  //关闭用到的句柄
      CloseHandle(PostRecvEvent);
      CloseHandle(read_os.hEvent);
      CloseHandle(PostSendEvent);
      CloseHandle(write_os.hEvent);
      CloseHandle(hCommDev);
    end;procedure TComm.com_init;
    begin
      with Comm do
      begin
        BaudRate := 921600;     //波特率
        ByteSize := 8;          //数据长度
        Parity := 0;            //校验方式
        StopBits := 0;          //停止位
        EvtChar := Char($FE);   //每次接收完成字符
      end;  toSendList := TStringList.Create;
      comWatchThread := TcomWatchThread.Create;
      ReceiveAndDealWithDataFlag := false;
      SendDataFlag := false;
    end;end.
      

  5.   

    都记录下来保存在一个文本文件中,运行了两天都没问题 
    ---------------------------
    两个建议
    1)用一定动作代替保存log试试。
    2)只做收发之间的一个动作。以前俺的一个程序,在不同的线程里同时send了一种message,主程序就死。
      

  6.   

      ///打开串口 
      hCommDev:=CreateFile(pchar(comName),   //串口号 
                       GENERIC_READ or GENERIC_WRITE,//对串口以读写方式打开 
                       0, 
                       nil, 
                       OPEN_EXISTING, 
                       FILE_ATTRIBUTE_NORMAL or FILE_FLAG_OVERLAPPED,//允许重叠操作 
                       0 
                       ); 
      if hCommDev=INVALID_HANDLE_VALUE then 
      begin 
        openIni := '打开串口"'+comName+'"失败.'; 
        exit; 
      end; 
      comBuf:=SetupComm(hCommDev,comBufferSize,comBufferSize);//设置接收和发送缓冲区大小皆为4096字节   if comBuf=False then 
      begin 
        openIni := '设置接收和发送缓冲区大小失败.';
    //*************************************************
    //    这儿就应当回收当前打开的文件;
    //************************************************* 
        exit; 
      end;  
    串口操作,在操作系统里其实就是对一个文件进行操作;也就是说CreateFile是创建或是打开一个文件,如果成功:
    返回值将是文件句柄;在设置串口时,如果操作失败,那么你就应当回收这个文件句柄资源,但在你的源码中没有看到回收![color=#FF0000][/color]
    下面是SPCOMM的源码,可以给你些提示吧。{SPCOMM SOURCE CODE}
         if (hCommFile <> 0) then
            raise ECommsError.Create( 'This serial port already opened' );     hNewCommFile := CreateFile( PChar(FCommName),
                                     GENERIC_READ or GENERIC_WRITE,
                                     0, {not shared}
                                     nil, {no security ??}
                                     OPEN_EXISTING,
                                     FILE_ATTRIBUTE_NORMAL or FILE_FLAG_OVERLAPPED,
                                     0 {template} );     if hNewCommFile = INVALID_HANDLE_VALUE then
            raise ECommsError.Create( 'Error opening serial port' );     // Is this a valid comm handle?
         if GetFileType( hNewCommFile ) <> FILE_TYPE_CHAR then
         begin
              CloseHandle( hNewCommFile );
              raise ECommsError.Create( 'File handle is not a comm handle ' )
         end;     if not SetupComm( hNewCommFile, 4096, 4096 ) then
         begin
              CloseHandle( hCommFile );
              raise ECommsError.Create( 'Cannot setup comm buffer' )
         end;
    ............
      

  7.   

      //关闭用到的句柄 
      CloseHandle(PostRecvEvent); 
      CloseHandle(read_os.hEvent); 
      CloseHandle(PostSendEvent); 
      CloseHandle(write_os.hEvent); 
      CloseHandle(hCommDev); 楼主,以上代码有啊.
      

  8.   

    电压问题可能性不会很大,因为,这个设备可以不在接电池情况下,连接电脑USB,USB给设备供电,照样可以正常工作.而且,还可以通过USB给设备电池充电.