主体程序:
uses
  ......,Unit2;  //unit2是线程单元var
  Form1: TForm1;
  ReceiveData:TReceiveData;
implementation
{$R *.dfm}procedure TForm1.FormShow(Sender: TObject);
begin
  ReceiveData:=TReceiveData.Create(True);
end;procedure TForm1.Button1Click(Sender: TObject);
begin
  if Not comm.PortOpen then
  begin
      comm.CommPort:=1;
      comm.Settings:='9600,n,8,1';
      comm.PortOpen:=True;
      comm.InputLen:=0;
      Self.Caption:='串口已打开';
  end;
  ReceiveData.Resume;
end;
线程单元:
procedure TReceiveData.ReadData;
begin
  if (Form1.Comm.InBufferCount>0) then
  begin
      Form1.Memo1.Lines.Add(Form1.Comm.Input);
  end;
end;procedure TReceiveData.Execute;
begin
  while not terminated do
  begin
      Synchronize(ReadData);
  end;
end;

解决方案 »

  1.   

    没有错,你这么写肯定是100%呀。
    你最好把接受数据写在MSComm的接受事情中。
      

  2.   

    这么写等于没有操作是在子线程中执行的,所有的操作全部同步到主线成中执行了,这和在主线程中写个for循环式一样的,cpu就回到100%了
      

  3.   

    那我应该怎么改呢,我又不想用Timer来监控。
    我在它的OnComm事件里写了Memo1.Lines.Add(Comm.Input);
    也没反应
    我不太清楚这个控件是怎么工作的,我原先的设想是实现能在收的时候也能发送的,所以开了两个线程,一个用来接收,一个用来发送数据,尽量不把这些放到主线程中,因为在以前的程序中会发现有时候会出现死机及响应时间较长的情况
      

  4.   

    狂顶!!
    只要一用线程CPU就100%,SLEEP和APPLICATION.PROCCESS……都试过了,不顶用!
      

  5.   

    mscomm组件我也没有用过,也不知道它是不是线程安全的,搂住可以看看网上有没有他的demo,或者这样改一下实事:procedure TReceiveData.ReadData;
    begin
       Form1.Memo1.Lines.Add(Form1.Comm.Input);
    end;procedure TReceiveData.Execute;
    begin
      while not terminated do
      begin
         
         if (Form1.Comm.InBufferCount>0) then  Synchronize(ReadData);
      end;
    end;
      

  6.   

    看了你的代码,我发现一个问题就是你线程里面操作的comm是在主窗体上的,为什么不在线程内部自己创建一个呢?mscomm是非可视化构件,应该是线程安全的。然后显示的信息可以采用同步控制的办法来显示在memo1中。因为vcl可视化构件在多线程中是线程不安全的,必须使用同步控制,Synchronize;另外就是如果是需要有定时功能的话(也就是间隔多少时间采集一次数据)那么你可以在线程中使用sleep函数,也可以使用waitforsingleobject来处理,不要用timer控件。有什么问题继续交流,这是我自己的一点经验。
      

  7.   

    To  bluekitty(可爱猪猪):
      你的代码我试过了,cpu一样会升到100%To  cqwty(笨小孩):
      下面是我的代码,报错procedure TReceiveData.Execute;
    begin
      if Not Unit1.CommCreated then
      begin
          comm:=TMSComm.Create(nil);       //此句报错,提示说"尚未调用CoInitialize"
          comm.Parent:=nil;
          comm.CommPort:=1;
          comm.Settings:='9600,n,8,1';
          comm.PortOpen:=True;
          comm.InputLen:=0;
          Unit1.CommCreated:=True;
      end;  while not Terminated do
      begin
          if Comm.InBufferCount>0 then
              Synchronize(ReadData);
      end;
    end;
      

  8.   

    MSCOMM不是有个事件接受数据吗?在事件里监控不好吗?
      

  9.   

    对,是可以用事件,但前几次用的那些基于mscomm的短信控件让我一直对事件不放心,所以我情愿自己来做
      

  10.   

    mscomm属于com类型的东西,对于这些,必须先CoInitialize
      

  11.   

    begin
      while not terminated do
      begin
          Synchronize(ReadData);
          Sleep(30);              <-------加上这句就不是100%了 包爽
      end;
    end;
      

  12.   

    停了30毫秒会不会导致不能及时的读出数据,出现数据丢失的现象哦?我觉得这种东西不是定时采集数据,而是不知道数据什么时候到达,所以建议不要用sleep来处理吧!
      

  13.   

    MSComm控件本身就有一个负责读写的线程。在这个线程里完成实际的读写操作,然后向所属窗口发送读写事件。 所以再创建线程来处理读写有点多余了。
      关键是要处理好读写事件。一般把 MSComm的 RThreshold和InputLen设置为相同的值 
    TForm1.MSComm1OnComm(Sender:TObject);
    var v:variant; s:string;  Len,i:integer; b:byte;
    begin
      Len:=MSComm1.InputLen;
      while MSComm1.InbufferCount>=Len do
        begin
          v:=MSComm1.Input;
          try   
            s:=''; 
            for i:=0 to Len-1 do 
              begin
                b:=v[i];
                s:=s+Chr(b);
              end; 
           Memo1.Lines.Add(s);
         except
         end;
        end;
    end;
    由于串口事件的发生都是ms级的,所以上述处理不会导致CPU100%的,实际好像不占用CPU一样.除非你把波特率设置的非常非常High,并且不断的读写数据
    再完善点,开头可以加上先判断MSComm1.CommEvent的具体值,再进行相应处理。
    我现在的程序最多有10个串口(用了Moxa卡的),数据的读都是那么干的(RThreshold=InputLen=1)
      

  14.   

    补充一点,在窗口的事件里,应避免使用Sleep
    一Sleep,消息处理就暂停了,消息累计多的话,程序会翘的
      

  15.   

    cqwty(笨小孩):
      请问怎么CoInitialize?avenir(avenir):
      我猜你的代码本来是vb里的,你给的在delphi里运行不起来,我改了一下
    var
      v:string;
      s:string;
      Len,i:integer;
      b:char;
    begin
      Len:=MSComm1.InputLen;
      while MSComm1.InbufferCount>=Len do
      begin
          v:=MSComm1.Input;
          try
             for i:=1 to Len do
             begin
                 b:=v[i];
                 s:=s+v;
             end;
          except end;
      end;//while
      Memo1.Lines.Add(s);
    end;还有,我简化了一下,你看行不行
      Len:=MSComm1.InputLen;
      while MSComm1.InbufferCount>=Len do
      begin
          v:=MSComm1.Input;
          s:=s+v;
      end;//while
      Memo1.Lines.Add(s);
      

  16.   

    我当初用的InputLen都是1,
    没有try有时会触发异常,原因是 V:=MSComm1.Input有时读不到内容,具体怎么造成的不太清楚,可能跟MSComm的读写有关。 当读不到内容时, b:=v[0]会触发异常的所以省去try,当InputLen>1时,不知道是否会有想不到的事发生。
    此外 s:=s+v 呵呵,我一直不知道这么用。我一直把数据都当成二进制数来处理,一般的过程就是
        while Commxxx.InputLen>0 do
          begin
            v:=MSComm1.Input;
            try b:=v[0]; 。处理b; except end;  
          end;
      

  17.   

    一看mscomm就觉得有些乱,用spscomm
      

  18.   

    procedure TReceiveData.Execute;
    begin
      if Not Unit1.CommCreated then
      begin
          CoInitialize(null);
          comm:=TMSComm.Create(nil);       //此句报错,提示说"尚未调用CoInitialize"
          comm.Parent:=nil;
          comm.CommPort:=1;
          comm.Settings:='9600,n,8,1';
          comm.PortOpen:=True;
          comm.InputLen:=0;
          Unit1.CommCreated:=True;
      end;  while not Terminated do
      begin
          if Comm.InBufferCount>0 then
              Synchronize(ReadData);
      end;
    end;
    另外记住,当你线程结束的时候要CoUninitialize;
      

  19.   

    to cqwty(笨小孩):  delphi说"CoInitialize"未定义,我看了一下帮助,也没看出个所以然来,还请麻烦看一下了~~~to avenir(avenir):  我用了改进后的代码试了一下,发现个问题,就是会发生数据接收不全的情况,具体请看下面  在超级终端里输入at+cmgf=?,猫返回
      OK
      at+cmgf=?
      +CMGF: (0,1)  可用程序来做这些操作,程序中却显示
      at+cmgf=
      ?
      +CMG
      F: (0,1)这是怎么回事?
      

  20.   

    在uses里面加入activex单元文件
      

  21.   

    早就听说mscomm不好用,果然如此
      

  22.   

    procedure TReceiveData.ReadData;
    begin
      if (Form1.Comm.InBufferCount>0) then
      begin
          Form1.Memo1.Lines.Add(Form1.Comm.Input);
      end
      else
       sleep(10);  //没有数据时延时等待
    end;
      

  23.   

    主体程序:
    uses
      ......,Unit2;  //unit2是线程单元var
      Form1: TForm1;
      ReceiveData:TReceiveData;
      
    implementation
    {$R *.dfm}procedure TForm1.FormShow(Sender: TObject);
    begin
      ReceiveData:=TReceiveData.Create(false);  //false
    end;procedure TForm1.Button1Click(Sender: TObject);
    begin
      if Not comm.PortOpen then
      begin
          comm.CommPort:=1;
          comm.Settings:='9600,n,8,1';
          comm.PortOpen:=True;
          comm.InputLen:=0;
          Self.Caption:='串口已打开';
      end;
      //ReceiveData.Resume;  //屏蔽它
    end;
    线程单元:
    procedure TReceiveData.ReadData;
    begin
      if (Form1.Comm.InBufferCount>0) then
      begin
          Form1.Memo1.Lines.Add(Form1.Comm.Input);
      end;
    end;procedure TReceiveData.Execute;
    begin
      while not terminated do
      begin
          if IsWork then  //这里用类中的全局状态
            Synchronize(ReadData);
          Sleep(10); //释放cpu 资源
      end;
    end;////////////////增加全局的状态
    TReceiveData=class(TThread)
      public
         isWork :boolean;   //////允许任务进行工作
      

  24.   

    我用spcomm解决了,mscomm实再是太麻烦了