Best serial practice

Status
Not open for further replies.

Manu

Well-known member
Hello,
In many projects, I often need to get some dialogue between computer and teensy and I have never find the better code to achieve this task. There are many ways to do this and on PJRC website Paul explain that too many (Serial.available()) can lead in overrun situations.
So I'd like to have some advices about some optimized ways to handle serial commands without taking too much resources from the main loop. For example, I currently have some code that act like this :

Code:
void setup() {
  Serial.begin (115200);
  ...
}

void loop() {
  
  if (Serial.available() || Mode_Conf == true) // Configuration Mode
  {
    ModeConfiguration();  // Go in a function that threat serial
  }
  else {                  // Normal Mode
    // Do the work....
    }
}

Is this the right thing to do ?

Thank,
Manu
 
Code:
void ModeConfiguration() {
  while (Serial.available() > 0) {
    char c = tolower(Serial.read());
    if (!strchr("abcdefghijklmnopq", c)) {
      Serial.println("N"); // Commande Invalide
      return;
    }
    Mode_Conf = true;
    switch (c) {
      case 'a':
        setEEPROM_IDTrames(0);
        break;
      case 'b':
        setEEPROM_IDTrames(1);
        break;
      case 'c':
        setEEPROM_IDTrames(2);
        break;
      case 'd':
        setEEPROM_IDTrames(3);
        break;
      case 'e':
        setEEPROM_IDTrames(4);
        break;
      case 'f':
        setEEPROM_TramesActives(0);
        break;
      case 'g':
        setEEPROM_TramesActives(1);
        break;
      case 'h':
        setEEPROM_TramesActives(2);
        break;
      case 'i':
        setEEPROM_TramesActives(3);
        break;
      case 'j':
        setEEPROM_TramesActives(4);
        break;
      case 'k':
        setEEPROM_ZTState();
        break;
      case 'l':
        setEEPROM_VitesseCAN();
        break;
      case 'm':
        setEEPROM_Units();
        break;
      case 'n':
        setEEPROM_PeriodeTrames();
        break;
      case 'o':
        sendConfToComputer();
        break;
      case 'p':
        setEEPROM_BaseAddress();
        break;
      case 'q':
        delay (DelaiReset);
        resetCPU();
        break;
      default:
        Serial.println("N"); // Invalid Command
        break;
    }
  }
}
 
Note - you'll usually find a newline character pushing after the sent text - at least from SerMon entry, so accept and ignore that.

Not noted what Teensy is in use? But the second note on that page generally applies to Teensy USB handling:
On a Teensy, the entire packet, up to 64 bytes, becomes available all at once. Sketches that do other work while receiving data might depend on slow reception behavior, where successive calls to Serial.available() are very unlikely to return true. On a Teensy receiving large amounts of data, it may be necessary to add a variable to count the number of bytes processed and limit the delay before other important work must be done.

There was a forum post recently from Paul noting that if data coming in on USB is in multiple packets - won't apply to single character/packet transfer - data in the following packets won't be known until the first packet is exhausted. So as that page notes: "Usually the return value from Serial.available() should be tested as a boolean,"

So the overhead of going to Mode_Conf might not be helpful. Only a code SNIPPET was included showing Mode_Conf being set, but not being cleared which suggests a problem.
 
Note - you'll usually find a newline character pushing after the sent text - at least from SerMon entry, so accept and ignore that.
No always, but often. In my case I can send multiples commands in a single shot (i.e : L1A500IQ)

Not noted what Teensy is in use? But the second note on that page generally applies to Teensy USB handling:

There was a forum post recently from Paul noting that if data coming in on USB is in multiple packets - won't apply to single character/packet transfer - data in the following packets won't be known until the first packet is exhausted. So as that page notes: "Usually the return value from Serial.available() should be tested as a boolean,"
Teensy 3.2 here. The reference you post is the one that make me think about the better way to handle serial com :D

So the overhead of going to Mode_Conf might not be helpful. Only a code SNIPPET was included showing Mode_Conf being set, but not being cleared which suggests a problem.
In this case, going in Mode_Conf stop any activity over the SPI and CAN devices as we want to set them. Some commands in Mode_Conf need some arguments to execute. For exampme there are several possible choices for setEEPROM_VitesseCAN() :
Code:
void setEEPROM_VitesseCAN() {
  while (Serial.available() == 0) {}
  int d = Serial.parseInt();
  byte v = EEPROM.read (0);
  switch (d) {
    case 1: //250kbps
      v &= ~(1UL << 7);
      v &= ~(1UL << 6);
      EEPROM.write(0, v);
      break;
    case 2: // 500kbps
      v &= ~(1UL << 7);
      v |= 1UL << 6;
      EEPROM.write(0, v);
      break;
    case 3:  //1Mbps
      v |= 1UL << 7;
      v |= 1UL << 6;
      EEPROM.write(0, v);
      break;
    default:  // 500kbps
      v &= ~(1UL << 7);
      v |= 1UL << 6;
      EEPROM.write(0, v);
      break;
  }
}

And yes the boolean 'Mode_Conf' is never cleared because, unless the conf is fully set, the device need to NOT operate. So the only way to go again in Normal_Mode after entering the Mode_Conf is to reset the teensy 3.2 using the 'q' command, or do a power cycle.

Anyway, many thanks for your interest in this debate :D
Manu
 
Status
Not open for further replies.
Back
Top