Autor Beitrag
bidi
Hält's aus hier
Beiträge: 3


D7
BeitragVerfasst: Fr 26.08.05 14:18 
Hallo!

Ich habe einen TThread, der während der gesammten Programm-Laufzeit läuft und Daten "sammelt". d.h. er Liest Daten von der Seriellen-Schnittstelle sowie von einem USB-Gerät (über eine DLL). Diese Daten, in meinem Fall Temperaturen sollen dem MainThread zur verfügung gestellt werden.
Bis jetzt habe ich folgenden Code:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
234:
235:
236:
237:
238:
239:
240:
241:
242:
243:
244:
245:
246:
247:
248:
249:
250:
251:
252:
253:
254:
255:
256:
257:
258:
259:
260:
261:
262:
263:
264:
265:
266:
267:
268:
269:
270:
271:
272:
273:
274:
275:
276:
277:
278:
279:
280:
281:
282:
283:
284:
285:
286:
287:
288:
289:
290:
291:
292:
unit HWUnit;

interface

uses
  Forms, Classes, RegExpr, SysUtils, AdPort, DateUtils, DFZUnit;


type
  TempSensor = record
  romid: String;
  temp: double;
  changed: TDateTime;
end;


type
  THWThread = class(TThread)
  private
    { Private-Deklarationen }
    DataReg: TRegExpr;
    BufferReg: TRegExpr;

    ComPort: TApdComPort;
    com_buffer: String;

    TempSensors: Array[0..11of TempSensor;
    Inputs: Array[0..4of Boolean;
    Outputs: Array[0..7of Boolean;
    ADCs: Array[0..1of Integer;

    SolZae: TDFZaehler;
    FWWLiter: double;


    function GetSolarDurchfluss: double;
    function GetSolarLiter: double;

    function GetWWLiter: double;

    function GetInput(Index: Integer): Boolean;
    function GetTemp(Index: Integer): double;
    function GetADC(Index: Integer): Integer;

    function GetOutput(Index: Integer): Boolean;
    procedure SetOutput(Index: Integer; Value: Boolean);

    procedure ExtractBuffer(const AInputString : string);
    procedure ExtractData (const AInputString : string);
  protected
    procedure Execute; override;

  public
    constructor Create(CreateSuspended: Boolean);
    destructor Destroy; override;

    property Input[Index: Integer]: Boolean read GetInput;
    property Temp[Index: Integer]: Double read GetTemp;
    property ADC[Index: Integer]: Integer read GetADC;
    property Output[Index: Integer]: Boolean read GetOutput write SetOutput;

    property SolarDurchfluss: Double read GetSolarDurchfluss;
    property SolarLiter: Double read GetSolarLiter;

    property WWLiter: Double read GetWWLiter;
    property debg: string read com_buffer;

  end;

var
  HWThread: THWThread;

const
  DataRegEx = '>(([0-9A-F]{2} ){8}) (.[0-9]{1,}\.[0-9]{4})°C<';
  BufferRegEx = '([^<]*)$';

  VLH = 0;
  RLH = 1;
  P1 = 2;
  P2 = 3;
  P3 = 4;
  P4 = 5;
  RLS = 6;
  VLS = 7;
  WW1 = 8;
  WW2 = 9;
  WW3 = 10;
  WW4 = 11;

implementation

  function OpenDevice(CardAddress: Longint): Longint; stdcallexternal 'K8055d.dll';
  procedure CloseDevice; stdcallexternal 'K8055d.dll';

  function ReadAnalogChannel(Channel: Longint):Longint; stdcallexternal 'K8055d.dll';
  procedure ReadAllAnalog(var Data1, Data2: Longint); stdcallexternal 'K8055d.dll';
  procedure OutputAnalogChannel(Channel: Longint; Data: Longint); stdcallexternal 'K8055d.dll';
  procedure OutputAllAnalog(Data1: Longint; Data2: Longint); stdcallexternal 'K8055d.dll';
  procedure ClearAnalogChannel(Channel: Longint); stdcallexternal 'K8055d.dll';
  procedure ClearAllAnalog; stdcallexternal 'K8055d.dll';
  procedure SetAnalogChannel(Channel: Longint); stdcallexternal 'K8055d.dll';
  procedure SetAllAnalog; stdcallexternal 'K8055d.dll';
  procedure WriteAllDigital(Data: Longint);stdcall;  external 'K8055d.dll';
  procedure ClearDigitalChannel(Channel: Longint); stdcallexternal 'K8055d.dll';
  procedure ClearAllDigital; stdcallexternal 'K8055d.dll';
  procedure SetDigitalChannel(Channel: Longint); stdcallexternal 'K8055d.dll';
  procedure SetAllDigital; stdcallexternal 'K8055d.dll';
  function ReadDigitalChannel(Channel: Longint): Boolean; stdcallexternal 'K8055d.dll';
  function ReadAllDigital: Longint; stdcallexternal 'K8055d.dll';
  function ReadCounter(CounterNr: Longint): Longint; stdcallexternal 'K8055d.dll';
  procedure ResetCounter(CounterNr: Longint); stdcallexternal 'K8055d.dll';
  procedure SetCounterDebounceTime(CounterNr, DebounceTime:Longint); stdcallexternal 'K8055d.dll';

constructor THWThread.Create(CreateSuspended: Boolean);
var
  i: Integer;
begin
  OpenDevice(0);
   DataReg := TRegExpr.Create;
  DataReg.Expression := DataRegEx;

   BufferReg := TRegExpr.Create;
  BufferReg.Expression := BufferRegEx;

  ComPort := TApdComPort.Create(nil);
  ComPort.Baud := 9600;
  ComPort.ComNumber := 1;
  ComPort.Open := True;

  // Solarzähler mit 10l/Impuls
  SolZae := TDFZaehler.Create;
  SolZae.DurchflussProImpuls := 10;
  SolZae.MindestDurchfluss := 1;


  TempSensors[VLH].romid := '10 F9 E9 3A 00 08 00 13';
  TempSensors[RLH].romid := '10 ED 06 3B 00 08 00 AE';
  TempSensors[P1].romid := '10 8B F1 3A 00 08 00 A7';
  TempSensors[P2].romid := '10 C2 E0 3A 00 08 00 F5';
  TempSensors[P3].romid := '10 07 F6 3A 00 08 00 61';
  TempSensors[P4].romid := '10 29 FB 3A 00 08 00 28';
  TempSensors[RLS].romid := '10 D7 CA 3A 00 08 00 00';
  TempSensors[VLS].romid := '10 C2 F8 3A 00 08 00 B7';
  TempSensors[WW1].romid := '10 B2 09 3B 00 08 00 CB';
  TempSensors[WW2].romid := '10 6C F6 3A 00 08 00 5A';
  TempSensors[WW3].romid := '10 11 50 AA 00 08 00 C6';
  TempSensors[WW4].romid := '10 ED 7E AC 00 08 00 9A';

  for i := 0 to Length(TempSensors)-1 do
  begin
    TempSensors[i].temp := -255;
    TempSensors[i].changed := Now();
  end;

  ClearAllAnalog();
  ClearAllDigital();
  SetCounterDebounceTime(1,250);
  ResetCounter(1);
  inherited;
end;

destructor THWThread.Destroy;
begin
  ComPort.Open := False;
  CloseDevice;

  DataReg.Free;
  BufferReg.Free;

  SolZae.Free;
end;

procedure THWThread.Execute;
var
  data: string;
  count, i: Integer;

begin


  while not Terminated do
  begin

      // Com-Port-Buffer auf Daten prüfen
      count := ComPort.InBuffUsed;
      if count >= 37-length(com_buffer) then
      begin
        for i:=1 to count do
        data := data + ComPort.GetChar;
        data := com_buffer + data;
        ExtractData(data);
        ExtractBuffer(data);
      end;


      ReadAllAnalog(ADCs[0],ADCs[1]);

      for i:=0 to Length(Inputs)-1 do
        Inputs[i] := ReadDigitalChannel(i+1);

      if ADCs[0] < 90 then SolZae.Level := false;
      if ADCs[0] > 100 then SolZae.Level := true;



      sleep(10);

  end;
end;

{ Durchfluss-Zähler }

function THWThread.GetWWLiter: double;
begin
  Result := ReadCounter(1);
  ResetCounter(1);
end;

function THWThread.GetSolarDurchfluss: double;
begin
  Result := SolZae.Durchfluss;
end;
function THWThread.GetSolarLiter: double;
begin
  Result := SolZae.Liter;
end;


{ E/A - USB }
function THWThread.GetInput(Index: Integer): Boolean;
begin
  Result := Inputs[Index];
end;

function THWThread.GetADC(Index: Integer): Integer;
begin
  Result := ADCs[Index];
end;
function THWThread.GetOutput(Index: Integer): Boolean;
begin
  Result := Outputs[Index];
end;   
procedure THWThread.SetOutput(Index: Integer; Value: Boolean);
begin
  Outputs[Index] := Value;
  if Value then SetDigitalChannel(index+1)
  else ClearDigitalChannel(index+1);
end;


{******************************************************************************}
{ Temperatur-Sensoren                                                          }
{                                                                              }
{                                                                              }
{******************************************************************************}
procedure THWThread.ExtractData (const AInputString : string);
var
  i: integer;
begin
  if DataReg.Exec (AInputString) then
  repeat
    for i:=0 to Length(TempSensors)-1 do
    begin
      if TempSensors[i].romid = trim(DataReg.Match[1]) then
      begin
         DecimalSeparator := '.';
         TempSensors[i].temp := StrToFloat(DataReg.Match[3]);
         break;
      end;
    end;
  until not DataReg.ExecNext;
end;

procedure THWThread.ExtractBuffer(const AInputString : string);
begin
  if BufferReg.Exec (AInputString) then com_buffer := BufferReg.Match[0];
end;

function THWThread.GetTemp(Index: Integer): double;
begin
  result := TempSensors[Index].temp;
end;



initialization
  HWThread := THWThread.Create(false);
finalization
  HWThread.Terminate;
  HWThread.WaitFor;
  HWThread.Free;
end.


Man Beachte die property Temp mit GetTemp sowie ExtractData und Execute.
In der Schleife werden ggf. vorhandene Daten vom COM-Port gelesen und an ExtractData übergeben. ExtractData "extrahiert" aus dem empfangenen String die Temperatur und schreibt sie in TempSensors[?].temp.

Aus dem primären Thread greife ich nun zu "willkürlichen" Zeitpunkten auf HWThread.Temp[P1] zu. Dies liefert mir auch werte zurück... jedoch scheit da was nicht hinzuhauen. Ich habe diese Temperaturen minütlich in einer Datenbank gespeichert und daraus ein Diagramm erstellt. (siehe Anhang)
Man kann erkennen, dass die Wert sagen wir "schwingen" und die Amplitude zunimmt. Die am COM-Port empfangenen Daten sind korrekt. Immer wenn diese Schwingung verschwindet habe ich das Programm neu gestartet... im verlauf der Zeit nimmt diese extreme Ausmaße an.

Vermutlich kann ich nicht einfach mit HWThread.Temp[x] aus dem primären Thread auf diese Temperaturen zugreifen. Bitte sagt mir also was ich anders machen muss, damit es funktioniert.

PS.: Bin auch per ICQ zu erreichen :-)

schonma Danke und Tschöö
BiDi
Einloggen, um Attachments anzusehen!
Sprint
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 849



BeitragVerfasst: Fr 26.08.05 15:25 
user profile iconbidi hat folgendes geschrieben:
Vermutlich kann ich nicht einfach mit HWThread.Temp[x] aus dem primären Thread auf diese Temperaturen zugreifen. Bitte sagt mir also was ich anders machen muss, damit es funktioniert.

Nehmen wir mal an die Daten werden korrekt im Thread verarbeitet, vielleicht hilft dann schon ein Synchronize, TMultiReadExclusiveWriteSynchronizer oder ein TCriticalSection.

_________________
Ciao, Sprint.
bidi Threadstarter
Hält's aus hier
Beiträge: 3


D7
BeitragVerfasst: Fr 26.08.05 15:49 
Ich habe mal versucht das umzusetzen...
folgende Änderungen habe ich gemacht:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
procedure THWThread.ExtractData (const AInputString : string);  
var  
  i: integer;
  new_temp: double;
begin
  if DataReg.Exec (AInputString) then
  repeat
    HWmrews.BeginRead;
    try
      for i:=0 to Length(TempSensors)-1 do
      begin
        if TempSensors[i].romid = trim(DataReg.Match[1]) then
        begin
          DecimalSeparator := '.';
          new_temp := StrToFloat(DataReg.Match[3]);
          if (TempSensors[i].temp <> new_temp) then
          begin
            HWmrews.EndRead;
            HWmrews.BeginWrite;
            TempSensors[i].temp := new_temp;
            HWmrews.EndWrite;
            HWmrews.BeginRead;
          end;
          break;
        end;
      end;
    finally
      HWmrews.EndRead;
    end;
  until not DataReg.ExecNext;
end;


ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
function THWThread.GetTemp(Index: Integer): double;  
begin  
  HWmrews.BeginRead;
  result := TempSensors[Index].temp;
  HWmrews.EndRead;
end;


Außerdem habe ich TempSensors zu einer globalen Variable gemacht.... Ich gehe jetzt erstma Arbeiten in der Hoffnung, dass meine Diagramm besser aussieht, wenn ich wieder komme.

Weitere Vorschläge sind gern willkommen :-)
bidi Threadstarter
Hält's aus hier
Beiträge: 3


D7
BeitragVerfasst: Fr 26.08.05 22:52 
Leider hat sich noch keine Verbesserung eingestellt :-(

Hat jemand noch eine Idee?