How to get a flag from an Arduino button through serial communication? - c#

My objective is to obtain a flag that is sent from the Arduino by a button. This flag is going to be sent through serial communication to a C# windows form program where i will be able to obtain the flag.
The data sent to the serial port by the Arduino is "ON" and "OFF", "ON" when the button is clicked and "OFF" when the button is not clicked. This flag will be used to turn on and off the red chart that will be displayed in the windows form.
My problem is how do i get this "ON" and "OFF" from the serial communication keeping in mind that data from the sensors are also being sent to the windows form application.
//C# Code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using rtChart;
namespace Distance_Sensor_using_Flight_of_time
{
public partial class Form1 : Form
{
string recvData = "temporary";
bool breakloop = false;
kayChart chartData;
bool buttonPress = false;
string bufferString = "";
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
//chart1.Series.Add("Series1");
//Connection COM & Baud Rate
string[] ports = SerialPort.GetPortNames();
string[] rates = new string[10] { "300", "600", "1200", "2400", "9600", "14400", "19200", "38400", "57600", "115200" };
cboBaudRate.SelectedText = "9600";
cboCOM.Items.AddRange(ports);
cboBaudRate.Items.AddRange(rates);
if (ports.Length >= 1)
cboCOM.SelectedIndex = 0;
//kayChart real time
chartData = new kayChart(chart1, 60);
btnStart.Enabled = false;
btnSave.Enabled = false;
chart1.Series["Series1"].Enabled = false;
}
private void BtnConnect_Click(object sender, EventArgs e)
{
try
{
if (btnConnect.Text == "Disconnect")
{
if (btnStart.Text == "Stop")
MessageBox.Show("Please click \"Stop\" button first!");
else
{
serialPort1.Close();
btnStart.Enabled = false;
btnConnect.Text = "Connect";
}
}
else
{
serialPort1.PortName = cboCOM.Text;
serialPort1.BaudRate = Convert.ToInt32(cboBaudRate.Text);
serialPort1.Parity = Parity.None;
serialPort1.StopBits = StopBits.One;
serialPort1.DataBits = 8;
serialPort1.Open();
btnStart.Enabled = true;
btnConnect.Text = "Disconnect";
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message, "Message", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void serialDataReceive(object sender, SerialDataReceivedEventArgs e)
{
if (!breakloop)
{
SerialPort sData = sender as SerialPort;
recvData = sData.ReadLine();
bufferString = recvData;
//rtbData.Invoke((MethodInvoker)delegate {rtbData.AppendText(recvData); });
//update chart
if (recvData == "ON\r" || recvData == "OFF\r")
{
if (recvData == "ON")
buttonPress = true;
else
buttonPress = false;
}
else
{
double data;
bool result = Double.TryParse(recvData, out data);
if (result)
{
chartData.TriggeredUpdate(data);
if (buttonPress == false)
{
chart1.Invoke((MethodInvoker)delegate { chart1.Series["Series1"].Enabled = false; });
chartData.serieName = "Length";
}
else
{
chart1.Invoke((MethodInvoker)delegate { chart1.Series["Series1"].Enabled = true; });
chartData.serieName = "Series1";
}
}
}
rtbData.Invoke((MethodInvoker)delegate { rtbData.AppendText(recvData); });
}
}
private void BtnStart_Click(object sender, EventArgs e)
{
try
{
if (btnStart.Text == "Start")
{
serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialDataReceive);
btnStart.Text = "Stop";
breakloop = false;
}
else
{
btnStart.Text = "Start";
breakloop = true;
//serialPort1.DataReceived += null;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Message", MessageBoxButtons.OK, MessageBoxIcon.Error);
btnStart.Text = "Start";
}
}
private void RtbData_TextChanged(object sender, EventArgs e)
{
rtbData.SelectionStart = rtbData.Text.Length;
rtbData.ScrollToCaret();
}
}
}
//Arduino Code
/* This example shows how to get single-shot range
measurements from the VL53L0X. The sensor can optionally be
configured with different ranging profiles, as described in
the VL53L0X API user manual, to get better performance for
a certain application. This code is based on the four
"SingleRanging" examples in the VL53L0X API.
The range readings are in units of mm. */
#include <Wire.h>
#include <VL53L0X.h>
VL53L0X sensor;
// Uncomment this line to use long range mode. This
// increases the sensitivity of the sensor and extends its
// potential range, but increases the likelihood of getting
// an inaccurate reading because of reflections from objects
// other than the intended target. It works best in dark
// conditions.
//#define LONG_RANGE
// Uncomment ONE of these two lines to get
// - higher speed at the cost of lower accuracy OR
// - higher accuracy at the cost of lower speed
//#define HIGH_SPEED
#define HIGH_ACCURACY
const int buttonPin = 2;
const int ledPin = 8;
int buttonState = 0;
bool inLoop = false;
void setup()
{
Serial.begin(9600);
Wire.begin();
// initialize the LED pin as an output:
pinMode(ledPin, OUTPUT);
// initialize the pushbutton pin as an input:
pinMode(buttonPin, INPUT);
sensor.init();
sensor.setTimeout(500);
#if defined LONG_RANGE
// lower the return signal rate limit (default is 0.25 MCPS)
sensor.setSignalRateLimit(0.1);
// increase laser pulse periods (defaults are 14 and 10 PCLKs)
sensor.setVcselPulsePeriod(VL53L0X::VcselPeriodPreRange, 18);
sensor.setVcselPulsePeriod(VL53L0X::VcselPeriodFinalRange, 14);
#endif
#if defined HIGH_SPEED
// reduce timing budget to 20 ms (default is about 33 ms)
sensor.setMeasurementTimingBudget(20000);
#elif defined HIGH_ACCURACY
// increase timing budget to 200 ms
sensor.setMeasurementTimingBudget(200000);
//sensor.setMeasurementTimingBudget(900000);
#endif
}
void loop()
{
buttonState = digitalRead(buttonPin);
Serial.print(sensor.readRangeSingleMillimeters());
if (sensor.timeoutOccurred()) { Serial.print(" TIMEOUT"); }
Serial.println();
if (buttonState == HIGH && inLoop == false)
{
Serial.write("ON");
Serial.println();
digitalWrite(ledPin, HIGH);
inLoop = true;
}
else if (buttonState == LOW && inLoop == true)
{
Serial.write("OFF");
Serial.println();
digitalWrite(ledPin, LOW);
inLoop = false;
}
}
I expect that the chart will turn red once the button is clicked and blue when the button is not clicked. Thank you in advance.

Although what you are doing may work (ie just trying to figure out what the message is on the receive side), it is far more scale-able if you use some form of message header and a delimiter. So your messages would look like this:
"btnState,true"
"btnState,false"
"data,124"
On the receive side, you will need to do a recvData.Split(',') and then check the first member of the array to find out what they message type is and then parse the second part accordingly.
Also, relating to your code specifically, I am unsure why you chose to use Serial.write for you "ON" and "OFF" instead of sticking to Serial.println. I am not positive without testing, but pretty sure you are trying to use the println as a message delimiter, and I think it may be sending the write and the empty println as two separate messages (which would explain why your on off equality may fail).

Related

Reading to newline from serial port returning first value

I'm trying to read data from a serial port that I have an Arduino and joystick connected to.
When trying to print out the received data to check if I'm getting it, it continues to print out the same value it was at when it connected.
I am sending data from my serial port in this format: Xaxis:yAxis:switchBool
Heres my C# code in a WPF application
public partial class MainWindow : Window {
public Timer loopTimer;
string comport = "COM7";
SerialPort sp;
public MainWindow() {
InitializeComponent();
SetTimer();
OpenPort();
}
private void SetTimer() {
//Setup the timer
loopTimer = new Timer(500);
// Hook up the Elapsed event for the timer.
loopTimer.Elapsed += TryRead;
loopTimer.AutoReset = true;
loopTimer.Enabled = false;
}
public void OpenPort() {
sp = new SerialPort();
try {
string portName = comport;
sp.PortName = portName;
sp.BaudRate = 9600;
sp.Open();
Debug.WriteLine("Connected");
loopTimer.Enabled = true;
}
catch (Exception) {
MessageBox.Show("Please give a valid port number or check your connection");
loopTimer.Enabled = false;
}
}
public void TryRead(object sender, EventArgs e) {
string s = sp.ReadLine();
Debug.WriteLine(s);
Debug.WriteLine("-");
}
}
Here's my arduino code:
int xPin = A1;
int yPin = A0;
int swPin = A2;
float deadzone = .05;
void setup() {
Serial.begin(9600);
pinMode(swPin, INPUT);
}
void loop() {
float xVal = (((analogRead(xPin) + 1) / 1023.) * 2) -1;
if (xVal < deadzone && xVal > -deadzone ) {
xVal = 0;
}
float yVal = (((analogRead(yPin) + 1) / 1023.) * 2) -1;
if (yVal < deadzone && yVal > -deadzone ) {
yVal = 0;
}
int swVal = analogRead(swPin);
bool switchDown;
if (swVal == 0) {
switchDown = true;
} else {
switchDown = false;
}
Serial.println( String(xVal) + ":" + String(yVal) + ":" + switchDown);
}
Here's an example of what the data should and does look like in the Arduino's serial monitor when moving the thumbstick around:
-1.00:0.70:0
-0.80:0.50:0
-0.70:0.60:0
Running my C# code above and not moving the thumbstick I only get 0.00:0.00:0.00 every time I read, and if I move it before starting I will only receive whatever value that was.
Instead of reading on an interval I would just read whenever new data arrives on the bus. below is an example of how to do that.
SerialPort Port= new SerialPort("Com7");
Port.DataReceived+=OnSerialRecieve;
private void OnSerialRecieve(object sender, SerialDataReceivedEventArgs e)
{
if ((sender as SerialPort).IsOpen)
{
string DataRecieved=(sender as SerialPort).ReadExisting();
}
}
from there you can split it up as you need to. otherwise if you know the exact amount of data your expecting you can sue SerialPort.ReadByte to read exactly the number of bytes you need.

Read Serial Port on C# allocating on an array no forgetting "00"

I'm trying to do a program that reads a serie of data from a serial port (COM3). The problem is that my code is for example (in decimal):
170 85 01 128 01 129 46 00 00 00 00 00 05 46
The way I'm reading the bytes "00" aren't been allocated on the array or variable:
I try a lot of ways like:
await port.BaseStream.ReadAsync(buffer, 0, 1);
And like shows on microsoft web site:
using System;
using System.IO.Ports;
class PortDataReceived
{
public static void Main()
{
SerialPort mySerialPort = new SerialPort("COM1");
mySerialPort.BaudRate = 9600;
mySerialPort.Parity = Parity.None;
mySerialPort.StopBits = StopBits.One;
mySerialPort.DataBits = 8;
mySerialPort.Handshake = Handshake.None;
mySerialPort.RtsEnable = true;
mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
mySerialPort.Open();
Console.WriteLine("Press any key to continue...");
Console.WriteLine();
Console.ReadKey();
mySerialPort.Close();
}
private static void DataReceivedHandler(
object sender,
SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
Console.WriteLine("Data Received:");
Console.Write(indata);
}
}
But all this methods doesn't work.
Does any one knows any way from get this data and allocate in an array?
How about something to investigate what's happening? If you start a new Winforms project with a single form, a button (buttonStart), and six text boxes, and then put this code behind it
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;
namespace WindowsFormsApplication4
{
public partial class Form1 : Form
{
int RxRead;
int n;
public Form1()
{
InitializeComponent();
}
private void buttonStart_Click(object sender, EventArgs e)
{
serialPort1.PortName = "COM3";
serialPort1.BaudRate = 9600;
serialPort1.Open();
}
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
for (n = 0; n < 23; n++)
{
if (serialPort1.BytesToRead > 0)
{
RxRead = serialPort1.ReadByte();
if (n == 0)
{
textBox1.AppendText(RxRead.ToString());
}
if (n == 1)
{
textBox2.AppendText(RxRead.ToString());
}
if (n == 2)
{
textBox3.AppendText(RxRead.ToString());
}
if (n == 3)
{
textBox4.AppendText(RxRead.ToString());
}
if (n == 4)
{
textBox5.AppendText(RxRead.ToString());
}
if (n == 5)
{
textBox6.AppendText(RxRead.ToString());
}
if (n == 6)
{
serialPort1.Close();
}
}
}
}
}
}
Then I would hope that, when you press the start button, you will get the first six bytes displayed in the text boxes. This would let you see whether the 00 bytes are actually being read at all, or whether they are being discarded for some reason? I haven't got a serial port hooked up on my machine, so my apologies if there are any errors in the code.
Cheers,
Nick
If it's any help, here is a program that I wrote a long while back to pick up data coming in over a serial port from two sensors. It's very clunky programming, but as I recall it did (mostly!) work, so there may be something you can use.
Cheers,
Nick
[][1
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;
namespace serial_port_with_events_attempt_4
{
public partial class Form1 : Form
{
string RxString;
int RxRead;
int i;
int j;
int RxDec1;
int RxDec2;
int RxDec3;
float RxFloat;
float RxFloat2;
string locnString = "Unknown";
DateTime deleteDate;
string deleteDateString;
string testString;
public Form1()
{
InitializeComponent();
deleteDate = DateTime.Today;
deleteDate = deleteDate.AddDays(-7);
deleteDateString = deleteDate.ToString();
textBox1.AppendText(deleteDateString);
}
private void buttonStart_Click(object sender, EventArgs e)
{
serialPort1.PortName = "COM8";
serialPort1.BaudRate = 9600;
serialPort1.Open();
if (serialPort1.IsOpen)
{
buttonStart.Enabled = false;
buttonStop.Enabled = true;
//textBox1.ReadOnly = false;
}
}
private void buttonStop_Click(object sender, EventArgs e)
{
if (serialPort1.IsOpen)
{
serialPort1.Close();
buttonStart.Enabled = true;
buttonStop.Enabled = false;
//textBox1.ReadOnly = true;
}
}
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
for (j = 0; j<23 ; j++)
{
if (serialPort1.BytesToRead > 0)
{
RxRead = serialPort1.ReadByte();
this.Invoke(new EventHandler(DisplayText));
}
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
}
private void DisplayText(object sender, EventArgs e)
{
if (RxRead == 126)
{
//textBox1.AppendText(Environment.NewLine);
i = 0;
}
if (i< 23)
{
if (i == 13)
{
testString = RxRead.ToString();
textBox1.AppendText(testString);
if (RxRead == 82) // 82 in this position means that the temp sensor is the low range one (R1L)
{
//textBox1.AppendText("Temperature in Nick's office = ");
locnString = ("Nicks office");
}
if (RxRead == 195) // 195 in this position means that the temp sensor is the high range one (R1H)
{
//textBox1.AppendText("Temperature in Nick's office = ");
locnString = ("Sitting Room");
}
}
if (i == 17)
{
RxDec1 = RxRead - 48; // Read the tens unit
}
if (i == 18)
{
RxDec2 = RxRead - 48; // Read the units
}
if (i == 20)
{
RxDec3 = RxRead - 49; // read the decimal
}
if (i == 22)
{
RxFloat = ((RxDec1 * 10) + RxDec2);
RxFloat2 = RxDec3;
RxFloat2 = RxFloat2 / 10;
RxFloat = RxFloat + RxFloat2;
// Frig about to get the reads in the right format and added together
RxString = RxFloat.ToString();
if (RxFloat < 30 && RxFloat >10)
{
//textBox1.AppendText(RxString);
if (locnString == "Nicks office")
{
button1.Text = RxString;
}
if (locnString == "Sitting Room")
{
button2.Text = RxString;
}
// Put the value in the main text box if it is not corrupt, (checking if the range is reasonable
temperature1DataSetTableAdapters.Temp1TableAdapter temp1tableadapter = new temperature1DataSetTableAdapters.Temp1TableAdapter();
temp1tableadapter.Insert(DateTime.Now, RxFloat, locnString);
// Add a new line into the temperature database
}
deleteDate = DateTime.Today;
deleteDate = deleteDate.AddDays(-7);
deleteDateString = deleteDate.ToString();
textBox1.Clear();
textBox1.AppendText(deleteDateString);
temperature1DataSetTableAdapters.TempTableAdapter temp2tableadapter = new temperature1DataSetTableAdapters.TempTableAdapter();
temp2tableadapter.DeleteTempQuery(deleteDate);
//textBox1.AppendText("BreakpointA");
textBox1.AppendText(testString);
// Delete any old data.
// TODO Doesn't seem to be working. Don't understand why not. The code gets to here as Breakpoint A gets triggered
this.tempTableAdapter.Fill(this.temperature1DataSet.Temp);
chart1.DataBind();
// These two lines refresh the chart. Took me a long time to figure this out. Basically, you have to
// rerun the query and then run the DataBind method to update the chart control.
// Good article on table adapters http://msdn.microsoft.com/en-us/library/bz9tthwx%28VS.80%29.aspx
//** test code for second chart.
this.tempSensor2AdapterTableAdapter.tempSensor2Fill(this.temperature1DataSet.tempSensor2Adapter);
chart2.DataBind();
}
}
i=i+1;
}
private void Form1_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'temperature1DataSet.tempSensor2Adapter' table. You can move, or remove it, as needed.
this.tempSensor2AdapterTableAdapter.tempSensor2Fill(this.temperature1DataSet.tempSensor2Adapter);
// TODO: This line of code loads data into the 'temperature1DataSet.Temp' table. You can move, or remove it, as needed.
this.tempTableAdapter.Fill(this.temperature1DataSet.Temp);
chart2.ChartAreas[0].AxisX.LabelStyle.Format = "{0:dd/MM H:mm}";
chart1.ChartAreas[0].AxisX.LabelStyle.Format = "{0:dd/MM H:mm}";
}
}
}

Zedgraph Serial plotting, cant pause the time variable. Environment.tickcount improper use

So here's my problem, First image
the highlighted portion was the time when i put the serial port close(i call it pause). Here's my code on that button:
private void disconnectbutton_Click(object sender, EventArgs e)
{
if (serialPort.IsOpen == false) return;
serialPort.Close();
}
Now, my problem here is, when I reconnect my Program to Arduino, here's my code:
public void connectbutton_Click(object sender, EventArgs e)
{
try
{
serialPort.PortName = portscombobox.Text;
serialPort.BaudRate = Convert.ToInt32(baudratecombobox.Text);
if (serialPort.IsOpen) return;
serialPort.Open();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
MessageBox.Show("Invalid COM Port number... Please choose the correct COM Port number. \n Looking at Device manager will help :)");
Application.Restart();
}
The graph didn't follow the last points position, specifically the time it stopped. The curve pick the last y-value and draw it until the time I reconnect but there's no problem on the curve when disconnected/pause. You can look at the 2nd pic to show there's no feed while disconnected.
Second image
When i reconnect, the graph will look like the first picture above..
I believe my problem here was the improper use of Environment.tickcount and I tried searching for the solution but unfortunately I cant solve this on my own based on my knowledge.
I want my graph will only move to its x axis(time) when I try to connect it to arduino and read the data, and my elapsed time should only run when Im only connected not disconnected.
Here's 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;
using ZedGraph;
namespace WindowsFormsApplication4
{
public partial class Form1 : Form
{
string datafromcom;
delegate void SetTextCallback(string text);
// Starting time in milliseconds
int tickStart = 0;
//double time = 0;
//int t;
public Form1()
{
InitializeComponent();
checkbox1.Enabled = false;
checkbox2.Enabled = false;
checkbox3.Enabled = false;
checkbox4.Enabled = false;
}
public void connectbutton_Click(object sender, EventArgs e)
{
try
{
serialPort.PortName = portscombobox.Text;
serialPort.BaudRate = Convert.ToInt32(baudratecombobox.Text);
if (serialPort.IsOpen) return;
serialPort.Open();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
MessageBox.Show("Invalid COM Port number... Please choose the correct COM Port number. \n Looking at Device manager will help :)");
Application.Restart();
}
serialPort.DtrEnable = true;
serialPort.RtsEnable = true;
getbutton.Enabled = false;
checkbox1.Enabled = true;
checkbox2.Enabled = true;
checkbox3.Enabled = true;
checkbox4.Enabled = true;
exitbutton.Enabled = false;
connectbutton.Enabled = false;
disconnectbutton.Enabled = true;
portscombobox.Enabled = false;
baudratecombobox.Enabled = false;
}
private void disconnectbutton_Click(object sender, EventArgs e)
{
if (serialPort.IsOpen == false) return;
serialPort.Close();
//tickStart += new tickStart();
exitbutton.Enabled = true;
connectbutton.Enabled = true;
disconnectbutton.Enabled = false;
portscombobox.Enabled = true;
baudratecombobox.Enabled = true;
checkbox1.Enabled = false;
checkbox2.Enabled = false;
checkbox3.Enabled = false;
checkbox4.Enabled = false;
}
private void Form1_Load(object sender, EventArgs e)
{
//this.Size = Screen.PrimaryScreen.WorkingArea.Size;
GraphPane myPane = z1.GraphPane;
z1.IsShowHScrollBar = true;
z1.IsShowVScrollBar = true;
z1.IsEnableHZoom = true;
z1.IsEnableVZoom = true;
// Disable the AutoScrollRange option (because we have set the scroll range manually)
z1.IsAutoScrollRange = true;
// Synchronize the Axes
z1.IsSynchronizeYAxes = true;
z1.IsSynchronizeXAxes = true;
z1.GraphPane.IsBoundedRanges = true;
// Horizontal pan allowed
z1.IsEnableHPan = true;
z1.IsEnableVPan = true;
z1.IsShowPointValues = true;
//z1.PointValueFormat = "0.00";
z1.PointDateFormat = "d";
// Change the color of the title
myPane.Title.FontSpec.FontColor = Color.Black;
myPane.Title.Text = " ";
myPane.XAxis.Title.Text = "Time (Seconds)";
myPane.YAxis.Title.Text = "Sample Potential, Volts";
// Save 20000 points. At 50 ms sample rate, this is one minute
// The RollingPointPairList is an efficient storage class that always
// keeps a rolling set of point data without needing to shift any data values
RollingPointPairList list = new RollingPointPairList(20000);
// Initially, a curve is added with no data points (list is empty)
// Color is blue, and there will be no symbols
LineItem curve = myPane.AddCurve(null, list, Color.Black, SymbolType.None);
//Sample at 50ms intervals
//timer1.Interval = 100;
//timer1.Enabled = true;
//timer1.Start();
// Just manually control the X axis range so it scrolls continuously
// instead of discrete step-sized jumps
myPane.XAxis.Scale.Min = 0;
myPane.XAxis.Scale.Max = 10;
myPane.XAxis.Scale.MinorStep = .5;
myPane.XAxis.Scale.MajorStep = 1;
myPane.YAxis.Scale.Min = -10;
myPane.YAxis.Scale.Max = 10;
myPane.YAxis.Scale.MinorStep = .1;
myPane.YAxis.Scale.MajorStep = 1;
// Add gridlines to the plot, and make them gray
myPane.XAxis.MajorGrid.IsVisible = true;
myPane.YAxis.MajorGrid.IsVisible = true;
myPane.XAxis.MajorGrid.Color = Color.LightGray;
myPane.YAxis.MajorGrid.Color = Color.LightGray;
myPane.Fill.Color = System.Drawing.Color.DarkGray;
// Make both curves thicker
curve.Line.Width = 2F;
// Increase the symbol sizes, and fill them with solid white
curve.Symbol.Size = 8.0F;
curve.Symbol.Fill = new Fill(Color.White);
// Add a background gradient fill to the axis frame
myPane.Chart.Fill = new Fill(Color.White,
Color.FromArgb(255, 255, 255), -45F);
// Scale the axes
z1.AxisChange();
//z1.AxisChange();
z1.GraphPane.AxisChange();
// Save the beginning time for reference
tickStart = Environment.TickCount;
}
private void exitbutton_Click(object sender, EventArgs e)
{
Application.Exit();
}
public void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
while (serialPort.BytesToRead > 0)
{
datafromcom = serialPort.ReadLine();
if (datafromcom.Trim() != "")
{
float dtfm = float.Parse(datafromcom);
//richtextbox.Text = "dynamic";
if (z1.GraphPane.CurveList.Count <= 0)
return;
// Get the first CurveItem in the graph
LineItem curve = z1.GraphPane.CurveList[0] as LineItem;
if (curve == null)
return;
// Get the PointPairList
IPointListEdit list = curve.Points as IPointListEdit;
// If this is null, it means the reference at curve.Points does not
// support IPointListEdit, so we won't be able to modify it
if (list == null)
return;
double time = (Environment.TickCount - tickStart) / 1000.0;
//curve.AddPoint(time, iDAT);
list.Add(time, dtfm);
Scale xScale = z1.GraphPane.XAxis.Scale;
if (time > xScale.Max - xScale.MajorStep)
{
xScale.Max = time + xScale.MajorStep ;
xScale.Min = xScale.Max - 10.0;
}
z1.AxisChange();
z1.Invalidate();
this.BeginInvoke(new SetTextCallback(SetText), new object[] { datafromcom });
}
}
}
catch (Exception )
{
}
}
private void SetText(string text)
{
this.richtextbox.Text = text;
//richtextbox.AppendText(text);
richtextbox.ScrollToCaret();
}
public void timer1_Tick(object sender, EventArgs e)
{
}
private void resetbutton_Click(object sender, EventArgs e)
{
Application.Restart();
}
}
}

