Serial port via USB-C freezes computer programs

Hi all.

I was using Arduinos to monitor some machine production in my work.

The Arduinos received a trigger every time that the machine produced a part and, connected via USB serial to a computer, they send the number of pieces and the speed of production to a Windows computer (the computer runs a program that manages that info).

Some of the machines required an 5V inductive sensor and some other send a 24V trigger directly when they do finish a cycle.

As I was tired of passing 24V to 5V and signal noise, as soon as the OPTA was released I bought 7 of them to replace my UNOs. The idea was to work directly at 24V getting the signal from some machines and using inductive sensors but at 24V in the ones that can not send any trigger (generally old not-CNC machines).

This is the skecth that I used in my UNOs adapted to the new OPTA:

const byte rpmInputPin = A0;                 // Input pin for the triggers from the machine.
const int rpmMeasurementCycles = 1;          // Number of triggers required to calculate the rpm (in Arduino UNO sometimes it was better to have some more).
const int printInterval = 3600;              // Time before sending the data to the computer. In some machines, if they are very fast, it's a way of limiting how many times we are sending data
int long unsigned currentQuantity = 0;       // Variable with the total amount of parts produced by the machine.
int long unsigned previousQuantity = 0;      // Variable with the previous amount of parts produced. We are going to use this to compare if the machine has stopped working after some time working.
volatile unsigned long startTime, stopTime;  // Variables to store the difference of time between triggers.
volatile byte rpmCount;                      // The number of current triggers received. We will compare it against rpmMeasurementCycles to see if we have reached the amount of cycles required to calculate the rpm
volatile byte testState;                     // Variable with the current state of the program (so we can use it inside a Case).
long int waitingTimeForStop = 15000;         // Machine's operators may increase or reduce the machine's speed, so we set an amount of time to check if the machine is going slower or if it has been stopped.
unsigned long previousWaitingForStop = 0;    // Variable used to compare if the amount of time stored in waitingTimeForStop has already passed.
unsigned long rpmPeriod;
unsigned long currentMillis;              // Variable to store the current time.
unsigned long previousMillis = 0;         // Variable to compare the current time with a past event.
float rpm2rph;                            // Variable to calculate the pieces per hour
int unsigned rph;                         // The parts per hour of the machine that we are going to send via the serial port.
int val;                                  // Variable that will store the data received via the serial port from the computer.
const int relayPin1 = D0;                 // Pin with a relay that we are going to use when some data is received from the serial port.
long int BOUNCE_DURATION = 150000;        // Value used to clean the triggers received. It makes sure that the triggers are real and not produced for electrical noise.
volatile unsigned long bounceTime = 200;  // Variable used to store the last microsecond that we received a valid trigger.

bool machineWorking = false;  // A variable that will be set to true if the machine is working.

void setup() {
  pinMode(relayPin1, OUTPUT);    // Declaramos que el pin del primer relé será un pin de salida.
  digitalWrite(relayPin1, LOW);  // We make sure that the relay is off when the OPTA starts.
  Serial.begin(115200);          // We do start the serial port at 115.200 bauds.
  pinMode(rpmInputPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(rpmInputPin), rpmMeasure, RISING);
}


/*
This is the function that we are going to use to increase the count of parts produced and also to store the times between triggers
if the time between them are less than the anti-bouncing time.
*/
void rpmMeasure() {
  if (micros() - bounceTime > BOUNCE_DURATION) {
    currentQuantity++;
    bounceTime = micros();
    switch (testState) {
      case 0:
        startTime = micros();
        testState = 1;
        break;
      case 1:
        rpmCount++;
        if (rpmCount == rpmMeasurementCycles) {
          stopTime = micros();
          testState = 2;
          break;
        }
        break;
    }
  }
}


