Go Down

Topic: Need faster serial transfer - Arduino and C# (Read 3 times) previous topic - next topic

Osgeld

the speed reported by various users can get near 1Mbs over serial so you have lots of room

robtillaart


Have had excellent results with 345600 baud sending to putty.exe (lots of raw data ~8K analog samples/second) 

what is the highes number you need to send?
if the range is between 0..255 a byte would be sufficient and you could write

XDBDBDBDB\n

that is ~50% less communication!

furthermore you can do the conversion to integer yourself directly...
Code: [Select]

if (Serial.available() >= 18)
   {
      c = Serial.read();
      if (c=='X')
      {
         for (int i=0; i<4; i++)
         {
             Direction[i] = Serial.read();
             speed[i] = Serial.read() - '\0';
             speed[i] = speed[i] * 10 + Serial.read() - '\0';
             speed[i] = speed[i] * 10 + Serial.read() - '\0';
          }
          c=Serial.read();

        SetPins();
        PrintPots();
    }


I see 2 loops in your code : for (int i = 0; i<5;i++)   and  for (int i=0; i<4; i++)  there is a difference, is it intentional?
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

amatic

Thank you for your replies.

@elsupremo
yes, the num is 4 chars long (I set it to 4 only after having the error you described :)
I've set the baud rate to 57600. That part works good. Even the 115200 works and I haven't seen any errors.

@robtillaart
Output messages from arduino are analog readings (0-1023), so two bytes are needed. And you're right, pwm values can be placed in only byte. I can even cram the direction values to one byte, so plus 4 pwm values, that's only 5 bytes.

The two loops you mention are intentionaly different. The reading loop has 4 chunks of data to read - motor direction and speed. The printing loop has 5 chunks from analog pins - four are potentiometer readings, and one is a thermistor reading.

----
More questions:
1. Would it be advisable not to use the start and stop bytes, just raw messages?


2. Does anyone know of a way to speed up C# serial communication? The fastes I can get it to run using DataReceived event is 15 ms.
I'm googleing as we speak, but nothing seems to be working.

by the way, I've found an elegant way of converting integers to bytes:
Code: [Select]

byte output [12];
// snip

for (int i=0;i<5;i++)
    {
      int x=analogRead(i);
      output[1+2*i] = x & 0xFF;
      output[2+2*i] = (x >> 8) & 0xFF;
    }
    Serial.write(output,12);


On the C# side, the code is:
Code: [Select]

           byte [] SI = new byte[12];
// formated as '0aabbccddee0'
// snip

            serialPort1.Read(SI, 0, 12);
            for (int i = 0; i < 4; i++)
            {
                Angle[i].Position = SI[i * 2 + 1] | (SI[i * 2 + 2] << 8);
            }

            temperature = SI[10] | (SI[11] << 8);
            DataReceived = true;
           

Currently I'm having trouble

amatic

I'm thinking that the biggest problem is on the C# side and the separate serial threads. My knowledge on threads is low.

Here's the code:
Code: [Select]

        public MainForm()
        {
            InitializeComponent();

            serialPort1.BaudRate = 57600;
            serialPort1.PortName = "COM5";
            serialPort1.ReceivedBytesThreshold = 12;
           
            stopwatch.Start();
            Application.Idle += new EventHandler(MainLoop);
        }



private void MainLoop(object sender, EventArgs e)
          {
                  if (DataReceived)
                  {
                      label31.Text = stopwatch.ElapsedMilliseconds.ToString();
                      DataReceived = false;
                      stopwatch.Reset();
                      stopwatch.Start();
                    }
}
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
                serialPort1.Read(SI, 0, 12);
                this.Invoke(new EventHandler(ReadPots));
}
private void ReadPots(object sender, EventArgs e)
{
      for (int i = 0; i < 4; i++)
      {
                Angle[i].Position = SI[i * 2 + 1] | (SI[i * 2 + 2] << 8);
       }

       temperature = SI[10] | (SI[11] << 8);
       DataReceived = true;
}

PaulS

Quote
I'm thinking that the biggest problem is on the C# side and the separate serial threads.

No. The problem is with you creating a new thread for each read. My code looks like:
Code: [Select]
public static System.IO.Ports.SerialPort port;
delegate void SetTextCallback(string text);

// This BackgroundWorker is used to demonstrate the
// preferred way of performing asynchronous operations.
private BackgroundWorker hardWorker;

private Thread readThread = null;

public Form1()
{
InitializeComponent();

hardWorker = new BackgroundWorker();
sendBtn.Enabled = false;
}

private void btnConnect_Click(object sender, EventArgs e)
{
System.ComponentModel.IContainer components =
new System.ComponentModel.Container();
port = new System.IO.Ports.SerialPort(components);
port.PortName = comPort.SelectedItem.ToString();
port.BaudRate = Int32.Parse(baudRate.SelectedItem.ToString());
port.DtrEnable = true;
port.ReadTimeout = 5000;
port.WriteTimeout = 500;
port.Open();

readThread = new Thread(new ThreadStart(this.Read));
readThread.Start();
this.hardWorker.RunWorkerAsync();

There is ONE thread to read serial data. When data arrives, the Read() method is called:
Code: [Select]
public void Read()
{
while (port.IsOpen)
{
try
{
if (port.BytesToRead > 0)
{
string message = port.ReadLine();
this.SetText(message);
}
}
catch (TimeoutException) { }
}
}


The SetText() method then determines what to do with the data:
Code: [Select]
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.receiveText.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
                this.receiveText.Text += "Text: ";
                this.receiveText.Text += text;
                this.receiveText.Text += Environment.NewLine;
            }
}

It either Invokes a method on another thread (the UI thread) if called by the serial thread, or, if called by the UI thread, does something with the text.

Of course, your thread method can have a different name, and do something different with the serial data, but you should not be creating new threads/event handlers each time data arrives on the serial port.

Go Up