1

I'm running into a problem with a GikFun Arduino Nano. The symptom appears when I'm reading the receive buffer to clear it after an operation completes. The unit just appears to stop somewhere in the loop function and never continues.

I know that this unit has a CH340 UART on it which seems to have issues.

Any suggestions on what I can do?

OP Edits

This code is more or less based on the code from this Make: article. I originally had this assembled through an Arduino Uno R3 with an HC-06 (Kootek BT2S) module. Everything connected via solderless bread-board.

This entire circuit works properly with the UNO, which I had it running on SoftwareSerial using pins 2, 3. After putting this on a perf-board in a project box using the GikFun Nano, it was not behaving. I had a number of wiring issues, which I resolved, but still had issues communicating on the HC-06/SoftwareSerial. I re-did the wiring using pins 0, 1 for the Serial and removed the SoftwareSerial references. The circuit worked as I expected with the HC-06 working as it had before. But if I issued more than 1-2 commands via Bluetooth the unit would just get stuck. I also tried this without the HC-06 connected and just used the Serial Monitor through the IDE same behavior. It would randomly lock up after clearing the receive buffer.

Code - as requested:

const int statusLED = 13; //the pin you connect your status LED to
const int desiredBaud = 4;//index of your desired baud rate 4 is 9600
char* myPin = "1234";//change to the pin of your choice

const int memRed=0;
const int memGreen=1;
const int memBlue=2;

const int redPin= 9;
const int greenPin= 10;
const int bluePin= 11;
const int cmdLed= 12;

// Max Red - 255
const int max_red = 255;
// Max Green - 90
const int max_green = 255;
// Max Green - 100
const int max_blue = 255;

int red= 255;
int green= 255;
int blue= 255;

unsigned int baudLookup[] = 
{
  1200,  //code 1
  2400,  //code 2
  4800,  //code 3
  9600,  //code 4
  19200, //code 5
  38400, //code 6
  57600  //code 7
}; 

void setup()
{
  Serial.begin(9600);
  pinMode(redPin, OUTPUT);  
  pinMode(greenPin, OUTPUT);  
  pinMode(bluePin, OUTPUT);  
  pinMode(cmdLed, OUTPUT);
  pinMode(statusLED, OUTPUT);
  digitalWrite(statusLED, HIGH);

  Serial.begin(9600);
  delay(1500);//wait for reset to complete

  Serial.print("AT");
  delay(1500);//wait for reset to complete
  while(Serial.available()) {
    Serial.read();
  }
  delay(1500);//wait for reset to complete

  digitalWrite(statusLED, HIGH); //SUCCESS!

  digitalWrite(redPin, map( red, 0, 255, 0, max_red) );
  digitalWrite(greenPin, map( green, 0, 255, 0, max_green) );
  digitalWrite(bluePin, map( blue, 0, 255, 0, max_blue) );
}

void loop()
{
  digitalWrite(statusLED, LOW); //fast blink means success
  delay(200);
  digitalWrite(statusLED, HIGH);
  delay(200);

  String stat;
  char buffer[13];
  buffer[12]= 0;
  if( Serial.available() >= 3 ) {
    String stat = String("OK");

    Serial.readBytes(buffer, 3);
    buffer[3]= 0;
    String command= String(buffer);

    Serial.println(command);
    if( command == "GET" ) {
      char outBuffer[7];
      sprintf(outBuffer, " %02x%02x%02x", red, green, blue);
      stat += outBuffer;
    }
    else if( command == "SET" ) {
      if( Serial.available() >= 6 ) {
        Serial.readBytes(buffer, 6);

        int redVal= (getVal(buffer[0])<<4) | (getVal(buffer[1]));
        int greenVal= (getVal(buffer[2])<<4) | (getVal(buffer[3]));
        int blueVal= (getVal(buffer[4])<<4) | (getVal(buffer[5]));

        digitalWrite(redPin, map( redVal, 0, 255, 0, max_red) );
        digitalWrite(greenPin, map( greenVal, 0, 255, 0, max_green) );
        digitalWrite(bluePin, map( blueVal, 0, 255, 0, max_blue) );

        red= redVal;
        green= greenVal;
        blue= blueVal;

        char outBuffer[7];
        sprintf(outBuffer, " %02x%02x%02x", redVal, greenVal, blueVal);
        stat += outBuffer;
      } else {
        stat = "ERR";
      }
    }
    else {
      Serial.println("No Command");
    }
    Serial.println(stat);
    Serial.println("Clearing receive buffer");
    delay(1500);
    while(Serial.available()) {
      Serial.read();
      delay(100);
    }
    delay(1500);
  }
}

