Go Down

Topic: Unable to properly use VS Serial Monitor but Arduino IDE works (Read 287 times) previous topic - next topic

sumguy

The arduino Serial Monitor and Visual Studio are both PC programs that do similar jobs, Visual Studio can be made a little more flexible in my opinion.

If you try the example I posted and it works ok then maybe you would like to try the next step which is to read the value of the character you are sending.

Here we modify the arduino sketch to echo only the character value sent by Visual Studio

Code: [Select]
char receivedChar;
boolean newData = false;

void setup() {
 Serial.begin(9600);
 Serial.println("<Arduino is ready>");
}

void loop() {
 recvOneChar();
 showNewData();
}

void recvOneChar() {
 if (Serial.available() > 0) {
 receivedChar = Serial.read();
 newData = true;
 }
}

void showNewData() {
 if (newData == true) {
 //Serial.print("This just in ... ");
 Serial.print(receivedChar);
 newData = false;
 }
}



At the C# end we add a new routine that displays the value instead of the character, this routine is called byteDebug.

Code: [Select]
 private void byteDebug(byte sData)
        {

            
            richTextBox1.AppendText(sData + " ");

        }


The invoke for this delegate also needs the name change, change the following line

Code: [Select]
this.BeginInvoke((new myDelegate(stringDebug)), myData);

to this

Code: [Select]
this.BeginInvoke((new myDelegate(byteDebug)), myData);

When you run this it really is a good idea to have a copy of the ASCII table close by so that you understand which characters the numbers represent.






ron_sutherland

The Arduino IDE does some tricks that may be adding confusion. When the compile and upload button is pushed it the IDE GUI closes the serial port so that the upload tool (avrdude) can use it. In older versions of the IDE the Serial Monitor would close, and then the user would have to open it back up after the update, but now it waits while disconnected from the port. With VS Code I have to close the serial terminal program (e.g. picocom) before running the upload tool. I forget to do this all the time and get reminded when the upload tool (avrdude) complains.

sumguy

This example uses strings to communicate, the C# code is slightly simpler than the previous example but the arduino is a little more complex.

Both programs have a routine called txData and a routine called rxData, lets look a rxData first.

The C# rxData contains the line
Code: [Select]
richTextBox1.AppendText(port.ReadLine() + "\n");


the ReadLine method reads data arriving at the serial port buffer until it finds the newline character which is decimal 10

Fortunately the arduino has a similar method which we can give a search character a value, so here we give it the same value as the C# method a value of decimal 10

The arduino rxData
Code: [Select]
Serial.readBytesUntil(10,myString,40);

In both cases the decimal value of 10 is discarded and not contained within the byte array (string).

Although it is not important with C# the arduino strings need to be terminated with a zero, the arduino byte array must always be at least 1 byte longer than the string it contains. For example the string "arduino" is 7 bytes then add the terminating zero so the array should be at least 8 bytes long. In the example arduino code I fill the variable myString with zeros before each serial read with the following.

Code: [Select]
memset(myString,0,sizeof(myString));

The terminating zero is neccessary for library routines that compare,display or manipulate the strings, that is for another time.

The C# txData routine contains the WriteLine method, this method automatically appends the newline character (decimal 10)

Code: [Select]
port.WriteLine(textBox1.Text);

The arduino txData may not be clear at first glance but what it does is take a pointer to the memory location that contains the first character/byte of "myString", the while loop increments the pointer through the string, transmitting each byte, until it encounters the zero terminator after which we transmit the newline character decimal 10 so that C# knows the string is complete.

Code: [Select]
  const char *pointer;
          pointer = myString;
    while (*pointer) {
          Serial.print(*pointer);
          pointer++;     
}
         Serial.write(10);


The C# program has 5 controls, a richTextbox, 2 textBoxes and 2 buttons. The idea is to transmit the text from the two textBoxes, for example Motor1 in textbox 1 and run in textbox 2.

