AdvancedHMI Software
General Category => Support Questions => Topic started by: ENA on November 18, 2013, 04:39:52 AM
-
Hello.
Is it possible to process signals and data inside HMI?
E.g., if I have several binary signals from PLC, lets call them S1, S2 and S3 (bits or inputs of PLC), can I use BasicIndicator to turn red for a specific combination of symbols?
So, if (S1=1 or S2=1 or S3=0) Basic Indicator should be red (e.g. General Error).
Also, if I have several integer values, is it possible to make calculations inside HMI?
I'm sorry if this is a elementary question or if it was discussed already, I didn't find answers. I was trying to make myself clear, hope I'm not to vague.
-
The BasicInidicator is a 3 color display controlled by 2 bits. You put the 2 bit addresses in PLCAddressSelectColor2 and PLCAddressSelectColor3. You can then set the 3 colors with the color properties. If both bits are false, it will show Color1, if the value in PLCAddressSelectColor2 is true, then it will show Color2, etc.
To do calculations, you will need to write a little bit of code. If you want to add 3 numbers, you can add 3 DataSubscribers to the form and set PLCAddressValue for each of the integers. Add a Label to the form to show the sum. Double click the first DataSubscriber to get back to the code.
Label1.Text=DataSubscriber1.Value+DataSubscriber2.Value+DataSubscriber3.Value
You will need to put this code in the DataChanged event for each of the DataSubscribers.
-
Thank you for your answer Archie.
I tried what you suggested, but it doesn't seem to work hat way. I have data subscribers DS_INT1 and DS_INT2. DS_INT1 reads from N100:0 and DS_INT2 reads from N100:1. Also there is a label called NLabel. Code is as you said (I both tried with NLabel.Text and NLabel.Value):
NLabel.Text = DS_INT1.Value + DS_INT2.Value
Lets assume that N100:0 = 21 and N100:1 = 1.
Label then shows: 211
It doesn't add values, but only appends value from one adress (DataSubscriber) to the value from another.
Would appreciate your further comments on this.
-
I tried what you suggested, but it doesn't seem to work hat way. I have data subscribers DS_INT1 and DS_INT2. DS_INT1 reads from N100:0 and DS_INT2 reads from N100:1. Also there is a label called NLabel. Code is as you said (I both tried with NLabel.Text and NLabel.Value):
NLabel.Text = DS_INT1.Value + DS_INT2.Value
Lets assume that N100:0 = 21 and N100:1 = 1.
Label then shows: 211
It doesn't add values, but only appends value from one adress (DataSubscriber) to the value from another.
NLabel.Text = CInt(DS_INT1.Value) + CInt(DS_INT2.Value)
Ironically I teach this in training classes to be careful about implicit conversion because it will concatenate strings instead of mathematically sum their values. The strings have to be explicitly converted to integers.
-
Thank you Archie, that fixed it. I had a feeling it could be something like that, but I'm a complete newbie with Visual Basic (I'm actually an electromechanical engineer trying to implement SCADA for my PLC systems), and don't have a clue about syntax etc.
Following this example, I tried to experiment with BasicIndicator mentioned in the first post. Idea is to subscribe to bits in PLC and, when they change, change the color of Indicator.
This code is ni DataSubscriber DataChanged sub:
If DS_NZS.Value <> 0 Or DS_NAPON.Value <> 0 'This is where I could put all of my signals and conditions
Indicator.SelectColor2 = True
Else Indicator.SelectColor2 = False
End If
Code builds successfully, but it breaks with a message:
"Conversion from string "False" to type "Double" is not valid."
I tried dissecting the code, but can't find where my mistake is. I'm not even sure if this is the correct way to do what I want.
-
The addresses used in DZ_NZS must be pointing to boolean (or bit) values and returning "True" or "False". It is trying to convert this to a value so it can compare it to 0
If DS_NZS.Value<>"False" or DS_NAPON.Value<>"False" then
or
If DS_NZS.Value or DS_NAPON.Value then
Would it be easier to just put the tag names in PLCAddressSelectColor2 and PLCAddressSelectColor3 instead of trying to write your own VB code?
-
Would it be easier to just put the tag names in PLCAddressSelectColor2 and PLCAddressSelectColor3 instead of trying to write your own VB code?
Yes, it would. But, as I understand, then I'm limited to two bits for one indicator. I might need to link e.g. 4 or 5 status bits from PLC to one "General Error" Indicator.
Anyway, this is now working and I must thank you yet again. :)
-
Hello! I have another question.
If I have some instructions that should be executed only once, at startup of my application, how and where should I write them in code?
-
If I have some instructions that should be executed only once, at startup of my application, how and where should I write them in code?
Double click your MainForm to get back to the Form_Load event.
-
Thnx Archie.
For now I managed to initialize Excel file at the startup of application, as globally accessible. I have a hidden form which only purpose is data acquisition using DataSubscribers and periodical export (using timer) of selected data into Excel file, along with ID, date and time.
I have a button for quitting application in my MainForm and when pressed the following code is executed:
DataPolling.Excel_export.Enabled = False
GlobalVariables.oExcel_file1.Quit()
Enviroment.Exit(0)
DataPolling - hidden form with data subscribers
Excel_export - timer for periodical export of data
GlobalVariables - public class where I keep my global variables
oExcel_file1 - public object pointing to excel file
When I quit my application using my quit button, sometimes, Windows give message "AdvancedHMI has stopped working". If I comment the line disabling timer the application quits correctly. Is that line even necessary, am I obligated to stop timer when quitting application?
-
Most of the time you are not obligated to stop the timer. It depends on your code in the tick event. If the form begins to close just as the tick event fires, your code may access a resource that has been disposed and causing an exception or lock up.
I would actually encapsulate the timer disable in the form that contains the timer:
Protected Overrides Sub OnFormClosing(e As System.Windows.Forms.FormClosingEventArgs)
Excel_export.Enabled = False
MyBase.OnFormClosing(e)
End Sub
-
I modified my code as you suggested. For now it hasn't sent any errors.
I'm quite stuck on an another problem. I have an excel file with columns:
A - entry ID
B - date
C - time
D - data1
E - data2
I placed a chart object in my form. I would like to plot my data1 versus date and time. If it would make it easier, I can export date and time in one cell.
I tried several code examples I found on the internet, but had no luck. :(
Ultimately, I would like to have a drop down menu to select which data to plot (data1, data2, ....), two calendars to select start and stop date, and a basic button which would plot the data. But for the beggining, I would just like to be able to plot my excel data to a chart. Please help.
Also in Excel there are many chart styles. Is there a way to apply one of those styles to a chart in a form?
-
I'm a little confused with what is in Excel and what is on a Visual Studio form. Are you just storing the data in Excel and reading back in Visual Basic to show on a chart?
-
Yes, exactly.
Excel file is a storage file where I keep all my data logs. That file opens when my application starts. Applications periodically or on demand writes data to file with a timestamp and saves file after each write. File is open all the time the application is running.
I write my data to excel file from a form that is hidden, user never sees it, but is running in a background.
On a separate form, for when user wants to graphically analyze data, I placed a chart. From that form I will read data from Excel file and plot it in the chart.
I can't figure out that last part of reading and plotting the data.
-
And another question, when my application crashes for whatever reason, my excel files of course stay open, because application didn't exit properly. How can I "clean up" behind application so it closes all open files? I suppose this question could expand on how do I do a general garbage collection?
I'm sorry I'm so tiring and have so many questions, I would like to make this work. Really appreciate all you help.
-
What are you using to write to Excel within VB?
-
My global variables for excel files:
Public Class GlobalVariables
'**************************************************************************************************
'Excel file1
'data log
Public Shared CellIndexRow_file1 As Long = 2 'prvi red je zaglavlje
Public Shared oExcel_file1 As Object
Public Shared oBook_file1 As Object
Public Shared oSheet_file1 As Object
'**************************************************************************************************
'**************************************************************************************************
'Excel file2
'event list
Public Shared CellIndexRow_file2 As Long = 2 'prvi red je zaglavlje
Public Shared oExcel_file2 As Object
Public Shared oBook_file2 As Object
Public Shared oSheet_file2 As Object
'**************************************************************************************************
End Class
In load event function of my main form (actually called "PregledSustava"), this is code to set all the variables:
Private Sub MainForm_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
'**************************************************************************************************
'Excel file1 initialization, initialization of pointera on first empty row in Excel
'data log
GlobalVariables.oExcel_file1 = CreateObject("Excel.Application")
GlobalVariables.oExcel_file1 = New Excel.Application
GlobalVariables.oExcel_file1.Workbooks.Open("E:\Documents\Documents\AdvancedHMI\Proba_Excell\AdvancedHMI\bin\Debug\excel_logs\HMItest.xlsx")
GlobalVariables.oBook_file1 = GlobalVariables.oExcel_file1.Workbooks(1)
GlobalVariables.oSheet_file1 = GlobalVariables.oBook_file1.Worksheets(1)
While (GlobalVariables.oSheet_file1.Range("A" + CStr(GlobalVariables.CellIndexRow_file1)).Value <> 0)
GlobalVariables.CellIndexRow_file1 = GlobalVariables.CellIndexRow_file1 + 1
End While
'**************************************************************************************************
'**************************************************************************************************
'Excel file2 initialization, initialization of pointera on first empty row in Excel
'event log
GlobalVariables.oExcel_file2 = CreateObject("Excel.Application")
GlobalVariables.oExcel_file2 = New Excel.Application
GlobalVariables.oExcel_file2.Workbooks.Open("E:\Documents\Documents\AdvancedHMI\Proba_Excell\AdvancedHMI\bin\Debug\excel_logs\event_log.xlsx")
GlobalVariables.oBook_file2 = GlobalVariables.oExcel_file2.Workbooks(1)
GlobalVariables.oSheet_file2 = GlobalVariables.oBook_file2.Worksheets(1)
While (GlobalVariables.oSheet_file2.Range("A" + CStr(GlobalVariables.CellIndexRow_file2)).Value <> 0)
GlobalVariables.CellIndexRow_file2 = GlobalVariables.CellIndexRow_file2 + 1
End While
'**************************************************************************************************
'**************************************************************************************************
'start timer for periodical export of data in Excel
DataPolling.Excel_export.Enabled = True
'period of data export in seconds or minutes
DataPolling.Excel_export.Interval = 5 * 1000 '*60
'**************************************************************************************************
'**************************************************************************************************
'DataPolling form must be activated to start polling data, then hide it and show MainForm
DataPolling.Show()
DataPolling.Hide()
Me.Show()
'**************************************************************************************************
End Sub
In DataPolling form is a timer to periodically export data, this is function that handles timer tick:
Private Sub Excel_export_tick(sender As Object, e As EventArgs) Handles Excel_export.Tick
'**************************************************************************************************
'writing data in Excel columns A-E, row determined by CellIndexRow_file1
GlobalVariables.oSheet_file1.Range("A" + CStr(GlobalVariables.CellIndexRow_file1)).Value = GlobalVariables.CellIndexRow_file1 - 1
GlobalVariables.oSheet_file1.Range("B" + CStr(GlobalVariables.CellIndexRow_file1)).Value = DateString
GlobalVariables.oSheet_file1.Range("C" + CStr(GlobalVariables.CellIndexRow_file1)).Value = TimeOfDay()
GlobalVariables.oSheet_file1.Range("D" + CStr(GlobalVariables.CellIndexRow_file1)).Value = DS_INT1.Value
GlobalVariables.oSheet_file1.Range("E" + CStr(GlobalVariables.CellIndexRow_file1)).Value = DS_INT2.Value
'go to next row
GlobalVariables.CellIndexRow_file1 = GlobalVariables.CellIndexRow_file1 + 1
'save changes to file
GlobalVariables.oBook_file1.Save()
'**************************************************************************************************
End Sub
Function of data subscriber in DataPolling form for DataChanged, writes event in excel when PLC input changes. This is where I get double entries in file for every event:
Private Sub DS_NZS_DataChanged(sender As Object, e As Drivers.Common.PlcComEventArgs) Handles DS_NZS.DataChanged
'function that handles BasicIndicator color change
Obradi_OpcaGreska()
If DS_NZS.Value = True Then
'**************************************************************************************************
'write event in Excel event log
GlobalVariables.oSheet_file2.Range("A" + CStr(GlobalVariables.CellIndexRow_file2)).Value = GlobalVariables.CellIndexRow_file2 - 1
GlobalVariables.oSheet_file2.Range("B" + CStr(GlobalVariables.CellIndexRow_file2)).Value = DateString
GlobalVariables.oSheet_file2.Range("C" + CStr(GlobalVariables.CellIndexRow_file2)).Value = TimeOfDay()
GlobalVariables.oSheet_file2.Range("D" + CStr(GlobalVariables.CellIndexRow_file2)).Value = "ALARM Low level"
GlobalVariables.oSheet_file2.Range("E" + CStr(GlobalVariables.CellIndexRow_file2)).Value = "Pumping station 1"
GlobalVariables.oSheet_file2.Range("F" + CStr(GlobalVariables.CellIndexRow_file2)).Value = "General"
'go to next row in file
GlobalVariables.CellIndexRow_file2 = GlobalVariables.CellIndexRow_file2 + 1
'save changes to file
GlobalVariables.oBook_file2.Save()
'**************************************************************************************************
End If
End Sub
When closing my main form:
Protected Overrides Sub OnFormClosing(e As System.Windows.Forms.FormClosingEventArgs)
DataPolling.Excel_export.Enabled = False
GlobalVariables.oExcel_file1.Quit()
GlobalVariables.oExcel_file2.Quit()
Environment.Exit(0)
MyBase.OnFormClosing(e)
End Sub
-
Try putting this in your main form:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
AddHandler AppDomain.CurrentDomain.UnhandledException, AddressOf MyApplication_UnhandledException
End Sub
Private Sub MyApplication_UnhandledException(ByVal sender As Object, ByVal e As System.UnhandledExceptionEventArgs)
'* Insert code to close open files
MsgBox("Unhandled Exception occurred")
End Sub
-
Works great! I have no open files left after application crash.