byte getVal(char c)
{
  if(c >= '0' && c <= '9') {
    return (byte)(c - '0');
  } else {
    return (byte)(c-'A'+10);
  }
}
  • 1
    You need to show code which experiences the problem. Even it not happening to a board with a different USB-serial implementation would not be proof against invalid assumptions in the serial code broken by permissible behavior of the converter or its driver. Of course, a hardware or driver issue is a possibility too, but don't jump straight to assuming that. – Chris Stratton May 31 '16 at 22:13
  • I'll post code shortly – Dave G May 31 '16 at 22:37
  • This mix of delays and buffer flushing is exactly the kind of invalid assumption I was talking about... it is just asking for unreliability, and your while loop that reads with delays could easily never terminate. Instead you should end your commands with something distinct, like a newline, and read until that. Generally you want to avoid flushing - or at least, only flush until a defined endpoint. Also, your description of what you were ultimate doing sounds like trying to use the hardware serial pins for both the USB-serial and the bluetooth, which isn't really workable. – Chris Stratton May 31 '16 at 22:59
  • @Chris I appreciate your feed back on this and yes assumptions are a total foul up on my part. As for the serial, I disconnected the HC-06 when using the monitor – Dave G May 31 '16 at 23:01
  • @Chris ... looking back over this you are 100% spot on with the possible infinite. I'm going to try and gut out some of the stupidity I introduced on this and give it another go. Would you please post an answer so I can at least give you credit for your feedback? – Dave G Jun 1 '16 at 0:27
0

The mix of delays and flushing in your code has a high chance of leading to unreliable operation. Consider for example:

Serial.println("Clearing receive buffer");
delay(1500);
while(Serial.available()) {
  Serial.read();
  delay(100);
}
delay(1500);

As the loop there can only consume about 10 characters per second, it would be quite easy for something on the far end to produce inputs faster than they are consumed, essentially making the loop infinite.

Time-based delineation of serial messages tends to be quite risky; better reliability is usually had by using a defined delimiting condition - for example, ending each message with a newline character and reading until that is seen.

USB-serial conversion also introduces added challenges for time-based schemes, as it introduces a sense of grouping into packets into a stream which in its native form does not have any.

  • Chris - again thank you for your help on this - I redid the logic gutting out all of the stupidity and got the program stable. This also included adding a serialEvent() implementation and remembering how to properly use the stdc library. Everything was going swimmingly until I think I accidentally shorted out my HC-06 and fried it. It was working fine before that happened and I've got a replacement on the way. – Dave G Jun 2 '16 at 19:45
  • Glad you made progress and sorry to hear about the accidental toasting. Just as a last caution, keep in mind that serialEvent() is not an interrupt or thread of its own - it runs only between calls to loop() so doesn't differ much other than visually from checking availability at some point within your loop. – Chris Stratton Jun 2 '16 at 20:26
  • Thanks for the heads up. I took the code that is detailed in the serial event documentation and it was behaving. – Dave G Jun 2 '16 at 20:30
  • The issue would be with whatever you did in your loop() - serialEvent() can only run when that is done taking up time, and so it can only make data available for the next iteration of loop(). – Chris Stratton Jun 2 '16 at 20:45
  • And that is exactly what I want – Dave G Jun 2 '16 at 20:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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