Delphi里在规定时间内检查串口数据

时间:2023-02-01 07:57:02
刚接触Delph,i是这样的,我有1个按钮,要求在3S内读一直取串口数据,每隔1S取1次。直达3S内的数据符合要求或者时间到达3S,再进行下一步动作。现在就在3S内检查串口数据这一步卡住。之前一直是搞单片机的,所以是单片机那种写法。请各位大侠帮忙指点啊!

while(3S时间没有到)
{
         检查串口数据
}

进行下一步                          后来发现这种写法不行,定时器都不能触发了


  Delay(1000);
   Delay(1000);
  Delay(1000);
检查串口数据                    这种写法也不行,串口时间都不响应了。

8 个解决方案

#1


  Delay(1000);
   Delay(1000);
  Delay(1000);
检查串口数据                    这种写法也不行,串口事件都不响应了。

#2


开个线程试    试       ?

#3


你可能对于事件没什么概念。
直接放个TTimer组件,响应OnTimer事件就可以了。

#4


用定时器,或者线程都可以操作

#5


你的想法错了,不能用定时器。否则你的程序会出问题。
使用Win32写的动态库来读取数据,然后使用delphi调用这个动态库就可以了。
因为串口有数据的时候会产生中断,自动触发线程去读数据。
要是公司行为,你给我协议。我写动态库给你!

#6


我建议如下:
1,delphi中串口数据的接收用控件(如spcomm)中的触发事件来接收,不要主动查询串口;在单片机中也很少用查询方式访问串口数据;
2,在这个触发事件中设置一下标志位,当接收到数据的时候,标志位置1表示收到数据
3,放置定时器,时间为1s触发,申请一个全局变量,用以计算定时器触发的次数;
4,触发中的程序内容是检测是否有数据收到,如果有数据收到,判断数据是否满足要求;如果满足要求,转入你的其他操作,同时定时器停止,计数器清零,否则定时器计数器加1;
5,当定时器计数器达到3时,如果你的数据还不能满足要求,转入你的故障操作,然后定时器停止,计数器清零;
6,按钮代码中,先清零计数器,再清零串口数据接收标志位,然后开启定时器;
7,其实自己补充一下调试细节

#7


98年写的接收串口数据的处理线程,你可以参考一下。
最好是用线程处理,在线程中 使用 WaitCommEvent 监控端口状态,并且进行数据读取和缓存。
hCom 是用CreateFile创建的端口句柄。

这个线程当时是挂在 ComDrv下面的,打开端口之后开始准备接收数据之后,就把这个线程跑起来。

你可以打开端口之后,跑起来这个线程,然后在主进程中等待3秒,到时间候检查缓冲区中的数据是否符合你的要求。

// TWaitComm
constructor TWaitComm.Create( hCom:THandle;dcb:TDCB;po:POVERLAPPED;Buf:PChar;pBufState:TPPortBufState );
begin
     FhCom    := hCom;
     FDcb     := dcb;
     Fpo      := po;
     FState   := tsRun;
     Priority := tpLowest;

     FPortBuf       := Buf;
     FpPortBufState := pBufState;

     inherited Create(False);
end;

procedure TWaitComm.SetState( const State:TThreadState );
begin
     FState := State;
end;

procedure TWaitComm.ProcRun;
var
   dwNOBR,dwErrorFlags:DWORD;
   ComStat:TCOMSTAT;
   iBufFreeSize:integer;
begin
     if (WaitCommEvent(FhCom, FdwEvtMask, Fpo)) then
     begin
          if ((FdwEvtMask and EV_RXCHAR)=EV_RXCHAR) then
          begin
               //等待缓冲区空闲
               while FpPortBufState^.NowOprt<>opIdle do Sleep(5);

               //设置缓冲区为写状态
               //取缓冲区剩余空间大小
               FpPortBufState^.NowOprt := opInWrite;
               iBufFreeSize := PORT_BUFFER_SIZE - FpPortBufState^.Tail;

               //读端口数据到缓冲区
               // only try to read number of bytes in queue
               ClearCommError( FhCom, dwErrorFlags, @ComStat ) ;
               if (iBufFreeSize>ComStat.cbInQue) then
                  dwNOBR := ComStat.cbInQue
               else
                   dwNOBR := iBufFreeSize;

               ReadFile(FhCom,FPortBuf[FpPortBufState^.Tail],dwNOBR,dwNOBR,Fpo);
               FpPortBufState^.Tail := FpPortBufState^.Tail + dwNOBR;

               //恢复缓冲区为空闲
               FpPortBufState^.NowOprt := opIdle;
          end;
     end;
end;

