You are on page 1of 8

Designing the software data logger for MASTECH

MS8229 part2
Author tasosPublished on October 8, 2012

Making DMM

In this third and last article of this series we will add two libraries in our Lazarus project and the event handling.
The compiled project can be found at TrustFm Opens in a new window website.
We are going to use the synaser library (part of synapse Opens in a new window) for the serial communication and the
PlotPanel Opens in a new windowin order to plot our real time graph.
For synaser we are going to add only the "synaser.pas" file into our project.

For the PlotPanel we need to add the "plotpanel.pas" file into our project.

More informations for synaser can be found here Opens in a new window and for PlotPanel here Opens in a new
window

So we need to add to the uses the needed classes :

?
1
uses
2 Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
3 ExtCtrls, ComCtrls, Spin, Buttons,
4 //Serial
5 Synaser,
6 //Plot
Plotpanel;
7

For synaser we are going to define two global variables :


BlockSerial : TBlockSerial;
Timeout : integer; //in ms

DMM Data Logger

The connection procedure is pretty self explanatory.


We are creating the object BlockSerial of the TBlockSerial class.
Now we can play around with the attributes of the BlockSerial object.
Notice that we are using the values found at the official documentation.
The IsConnected is a global boolean as well.
?
1
2 procedure TFormMain.Connect(ComPort:string);
3 begin
4 Blockserial:=TBlockserial.Create;
5 BlockSerial.RaiseExcept:=true;
6 try
BlockSerial.Connect(ComPort);
7 BlockSerial.Config(2400,8,'N',0,false,false); //These values work with the DMM MS8229
8 IsConnected := true;
9 StatusBar.Panels.Items[0].Text:='Status : CONNECTED';
10 except
on E : Exception do begin
11 ShowMessage(E.ClassName + ' error raised, with message : ' + E.Message);
12 IsConnected := false;
13 StatusBar.Panels.Items[0].Text:='Status : CONNECTION ERROR';
14 end;
15 end;
end;
16
17

Time for the disconnection procedure :

?
1
procedure TFormMain.Disconnect();
2begin
3 BlockSerial.Purge;
4 BlockSerial.Free;
5 IsConnected := false;
StatusBar.Panels.Items[0].Text:='Status : DISCONNECTED';
6end;
7

Now it is time to implement the GetCode procedure.


We are going to read byte by byte using the BlockSerial.RecvByte command.
Once we read one byte the first thing to do is to calculate it's segment number :

segment := TempByte shr 4; // //XXXXYYYY->0000XXXX get the segment number

Then if the segment number is 1 we are good to go and we read the rest 13 bytes byte by byte using
BlockSerial.RecvByte.
If the segment is between 2 and 14 then we need to ignore 14-segment number bytes in order to find the starting byte
(segment 1).

?
procedure TFormMain.GetCode();
1 var TempByte: byte;
2 segment: integer;
3 i:integer;
4 ignorebytes:integer;
begin
5 if (BlockSerial.LastError <> 0) then Exit;
6 if BlockSerial.CanRead(Timeout) then begin
7
8 TempByte := BlockSerial.RecvByte(Timeout);
9 segment := TempByte shr 4; //XXXXYYYY->0000XXXX get the segment number
10 if segment = 1 then begin
My_Multimeter.Code.Value[0] := TempByte;
11 for i:=1 to 13 do begin //read the rest 13 bytes
12 My_Multimeter.Code.Value[i] := BlockSerial.RecvByte(Timeout);
13 end;
14 end else begin
15
if (segment > 1) and (segment <= 14) then begin
16
17 ignorebytes:=14-segment;
18 if ignorebytes>0 then begin
19 for i:=1 to ignorebytes do begin
BlockSerial.RecvByte(Timeout); //ignore 14-segment bytes
20 end;
21 end;
22
23 TempByte := BlockSerial.RecvByte(Timeout); //try again to read the segment 1
24 segment := TempByte shr 4; //XXXXYYYY->0000XXXX get the segment number
if segment = 1 then begin
25 My_Multimeter.Code.Value[0] := TempByte;
26 for i:=1 to 13 do begin //read the rest 13 bytes
27 My_Multimeter.Code.Value[i] := BlockSerial.RecvByte(Timeout);
28 end;
29 end;
30
end;
31
32 end;
33 end;
34end;
35
36
37
38
39
40
41

I hope that this reading method is clear enough. Of course you can use your reading method as well.

