Bonjour à tous,
Je vais vous expliquer mon problème, je dois réaliser la régulation d'un chauffage à l'aide d'un PID. J'utilise actuellement Lazarus pour mon projet sur demande de mon tuteur.
J'étais parti sur l'idee d'un timer mais cela ne plaisait pas trop à mon tuteur qui m'a conseillé d'utiliser la fonction ProcessMessages. J'utilise des modules d'entrées sorties analogiques et un module de sortie relais en RS485.
Le probleme c'est que je ne comprends pas bien la fonction processMessage, je suis allé me renseigner a pleins d'endroit sur le net et de partout je vois des gens qui critique l'utilisation de cette application. Je vous met à la suite mon code
j'ai mis en gras italique la partie du code ou est situé mon problème. L'objectif c'est que au final mon PID me donne un valeur que je module afin qu'elle soit comprise entre 0 et 1 et que je demande a mon module de sortie relais de rester fermer x temps ( x etant la commande modulé* la duree d'une periode) et de s'ouvrir le reste du temps de la periode.Code:unit main; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, LazSerial, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls, LazSynaSer, dateutils, Lclintf; type { TForm1 } TForm1 = class(TForm) ButtonStop: TButton; ButtonStart: TButton; CheckBox1: TCheckBox; Edit1: TEdit; Edit2: TEdit; Edit3: TEdit; Edit4: TEdit; EditAdresse: TEdit; Editcmd: TEdit; Label1: TLabel; Label2: TLabel; Label3: TLabel; Label4: TLabel; Label5: TLabel; Label6: TLabel; LEtat2: TLabel; LEtat: TLabel; LazSerial1: TLazSerial; Memo1: TMemo; Memo2: TMemo; Memo3: TMemo; Memo4: TMemo; Timer1: TTimer; procedure ButtonStopClick(Sender: TObject); procedure ButtonStartClick(Sender: TObject); procedure CheckBox1Change(Sender: TObject); procedure Edit4Change(Sender: TObject); procedure EditAdresseChange(Sender: TObject); procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure FormCreate(Sender: TObject); Procedure CommandeADAM(adr:string; cmd:string; var reponse:string); procedure Timer1Timer(Sender: TObject); private { private declarations } public { public declarations } end; var Form1: TForm1; TimeOut : boolean; str_retour :string; str_answer :string; integrale : real; ancienne_valeur: real; delta_Temp_pre:real; delta_Temp_pre2: real; com_pre : real; stopautomate : boolean; //ButtonQuitter : boolean; RAZ_Automate : boolean; x: real; z: real; implementation {$R *.lfm} { TForm1 } Procedure TForm1.CommandeADAM( adr:string; cmd:string; var reponse:string); var Atime, Btime: TDateTime; Etime: int64; // temps écoulé chaine : string; begin LazSerial1.WriteData( adr + cmd + CRLF); chaine :=''; TimeOut:= False; Atime:= now; While not TimeOut do // On attend la reponse Begin ETime := MilliSecondsBetween (Now, Atime); TimeOut := LazSerial1.DataAvailable; if Etime >= 50 then TimeOut := True; // TimeOut end; if LazSerial1.DataAvailable then begin // Reponse OK Btime:= now; TimeOut:= False; While not TimeOut do Begin chaine := chaine + LazSerial1.ReadData; ETime := MilliSecondsBetween (Now, Btime); if AnsiLastChar (chaine) = #13 then Timeout := True; // chaine complete if Etime >= 50 then TimeOut := True; // TimeOut end; end else chaine := 'error'; reponse := chaine; end; procedure TForm1.Timer1Timer(Sender: TObject); var Temp : real ; // température converti en reel e: integer; // vérification (code erreur) 0 = ok ; x = erreur au caractere x commande1: real; commande2: real; delta_Temp: real; kp : real; ki: real; kd : real; dT: real; derivee : real;// tout les var precedentes servent a calculer commande periode : longword; y: real; temps_haut:longword; temps_bas: longword; th:string; tb:string; timedown : boolean; debut: integer; fin: integer; begin debut:=GetTickCount ; CommandeADAM( EditAdresse.text, Editcmd.text, str_retour); Memo1.Lines.add ('Reçu:' + str_retour +' - ' + IntToStr(Memo1.Lines.Count)); delete(str_retour,1,1); //supprimé le > qui est le premier caractère delete(str_retour,8,3); // supprimé le 8 eme caractère Val (str_retour,Temp,e); // convertir la chaine en reel delta_temp:= strtofloat(Edit4.text) - Temp ; //calcul de l'erreur // Méthode1: kp:= 1; ki:=0; kd:=0; dt:=1000; derivee:= (delta_Temp - ancienne_valeur) / dt; //calcul de la derivee ancienne_valeur := delta_Temp; // mise en memoire de ancienne valeur integrale += integrale + delta_Temp * dt ; //calcul integrale commande1 := kp * delta_Temp + ki * integrale + kd * derivee; //calcul de la commande Memo4.Lines.add ( floattostr (commande1)); periode :=2000; // durée d'une période x:= commande1 /10 * periode; z:= periode - x; fin:= GettickCount - debut; Memo3.Lines.add ('Tps du prog: ' + floattostr(fin)+ 'ms'); end; procedure TForm1.ButtonStartClick(Sender: TObject); var BeginTime : cardinal; TimeOut : boolean; begin ButtonStop.Enabled := true; ButtonStart.Enabled := false; StopAutomate := True; RAZ_Automate := true; while (StopAutomate) do begin TimeOut := False; BeginTime := GetTickCount; Timer1Timer(owner);* while not TimeOut do begin application.ProcessMessages; CommandeADAM (Edit1.text, Edit3.text,str_answer); TimeOut := (GetTickCount - BeginTime) > x; end; Memo2.lines.add ( 'fermee: '+ floattostr(x) + ' ms'); // 1s Timeout :=false; while not TimeOut do begin application.ProcessMessages; CommandeADAM (Edit1.text, Edit2.text,str_answer); TimeOut := (GetTickCount - BeginTime) > z; end; Memo2.lines.add ( 'ouvert '+ floattostr(z) + ' ms'); end; LEtat.Caption := 'Arrêt'; LEtat2.Caption := 'Arrêt'; end; procedure TForm1.ButtonStopClick(Sender: TObject); begin StopAutomate := false; // arret automate PC ButtonStart.Enabled := true; ButtonStop.Enabled := false; //ButtonQuitter.Enabled := True; end; procedure TForm1.CheckBox1Change(Sender: TObject); begin Timer1.enabled := CheckBox1.Checked; end; procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction); begin LazSerial1.close; end; procedure TForm1.FormCreate(Sender: TObject); begin LazSerial1.Device:= 'COM4'; LazSerial1.Open; end; end.
Si des zones d'ombres subsistent dites le moi j'essayerai d'éclairer tout cela
Cordialement,
Quentin
-----