The two strings are echoed back by the arduino and retrieved by pressing button2, this second button was included purposely to demonstrate that the data/strings remain in the port's receiving buffer until you decide to read them

Arduino
Code: [Select]

byte myString[40];
;
boolean newData = false;

void setup() {
 Serial.begin(9600);
}

void loop() {
 rxData();
 txData();
}

void rxData() {

 if (Serial.available() > 0) {
          memset(myString,0,sizeof(myString));
          Serial.readBytesUntil(10,myString,40);
          newData=true;
}
}

void txData() {

 if (newData == true) {
          const char *pointer;
          pointer = myString;
    while (*pointer) {
          Serial.print(*pointer);
          pointer++;     
}
         Serial.write(10);
         newData = false;
}
}


C#
Code: [Select]
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 WindowsFormsApplication9
{
    public partial class Form1 : Form
    {
        SerialPort port = new SerialPort();

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            button2.Enabled = false;
            port.PortName = "COM3";
            port.Open();
            port.ReadExisting();
        }


        void txData()
        {

            if (port.IsOpen)
            {
                port.WriteLine(textBox1.Text);
                port.WriteLine(textBox2.Text);

            button1.Enabled = false;
            button2.Enabled = true;
        }
        }

        void rxData() {
            if (port.IsOpen)
            {
                while (port.BytesToRead > 0)
                {
                    try
                    {
                        richTextBox1.AppendText(port.ReadLine() + "\n");
                       
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                    }
                    }
               
                    button1.Enabled = true;
                    button2.Enabled = false;
            }
       
        private void button1_Click(object sender, EventArgs e)
        {
            txData();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            rxData();
        }
    }
}








jim-yang

This example uses strings to communicate, the C# code is slightly simpler than the previous example but the arduino is a little more complex.

Both programs have a routine called txData and a routine called rxData, lets look a rxData first.

The C# rxData contains the line
Code: [Select]
richTextBox1.AppendText(port.ReadLine() + "\n");


the ReadLine method reads data arriving at the serial port buffer until it finds the newline character which is decimal 10

Fortunately the arduino has a similar method which we can give a search character a value, so here we give it the same value as the C# method a value of decimal 10

The arduino rxData
Code: [Select]
Serial.readBytesUntil(10,myString,40);

In both cases the decimal value of 10 is discarded and not contained within the byte array (string).

Although it is not important with C# the arduino strings need to be terminated with a zero, the arduino byte array must always be at least 1 byte longer than the string it contains. For example the string "arduino" is 7 bytes then add the terminating zero so the array should be at least 8 bytes long. In the example arduino code I fill the variable myString with zeros before each serial read with the following.

Code: [Select]
memset(myString,0,sizeof(myString));

The terminating zero is neccessary for library routines that compare,display or manipulate the strings, that is for another time.

The C# txData routine contains the WriteLine method, this method automatically appends the newline character (decimal 10)

Code: [Select]
port.WriteLine(textBox1.Text);

The arduino txData may not be clear at first glance but what it does is take a pointer to the memory location that contains the first character/byte of "myString", the while loop increments the pointer through the string, transmitting each byte, until it encounters the zero terminator after which we transmit the newline character decimal 10 so that C# knows the string is complete.

Code: [Select]
 const char *pointer;
          pointer = myString;
    while (*pointer) {
          Serial.print(*pointer);
          pointer++;      
}
         Serial.write(10);


The C# program has 5 controls, a richTextbox, 2 textBoxes and 2 buttons. The idea is to transmit the text from the two textBoxes, for example Motor1 in textbox 1 and run in textbox 2.

The two strings are echoed back by the arduino and retrieved by pressing button2, this second button was included purposely to demonstrate that the data/strings remain in the port's receiving buffer until you decide to read them

Arduino
Code: [Select]

byte myString[40];
;
boolean newData = false;

void setup() {
 Serial.begin(9600);
}

void loop() {
 rxData();
 txData();
}

