0

I got a C# WPF application wich communcates with my arduino uno over serial port. Everything works fine for 3 to 20 seconds then i can not send or receive anything from/to the arduino.

What im trying to archieve: Connected a arduino uno to an optical sensor of a mouse to read from its registers, now i want to process the data on my pc.

I tried using another arduino uno and also some other mouse optical sensor, wich did not change anything. Opening and closing the serialport after each communication did not work for me. I have seen a few questions here on stack exchange, i looked through everyone but they could not help me. Serial.flush() seems to be not working, or its some kind of overflow i cant figure out.

I would really appreciate it if someone could explain me what the root of this problem is.

For completeness, here is my C# code:

 public class SerialCommunication
    {
        public SerialPort serialPort = new SerialPort();

        public SerialCommunication()
        {
            string[] ports = SerialPort.GetPortNames();
            if (ports.Count() == 1)
            {
                MessageBox.Show("No serialport is available");
                return;
            }
            serialPort.PortName = ports[1];
            serialPort.BaudRate = 115200;
            serialPort.Parity = Parity.None;
            serialPort.DataBits = 8;
            serialPort.Handshake = Handshake.None;
            serialPort.StopBits = StopBits.One;
            serialPort.NewLine = "\r\n";
            serialPort.WriteTimeout = 2000;
            serialPort.ReadTimeout = -1;

            serialPort.Open();
        }
    }

public partial class MainWindow : Window
    {
        public static readonly object _lock = new object();

        private SerialCommunication serialCommunication = new SerialCommunication();

        public MainWindow()
        {
            InitializeComponent();
            GetWindow(this).KeyDown += HandelKeyDown;

            serialCommunication.serialPort.DataReceived += (sender, args) =>
            {
                string bufferstring = ((SerialPort)sender).ReadLine();
                OnMessageReceived(bufferstring);
                //serialCommunication.serialPort.DiscardOutBuffer();
                //serialCommunication.serialPort.DiscardInBuffer();
                //Thread.Sleep(3);
                //byte[] buffer = new byte[15];
                //((SerialPort)sender).Read(buffer, 0, buffer.Length);
                //string bufferstring = Encoding.UTF8.GetString(buffer);
            };
            serialCommunication.serialPort.WriteLine("OK");
        }

        private void OnMessageReceived(string message)
        {
            if (message.Length != 15 || message.Contains('O') || message.Contains('K') || message.Contains('\n') || message.Contains('\r'))
            {
                serialCommunication.serialPort.DiscardInBuffer();
                serialCommunication.serialPort.DiscardOutBuffer();
                serialCommunication.serialPort.WriteLine("OK");
                return;
            }

            //Format: "y: 0x%02X,x: 0x%02X"
            string x = message.Substring(3, 4);
            string y = message.Substring(11, 4);

            int offsetX = (Convert.ToInt32(x, 16) - 128);
            int offsetY = (Convert.ToInt32(y, 16) - 128);

            // the next three lines only visualize the received data but do not change it  
            MoveX(offsetX / 50);
            MoveY(offsetY / 50);
            ShowMessage(message);
            Thread.Sleep(2);
            serialCommunication.serialPort.WriteLine("OK");
        }
}

Foto of how the application and data it receives look like: On the right side is the data, at the top the current position

Here is my arduino code:

#include <Arduino.h>

// 5v
#define POWER 13
// Serial I/O
#define SDIO 11
// Serial clock
#define SCK 12

// Registers
#define DELTAY 0x02
#define DELTAX 0x03

#define serialInputBufferSize 16
char dataBuffer[serialInputBufferSize];
unsigned short inputBufferLength = 0;

bool sendPosition = true;

char tmp[16];

void InitMouse()
{
  digitalWrite(SCK, HIGH);
  delayMicroseconds(5);
  digitalWrite(SCK, LOW);
  delayMicroseconds(1);
  digitalWrite(SCK, HIGH);

  // Wait for the serial transaction timer to time out:
  delay(1000);
}

