Arduino Uno: Problems with Serial.print()

Hi guys,

I'm working on a program to test turnout motors for model railroads. The Arduino controls these motors via relays and receives feedback via photocouplers.

I use Serial.print() to keep track of the number of succesful operations. However, This connection is often interrupted and won't start again. Please tell me, if you find any flaws in my code that might cause this problem.

// ports:
#define COIL_A  12 // relays for turnout motors
#define COIL_B  10 
#define COIL_C   8
#define COIL_D   6
#define OPTOS    4 // activates input of photocouplers using a relay
#define RM_A     9  // outputs of photocouplers
#define RM_B    11  
#define RM_C     5  
#define RM_D     7

// durations:
#define T_ON   250  // turn on motors
#define T_REC  250  // recharge capacitors
#define T_DISC 400 // downtime
#define T_OPTO 100  // activate photocouplers

// other:
#define IS    1     // frequency of messages
#define IMAX  100   // number of cycles
int i = 0;  
int j = 0; 

void setup(){
  pinMode(COIL_A, OUTPUT);
  pinMode(COIL_B, OUTPUT);
  pinMode(COIL_C, OUTPUT);
  pinMode(COIL_D, OUTPUT);
  pinMode(OPTOS, OUTPUT);
  pinMode(RM_A, INPUT_PULLUP);
  pinMode(RM_B, INPUT_PULLUP);
  pinMode(RM_C, INPUT_PULLUP);
  pinMode(RM_D, INPUT_PULLUP);
     
  Serial.begin(9600);
  Serial.println("Betriebsbereit."); // This means "ready".
}

void loop(){
  // Activate A and C  
  delay(400);
  digitalWrite(COIL_A, HIGH);
  delay(T_ON);
  digitalWrite(COIL_A, LOW);
  delay(T_REC);
  digitalWrite(COIL_C, HIGH);
  delay(T_ON);
  digitalWrite(COIL_C, LOW);
  
  // Read results for A and C
  delay(T_REC);
  digitalWrite(OPTOS, HIGH);
  delay(T_OPTO);
  if(HIGH == digitalRead(RM_A)){
    error('A');
  }else if(HIGH == digitalRead(RM_C)){
    error('C');
  }    
  digitalWrite(OPTOS, LOW);
  
  
    // Activate B and D  
  delay(400);
  digitalWrite(COIL_B, HIGH);
  delay(T_ON);
    digitalWrite(COIL_B, LOW);
  delay(T_REC);
  digitalWrite(COIL_D, HIGH);
  delay(T_ON);
  digitalWrite(COIL_D, LOW);
  
  // Read results for B and D
  delay(T_REC);
  digitalWrite(OPTOS, HIGH);
  delay(T_OPTO);
  if(HIGH == digitalRead(RM_B)){
    error('B');
  }else if(HIGH == digitalRead(RM_D)){
    error('D');
  }    
  digitalWrite(OPTOS, LOW);

  // keeping track of the number of cycles
  i++;
  j++;

  if (IS == j){   
    Serial.print("i = ");
    Serial.println(i);
    j = 0;
  }
 
  if (i >= IMAX){ 
   // Message to show up when a series is completed
    Serial.println("Versuch abgeschlossen.");
    Serial.print("Erfolgreiche Schaltvorgaenge: ");
    Serial.println(i);
    Serial.end();
    while(true){
      // do nothing
    }
  }
  
}

void error(char k){
  // Messages to show up as soon as a motor fails
  Serial.print("Endschalter leitet nicht:");
  Serial.println(k);
  Serial.println("Versuch angehalten.");
  Serial.print("Erfolgreiche Schaltvorgänge: ");
  Serial.println(i);
  Serial.end();
  while(true){
    // do nothing
  }
}

When I start the program, the Serial Monitor looks like this:

Betriebsbereit.
i = 1
i = 2
i = 3

However, after some time has passed, no new text will show up on the Serial Monitor. Sometimes it goes as far as i = 60, sometimes it stops just after "Betriebsbereit.". But whatever happens, the Arduino continues its program and keeps toggling the relays. But I do not receive any feedback. So if a motor breaks, I do not know how long it worked before. Any help appreciated. Thanks.

However, after some time has passed, no new text will show up on the Serial Monitor.

"Some time"?

Sometimes it goes as far as i = 60, sometimes it stops just after Sometimes it goes as far as i = 60, sometimes it stops just after "Betriebsbereit."..

From when you first open Serial Monitor, the only thing displayed is "Betriebsbereit."? Just a single line of text?

Board?

I doubt it is causing the problem but you really should be using the F-macro...

  Serial.println( F( "Betriebsbereit." ) ); // This means "ready".

Yes, sometimes the text would only read "Betriebsbereit", sometimes it would go as far as "i = 60".

A few minutes ago, I set the baud rate to 115200 and removed most of the strings. It worked. The text went as far as

99
100
Versuch abgeschlossen.
Erfolgreiche Schaltvorgaenge: 100"

So it seems, that the length of the "i = " string was the problem.

Thank you for your help. I will now try using the F-macro.

A few hours ago, I set the baud rate at 115200 and reintroduced the strings in this form:

...
Serial.println(F("Betriebsbereit."));
...
Serial.print(F("i = "));
Serial.println(i);
...

I also increased the number of cycles to 1000. The problem occured again. The Serial Monitor did not display anything past i = 600, yet the Arduino continued to toggle the relays. Any ideas?

Btw, the board is an Arduino Uno, as written in the title of this thread.

Try this - with the serial monitor open press the reset button on your uno. Do you get "Betriebsbereit.".

My uno's packed away for a house move, and I can't remember if the serial monitor still works after a reset.

How are you powering the relays if its from the Uno then you are (most likely) causeing it to reset.

Mark

I use npn transistors to power the relays. The base of each transistor is connected to its port via a 4k7 resistor. There is a flyback diode on each relay. Also, I placed a 100µF capacitor on the circuit board to decrease ripple. Each relay draws a current of 40mA.

I will try resetting the Arduino as soon as the problem occurs again. Also, I'll try adding a second capacitor. Thank you for your suggestion.

What is that Serial.end() supposed to be doing ? I never noticed anyone else using that before, and I doubt that you need to.

I will try resetting the Arduino as soon as the problem occurs again.

No I mean that you should try it and tell is what you get.

Where is you power coming from? You are not powering the relays from the transistors you are controlling the power to the relays with the transistors.

Mark

The power comes from my computer via USB. Do you think, this could be a problem? The voltage between the 5V pin and GND is 4.9V. Ripple is at approx. 50mV RMS. Do you think, an additional AC power supply would help?

The power comes from my computer via USB.

Yes you (at best) 500mA for every thing (Uno included). Try disconnecting the transistors from the uno and then run the code.

Mark

I wouldn't be surprised if you've found a problem with the serial monitor, rather than a problem with the arduino.
Can you try a different serial program? (putty is popular...)

@westfw:
I am not familiar with Putty. How would this help me?

@holmes4:
I am now using an external power supply. Also, I fitted additional capacitors. Ripple is down, voltage is at 4.99V. I'm currently running the program with IMAX set to 3000. The output stopped at i = 151.

When I push the reset button or when I open the Serial Monitor, the program restarts. The output reads "Betriebsbereit" again, unless the output was interrupted. In that case, the program does not restart and I cannot open Serial Monitor again. If I try, I receive this error message (translated from German): "The serial port 'COM4' is already in use. Try shutting down other applications that might be using it." What could be the reason for that?

This is the whole text of the error message:

processing.app.SerialException: Der serielle Port 'COM4' wird bereits verwendet. Probieren Sie, andere Programme zu beenden, die ihn benutzen könnten.
at processing.app.Serial.(Serial.java:171)
at processing.app.Serial.(Serial.java:92)
at processing.app.SerialMonitor.openSerialPort(SerialMonitor.java:207)
at processing.app.Editor.handleSerial(Editor.java:2481)
at processing.app.Editor$17.actionPerformed(Editor.java:665)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
at javax.swing.AbstractButton.doClick(AbstractButton.java:357)
at javax.swing.AbstractButton.doClick(AbstractButton.java:337)
at javax.swing.plaf.basic.BasicMenuItemUI$Actions.actionPerformed(BasicMenuItemUI.java:1194)
at javax.swing.SwingUtilities.notifyAction(SwingUtilities.java:1636)
at javax.swing.JComponent.processKeyBinding(JComponent.java:2851)
at javax.swing.JMenuBar.processBindingForKeyStrokeRecursive(JMenuBar.java:670)
at javax.swing.JMenuBar.processBindingForKeyStrokeRecursive(JMenuBar.java:678)
at javax.swing.JMenuBar.processBindingForKeyStrokeRecursive(JMenuBar.java:678)
at javax.swing.JMenuBar.processKeyBinding(JMenuBar.java:649)
at javax.swing.KeyboardManager.fireBinding(KeyboardManager.java:267)
at javax.swing.KeyboardManager.fireKeyboardAction(KeyboardManager.java:254)
at javax.swing.JComponent.processKeyBindingsForAllComponents(JComponent.java:2928)
at javax.swing.JComponent.processKeyBindings(JComponent.java:2920)
at javax.swing.JComponent.processKeyEvent(JComponent.java:2814)
at processing.app.syntax.JEditTextArea.processKeyEvent(JEditTextArea.java:1726)
at java.awt.Component.processEvent(Component.java:6040)
at java.awt.Container.processEvent(Container.java:2041)
at java.awt.Component.dispatchEventImpl(Component.java:4630)
at java.awt.Container.dispatchEventImpl(Container.java:2099)
at java.awt.Component.dispatchEvent(Component.java:4460)
at java.awt.KeyboardFocusManager.redispatchEvent(KeyboardFocusManager.java:1848)
at java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(DefaultKeyboardFocusManager.java:704)
at java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(DefaultKeyboardFocusManager.java:969)
at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(DefaultKeyboardFocusManager.java:841)
at java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:668)
at java.awt.Component.dispatchEventImpl(Component.java:4502)
at java.awt.Container.dispatchEventImpl(Container.java:2099)
at java.awt.Window.dispatchEventImpl(Window.java:2475)
at java.awt.Component.dispatchEvent(Component.java:4460)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)