Millis() and Micros() Based Functions "Bricking" Serial communication program?

Hello!

I am trying to create a sketch that will be unloaded onto an arduino uno that will allow it to communicate with a python GUI (via pyserial).

The basis of the code is that it will receive a sting from the GUI and based on substrings in that received string, it will call certain functions. I am working on a function that will write a series of pulses based on a binary string contained in the received data. The function that parses through the string seems to work. My issue is that based on whether the current character is a 1 or a 0 it will pulse the output for shorter or longer, respectively.

To do this I have a series of if statements that check the char and put a "delayMicroseconds(x)" in-between the PORTD ("faster digital write" - port manipulation) statement.

The problem I am having is that when I use that "delayMicroseconds ()" function the sketch no longer seems to work. I have even tried making my own microsecond based delay function and it still doesnt work. I have Serial.println function calls throughout the sketch for debugging purposes, when I comment out all time based lines (millis() and micros()) it works like it "should" - aside from the fact that I need the delay.

I will post the code below, any suggestions?

Thanks!

// Strings
String serialData = "";
String command = "";
String data1 = "";
String data2 = "";


//
bool gData = 0;   // Get Data
bool rData = 0;   // Read Data
char c = 0;
int v[2];
int data[128];
int readData[128];
int numBits;

unsigned long currentMillis;
unsigned long startMillis;



void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);

  command.reserve(6);
  data1.reserve(2);
  data2.reserve(128);
  serialData.reserve(139);

  DDRD = B01000000;
/*
  pinMode(13, INPUT);
  pinMode(12, OUTPUT);
  pinMode(11, INPUT);
  pinMode(10, INPUT);
  pinMode(9, INPUT);
  pinMode(8, INPUT);
  */
}



void loop() {
  // put your main code here, to run repeatedly:
  //digitalWrite(6, LOW);
  PORTD = PORTD | B01000000;
  if (Serial.available()){
    
    gData = 1;
    serialData = "";
    
  }

  while (gData){

    if( Serial.available()){
      
      c=Serial.read();

        // check for "*"
        if(c == '*'){ 
        
        gData = 0; 
          
        // serialData = serialData += c; 
         
        }
        
      serialData=serialData += c; 
      
      }
  }
  

    v[0] = serialData.indexOf(',');
    command = serialData.substring(0, v[0]);
  
    v[1] = serialData.indexOf(',', v[0]+1);
    data1 = serialData.substring(v[0]+1, v[1]);
  
    v[2] = serialData.indexOf('*', v[1]+1);
    data2 = serialData.substring(v[1]+1,v[2]);
  
  if (Serial.available()){
    Serial.println(serialData);
    Serial.println("Command: " + command);
    Serial.println("Data1: " + data1);
    Serial.println("data2: " + data2);
  }

  if (command == "TMODE"){
    enterTestMode(data1, data2);
  }

  if (command == "WRITE"){
    Write(data2);
  }


}

void enterTestMode(String d1, String d2){
  Serial.println("ENTERED TEST MODE FUNCTION");
}


void Write(String data){
    // data is the data as a binary string

    /*
        set D6 to High

        loop through data using for loop, when data[i] is a "1"
        call "pmPulse" to pulse LOW with a duration of 0. When
        data[i] is a "0" call "pmPulse" to pulse LOW with a 
        duration > 15.
    */
   pinMode(6, OUTPUT);   
   //PORTB = PORTB | B01000000;
   //digitalWrite(12, LOW);
   Serial.println("ENTERED WRITE FUNCTION");

   for(int i = 0; i < data.length(); i++){
       if (data[i] == '0'){
           pmPulse(false, 20);
       }
       else if (data[i] == '1'){
           pmPulse(false, 0);
       }
   }
   return;
}