Designing the software data logger for MASTECH


MS8229 part2
Author tasosPublished on October 8, 2012

Once setting up the synaser we are ready to add a TTimer in our project that :
1) Gets the code (GetCode)
2) Validates the parsed code (IsValidCode Opens in a new window)
3) Parses the status from the code (ParseStatus Opens in a new window)
4) Prints the code into the screen (PrintStatusInLabel)

?
//The timer !
1 procedure TFormMain.TimerTimer(Sender: TObject);
2 var y:double;
3 begin
4 Application.ProcessMessages;
5 GetCode();
StatusBar.Panels.Items[1].Text := 'Code : ' + PrintCode();
6 if IsValidCode then begin
7 StatusBar.Panels.Items[1].Text := StatusBar.Panels.Items[1].Text + ' [valid]';
8 ParseStatus();
9 LabelScreen.Caption := PrintStatusInLabel();
10
11 endStatusBar.Panels.Items[1].Text
else begin
:= StatusBar.Panels.Items[1].Text + ' [invalid]';
12 end;
13
14 FormMain.Refresh;
15
16 //Close the timer and disconnect if IsConnected is false
17 if not IsConnected then begin
Timer.Enabled:=false;
18 Disconnect();
19 end;
20end;
21
22
23
24

The on connect / disconnect event is a OnClick TButton event.


We simply enable or disable the TTimer.
Notice that disabling the timer on this event can cause errors since the timer can be doing a reading operation.
So we set the global variable IsConnected to false and then in the TTimer event (worker) on a "secure zone" makes the
disconnection.
This is a classic threading error for young players. Threads will be discussed in another series of lessons.
Right now look it this way : TTimer does a reading job.
Only TTimer knows when is done with the reading so i (external event) will simply inform the TTimer to disconnect
when he finishes his reading and he can securely disconnect.

?
1
2 //On connect disconnect
3 procedure TFormMain.ButtonConnectDisconnectClick(Sender: TObject);
4 begin
5
6 //Connect
7 if ButtonConnectDisconnect.Caption = 'Connect' then begin
8
Connect(EditPort.Text); //Connect at the port ...
9
10 if IsConnected then begin
11 ButtonConnectDisconnect.Caption:='Disconnect';
12 Timer.Interval:=SpinEditEveryXMs.Value;
13 Timer.Enabled:=true;
end;
14
15 //Disconnect
16 end else if ButtonConnectDisconnect.Caption = 'Disconnect' then begin
17
18 IsConnected := false; //this must stop the timer securely
19 ButtonConnectDisconnect.Caption:='Connect';
20
21 end;
end;
22
23

The print status in label can be something like that :

?
1 function TFormMain.PrintStatusInLabel():string;
2 var stemp:string;
begin
3
4 if My_Multimeter.Status.IsRS232 = true then
5 stemp += ' [RS233] ';
6
7 if My_Multimeter.Status.IsAuto = true then
8 stemp += ' [AUTO] ';
9
10 ifstemp
My_Multimeter.Status.AC_DC_None = AC then
+= ' [AC] '
11 else if My_Multimeter.Status.AC_DC_None = DC then
12 stemp += ' [DC] ';
13
14 stemp += My_Multimeter.Status.ValuePrefix + ' ' + My_Multimeter.Status.UnitPrefix +
15My_Multimeter.Status.UnitValue;
16
stemp += #13#10; //Break line
17
18 if My_Multimeter.Status.IsDiode = true then
19 stemp += ' DIODE ';
20
21 if My_Multimeter.Status.IsSound = true then
22 stemp += ' SOUND ';
23
24 ifstemp
My_Multimeter.Status.IsHold = true then
+= ' HOLD ';
25
26 if My_Multimeter.Status.IsRelative = true then
27 stemp += ' REL ';
28
29 if My_Multimeter.Status.IsBattery = true then
30 stemp += ' BAT ';
31
result := stemp;
32
33end;
34
35
36
37

At this point you should be able to get the readings on your screen (LabelScreen.Caption)
Of course once reading the values you can store them into a ListView / csv file.
You can use your dedicated functions in order to do this job.
This step is really easy to do and it is not explained in this article.
In the next page we will see the plot graph.

Designing the software data logger for MASTECH


MS8229 part2
Author tasosPublished on October 8, 2012

PlotPanel Opens in a new window contains a nice demo (TryPlotPanel) so we are based in the official demo example.
We create a new "graph" form .
We add these variables :

