Having serial monitor open keeps python from freezing

I've built a program that basically functions as an oscilloscope and a function generator. It receives a waveform (string of 256 values between 0 and 255, delimited by commas) from python over Serial, which it then outputs over D0 to D7. The user can send a new waveform by clicking a button on the python end. At the same time, it reads voltage values at A0, stores them into a buffer, then once per second transmits these values to python over the Serial connection.

Everything works well when the program starts, but after sending a few new waveforms from python, it gets stuck on the readFromSerial() function. However, if I open the Serial monitor, it clears up and goes back to working normally. With the monitor open, the user can send as many new waveforms as they like without problem.

When the sendStuff() function is removed, it also works without problems, so I assume there's some conflict between the sending and receiving of data over Serial.

Can anyone explain to me why this could be and how to fix it?

static byte table[256]; //this will hold the values transmitted from python

int i;
byte value;
float N = 256;
float f_clk = 54000;


static float freq;
int amp;
double place;
double M;

int datalen;
char startword;

char bufflen[4]; //stores the datalen information
char buff[1000]; //larger than we need but we can null term to end it
char buff2[10]; //intermediate buffer

const unsigned int numValues = 200;
byte readValues[numValues];
int counter;
int sendflag;


void setup() {
  Serial.begin(115200);

  for(i=0;i<9;i++){
    pinMode(i, OUTPUT);
  }
  pinMode(13, OUTPUT);

  place = 0;
  
  freq = 100; //default values
 
  amp=2.0;
  M = (freq*N)/f_clk;
  datalen = 767; //default; length of square wave set
  
  counter = 0;
  sendflag = 0; 
}


void readFromSerial() { //reads the identifier at the start of the incoming data and directs us to the right function

    startword = Serial.read();
   // Serial.print("startword: "); //for testing purposes
   // Serial.println(startword);
    
    if(startword == 'T') {
      getTable();
    }
   else {
    while(Serial.available()) { //use up the incoming string so we can try again next time
      char t = Serial.read();
    }
   }   
  }

void getTable() { //parses the incoming dataset
  for(int i=0;i<256;i++) {
    table[i] = 0; //clear the table to make room for new values
  }
  Serial.println("Getting Table!");  

  char bufflen[4];
  Serial.readBytes(bufflen, 3); //first, find length of incoming data
  bufflen[3] = '\0'; //null terminate
  datalen = atoi(bufflen);
  Serial.readBytes(buff, datalen); //read the right number of bytes
  buff[datalen] = '\0'; //null terminate
  int k = 0;
  int i=0;
  while(i<datalen){
    int j = 0;
    while(buff[i]!=44 && buff[i] != '\0') { //while we're on numbers (incoming format is 1,99,100,101,102, etc)
      buff2[j]=buff[i];
      i++;
      j++;
    } //now we're at a comma, which we want to ignore
    buff2[j] = '\0'; //null term the intermediate buff
    table[k] = atoi(buff2); //copy intermediate buff to the table
    k++;
    i++;
  }
} 


void makeWaveByPlace() { //output one value from the table, advance the placeholder, then return
  i = (int)place;
  PORTD = table[i];
  place = place + M;
  if(place > 255) {
    place = place - 255;
  }
}


void oscByParts() { //this collects values that we'll be sending to python later
  readValues[counter] = analogRead(A0)/4; //get a value
  counter++;
  if(counter>=numValues) {
    sendflag = 1; //stop collecting data
    counter = 0; //reset the counter
  }
 
}

void sendStuff() { //this sends the values over serial to python
  PORTD = 0; //silence the fungen while sending
  for(int i=0;i<numValues;i++) {
    Serial.println(readValues[i]);
  }
  Serial.println("..");
  Serial.flush();
  //sendflag = 0;
}


void loop() {
  long starttime = millis();
  while((millis()-starttime)<1000) { //do this for a second
    if(Serial.available()) { //if we're getting new data in
      readFromSerial(); 
    }
 
    makeWaveByPlace();
 
    if(sendflag == 0) {
      oscByParts(); //gathering data to be sent
    }
  }
  if(Serial.available()<=0) { //trying (unsuccessfully) to force it to not interfere with the incoming data
    
    sendStuff(); //send the data we gathered back to python, once every second
  }   
}
Serial.begin(115200);

  for(i=0;i<9;i++){
    pinMode(i, OUTPUT);
  }

Can you see a problem here?

That D0 and D1 are the TX/RX pins? Actually, I did expect that to cause a problem, but (perhaps surprisingly?) I can receive data from over the USB from python no problem even while outputting values there. It's only when I try to send data back from the arduino that it starts to fail.

The Arduino Uno, Nano and Mega use pins 0 and 1 for serial communication with the PC. Don't use them for other purposes.

The reason that the Serial Monitor appears to solve the problem is because it probably causes the Arduino to reset. You can probably get the same effect within a Python program by closing and opening the serial port. However if the code is properly written neither should be necessary.

...R
Python - Arduino demo

Yeah that makes sense. Okay! Thanks guys :slight_smile:

It looks to me like your function "getTable" is in need of some bounds-checking