void rxData() {

 if (Serial.available() > 0) {
          memset(myString,0,sizeof(myString));
          Serial.readBytesUntil(10,myString,40);
          newData=true;
}
}

void txData() {

 if (newData == true) {
          const char *pointer;
          pointer = myString;
    while (*pointer) {
          Serial.print(*pointer);
          pointer++;      
}
         Serial.write(10);
         newData = false;
}
}


C#
Code: [Select]
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 WindowsFormsApplication9
{
    public partial class Form1 : Form
    {
        SerialPort port = new SerialPort();

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            button2.Enabled = false;
            port.PortName = "COM3";
            port.Open();
            port.ReadExisting();
        }


        void txData()
        {

            if (port.IsOpen)
            {
                port.WriteLine(textBox1.Text);
                port.WriteLine(textBox2.Text);

            button1.Enabled = false;
            button2.Enabled = true;
        }
        }

        void rxData() {
            if (port.IsOpen)
            {
                while (port.BytesToRead > 0)
                {
                    try
                    {
                        richTextBox1.AppendText(port.ReadLine() + "\n");
                      
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                    }
                    }
              
                    button1.Enabled = true;
                    button2.Enabled = false;
            }
        
        private void button1_Click(object sender, EventArgs e)
        {
            txData();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            rxData();
        }
    }
}



I wasn't aware there was a second page, and didn't know to respond sooner. I was looking at the codes you posted and have some questions.

1. When I was trying the first code from 9/13, When you add the code to the private void Form1_Load  section, does that only run on the time the form is initialized? There's no sort of indexing when you read the array as well wouldn't the [port.DataReceived += new SerialDataReceuvedEventHandler(port_DataReceived);[/code] mean that the byte being read would be a sum of all the bytes that have already passed?

Also I had to change the code for it to compile. I don't think replacing your port declaration should make a difference?
Code: [Select]
port = new SerialPort("COM3"); //instead of port.PortName = "COM3";

2. When you say
Code: [Select]
port.Write("A"); this would write to the serial monitor correct? Like you said that there are only two controls in the C# app, and all I want to do is a display, would I need a control? One thing that I did was to create a label in my form and then update the text within the label.
Code: [Select]
String label5 = number3.Value.ToString();           //Generate the int to string to display
            display3.Text = label5;
Where I have a numericupdown control named number3, I take the value of the number inside, convert it into a string, and then have my label named display3 take the string to display.

3. I posted a question earlier in the forums but I cannot seem to find that post in my history... Don't we need multiple Serial ports i.e
Code: [Select]
Serial.begin(9600);
Serial1.begin(9600);
? That way you have one port reading data and the other to echo it back to the VS application? As you stated earlier, we need to build a serial monitor in the VS application, and you talk about having the Arduino echo the value sent from VS. I assume you mean that when the Arduino receives a value, it sends it back. If all I want to do is to see what is being echoed back, could I do something similar to #2. When the Arduino receives a byte I can then convert that byte into a char/string and then send it to the VS application where I can then have it displayed in a label?

4. Is the usage of the rich textbox important? Is it basically the output of the Serial Monitor?

5. Could using the Serial.readbytesuntil() replace the while(Serial.available) loop? As long as you could guarantee that the end condition isn't accidentally met while receiving data?

6. Is your port.Writeline(Textbox.text); basically the same thing with me updating the label?

ieee488

When using it on the Arduino IDE, the exchange is directly from Serial Monitor to the Arduino and back, so when I use a VS GUI to send it, I would have assumed the Arduino would be directly printing out to it's Serial Monitor.

The Serial Monitor uses up the one and only hardware serial port that the Arduino Uno has.

If you want to use Visual Studio to communicate with the Arduino Uno while also using the IDE's Serial Monitor, you need to use
a.) software serial library
and
b.) a USB-TTL adapter and connect to Arduino Uno's pins other than 0 and 1


.

Go Up