procedure TWaitComm.Execute;
begin
     { Place thread code here }
     while True do
     begin
          case FState of
           tsRun:
                 begin
                      ProcRun;
                 end;
           tsPause:
                 begin
                      Sleep(10);
                 end;
           tsEnd:
                 begin
                      Exit;
                 end;
          end; // end case
     end; // end while
end;
//=========================TWaitComm

#8


楼主好像没有用COM口控件,XE建议使用CPORT,D6、D7可以使用SPCOM,使用端口触发,一般不要用定时器

#1


  Delay(1000);
   Delay(1000);
  Delay(1000);
检查串口数据                    这种写法也不行,串口事件都不响应了。

#2


开个线程试    试       ?

#3


你可能对于事件没什么概念。
直接放个TTimer组件,响应OnTimer事件就可以了。

#4


用定时器,或者线程都可以操作

#5


你的想法错了,不能用定时器。否则你的程序会出问题。
使用Win32写的动态库来读取数据,然后使用delphi调用这个动态库就可以了。
因为串口有数据的时候会产生中断,自动触发线程去读数据。
要是公司行为,你给我协议。我写动态库给你!

#6


我建议如下:
1,delphi中串口数据的接收用控件(如spcomm)中的触发事件来接收,不要主动查询串口;在单片机中也很少用查询方式访问串口数据;
2,在这个触发事件中设置一下标志位,当接收到数据的时候,标志位置1表示收到数据
3,放置定时器,时间为1s触发,申请一个全局变量,用以计算定时器触发的次数;
4,触发中的程序内容是检测是否有数据收到,如果有数据收到,判断数据是否满足要求;如果满足要求,转入你的其他操作,同时定时器停止,计数器清零,否则定时器计数器加1;
5,当定时器计数器达到3时,如果你的数据还不能满足要求,转入你的故障操作,然后定时器停止,计数器清零;
6,按钮代码中,先清零计数器,再清零串口数据接收标志位,然后开启定时器;
7,其实自己补充一下调试细节

#7


98年写的接收串口数据的处理线程,你可以参考一下。
最好是用线程处理,在线程中 使用 WaitCommEvent 监控端口状态,并且进行数据读取和缓存。
hCom 是用CreateFile创建的端口句柄。

这个线程当时是挂在 ComDrv下面的,打开端口之后开始准备接收数据之后,就把这个线程跑起来。

你可以打开端口之后,跑起来这个线程,然后在主进程中等待3秒,到时间候检查缓冲区中的数据是否符合你的要求。

// TWaitComm
constructor TWaitComm.Create( hCom:THandle;dcb:TDCB;po:POVERLAPPED;Buf:PChar;pBufState:TPPortBufState );
begin
     FhCom    := hCom;
     FDcb     := dcb;
     Fpo      := po;
     FState   := tsRun;
     Priority := tpLowest;

     FPortBuf       := Buf;
     FpPortBufState := pBufState;

     inherited Create(False);
end;

procedure TWaitComm.SetState( const State:TThreadState );
begin
     FState := State;
end;

procedure TWaitComm.ProcRun;
var
   dwNOBR,dwErrorFlags:DWORD;
   ComStat:TCOMSTAT;
   iBufFreeSize:integer;
begin
     if (WaitCommEvent(FhCom, FdwEvtMask, Fpo)) then
     begin
          if ((FdwEvtMask and EV_RXCHAR)=EV_RXCHAR) then
          begin
               //等待缓冲区空闲
               while FpPortBufState^.NowOprt<>opIdle do Sleep(5);

               //设置缓冲区为写状态
               //取缓冲区剩余空间大小
               FpPortBufState^.NowOprt := opInWrite;
               iBufFreeSize := PORT_BUFFER_SIZE - FpPortBufState^.Tail;

               //读端口数据到缓冲区
               // only try to read number of bytes in queue
               ClearCommError( FhCom, dwErrorFlags, @ComStat ) ;
               if (iBufFreeSize>ComStat.cbInQue) then
                  dwNOBR := ComStat.cbInQue
               else
                   dwNOBR := iBufFreeSize;

               ReadFile(FhCom,FPortBuf[FpPortBufState^.Tail],dwNOBR,dwNOBR,Fpo);
               FpPortBufState^.Tail := FpPortBufState^.Tail + dwNOBR;

               //恢复缓冲区为空闲
               FpPortBufState^.NowOprt := opIdle;
          end;
     end;
end;

procedure TWaitComm.Execute;
begin
     { Place thread code here }
     while True do
     begin
          case FState of
           tsRun:
                 begin
                      ProcRun;
                 end;
           tsPause:
                 begin
                      Sleep(10);
                 end;
           tsEnd:
                 begin
                      Exit;
                 end;
          end; // end case
     end; // end while
end;
//=========================TWaitComm

#8


楼主好像没有用COM口控件,XE建议使用CPORT,D6、D7可以使用SPCOM,使用端口触发,一般不要用定时器