void loop() {

  currentMillis = millis();  // We set currentMillis to have the same value than millis() so we can do time comparations

  if (currentMillis - previousMillis >= printInterval) {
    previousMillis = currentMillis;
    previousQuantity = currentQuantity;  // We even the previous quantity of parts produced with the current one, so we can check if the number has increased.
   if (testState == 2) {
      previousWaitingForStop = currentMillis;                     // We do also even the moment of the last time that we checked if the machine was still working, so we are sure that the machine was sending triggers.
      noInterrupts();                                             // We do stop the interrupts while we are doing time calculations
      rpmPeriod = (stopTime - startTime) / rpmMeasurementCycles;  // We do calculate the time between the signals and we do divide it between the required signals.
      interrupts();                                               // We do activate interrupts again.
      rpm2rph = 1000000.0 / rpmPeriod;                            // We do pass the rpmperiod to pieces per hour (as we are working in microseconds, the value has to be divided by 1 million).
      rph = round(ceil(rpm2rph  * 3600.0));                       // We do round the rpm in order to send an int via serial
      Serial.print(int(currentQuantity));                         // So finally we send the data via serial in this format: quantity @ pieces per hour
      Serial.print("@");
      Serial.println(rph);
      previousQuantity = currentQuantity;  // Igualamos el contador anterior con el nuevo para poder comparar más adelante.
      rpmCount = 0;                        // We do reset the current rpmcount so we can start again to wait until we get as many triggers as rpmMeasurementCycles stores before calculations.
      testState = 0;                       // We do also set the current testState to zero, so we can start the cycle again.
    }
  }

  if (currentMillis - previousWaitingForStop > waitingTimeForStop) {  // Every amount of time we do this verification...
    previousWaitingForStop = currentMillis;
    if (currentQuantity == previousQuantity) {  // If during this period of time we haven't increased the number of cycles received from the machine, then it has stopped
      Serial.print(currentQuantity);
      Serial.println("@0");  // So we send the current quantity and zero speed.
      machineWorking = false;
    }
  }

  if (Serial.available()) {
    val = Serial.read();
    if (val == 'A') {  // If we do receive an A via serial from the computer, then we reset the current quantity of pieces produced
      currentQuantity = 0;
      previousQuantity = 0;
      Serial.println("A");
    }

    if (val == 'X') {  // This is to deactivate the realy when we do receive an X from the computer.
      digitalWrite(relayPin1, LOW);
      Serial.println("X");
    }

    if (val == 'Y') {  // Same but for activating in case that the computer sends an Y.
      digitalWrite(relayPin1, HIGH);
      Serial.println("Y");
    }

    if (val == 'W') {
      machineWorking = true;
      Serial.println("W");
    }

    if (val == 'Z') {  // As the OPTA doesn't restart itself when it starts a serial connection, in case that we need to reset it.
      NVIC_SystemReset();
      Serial.println("Reboot");
    }
  }
}

If I use the Serial Monitor in the IDE the OPTA works as the UNO.

But as soon that I want to use a different serial program, the program freezes.

1
(It connects)
2
(But I don't receive anything and, if I try to send data to the OPTA, the program freezes)

I'm worried because I have ordered 7 OPTAs and now it seems that they are not suitable for my project.

Is there anything that I can do to get the data via serial port via usb-c?

Greets from Barcelona

1 Like

Use a different terminal program.

Hi. Thanks for your answer.

I've finally found out that the problem was the flow control DTR/DSR configuration of the serial port.

Now it works like I need.

Greets from Barcelona

Greetings,
I have the same problem.
Could you tell me the serial port flow control DTR/DSR configuration parameters you set?

Thanks in advance.

Friendliness

@ardmicese

Si prega di utilizzare la lingua inglese nelle sezioni inglesi del forum.

Ciao ardmicese.

Scusa, non ho pensato di mettere i valori.

Nel mio caso per far funzionare tutto ho usato questi valori:
Bit di dati=8
Parità=none
Stop=2
Flow=0
RTS=0
DTR=0

Spero che vi siano utili.

Saluti da Barcellona!

Hi ardmicese.

Sorry, I didn't think to put the values.

In my case to make everything work I used these values:
Databits=8
Parity=none
Stop=2
Flow=0
RTS=0
DTR=0

I hope they help you.

Greetings from Barcelona!

2 Likes

Thanks in advance Adolfito121 for your prompt replay. I will try to change the parameters and I will let you know.