byte readRegister(byte addr)
{
  byte r = 0;

  // Set the dataline to output
  pinMode(SDIO, OUTPUT);
  for (int i = 7; i >= 0; i--)
  {
    digitalWrite(SCK, LOW);
    digitalWrite(SDIO, addr & (1 << i));
    digitalWrite(SCK, HIGH);
  }

  // Switch the dataline from output to input
  pinMode(SDIO, INPUT);
  // The datasheet mentions to wait at least 100 µsec
  // when switching from write to read operations.
  // This is needed for the chip to prepare the data
  delayMicroseconds(110);

  // Clock trough the register and read its data
  for (int i = 7; i >= 0; i--)
  {
    digitalWrite(SCK, LOW);
    digitalWrite(SCK, HIGH);
    r |= (digitalRead(SDIO) << i);
  }

  // Delay at the end guarantees >100 µsec before next transaction
  delayMicroseconds(110);

  return r;
}

byte y = 0;
byte x = 0;

void WaitForMovementThenSendPositionOffset()
{
  x = 0;
  y = 0;

  while (((y == 0 && x == 0) || x == NULL || y == NULL) && sendPosition)
  {
    delay(1); // kann eigentlich weg
    y = readRegister(DELTAY);
    x = readRegister(DELTAX);
  }

  if (sprintf(tmp, "y: 0x%02X,x: 0x%02X", y, x) > 0)
  {
    tmp[16] = 0;
    if (!Serial.println(tmp))
    {
      // Serial.end();
      // Serial.begin(9600);
      // Serial.begin(115200);
      Serial.flush();
    }

    sendPosition = false;
  }
}

void serialEvent()
{
  sendPosition = false;

  // Read serial data into the buffer
  while (Serial.available())
  {
    dataBuffer[inputBufferLength++] = Serial.read();
  }

  Serial.flush();

  if (strstr(dataBuffer, "OK"))
  {
    sendPosition = true;
    WaitForMovementThenSendPositionOffset();
  }
}

void setup()
{
  pinMode(SCK, OUTPUT);
  pinMode(SDIO, INPUT);
  pinMode(POWER, OUTPUT);

  digitalWrite(POWER, HIGH);

  Serial.setTimeout(1000);
  // Serial.begin(9600);
  Serial.begin(115200);

  InitMouse();
}

void loop()
{
}
6
  • what troubleshooting have you done?
    – jsotola
    Dec 30, 2019 at 0:14
  • @jsotola as mentioned above: I tried using another arduino uno and also some other mouse optical sensor, wich did not change anything. Opening and closing the serialport after each communication did not work for me. I have seen a few questions here on stack exchange, i looked through everyone but they could not help me. I also tried around with delay() and other useless stuff for 2 days now Dec 30, 2019 at 0:26
  • 1
    start with basics ... lower the baud rate ... use a simple Arduino sketch that sends repeatedly "ABC123" one character at a time with a short pause in between characters ... observe the result on the C# side of the connection
    – jsotola
    Dec 30, 2019 at 0:38
  • @jsotola i tried baudrate 9600 wich did not help, on the c# side i get the results i want. I will add a foto of how my wpf application looks like and the data it receives, but thank you Dec 30, 2019 at 1:02
  • 1
    you need to modify the arduino sketch to the minium code that still exhibits the undesired behavior ... that is why i said to start by sending ABC123 and see if it still happens
    – jsotola
    Dec 30, 2019 at 2:21

2 Answers 2

0

Every time you receives data, it tries to read a full line (SerialPort.ReadLine()). If there's not a full line available, it will block the current thread until there is or until it times out.

These calls will stack up and eventually cause the application to fail.

1
  • If i restart the c# application, it still does not work. I have to restart the arduino, then it works again. I think problem is on the arduino side, but i give it a try and use a buffer with SerialPort.Read() instead. Dec 30, 2019 at 13:37
0

The problem was in the serialEvent() method. I did not rest the bufferindex where i red the received message so it allways stayed there until the arduino ran out of memory and also i did not gave the arduino enough time to receive the message so i added delay(1) there.

Here is my updated code:

void serialEvent()
{
  inputBufferLength = 0;
  sendPosition = false;
  delay(1);
  // Read serial data into the buffer
  while (Serial.available())
  {
    if (inputBufferLength < serialInputBufferSize)
    {
      dataBuffer[inputBufferLength++] = Serial.read();
    }
    else
    {
      Serial.read();
    }
  }

  Serial.flush();

  if (strstr(dataBuffer, "OK"))
  {
    sendPosition = true;
    WaitForMovementThenSendPositionOffset();
  }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.