// Assumes if pulsing down, the pin is already high, vise versa!
void pmPulse(bool highLow, int duration){
    // "highLow" specifies whether to pulse high (1) or low (0)
    // duration specifies how long to pulse pin (DOWN OR UP) for

    if (highLow){   // pulse pin high
        if (duration != 0){
            //Serial.println("Wrote a HIGH 'Zero' pulse");
            PORTD = PORTD | B01000000;  // Sets Digital Pin 6 to high, keeps rest the same
            delayMicroseconds(duration);// Waits for specified duration in microseconds
            PORTD = PORTD & B10111111;  // Sets 6 to low, keeps rest the same
            return;
        }
        else{
            //Serial.println("Wrote a HIGH 'One' pulse");
            PORTD = PORTD | B01000000;  // Sets Digital Pin 6 to high, keeps rest the same
            PORTD = PORTD & B10111111;  // // Sets D6 to low, keeps rest the same
            return;
        }
    } 
    else{
        if (duration != 0){
            //Serial.println("Wrote a LOW 'Zero' pulse");
            PORTD = PORTD & B10111111;  // Sets Digital Pin 6 to LOW, keeps rest the same
            delayMicroseconds(duration);// Waits for specified duration in microseconds
            PORTD = PORTD | B01000000;  // Sets D6 to HIGH, keeps rest the same
            return;
        }
        else{
            //Serial.println("Wrote a LOW 'One' pulse");
            PORTD = PORTD & B10111111;  // Sets Digital Pin 6 to LOW, keeps rest the same
            PORTD = PORTD | B01000000;  // // Sets D6 to HIGH, keeps rest the same
            return;
        }
    }
}

Why do you bother using port registers when you communicate at 9600 bauds…?

The V array has room for only 2 elements and you try to write element #3 (Index 2) in there… overflowing will cause bad things to your code…

Enable all warnings for compilation, you might also get useful ones

I would suggest to study Serial Input Basics to handle this

1 Like

This line makes little sense. It is a shortcut for:
serialData = serialData = serialData + c;
You should shorten it to:
serialData += c;
or:
serialData = serialData + c;

It's not clear what and how you intended to do anything with a 'zero duration' output pulse.

I simplified the code and it seems to be performing OK. Maybe this will do what you intended and maybe not.

// Strings
String serialData = "";
String command = "";
String data1 = "";
String data2 = "";

void setup()
{
  // put your setup code here, to run once:
  Serial.begin(115200);

  pinMode(6, OUTPUT);
}



void loop()
{
  digitalWrite(6, HIGH);

  if (Serial.available())
  {
    char c = Serial.read();
    serialData += c;
    if (c == '*')
    {
      parseInput();
      serialData = "";
      while (Serial.available())
        Serial.read(); // Clear out the input buffer
    }
  }
}

void parseInput()
{
  int v[3];

  v[0] = serialData.indexOf(',');
  command = serialData.substring(0, v[0]);

  v[1] = serialData.indexOf(',', v[0] + 1);
  data1 = serialData.substring(v[0] + 1, v[1]);

  v[2] = serialData.indexOf('*', v[1] + 1);
  data2 = serialData.substring(v[1] + 1, v[2]);

  Serial.println(serialData);
  Serial.println("Command: " + command);
  Serial.println("Data1: " + data1);
  Serial.println("data2: " + data2);

  if (command == "TMODE")
  {
    enterTestMode(data1, data2);
  }

  if (command == "WRITE")
  {
    Write(data2);
  }
}

void enterTestMode(String d1, String d2)
{
  Serial.println("ENTERED TEST MODE FUNCTION");
}


void Write(String data)
{
  // data is the data as a binary string

  Serial.println("ENTERED WRITE FUNCTION");

  for (unsigned i = 0; i < data.length(); i++)
  {
    if (data[i] == '0')
    {
      pmPulse(20);
    }
    else if (data[i] == '1')
    {
      pmPulse(0);
    }
  }
  return;
}

// Assumes if pulsing down, the pin is already high, vise versa!
void pmPulse(int duration)
{
  digitalWrite(6, LOW);
  if (duration != 0)
    delayMicroseconds(duration); // Waits for specified duration in microseconds
  digitalWrite(6, HIGH);
}
1 Like

I am using port registers because I need the pulses to be fast. The speed of communication doesnt matter since it will receive the string of 1s and 0s to write, and then write them after it gets them.

Wow I didnt realize how I only gave it space for 2, thank you!

Thanks for recommending an article and thanks for bringing up all warning, I wasnt aware of that!

I am using a pulse duration of 0 to basically signify that I am writing a fast pulse. I cant use digital write because it is too slow.

Thank you for your input, I will try to modify this to do exactly what I need it to do!

Yes! Thanks for bringing that up, Not sure how I managed to do that...

If you want very short pulses, use a timer output. You should be able to get down to 1/16th microsecond.