{"id":29294,"date":"2022-08-22T00:55:03","date_gmt":"2022-08-22T07:55:03","guid":{"rendered":"https:\/\/digilent.com\/blog\/?p=29294"},"modified":"2022-08-22T00:55:03","modified_gmt":"2022-08-22T07:55:03","slug":"reading-generated-data-in-a-real-time-distributed-system-part-2","status":"publish","type":"post","link":"https:\/\/digilent.com\/blog\/reading-generated-data-in-a-real-time-distributed-system-part-2\/","title":{"rendered":"Reading Generated Data in a Real-Time Distributed System &#8211; Part 2"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.digilent.com\/blog\/wp-content\/uploads\/2022\/08\/2022-ReadingGeneratedData-part2-580.png\" alt=\"\" width=\"580\" height=\"290\" class=\"aligncenter size-full wp-image-29325\" data-wp-pid=\"29325\" \/><\/p>\n<p>This is second part in this series.<\/p>\n<p><a href=\"https:\/\/digilent.com\/blog\/reading-generated-data-in-a-real-time-distributed-system-part-1\/\">Part 1 &#8211; Setting Up an MS Database<\/a><\/p>\n<p><a href=\"https:\/\/digilent.com\/blog\/reading-generated-data-in-a-real-time-distributed-system-part-3\/\">Part 3 &#8211; Creating an Application to View Data<\/a><\/p>\n<p><a href=\"https:\/\/digilent.com\/blog\/reading-generated-data-in-a-real-time-distributed-system-part-4\/\">Part 4 &#8211; Distributing Applications<\/a><\/p>\n<p><a href=\"https:\/\/digilent.com\/blog\/reading-generated-data-in-a-real-time-distributed-system-part-5\/\">Part 5 &#8211; Using Additional Software Packages<\/a><\/p>\n<h2>Creating an Application to Collect and Pass Data<\/h2>\n<p style=\"font-weight: 400;\">In Part 1, we created an ODBC connection on the development computer, opened the database file, added a data table, and some data fields.\u00a0 In Part 2, we will create the front end application that will read different types of signals from our data acquisition device, display the data using various display objects, and write the collected data to the database.<\/p>\n<p style=\"font-weight: 400;\">As stated at the beginning of this article, for this application we will be using the <a href=\"https:\/\/www.mccdaq.com\/usb-data-acquisition\/USB-2408-Series.aspx\">Measurement Computing<span>\u00a0<\/span><span>USB-2408<\/span><\/a><span>\u00a0<\/span>and the Universal Library, Microsoft Visual Basic 2010, and an add-in to Visual Basic called BERGtools.<\/p>\n<p style=\"font-weight: 400;\">I\u2019ve chosen the<span>\u00a0<\/span><span>USB-2408<\/span><span>\u00a0<\/span>because it fills the needs of our application with one device.\u00a0 I wanted to emulate a system containing a temperature input from a thermocouple, a voltage input from a pressure transducer, pulsed output from a tachometer, and digital input signal from a door interlock.\u00a0 The<span>\u00a0<\/span><span>USB-2408<\/span><span>\u00a0<\/span>is capable of reading from all these various input types and more.\u00a0 I am emulating the signals externally, using a type T thermocouple, function generator set to sine wave, another function generator set to TTL pulsed output, and a 5 VDC output power supply respectively.<\/p>\n<p style=\"font-weight: 400;\">I\u2019m using Visual Basic 2010 because I want to keep it compatible with those folks who don\u2019t have Microsoft\u2019s latest version but want to build this application. It is assumed you know your way around the Visual Basic IDE, so I\u2019m going to skip most screen shots so as to focus on the code.<\/p>\n<p style=\"font-weight: 400;\">BERGtools is a free collection of displays and functions including meters, oscilloscopes, knobs, etc., I created to make viewing data \u2018easier on the eyes\u2019.\u00a0 We will use them here but you can easily work around them or use your own objects.<\/p>\n<p style=\"font-weight: 400;\">To begin, launch Visual Basic, and start a new project.\u00a0 We will call it \u201cDataCollectionToDatabase.\u201d\u00a0 Resize your form to 589,422.<\/p>\n<p style=\"font-weight: 400;\">Add a MenuStrip, DataGridView, Timer, OpenFileDialog,Thermometer, 2 KnobDials, an LED, 2 buttons, and 11 labels.\u00a0 Your form design should look like this:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2022\/08\/10-Form-Design.png\" alt=\"\" width=\"593\" height=\"498\" class=\"aligncenter size-full wp-image-29295\" data-wp-pid=\"29295\" \/><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2022\/08\/11-Properties.png\" alt=\"\" width=\"428\" height=\"429\" class=\"aligncenter size-full wp-image-29296\" data-wp-pid=\"29296\" srcset=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2022\/08\/11-Properties.png 428w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2022\/08\/11-Properties-150x150.png 150w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2022\/08\/11-Properties-300x300-cropped.png 300w\" sizes=\"auto, (max-width: 428px) 100vw, 428px\" \/><\/p>\n<p style=\"font-weight: 400;\">Of all the labels, only 4 need to be named:<\/p>\n<p style=\"font-weight: 400;\">The one over the thermometer:\u00a0 lblTempValue<\/p>\n<p style=\"font-weight: 400;\">The one over kdPressure (to the right):\u00a0 lblPressure<\/p>\n<p style=\"font-weight: 400;\">The one over kdTach (to the right):\u00a0 lblTach<\/p>\n<p style=\"font-weight: 400;\">The one to the right of Time:\u00a0 lblTime<\/p>\n<p style=\"font-weight: 400;\">All labels should set Autosize = true<\/p>\n<p style=\"font-weight: 400;\">From the Solution Explorer, click on the icon to \u201cShow All Files\u201d.\u00a0 Right click on References, select \u201cAdd Reference\u2026\u201d\u00a0 The Add Reference dialog will show.\u00a0 Click on .NET tab, Scroll down and select MccDaq, then click<span>\u00a0<\/span><strong>OK<\/strong>.<\/p>\n<p style=\"font-weight: 400;\">From the Solution explorer, right click on Form1.vb, and select View Code.\u00a0 Above<span>\u00a0<\/span>Public<span>\u00a0<\/span>Class<span>\u00a0<\/span>Form1\u00a0Insert the following:<\/p>\n<blockquote>\n<p style=\"font-weight: 400;\">ImportsSystem.Data.OleDb<\/p>\n<p style=\"font-weight: 400;\">ImportsSystem.Runtime.InteropServices<\/p>\n<p style=\"font-weight: 400;\">ImportsSystem.IO<\/p>\n<p style=\"font-weight: 400;\">\u00a0Next, add the variable declarations:<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0&#8216;For Universal Library<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0DiminventoryAs\u00a0MccDaq.DaqDeviceDescriptor()<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0PublicDaqboardAsNewMccDaq.MccBoard()<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0PublicUlStatAs\u00a0MccDaq.ErrorInfo<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0DimLastCounterValueAs\u00a0Int32= 0<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0DimbFirstEntryAsBoolean=False<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0&#8216;For database<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0DimsConnectionStringAs\u00a0String<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0PublicobjConnAsNewOleDbConnection()<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0DimdaMFGDataAsNewOleDbDataAdapter()<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0DimdsNewScanAsNewDataSet()<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0DimdtDataAsDataTable<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0DimtblTestDataAsDataTable<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0DimdrCurrentAsDataRow<\/p>\n<\/blockquote>\n<p><span>The top sections are the global variables for the Universal Library.\u00a0 The bottom section are the global variables and declarations for the database.<\/span><\/p>\n<h2>Instantiate the USB-2408<\/h2>\n<p><span>Paste the following into the Form1_Load() event:<\/span><\/p>\n<blockquote>\n<p style=\"font-weight: 400;\">MccDaq.DaqDeviceManager.IgnoreInstaCal() \u00a0 \u00a0&#8216;don&#8217;t use information from InstaCal.<\/p>\n<p style=\"font-weight: 400;\">System.Windows.Forms.Cursor.Current =Cursors.WaitCursor&#8217;change cursor to wait.<\/p>\n<p style=\"font-weight: 400;\">&#8216;Load all the boards it can find<\/p>\n<p style=\"font-weight: 400;\">inventory = MccDaq.DaqDeviceManager.GetDaqDeviceInventory(MccDaq.DaqDeviceInterface.Any)<\/p>\n<p style=\"font-weight: 400;\">DimnumDevDiscoveredAs\u00a0Integer= inventory.Length \u00a0\u00a0&#8216;how many was that?<\/p>\n<p style=\"font-weight: 400;\">System.Windows.Forms.Cursor.Current =Cursors.WaitCursor \u00a0\u00a0&#8216;change cursor to wait.<\/p>\n<p style=\"font-weight: 400;\">DimBoardfoundAsBoolean=False<\/p>\n<p style=\"font-weight: 400;\">IfnumDevDiscovered &gt; 0Then<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0\u00a0ForboardNumAsInteger= 0To\u00a0numDevDiscovered &#8211; 1<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 Try<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 &#8216;Create a new MccBoard object for Board and assign a board number<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 &#8216;to the specified DAQ device with CreateDaqDevice()<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Daqboard = MccDaq.DaqDeviceManager.CreateDaqDevice(boardNum,inventory(boardNum))<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 IfDaqboard.BoardName.Contains(&#8220;2408&#8221;)Then<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Boardfound =True<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Daqboard.FlashLED()<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0Exit For<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Else<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0MccDaq.DaqDeviceManager.ReleaseDaqDevice(Daqboard)<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 EndIf<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 CatchuleAs\u00a0MccDaq.ULException<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 MsgBox(ule.ErrorInfo.Message)<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 EndTry<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0Next<\/p>\n<p style=\"font-weight: 400;\">EndIf<\/p>\n<p style=\"font-weight: 400;\">IfBoardfound =False\u00a0Then<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 MsgBox(&#8220;No<span>USB-2408<\/span>series board found in system. &#8220;,MsgBoxStyle.Critical,&#8221;No Board detected&#8221;)<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0End<\/p>\n<p style=\"font-weight: 400;\">EndIf<\/p>\n<p style=\"font-weight: 400;\">UlStat = Daqboard.FlashLED()<\/p>\n<p style=\"font-weight: 400;\">DimMyBoardNameAsString= Daqboard.BoardName.Trim<\/p>\n<p style=\"font-weight: 400;\">Me.Text = MyBoardName +&#8221;found as board number: &#8220;+ Daqboard.BoardNum.ToString<\/p>\n<\/blockquote>\n<p><span>This snippet of code queries the system for any supported Measurement Computing devices, accessible through the Universal Library.\u00a0 It sifts through the devices found, looking for a\u00a0<\/span><span onmouseover=\"ikb_showGlossaryToopTip(20);\" class=\"glossaryToolTip\">USB-2408<\/span><span>.\u00a0 If one is found, it uses it and changes the Form1.Text with an appropriate statement.\u00a0 It not, it pops up a message box stating it didn\u2019t find a\u00a0<\/span><span onmouseover=\"ikb_showGlossaryToopTip(20);\" class=\"glossaryToolTip\">USB-2408<\/span><span>. \u00a0<\/span><\/p>\n<h2>Create the Local Database<\/h2>\n<p><span>Add this line into the Form1_Load() event after the above code:<\/span><\/p>\n<blockquote>\n<p style=\"font-weight: 400;\">&#8216;Create the local database to DataGridView1<\/p>\n<p style=\"font-weight: 400;\">CreateDataBase()<\/p>\n<\/blockquote>\n<p style=\"font-weight: 400;\">And add the following subs and functions after the End Sub of the Form1_Load() event:<\/p>\n<blockquote>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0PrivateSub\u00a0CreateDataBase()<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0DimdsAsNewDataSet<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ds =CreateDataSet()<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 DataGridView1.DataSource = ds.Tables(&#8220;MeasuredData&#8221;)<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0EndSub<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0PrivateFunction\u00a0CreateDataSet()AsDataSet<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&#8216;Creating a DataSet object for tables<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0DimMeasuredDataAsDataSet=NewDataSet()<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u2018Creating a table object<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0DimdtDataAsDataTable= CreateDACTable()<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 MeasuredData.Tables.Add(dtData)<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0ReturnMeasuredData<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0EndFunction<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0PrivateFunction\u00a0CreateDACTable()AsDataTable<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 dtData =NewDataTable(&#8220;MeasuredData&#8221;)<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u2018Adding columns<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 AddNewColumn(dtData,&#8221;System.String&#8221;,&#8221;Time&#8221;)<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 AddNewColumn(dtData,&#8221;System.String&#8221;,&#8221;Temperature&#8221;)<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 AddNewColumn(dtData,&#8221;System.String&#8221;,&#8221;Pressure&#8221;)<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 AddNewColumn(dtData,&#8221;System.String&#8221;,&#8221;Tachometer&#8221;)<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 AddNewColumn(dtData,&#8221;System.String&#8221;,&#8221;Interlock&#8221;)<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0ReturndtData<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0EndFunction<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0PrivateSub\u00a0AddNewColumn(ByReftableAsDataTable,ByValcolumnTypeAsString,ByVal\u00a0columnNameAsString)<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0DimcolumnAsDataColumn= table.Columns.Add(columnName,Type.GetType(columnType))<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0EndSub<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0PrivateSubAddNewRow(ByReftableAsDataTable,ByReftimeAsString,ByReftemperatureAsDouble,ByRefpressureAsDouble,ByRefRPMAsInt32,ByRefinterlockAsBoolean)<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0DimnewrowAsDataRow= table.NewRow()<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 newrow(&#8220;Time&#8221;) = time<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 newrow(&#8220;Temperature&#8221;) = temperature<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 newrow(&#8220;Pressure&#8221;) =pressure<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 newrow(&#8220;Tachometer&#8221;) = RPM<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 newrow(&#8220;Interlock&#8221;) =interlock<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 table.Rows.Add(newrow)<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0EndSub<\/p>\n<\/blockquote>\n<p style=\"font-weight: 400;\">The above does the following:<\/p>\n<p style=\"font-weight: 400;\">Create a Dataset that includes a table called MeasuredData, and links it to the DataGridView1\u2019s Datasource. MeasuredData has 1 row, made up of 5 columns with the field names; Time, Temperature, Pressure, Tachometer, and Interlock.\u00a0\u00a0 Create the 5 columns with these names, and place the names in the top row.<\/p>\n<p style=\"font-weight: 400;\">\u00a0From the Form View, double click on \u201cStart\u201d button, and add the following to the btnStartStop_Click() event:<\/p>\n<blockquote>\n<p style=\"font-weight: 400;\">If<span>\u00a0<\/span>btnStartStop.Text =<span>\u00a0<\/span>&#8220;Start&#8221;<span>\u00a0<\/span>Then<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 btnStartStop.Text =<span>\u00a0<\/span>&#8220;Stop&#8221;<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 OpenDatabase()<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 UlStat = Daqboard.CClear(0)<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Timer1.Enabled =<span>\u00a0<\/span>True<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span>\u00a0<\/span>Else<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 btnStartStop.Text =<span>\u00a0<\/span>&#8220;Start&#8221;<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Timer1.Enabled =<span>\u00a0<\/span>False<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span>\u00a0<\/span>End<span>\u00a0<\/span>If<\/p>\n<\/blockquote>\n<p style=\"font-weight: 400;\">Aside from the button text alternating between \u201cStart\u201d and \u201cStop\u201d, when the button text is \u201cStart\u201d, open the external database, reset the counter and start Timer1.\u00a0 When the button text is \u201cStop\u201d, stop Timer1.<\/p>\n<p style=\"font-weight: 400;\">Opening the external data base is essential to this project, and has its own subroutine.<\/p>\n<h2 style=\"font-weight: 400;\"><strong>How to Open the External Database<\/strong><\/h2>\n<p style=\"font-weight: 400;\">Paste this in below the End Sub of the btnStartStop_Click()event:<\/p>\n<blockquote>\n<p style=\"font-weight: 400;\">PrivateSubOpenDatabase()<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&#8216;How to open an oleDB data base<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 sConnectionString =&#8221;Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\\Users\\Public\\Documents\\MCCGenericOdbc.mdb&#8221;<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 objConn =NewOleDbConnection(sConnectionString)<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 objConn.Open()<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 daMFGData =NewOleDbDataAdapter(&#8220;Select * From TestData&#8221;, objConn)<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 dsNewScan =New\u00a0DataSet(&#8220;NewScan&#8221;)<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 daMFGData.FillSchema(dsNewScan,SchemaType.Source,&#8221;TestData&#8221;)<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 daMFGData.Fill(dsNewScan,&#8221;TestData&#8221;)<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 \u2018Create a new instance of a DataTable.<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 tblTestData = dsNewScan.Tables(&#8220;TestData&#8221;)<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 objConn.Close()<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0EndSub<\/p>\n<\/blockquote>\n<p style=\"font-weight: 400;\">Opening a link to a Microsoft Access database, requires a proper connection string like this:<\/p>\n<blockquote>\n<p style=\"font-weight: 400;\">sConnectionString =&#8221;Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\\Users\\Public\\Documents\\MCCGenericOdbc.mdb&#8221;<\/p>\n<\/blockquote>\n<p style=\"font-weight: 400;\">The \u201c;\u201d delineates the Provider type from the database path and filename.\u00a0 It is important this be correct and be correctly formatted.\u00a0 The connection string is used to instantiate the database connection, called objConn.\u00a0 Open the connection and create a data adapter, by selecting the table \u201cTestData\u201d in the database and name it \u201cdaMFGData\u201d.\u00a0 Create a dataset, \u201cdaNewScan\u201d,set it up with the proper fields using FillSchema and Fill. Create a local data table aligned to the one in the database called \u201ctblTestData\u201d.<\/p>\n<p style=\"font-weight: 400;\">Lastly, close the connection for now.<\/p>\n<h2>Collecting Data and Sending to the Database<\/h2>\n<p style=\"font-weight: 400;\">From the Form view, double click on Timer1.\u00a0 Enter the following in the Timer1_Tick()event:<\/p>\n<blockquote>\n<p style=\"font-weight: 400;\">DimMyDataScan(4)AsObject&#8217;array to hold the data generated by the scan<\/p>\n<p style=\"font-weight: 400;\">&#8216;Read the temperature<\/p>\n<p style=\"font-weight: 400;\">UlStat = Daqboard.TIn(0, MccDaq.TempScale.Celsius, MyDataScan(1), MccDaq.VInOptions.Default)<\/p>\n<p style=\"font-weight: 400;\">IfUlStat.Value &lt;&gt; MccDaq.ErrorInfo.ErrorCode.NoErrorsThen<\/p>\n<p style=\"font-weight: 400;\">errhandler(UlStat)<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0Exit Sub<\/p>\n<p style=\"font-weight: 400;\">EndIf<\/p>\n<p style=\"font-weight: 400;\">Thermometer1.TempValue = MyDataScan(1)<\/p>\n<p style=\"font-weight: 400;\">lblTempValue.Text =Convert.ToDouble(MyDataScan(1)).ToString(&#8220;##0.00&#8243;) &amp;&#8221;\u00b0C&#8221;<\/p>\n<p style=\"font-weight: 400;\">&#8216;Read the voltage (Pressure)<\/p>\n<p style=\"font-weight: 400;\">UlStat = Daqboard.VIn(1, MccDaq.Range.Bip10Volts, MyDataScan(2), MccDaq.VInOptions.Default)<\/p>\n<p style=\"font-weight: 400;\">IfUlStat.Value &lt;&gt; MccDaq.ErrorInfo.ErrorCode.NoErrorsThen<\/p>\n<p style=\"font-weight: 400;\">errhandler(UlStat)<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0Exit Sub<\/p>\n<p style=\"font-weight: 400;\">EndIf<\/p>\n<p style=\"font-weight: 400;\">MyDataScan(2) *= 10\u00a0&#8216;apply scaling (Makes the data look cooler, it uses more of the pressure meter!)<\/p>\n<p style=\"font-weight: 400;\">lblPressure.Text =Convert.ToSingle(MyDataScan(2)).ToString(&#8220;##0.00&#8221;)<\/p>\n<p style=\"font-weight: 400;\">kdPressure.UpdateKnob(MyDataScan(2))<\/p>\n<p style=\"font-weight: 400;\">&#8216;Read the counter (Tachometer)<\/p>\n<p style=\"font-weight: 400;\">UlStat = Daqboard.CIn(0, MyDataScan(3))<\/p>\n<p style=\"font-weight: 400;\">IfUlStat.Value &lt;&gt; MccDaq.ErrorInfo.ErrorCode.NoErrorsThen<\/p>\n<p style=\"font-weight: 400;\">errhandler(UlStat)<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0Exit Sub<\/p>\n<p style=\"font-weight: 400;\">EndIf<\/p>\n<p style=\"font-weight: 400;\">DimNewCountReadAsInteger= (MyDataScan(3) &#8211; LastCounterValue)<\/p>\n<p style=\"font-weight: 400;\">LastCounterValue = MyDataScan(3)<\/p>\n<p style=\"font-weight: 400;\">DimTachValAsDouble= (NewCountRead * 60)&#8217;apply scaling to RPM from RPS<\/p>\n<p style=\"font-weight: 400;\">kdTach.UpdateKnob(TachVal \/ 100)<\/p>\n<p style=\"font-weight: 400;\">lblTach.Text = (TachVal).ToString(&#8220;####0&#8221;)<\/p>\n<p style=\"font-weight: 400;\">&#8216;Read the digital bit (door interlock)<\/p>\n<p style=\"font-weight: 400;\">DimMyDigBitAsBoolean<\/p>\n<p style=\"font-weight: 400;\">UlStat = Daqboard.DBitIn(MccDaq.DigitalPortType.FirstPortA, 0, MyDigBit)<\/p>\n<p style=\"font-weight: 400;\">IfUlStat.Value &lt;&gt; MccDaq.ErrorInfo.ErrorCode.NoErrorsThen<\/p>\n<p style=\"font-weight: 400;\">errhandler(UlStat)<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0Exit Sub<\/p>\n<p style=\"font-weight: 400;\">EndIf<\/p>\n<p style=\"font-weight: 400;\">Led1.Value = MyDigBit<\/p>\n<p style=\"font-weight: 400;\">MyDataScan(4) =&#8221;0&#8243;<\/p>\n<p style=\"font-weight: 400;\">IfMyDigBit =TrueThenMyDataScan(4) =&#8221;1&#8243;<\/p>\n<p style=\"font-weight: 400;\">&#8216;Read the current Time<\/p>\n<p style=\"font-weight: 400;\">MyDataScan(0) =Convert.ToString(System.DateTime.Now)<\/p>\n<p style=\"font-weight: 400;\">lblTime.Text = MyDataScan(0)<\/p>\n<\/blockquote>\n<p style=\"font-weight: 400;\">In the above code, create an array called MyDataScan() to hold the collected data. Using Measurement Computing\u2019s Universal Library functions, read from each of the 4 types of sensors; Temperature, voltage, counter, and digital input (TTL).\u00a0 Also read the time.<\/p>\n<p style=\"font-weight: 400;\">Note: proceeding each library call there is a small If-Then routine:<\/p>\n<blockquote>\n<p style=\"font-weight: 400;\">IfUlStat.Value &lt;&gt; MccDaq.ErrorInfo.ErrorCode.NoErrorsThen<\/p>\n<p style=\"font-weight: 400;\">errhandler(UlStat)<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0Exit Sub<\/p>\n<p style=\"font-weight: 400;\">EndIf<\/p>\n<\/blockquote>\n<p style=\"font-weight: 400;\">Each time a call is made to the Universal Library, an integer value is returned into UlStat.\u00a0 If UlStat equals zero, then the function executed correctly and the data is good.\u00a0 If UlStat is not equal to 0, then there was a problem executing the function, and the value of UlStat can be used to handle the error.\u00a0 If you were writing a more elaborate program, you would want to manage the returned error in your program so as to keep the program from using bad data or worse, crashing.\u00a0 More on that, in a bit.<\/p>\n<p style=\"font-weight: 400;\">Use the array to scale data if needed, and update all the meters, gauges, labels.<\/p>\n<p style=\"font-weight: 400;\">Next we are going to write the data to our DataGridView.\u00a0 Here\u2019s how:<\/p>\n<blockquote>\n<p style=\"font-weight: 400;\">&#8216;This goes to the datagrid<\/p>\n<p style=\"font-weight: 400;\">IfbFirstEntry =FalseThen<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0DimnewrowAsDataRow= dtData.NewRow()<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0 newrow(&#8220;Time&#8221;) = MyDataScan(0)<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0 newrow(&#8220;Temperature&#8221;) =MyDataScan(1).ToString()<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0 newrow(&#8220;Pressure&#8221;) = MyDataScan(2).ToString<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0 newrow(&#8220;Tachometer&#8221;) = TachVal.ToString<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0 newrow(&#8220;Interlock&#8221;) = MyDataScan(4)<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0 dtData.Rows.Add(newrow)<\/p>\n<p style=\"font-weight: 400;\">bFirstEntry =True<\/p>\n<p style=\"font-weight: 400;\">\u00a0Else<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0DimdrEditRowAsDataRow<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0 drEditRow= dtData.NewRow()<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0 drEditRow= dtData.Rows.Item(0)<\/p>\n<p style=\"font-weight: 400;\">drEditRow.BeginEdit()<\/p>\n<p style=\"font-weight: 400;\">drEditRow(&#8220;Time&#8221;) =DateTime.Now.ToString()<\/p>\n<p style=\"font-weight: 400;\">drEditRow(&#8220;Temperature&#8221;) =Format(MyDataScan(1),&#8221;##0.0#&#8221;)<\/p>\n<p style=\"font-weight: 400;\">drEditRow(&#8220;Pressure&#8221;) =Format(MyDataScan(2),&#8221;##0.0#&#8221;)<\/p>\n<p style=\"font-weight: 400;\">drEditRow(&#8220;Tachometer&#8221;) =Format(TachVal,&#8221;####&#8221;)<\/p>\n<p style=\"font-weight: 400;\">drEditRow(&#8220;Interlock&#8221;) =MyDataScan(4)<\/p>\n<p style=\"font-weight: 400;\">drEditRow.EndEdit()<\/p>\n<p style=\"font-weight: 400;\">EndIf<\/p>\n<\/blockquote>\n<p style=\"font-weight: 400;\">We implement an If-Then-Else routine here because we need to add a new row to the grid. When the finished program runs, each time new data is collected, it is repeatedly written to the first row.\u00a0 We are not looking to collect and store data as it is received, we only want the one row of data. To make that work, we use the IF-Then-Else.\u00a0 The decision (IF) is based on &#8216;is this the first time in this timer loop?&#8217; If it is, then we add a first row.\u00a0 If not, then just keep updating the same row. In the IF portion, we call .NewRow, and in the Else portion we call .BeginEdit() and .EndEdit().<\/p>\n<p style=\"font-weight: 400;\">Now we will write the data out to our external database.\u00a0 Add the following code:<\/p>\n<blockquote>\n<p style=\"font-weight: 400;\">Try\u00a0&#8216;This goes out to the database<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 objConn.Open()<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u2018Obtain a new Data Row object from the DataTable.<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 drCurrent = tblTestData.NewRow()<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 drCurrent = tblTestData.Rows.Find(1)<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 drCurrent = tblTestData.Rows(0)<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 drCurrent.BeginEdit()<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 drCurrent(&#8220;Time&#8221;) =DateTime.Now.ToString()<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 drCurrent(&#8220;Temperature&#8221;) =MyDataScan(1).ToString()<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 drCurrent(&#8220;Pressure&#8221;) =Format(MyDataScan(2),&#8221;##0.0#&#8221;)<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 drCurrent(&#8220;Tachometer&#8221;) =TachVal<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 drCurrent(&#8220;Interlock&#8221;) =MyDataScan(4)<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 drCurrent.EndEdit()<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 DimobjCommandBuilderAs\u00a0NewOleDbCommandBuilder(daMFGData)<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 objCommandBuilder.QuotePrefix =&#8221;[&#8220;<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 objCommandBuilder.QuoteSuffix =&#8221;]&#8221;<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 DimrAsInteger= daMFGData.Update(dsNewScan,&#8221;TestData&#8221;)<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 objConn.Close()<\/p>\n<p style=\"font-weight: 400;\">CatchexAsOleDbException<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 Timer1.Enabled =False<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 objConn.Close()<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 MsgBox(ex.Message.ToString(),MsgBoxStyle.Information,&#8221;Error Message&#8221;)<\/p>\n<p style=\"font-weight: 400;\">EndTry<\/p>\n<\/blockquote>\n<p style=\"font-weight: 400;\">Writing to the real database is all most the same as writing to the DataGridView.\u00a0 However here we have to open the database connection, find the first row, use the oleDbCommandBuilder() (be sure to include the QuotePrefix and QuoteSuffix), update the table, and close the database connection.<\/p>\n<p style=\"font-weight: 400;\">Now, for a little program management. Add our error handler subroutine. After the Timer1_Tick\u2019s End sub, add the following:<\/p>\n<blockquote>\n<p style=\"font-weight: 400;\">PublicSuberrhandler(ByValulstatAs\u00a0MccDaq.ErrorInfo)<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0&#8216;Generic UL error handler<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 Timer1.Enabled =False<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0Try<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 objConn.Close()<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0CatchexAsException<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0EndTry<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0MessageBox.Show(ulstat.Message,&#8221;Universal Library Error&#8221;,MessageBoxButtons.OK,MessageBoxIcon.Error)<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 btnStartStop.Text =&#8221;Start&#8221;<\/p>\n<p style=\"font-weight: 400;\">EndSub<\/p>\n<\/blockquote>\n<p style=\"font-weight: 400;\">If there is an Universal Library error, stop the timer, close the database connection if it is open, display an error message stating the problem encountered, and reset the Start\/Stop button to display \u201cStart\u201d.\u00a0 In a more involved application, you might have a Case statement, handling the problem\u00a0programmatically, or offering solutions either in a more verbose message telling the user what happened and how to resolve it.<\/p>\n<p style=\"font-weight: 400;\">Add a graceful way to exit the program:<\/p>\n<p style=\"font-weight: 400;\">From the Form view, regarding the MenuStrip1, click on<span>\u00a0<\/span><strong>File<\/strong>, and then double click on<span>\u00a0<\/span><strong>Exit<\/strong>, and add the following code:<\/p>\n<blockquote>\n<p style=\"font-weight: 400;\">Timer1.Enabled =False<\/p>\n<p style=\"font-weight: 400;\">End<\/p>\n<\/blockquote>\n<p style=\"font-weight: 400;\">Because this is Windows, and there is always more than one way to do anything, go back to the Form view, double click on the \u2018End\u2019 button, and paste the same syntax there.<\/p>\n<p style=\"font-weight: 400;\">We are still missing a couple items, but that is as far as we need to go for this section.<\/p>\n<p style=\"font-weight: 400;\">You can now build and run this application.\u00a0 When you click \u201cStart\u201d, it will begin reading from the sensors connected to the<span>\u00a0<\/span><span>USB-2408<\/span>, update the screen, and log the data to the database.\u00a0 A word of caution, if you are expecting to open the database and look at the table hoping to see the data updating in real time, that won\u2019t happen. \u00a0What you will see on your screen is a snapshot in time, not real time, updating data.\u00a0 You can stop the application at any time, open the database and table and see that the table has been updated.<\/p>\n<p style=\"font-weight: 400;\">In the Part 3 we will build the application capable of reading the data in real time.<\/p>\n<div class='watch-action'><div class='watch-position align-left'><div class='action-like'><a class='lbg-style6 like-29294 jlk' data-task='like' data-post_id='29294' data-nonce='8896bc70a6' rel='nofollow'><img src='https:\/\/digilent.com\/blog\/wp-content\/plugins\/wti-like-post-pro\/images\/pixel.gif' title='Like' \/><span class='lc-29294 lc'>0<\/span><\/a><\/div><div class='action-unlike'><a class='unlbg-style6 unlike-29294 jlk' data-task='unlike' data-post_id='29294' data-nonce='8896bc70a6' rel='nofollow'><img src='https:\/\/digilent.com\/blog\/wp-content\/plugins\/wti-like-post-pro\/images\/pixel.gif' title='Unlike' \/><span class='unlc-29294 unlc'>0<\/span><\/a><\/div><\/div> <div class='status-29294 status align-left'>Be the 1st to vote.<\/div><\/div><div class='wti-clear'><\/div>","protected":false},"excerpt":{"rendered":"<p>This is second part in this series. Part 1 &#8211; Setting Up an MS Database Part 3 &#8211; Creating an Application to View Data Part 4 &#8211; Distributing Applications Part &hellip; <\/p>\n","protected":false},"author":59,"featured_media":29342,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[4325,4361,4327,1563],"tags":[4359,4358],"ppma_author":[4507],"class_list":["post-29294","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-debug-validation-test","category-data-acquisition","category-projects","category-guide","tag-daq","tag-mcc"],"jetpack_featured_media_url":"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2022\/08\/2022-ReadingGeneratedData2-part2-580.png","jetpack_sharing_enabled":true,"authors":[{"term_id":4507,"user_id":59,"is_guest":0,"slug":"jgreenberg","display_name":"Jeff Greenberg","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/4733b4dee4cf309719f59882b387a0c9fcd17b506ca0858a86a1ecd2c7ed324a?s=96&d=mm&r=g","1":"","2":"","3":"","4":"","5":"","6":"","7":"","8":"","9":"","10":""}],"post_mailing_queue_ids":[],"_links":{"self":[{"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/posts\/29294","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/users\/59"}],"replies":[{"embeddable":true,"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/comments?post=29294"}],"version-history":[{"count":0,"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/posts\/29294\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/media\/29342"}],"wp:attachment":[{"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/media?parent=29294"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/categories?post=29294"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/tags?post=29294"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=29294"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}