?
1public
2 My_PlotPanel: TPlotpanel;
3 Xcur : integer; //Xcur is the current time stamp
4 Xwidth : integer;

We make the CreatePanel and the ClearPanel procedures.

?
1 procedure TFormGraph.CreatePanel(Sender: TObject);
begin
2 My_PlotPanel:=Tplotpanel.Create(Self);
3 My_PlotPanel.Top:=8;
4 My_PlotPanel.Left:=8;
5 My_Plotpanel.Width:=462;
My_PlotPanel.Height:=300;
6 My_PlotPanel.Margin:=10;
7 My_PlotPanel.Anchors:=[akTop,akLeft,akBottom,akRight];
8 My_PlotPanel.Color:=clBtnFace;
9 My_PlotPanel.BackColor:=clWhite;
My_PlotPanel.GridColor:=clSilver;
10 My_PlotPanel.PlotPen.Color:=clBlue;
11 My_PlotPanel.PlotPen.Width:=2;
12 My_PlotPanel.XLabel:='Record number';
13 My_PlotPanel.YLabel:='Value';
14end;
15procedure TFormGraph.ClearPanel();
16begin
17 My_PlotPanel.Freeze(True);
18 My_PlotPanel.XMarks:=true;
19 My_PlotPanel.YMarks:=true;
My_PlotPanel.XMarksFont.Color:=clBlack;
20 My_PlotPanel.YMarksFont.Color:=clBlack;
21 My_PlotPanel.XMin:=0;
22 My_PlotPanel.XMax:=Xwidth;
23 My_PlotPanel.YMin:=0;
24 My_PlotPanel.YMax:=10;
My_PlotPanel.XInterval:=1;
25 My_PlotPanel.YInterval:=1;
26 My_PlotPanel.ClearData;
27 My_PlotPanel.Freeze(False);
28end;
29
30
31
32
33
34

Focus your attention at the TryPlotPanel -> TimerPlot tab -> Start/Stop Chart button event

On the new form on the create event we do :

?
1procedure TFormGraph.FormCreate(Sender: TObject);
2begin
3 CreatePanel(nil);
4 ClearPanel();
5end;

Now the TTimer can plot the graph !

?
1 //The timer !
procedure TFormMain.TimerTimer(Sender: TObject);
2 var y:double;
3 begin
4 Application.ProcessMessages;
5 GetCode();
StatusBar.Panels.Items[1].Text := 'Code : ' + PrintCode();
6 if IsValidCode then begin
7 StatusBar.Panels.Items[1].Text := StatusBar.Panels.Items[1].Text + ' [valid]';
8 ParseStatus();
9 LabelScreen.Caption := PrintStatusInLabel();
10
11 //Plot the graph !
if CheckBoxEnableGraph.Checked then begin
12
13 inc(FormGraph.Xcur); //increase the time stamp
14
15 With FormGraph.My_PlotPanel do begin
16 Freeze(True);
17 PlotPen.Width:=2;
PlotMode:=pmLine;
18
19 if TryStrToFloat(My_Multimeter.Status.ValueNoPrefix,y) then begin
20
21 AddXY(FormGraph.Xcur,y); //Plot x,y point
22
23 //Autoscale
24 if FormGraph.CheckBoxAutoscaleY.Checked then begin
if FormGraph.Xcur > 10 then AutoScale(0); //Autoscale x,y
25 end else begin
26 YMax:=FormGraph.SpinEditMaxY.Value;
27 YMin:=FormGraph.SpinEditMixY.Value;
28 end;
29
30 XMin:=FormGraph.Xcur-FormGraph.Xwidth; //Scale X to XWidth
XMax:=FormGraph.Xcur;
31 XInterval:=1;
32 YInterval:=(YMax-YMin)/10;
33
34 end;
35
36 Freeze(False);
end;
37
38 end;
39 end else begin
40 StatusBar.Panels.Items[1].Text := StatusBar.Panels.Items[1].Text + ' [invalid]';
41 end;
42
43 FormMain.Refresh;
44
//Close the timer and disconnect if IsConnected is false
45 if not IsConnected then begin
46 Timer.Enabled:=false;
47 Disconnect();
48 end;
49end;
50
51
52
53
54
55
56
57

We are done !
DMM Data Logger can be downloaded from here Opens in a new window

DMM Data Logger

You might also like