|
Well you just made me realize how much I don't know . Where specifically in my code can I put this delay?
Thread.Sleep(100);
I really appreciate your effort ,but it would be way more helpful if you could comment on where in my code I can implement this?
|
|
|
|
|
Hi,
I've thrown out most all of your code! My code example replaces everything (it still needs port initialization). Under the assumptions I made (master-slave operation, PC sends command then peripheral replies), there is no need for events, secondary threads, Invoke, etc.
If you can't turn your peripheral into a slave, which would mean it can still send results whenever it likes, then you need more of your code, however even then a delay could save your day: put it anywhere between the start of the DataReceived event and the line that holds SerialPort.ReadLine; this would guarantee (actually increase the probability) that an entire message up to and including newline is present in the serial buffer when ReadLine gets called. However now the delay also increases the probability that you would loose a message, so it makes sense to opt for a shorter delay (I would at first not go below 20 msec though).
|
|
|
|
|
I have solved this problem and the code is as follows:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
using System.Diagnostics;
namespace PlantMonitoringApp
{
public partial class Form1 : Form
{
public SerialPort myport;
private DateTime datetime;
string in_data;
public Form1()
{
Sensor newSensor;
newSensor = new Sensor();
InitializeComponent();
}
private void start_btn_Click(object sender, EventArgs e)
{
myport = new SerialPort();
myport.BaudRate = 9600;
myport.PortName = "COM3";
myport.Parity = Parity.None;
myport.DataBits = 8;
myport.StopBits = StopBits.One;
myport.DataReceived += Myport_DataReceived1;
try
{
myport.Open();
time_text_box.Text = "";
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error");
}
time_text_box.Text = "";
}
void Myport_DataReceived1(object sender, SerialDataReceivedEventArgs e)
{
in_data = myport.ReadLine();
this.Invoke(new EventHandler(displaydata_event));
}
private void displaydata_event(object sender, EventArgs e)
{
datetime = DateTime.Now;
string time = datetime.Hour + ":" + datetime.Minute + ":" + datetime.Second;
time_text_box.Text = time;
string[] sensorData = in_data.Split(new char[] { ' ', ' ' });
List<string> tokens = new List<string>();
try
{
foreach (string s in sensorData)
{
if (s.Length != 0)
{
tokens.Add(s);
}
}
txtTemperature.Text = tokens[0];
txtHumidity.Text = tokens[1];
txtSoil_moisture.Text = tokens[2];
}
catch (Exception ex1)
{
Console.WriteLine(tokens.Count+" "+in_data+ " "+ex1.Message);
}
}
private void stop_btn_Click(object sender, EventArgs e)
{
try
{
myport.Close();
}
catch (Exception ex2)
{
MessageBox.Show(ex2.Message, "Error");
}
}
}
}
The thing is that I want to make a separate class that I call Sensor.cs. I want to recieve data serial data there and and from that class enter the data in the text boexes in the Form.cs class.
Anybody that can give me some tips here?
|
|
|
|
|
Hi,
I see no problems; create a Sensor class that has:
- a private SerialPort object;
- three private numeric results (temp, moist, soilMoist); could be int, float, double,...;
- a constructor taking the parameters you may need (e.g. port name) and creating the serial port; this is also where you should wire the DataReceived event, so it executes once, not for every start!
- a public Start() method that does what your start button does now; you should remove the DataReceived wiring here.
- a public Stop() method that does what your stop button does now;
- a DataReceived event handler that does what your current one does, except it interprets the incoming string, turns the fields into numbers using float.Parse() or float.TryParse() or something similar, and stuffs the results in the numeric class fields temp, moist, soilMoist; saving results in simple numeric variables does not violate thread safety, there will be no need to use any Invoke.
- three public properties Temp, Moist, SoilMoist that offer a getter to read those results;
- a public Dispose() method that calls SerialPort.Dispose(), something you have omitted so far.
As a result, a Sensor instance would collect whatever you receive on the serial port from calling Start() till calling Stop() or Dispose(). And reading the result properties would immediately return the most recent value that is available (and zero if no results yet).
In order to see the results in your current Form's TextBoxes, you could use a System.Windows.Forms.Timer that periodically (say once every second) gets the results and moves them into the TextBoxes, using float.ToString() . Of course you then would call Start() and Stop/Dispose() only once.
Possible improvement: you could also add a private DateTime measured and a public property DateTime Measured, which will offer the DateTime when the data was last successfully updated.
PS: you can format the current time simply with DateTime.Now.ToString("HH:mm:ss");
|
|
|
|
|
Wow, that's a lot of things
Have no clue how to transform that into code .
Thanks for the reply anyways
|
|
|
|
|
Quote: Have no clue how to transform that into code
I suggest you get yourself a book on C# and study that. It will teach you the language, the relevant library classes, how the create your own classes, how to work with objects, etc.
I haven't seen it myself, lots of people recommend the e-book .NET Book Zero by Charles Petzold[^]. Personally I prefer a dead tree edition where you can easily navigate and annotate.
And once you get to know some of the fundamentals, start looking at other people's code, there are plenty of excellent articles here at CodeProject.
|
|
|
|
|
Hi, I am fairly new to C# coding so be gentle
I am trying to receive measurement data from a two sensors DHT11 and soimoisture sensor connected to my Arduino. At this stage I just want to receive the raw measurement data and represent them in separate text boxes. I have almost managed it but I am getting some errors.
More specifically I get this error:
System.ArgumentOutOfRangeException: 'Index was out of range. Must be non-negative and less than the size of the collection.<br />
Parameter name: index'
Here is my code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
namespace PlantMonitoringApp
{
public partial class Form1 : Form
{
private SerialPort myport;
private DateTime datetime;
private string in_data;
public Form1()
{
InitializeComponent();
}
private void start_btn_Click(object sender, EventArgs e)
{
myport = new SerialPort();
myport.BaudRate = 9600;
myport.PortName = port_name_tb.Text;
myport.Parity = Parity.None;
myport.DataBits = 8;
myport.StopBits = StopBits.One;
myport.DataReceived += Myport_DataReceived1;
try
{
myport.Open();
time_text_box.Text = "";
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error");
}
}
void Myport_DataReceived1(object sender, SerialDataReceivedEventArgs e)
{
in_data = myport.ReadLine();
this.Invoke(new EventHandler(displaydata_event));
}
private void displaydata_event(object sender, EventArgs e)
{
datetime = DateTime.Now;
string time = datetime.Hour + ":" + datetime.Minute + ":" + datetime.Second;
time_text_box.Text = time;
string[] sensorData = in_data.Split(new char[] { ' ',' ',' '});
List<string> tokens = new List<string>();
foreach (string s in sensorData)
{
if (s.Length !=0)
{
tokens.Add(s);
}
}
txtTemperature.Text = tokens[0];
txtHumidity.Text = tokens[1];
txtSoil_moisture.Text = tokens[2];
}
|
|
|
|
|
sample application to customize combo box with multi selection an check box in winform
|
|
|
|
|
Sounds interesting. Let us know when it is finished.
|
|
|
|
|
There's not an example for each and every scenario available. You'll have to learn from simpeler examples and learn to combine that.
Bastard Programmer from Hell
If you can't read my code, try converting it here[^]
"If you just follow the bacon Eddy, wherever it leads you, then you won't have to think about politics." -- Some Bell.
|
|
|
|
|
What have you tried?
Where are you stuck?
What help do you need?
Sent from my Amstrad PC 1640
Never throw anything away, Griff
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
Sounds like a country song.
".45 ACP - because shooting twice is just silly" - JSOP, 2010 ----- You can never have too much ammo - unless you're swimming, or on fire. - JSOP, 2010 ----- When you pry the gun from my cold dead hands, be careful - the barrel will be very hot. - JSOP, 2013
|
|
|
|
|
That would have been:
My dawg's dead;
What have you tried?
My wife ran away with my best friend;
Where are you stuck?
My truck broke;
What help do you need?
Sent from my Amstrad PC 1640
Never throw anything away, Griff
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
|
It's an elephant!
"(I) am amazed to see myself here rather than there ... now rather than then".
― Blaise Pascal
|
|
|
|
|
But is it in the room?
Sent from my Amstrad PC 1640
Never throw anything away, Griff
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
Hi, I am beginner in C# and I didn't found solved my problem.
In app I add tabPage with new text box and some others parameters (labels, etc.) and I wanna save all items to C# config file. The tabs is adds if app is running. Is it possible to save all TabPages in TabControl to C# config file ?
Code:
void AddTab()
{
bool existTabPage = false;
UInt16 allChceked = 0;
foreach (TabPage t in tabControl1.TabPages)
{
TabPage tabPage1 = new TabPage(tb_PlcUrl.Text);
if (tabControl1.TabPages.ContainsKey(tb_PlcUrl.Text))
{
existTabPage = true;
}
allChceked++;
}
if (!existTabPage && allChceked == tabControl1.TabCount)
{
TabPage tabPage1 = new TabPage();
tabPage1.Name = tb_PlcUrl.Text;
tabPage1.Text = tb_PlcUrl.Text;
TextBox tb = new TextBox();
tb.Location = new System.Drawing.Point(65, 19);
tb.Size = new System.Drawing.Size(133, 20);
tb.Text = tb_PlcUrl.Text;
tb.BorderStyle = BorderStyle.None;
tb.ReadOnly = true;
tabPage1.Controls.Add(tb);
Label labIpPlc = new Label();
labIpPlc.Location = new System.Drawing.Point(18, 19);
labIpPlc.Size = new System.Drawing.Size(133, 20);
labIpPlc.Text = "PLC1";
tabPage1.Controls.Add(labIpPlc);
tabControl1.TabPages.Add(tabPage1);
}
else MessageBox.Show("Already exist : *" + tb_PlcUrl.Text);
}
And if I close, the app make something like that:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
foreach (TabPage item in tabControl1.TabPages)
{
Properties.Settings.Default.TabPages[i] = tabControl1.TabPages[i];
i++;
}
Properties.Settings.Default.Save();
Application.Exit();
}
Thank you for help !
|
|
|
|
|
That isn't going to work, at least partly because you don;t know how many tabpages you have to start with.
If you weren't a beginner, I'd suggest a user control derived from TabPage which "knows" how to serialise and deserialise itself, or using JSON - but for a beginner that is quite a bit to learn.
So instead, consider writing a method which returns the relevant details from a tabpage as a string, with each element as key =value pairs, separated by semicolons:
Text="the text on the tab";Name="The Name";LabelText="The label text";... And then collecting those together as a bigger string, separated by newlines. Save that string, and when you restore it, use string.Split to separate the lines, then create a method that takes each line as a string and returns a new TabPage with the information filled in. Again, string.Split separates each key/value pair, and another split gives you the key and value. A simple switch lets you put each key value in the right place.
Make sense?
Sent from my Amstrad PC 1640
Never throw anything away, Griff
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
Create a model that holds the data, instantiate that model in the tab page parent (as a public property), and let each tab page get/set the properties that it cares about in the parent's model. When the form closes, have it save the model.
".45 ACP - because shooting twice is just silly" - JSOP, 2010 ----- You can never have too much ammo - unless you're swimming, or on fire. - JSOP, 2010 ----- When you pry the gun from my cold dead hands, be careful - the barrel will be very hot. - JSOP, 2013
|
|
|
|
|
For a better understanding, would you create a simple program? I assume that changing the TabControl from private to public in form.Designer.cs doesn't help?
Thank you
|
|
|
|
|
|
Remember that all of us were beginners once, and I'd guess many of us have, in the initial stages of learning UI development, and such advanced techniques as run-time Control generation, gotten ... confused
And, I think you are quite confused, here. In this loop:
foreach (TabPage t in tabControl1.TabPages)
{
TabPage tabPage1 = new TabPage(tb_PlcUrl.Text);
if (tabControl1.TabPages.ContainsKey(tb_PlcUrl.Text))
{
existTabPage = true;
}
allChceked++;
} You created a new TabPage, but you never used it: outside of the loop it is reclaimed by memory management ... effectively, it doesn't exist.
Serialization of WinForm Controls is problematic in terms of basic Types, like Fonts and Colors, and, for some Controls that contain other Controls (ex. DateTimePicker) or elements that are non serializable (ex. TreeView's NodeCollection). It's a shame WinForms did not include a powerful save/restore feature for all built-in Controls from the start.
I think your first goal should be a better understanding of C# and object.Control creation; for that, I suggest getting a really good book and combining study with programming small examples ... in the past the books on WinForms by Jesse Liberty and Chris Sells were most useful to me.
As you approach the task of saving and restoring run-time created Controls, like TabPages, I suggest you carefully consider:
1. basic attributes: text, color, location
1.a. basic state: visible, enabled, focused, selected, etc.
2. the issue of restoring event handlers ... which cannot be saved ... you've attached at run-time.
3. the extent to which the run-time user is constrained in terms of what they can create, how many whatevers they can create, etc.
4. ... of course: the data ... the unique content of each Control in the TabPage
I suggest you edit your post here, and describe the contents of one of your run-time created TabPage: when you want to save the content: what must be saved ?
«Where is the Life we have lost in living? Where is the wisdom we have lost in knowledge? Where is the knowledge we have lost in information?» T. S. Elliot
|
|
|
|
|
Thank you for understanding
I try to explain the problem clearly.
In application I have ListBox (only IP adress all PLC for communication).
You can add and remove PLC IP addresses to the ListBox.
-TabPages are created when Ip address is added to ListBox.
-the mentioned code treats duplicate ip addresses when creating a new Tabpages.
-After removing Ip from the listbox, the Tabpages with that ip address will be removed.
- Is there any other aleternate to treat the same Tabpages (because there cannot be 2 plc with the same Ip address)?
I want to store TabPage with Texbox values (location, color, visile etc. are not essential).
TabPages being created have a fixed structure like as:
this.tabPage1.BackColor = System.Drawing.SystemColors.Control;
this.tabPage1.Controls.Add(this.textBox5);
this.tabPage1.Controls.Add(this.textBox4);
this.tabPage1.Controls.Add(this.textBox3);
this.tabPage1.Controls.Add(this.textBox2);
this.tabPage1.Controls.Add(this.textBox1);
this.tabPage1.Controls.Add(this.labPlcIpAddress);
this.tabPage1.Location = new System.Drawing.Point(4, 22);
this.tabPage1.Name = "tabPage1";
this.tabPage1.Size = new System.Drawing.Size(384, 292);
this.tabPage1.TabIndex = 3;
this.tabPage1.Text = "Plc1";
this.textBox5.Location = new System.Drawing.Point(111, 153);
this.textBox5.Name = "tb_SQLName";
this.textBox5.Size = new System.Drawing.Size(188, 20);
this.textBox5.TabIndex = 11;
this.textBox5.Text = "name edited SQL column";
this.textBox4.Location = new System.Drawing.Point(111, 116);
this.textBox4.Name = "tb_SqleditColumn";
this.textBox4.Size = new System.Drawing.Size(188, 20);
this.textBox4.TabIndex = 10;
this.textBox4.Text = "SQL column name for editing";
this.textBox3.Location = new System.Drawing.Point(111, 67);
this.textBox3.Name = "textBox3";
this.textBox3.Size = new System.Drawing.Size(188, 20);
this.textBox3.TabIndex = 9;
this.textBox3.Text = "Query for update SQL database";
this.textBox2.Location = new System.Drawing.Point(111, 40);
this.textBox2.Name = "textBox2";
this.textBox2.Size = new System.Drawing.Size(188, 20);
this.textBox2.TabIndex = 8;
this.textBox2.Text = "Query for Select from SQL database";
this.textBox1.Location = new System.Drawing.Point(111, 13);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(188, 20);
this.textBox1.TabIndex = 7;
this.textBox1.Text = "Here is IP of plc";
Now it's obviously ?
|
|
|
|
|
Based on your response, I suggest:
1. Create a UserControl that contains the required TextBoxes : TabPageUC
1.a. expose the Text content of the TextBoxes in public Properties
1.b. create a serializer/deserializer for that UserControl
1.c. create a serializable static class that holds a List<TabPageUC>
In your main program:
2. maintain a data structure that maps TabPages to the contained TabPageUC control
2.a. write a method that adds a new TabPage, and then create an instance of TabPageUC to add to the Controls Collection of the new TabPage.
2.b. write a method to dispose of an existing TabPage, and its UserControl
In general:
3. familiarize yourself with the System.Runtime.Serialization namespace. and how DataContract and DataMember Annotations are used. And how a DataContractSerializer instance is used for both saving, and restoring content.
Take this on, and you will learn a lot.
«Where is the Life we have lost in living? Where is the wisdom we have lost in knowledge? Where is the knowledge we have lost in information?» T. S. Elliot
modified 26-Apr-19 15:50pm.
|
|
|
|
|
How to handle PCB components layout in designing LED switching power supply?
|
|
|
|
|