2016-09-05 2 views
-2

J'ai des problèmes pour obtenir les données du port série d'un équipement. Ci-dessous est l'image du résultat attendu:Delphi Données incohérentes provenant d'un matériel utilisant Cport

résultat Desire:

enter image description here

résultat non désiré:

enter image description here

J'utilise TTimer je peux obtenir automatiquement les données et mettre au mémo.

J'ai besoin que les données soient placées ligne par ligne dans le mémo.

Voici le code source:

procedure TForm3.Timer1Timer(Sender: TObject); 
var 
k: Integer; 
InBuffer: array[1..500] of char; 

begin 

for k:=1 to 500 do 
InBuffer[k]:=' '; 
Trim(InBuffer); 

if cport.Connected = true then 
begin 
ComLed1.Kind := lkGreenLight; 
cport.ReadStr(str,k); 
Trim(str); 
S:=str; 

if str = '' then 
begin 

end 
else 
begin 
memo1.lines.Add(str); 
end; 
end 
else 
begin 
ComLed1.Kind := lkredLight; 
txt_com_status1.Caption := 'Connected'; 
end; 
end; 

Ma question est quel est le problème? Et quelle est la solution pour cela?

+0

Il serait plus facile de lire votre code si vous utilisiez une indentation. –

+1

Supprimez CR (# 13) et LF (# 10) de votre chaîne. Il y a aussi un problème de synchronisation, car vous devez savoir quand l'équipement a fini d'envoyer la chaîne. –

+0

note de côté: si les paquets du hw ont SOP et EOP (il devrait), vous pouvez tamponner les données pour éviter le traitement des paquets fragmentés et utiliser S/EOP pour extraire, puis formater comme vous s'il vous plaît – ComputerSaysNo

Répondre

3

TMemo.Lines.Add() ajoute un ligne. Le texte que vous ajoutez aura un saut de ligne inséré à la fin de celui-ci. Il est clair que vous recevez les données matérielles en morceaux, et vous ajoutez chaque pièce séparément comme sa propre ligne dans le mémo.

Pour faire ce que vous essayez, vous devez soit:

  1. Lire les pièces du matériel et les mettre en cache jusqu'à ce que vous détectez la fin d'un message complet, puis Add() messages uniquement complets au Note. La manière de procéder dépend du protocole utilisé par le matériel pour vous envoyer des données. Enveloppe-t-il les données dans les marqueurs STX/ETX? Est-ce qu'il délimite les messages? Nous ne savons pas, vous n'avez fourni aucune information à ce sujet. Et votre code essaye (sans succès) de couper beaucoup de données qu'il ne devrait probablement pas jeter du tout. Ne pas utiliser Add() du tout. Vous pouvez utiliser la propriété SelText à la place pour éviter d'insérer des sauts de ligne inutiles.

    memo1.SelStart := memo1.GetTextLen; 
    memo1.SelLength := 0; 
    memo1.SelText := str; 
    

Cela dit, votre code de minuterie est en train de faire des choses bizarres. InBuffer est rempli avec des espaces, puis (sans succès) coupé, puis complètement ignoré. Vous transmettez une valeur k non initialisée à ReadStr(). La valeur str que vous lisez est tronquée sans succès avant d'être ajoutée au mémo. Vous affectez str à S et en ignorant S.

Essayez ceci:

procedure TForm3.Timer1Timer(Sender: TObject); 
var 
    str: AnsiString; 
begin 
    if cport.Connected then 
    begin 
    ComLed1.Kind := lkGreenLight; 
    txt_com_status1.Caption := 'Connected'; 
    cport.ReadStr(str, 256); 
    str := Trim(str);  
    if str <> '' then 
    begin 
     memo1.SelStart := memo1.GetTextLen; 
     memo1.SelLength := 0; 
     memo1.SelText := str; 
    end; 
    end 
    else 
    begin 
    ComLed1.Kind := lkredLight; 
    txt_com_status1.Caption := 'Disconnected'; 
    end; 
end; 

Sinon (en supposant que vous utilisez TComPort qui a un événement OnRxChar):

procedure TForm3.Timer1Timer(Sender: TObject); 
begin 
    if cport.Connected then 
    begin 
    ComLed1.Kind := lkGreenLight; 
    txt_com_status1.Caption := 'Connected'; 
    end 
    else 
    begin 
    ComLed1.Kind := lkredLight; 
    txt_com_status1.Caption := 'Disconnected'; 
    end; 
end; 

procedure TForm3.cportRxChar(Sender: TObject; Count: Integer); 
var 
    str: AnsiString; 
begin 
    cport.ReadStr(str, Count); 
    str := Trim(str);  
    if str <> '' then 
    begin 
    memo1.SelStart := memo1.GetTextLen; 
    memo1.SelLength := 0; 
    memo1.SelText := str; 
    end; 
end; 

Modifier sur la base de nouvelles informations fournies dans les commentaires, essayez quelque chose comme ceci:

private 
    buffer: AnsiString; 
    portConnected: boolean; 

procedure TForm3.Timer1Timer(Sender: TObject); 
begin 
    if cport.Connected then 
    begin 
    if not portConnected then 
    begin 
     portConnected := true; 
     buffer := ''; 
     ComLed1.Kind := lkGreenLight; 
     txt_com_status1.Caption := 'Connected'; 
    end; 
    end 
    else 
    begin 
    if portConnected then 
    begin 
     portConnected := false; 
     ComLed1.Kind := lkredLight; 
     txt_com_status1.Caption := 'Disconnected'; 
    end; 
    end; 
end; 

procedure TForm3.cportRxChar(Sender: TObject; Count: Integer); 
var 
    str: AnsiString; 
    i: integer; 
begin 
    cport.ReadStr(str, Count); 
    buffer := buffer + str; 
    repeat 
    i := Pos(#10, buffer); 
    if i = 0 then Exit; 
    str := Copy(buffer, 1, i-1); 
    Delete(buffer, 1, i); 
    memo1.Lines.Add(str); 
    until buffer = ''; 
end; 
+0

monsieur Remy le matériel ne J'ai stx/etx dessus, aussi il ne délimite aucun char .. J'ai besoin d'obtenir toutes les données du matériel, et obtenir seulement les données utiles. –

+0

est-ce possible si je mets un préfixe et un suffixe aux données de matériel et lis seulement les données entre elles? Dois-je utiliser la minuterie parce que le matériel est un programme à envoyer automatiquement? comment le faire monsieur? Merci d'avance à nouveau. :) –

+0

@YeojsonBarcelo Comme la plupart des protocoles, il doit y avoir un début et une fin définis pour chaque message envoyé, qu'il s'agisse d'un signal matériel ou d'un délimiteur logiciel. Comment exactement le matériel indique sur le port série où un message se termine et le suivant commence? Il doit y avoir quelque chose. Avec quel type d'appareil communiquez-vous? Que dit sa documentation sur le protocole série utilisé? –