How to pause for loop when pause button is clicked?

When I run the program and try to click the pause button, nothing happens. I am not sure how I can get this to work exactly. I have a bool variable called pause and pause is set to false. Once the pause button is clicked it should set that variable to true. Then the loop checks for that and should display a message to the user. Any help is greatly appreciated!
namespace Practice2
{
public partial class Form1 : Form
{
photocopier printer = new photocopier(500, 2500);
bool pause = false;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void btnStart_Click(object sender, EventArgs e)
{
if (checkText(txtNumberCopies.Text) == true)
{
int numberCopies = Convert.ToInt32(txtNumberCopies.Text);
int toner = Convert.ToInt32(lblTonerAmount.Text);
int paperCapacity = Convert.ToInt32(lblPaperAmount.Text);
if (toner <= 625 && paperCapacity <= 125)
{
txtMessage.Text = "Printer is low on Toner and Paper!";
}
else if (toner <= 625){
txtMessage.Text = "Printer Toner is low!";
}
else if (paperCapacity <= 125)
{
txtMessage.Text = "Printer Paper is low!";
}
else
{
txtMessage.Text = "Printing...";
txtMessage.Refresh();
for (int i = numberCopies; i != 0; i--)
{
int paper = Convert.ToInt32(lblPaperAmount.Text);
paper--;
if (paper == 480 || paper == 380 || paper == 400 || paper == 200)
{
MessageBox.Show("There is a paper Jam! Please remove the Jam and then hit the ok button to continue!", "Important Message", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
if (pause == true)
{
MessageBox.Show("Press the ok button when ready to continue", "Important Message", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
lblPaperAmount.Text = Convert.ToString(Convert.ToInt32(lblPaperAmount.Text) - 1);
lblTonerAmount.Text = Convert.ToString(Convert.ToInt32(lblTonerAmount.Text) - 1);
Thread.Sleep(1000);
}
txtMessage.Text = "Job is completed!";
}
}
}
private void btnAddPaper_Click(object sender, EventArgs e)
{
int paperAmount = Convert.ToInt32(lblPaperAmount.Text);
if (checkText(txtAddPaper.Text) == true && paperAmount <= 500)
{
lblPaperAmount.Text = Convert.ToString(paperAmount + Convert.ToInt32(txtAddPaper.Text));
}
else
{
txtMessage.Text = "Printer paper is at capacity!";
}
}
private bool checkText(string textBox)
{
if (textBox.Equals("") || textBox == null)
{
txtMessage.Text = "Please enter a value in the text box!";
return false;
}
return true;
}
private void btnReplaceToner_Click(object sender, EventArgs e)
{
lblTonerAmount.Text = Convert.ToString(printer.Toner);
}
private void btnPauseCancel_Click(object sender, EventArgs e)
{
pause = true;
}
}
}
The problem is that you're doing the work on the UI thread, so the UI thread is busy and can't process messages (e.g. button click). You need to do the work on a worker thread instead, using BackgroundWorker or Task.Run for instance.
A for loop is on the UI Thread so while the for loop is running you can't do anything with the UI. I suggest that you use a System.Windows.Forms.Timer to do the job. You set the interval to 1 and that will run pretty quickly, but not as quickly as a for loop, though. But interval = 1 is enough for you.
Let me show you:
Timer timer = new Timer () {Interval=1};
to create a new timer object.
enter
timer.Tick +=
in the constructer and press TAB twice and that should generate an event handler. Write the stuff you want to do in the event handler.
Call timer.Stop to pause the timer and timer.Start to start the timer.

Refreshing a chart control

This one is driving me a bit crazy. Any help gratefully received. It's a simple program to receive temperature data from an Arduino based temp sensor, and display it in a graph control on a form. The program works fine, and parses the temp data frame a treat. However..... the graph object doesn't refresh, and the whole point is to show the data over time. I thought that the chart1.DataBind command that I put in forced a refresh. I am using Visual Studio 2013 Express. Any thoughts as to what I am doing wrong very much appreciated.
// Start of program.
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;
namespace serial_port_with_events_attempt_4
{
public partial class Form1 : Form
{
string RxString;
int RxRead;
int i;
int RxDec1;
int RxDec2;
int RxDec3;
float RxFloat;
float RxFloat2;
string locnString;
public Form1()
{
InitializeComponent();
}
private void buttonStart_Click(object sender, EventArgs e)
{
serialPort1.PortName = "COM8";
serialPort1.BaudRate = 9600;
serialPort1.Open();
if (serialPort1.IsOpen)
{
buttonStart.Enabled = false;
buttonStop.Enabled = true;
textBox1.ReadOnly = false;
}
}
private void buttonStop_Click(object sender, EventArgs e)
{
if (serialPort1.IsOpen)
{
serialPort1.Close();
buttonStart.Enabled = true;
buttonStop.Enabled = false;
textBox1.ReadOnly = true;
}
}
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
RxRead = serialPort1.ReadByte();
this.Invoke(new EventHandler(DisplayText));
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
}
private void DisplayText(object sender, EventArgs e)
{
if (RxRead == 126)
{
textBox1.AppendText(Environment.NewLine);
i = 0;
}
if (i< 23)
{
if (i == 7)
{
if (RxRead == 51) // 51 in this position means that the temp sensor is the one in the wooden box
{
textBox1.AppendText("Temperature in Nick's office = ");
locnString = ("Nick's office");
}
}
if (i == 17)
{
RxDec1 = RxRead - 48; // Read the tens unit
}
if (i == 18)
{
RxDec2 = RxRead - 48; // Read the units
}
if (i == 20)
{
RxDec3 = RxRead - 49; // read the decimal
}
if (i == 22)
{
RxFloat = ((RxDec1 * 10) + RxDec2);
RxFloat2 = RxDec3;
RxFloat2 = RxFloat2 / 10;
RxFloat = RxFloat + RxFloat2;
RxString = RxFloat.ToString();
if (RxFloat < 30 && RxFloat >20)
{
// Put the value in the main text box if it is not corrupt, (checking if the range is reasonable
textBox1.AppendText(RxString); // Frig about to get the reads in the right format and added together
// Add a new line into the temperature database
temperature1DataSetTableAdapters.Temp1TableAdapter temp1tableadapter = new temperature1DataSetTableAdapters.Temp1TableAdapter();
temp1tableadapter.Insert(DateTime.Now, RxFloat, locnString);
}
// Delete any old data.
temperature1DataSetTableAdapters.TempTableAdapter temp2tableadapter = new temperature1DataSetTableAdapters.TempTableAdapter();
temp2tableadapter.DeleteTempQuery();
// The above two lines work, but I need to amend to select on date TODO
chart1.DataBind();
}
}
i=i+1;
}
private void Form1_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'temperature1DataSet.Temp' table. You can move, or remove it, as needed.
this.tempTableAdapter.Fill(this.temperature1DataSet.Temp);
}
}
}
Cheers,
Nick James

Categories

Resources