0

I used this simple code to understand the basics of serial communication. This achieves simple communication between the computer and arduino:

String receive_buffer;
void setup() {
  Serial.begin(9600);
}

void loop() {
  if(Serial.available()>0)  //check for any data received
  {   
      receive_buffer = Serial.readString();  //read received data      
      Serial.print("received data is: ");
      Serial.println(receive_buffer);        //display received data
  }

}

This works. Now, my next idea was to try communicating between two arduinos. I used this code for the reciever arduino.

The sender arduino contains a motor fitted with an encoder, and using the ppr value I calculate the rpm of the motor. The code for rpm works perfectly. I now want to communicate this data to the receiver.

Wiring: (RX,TX) of sender connected to (TX,RX) of receiver, and GND is made common.

Now, on arduino.cc, it says that Serial.write() can have String as an input. So, I tried typecasting the rpm value (which was int), into a String, and then send that string to the receiver through Serial.write().

float ppr=512.0;
int encpin=3;
volatile long pulsecount=0;
float revs;
float rps;
int rpm;


extern volatile unsigned long timer0_millis;


void setup()
{
  pinMode(encpin,INPUT_PULLUP);
  Serial.begin(9600);
  attachInterrupt(digitalPinToInterrupt(encpin),function,RISING);
                                        //when pulse is detected
                                           //interrupt triggered,
                                           //function callled  
}
//increments pulse by one
void function(){
  pulsecount+=1;
}


void loop()
{
 revs= pulsecount/ppr ;
 if(millis()>=1000)
  {
    rps= revs;
    rpm=rps*60;
    pulsecount=0; //resets pulsecount
    
    String strrpm= (String)rpm;
   
   
    //Serial.println(rpm);
    Serial.write(strrpm);
   
  
   // Serial.println("string rpm");
    //Serial.println(strrpm);
   
    noInterrupts ();  //resests millis() to 0
    timer0_millis = 0;
    interrupts ();
  }
}

However, I get an error:

43:24: error: no matching function for call to 'HardwareSerial::write(String&)'

The issue is not with typecasting. I tried to simply print strrpm and it worked fine. When tried Serial.write() with a different and simple string, i.e Serial.write("abcdef"); , it still gave the same error.

How then should I should I send my strrpm (string rpm) value to the receiver?

1 Answer 1

1

Serial.write() is meant for sending binary data. So if you want to send a string with it, you need to provide a c-string, not the Arduino implementation of the String class. That's done easily with a member function of that class:

Serial.write(strrpm.c_str());

That compiles successfully for me.

Though you should not do it like this. The String class is generally bad on small microcontrollers, especially on the AVR microcontrollers with little memory (like Uno, Nano, Mega, ...), because it causes memory fragmentation (see Majenkos "The Evils of Arduino Strings").

Instead you should just use the corresponding print() functions of the Serial class. They are made for sending human readable strings. No need to first build up a String object. Just do

Serial.println(rpm);

And it will do the string conversion itself without using the String class.


Besides that I have some notes on your code:

  • The way you use millis() is a bit weird. There is no need to actually reset the millis() value itself. Normally you would hold a timestamp in a variable and then only calculate the difference between millis() and the timestamp. That is also overflow safe. Like this

      unsigned long timestamp = 0;
    
      ...
      if(millis()-timestamp >= 1000){
          ...
          timestamp+=1000;
      }
    

    That doesn't use an extern variable, it is not resetting the millis() counter (which might mess with other things too, that rely on it) and is somewhat the standard way to do it.

  • You are using an atomic section for resetting the millis() counter, but not for accessing pulsecount. That is actually the place, where you absolutely need this. pulsecount is of type long, so it will need many instructions to do the calculation for revs. The your interrupt service routine can easily mess with the data in that moment, resulting in garbled data. Move the calculation into the if statement and use an atomic section like with the millis() counter to read it into a local variable then you can do the calculations. That will keep the time, where interrupts are turned off very short. You can also - instead of turning all interrupts off - just detach the pin interrupt for that time, so that other things are not affected. Like this code:

      void loop(){
          if(millis()-timestamp > 1000){
               // deactivate our pin interrupt, so it cannot mess with the data
               detachInterrupt(digitalPinToInterrupt(encpin));
               // copy pulsecount to local variable for further calculation
               long local_pulsecount = pulsecount;
               // reactivate our pin interrupt
               attachInterrupt(digitalPinToInterrupt(encpin),function,RISING);
               // Do calculation and print the value
               ...
               timestamp += 1000;
           }
       }
    
3
  • " Instead you should just use the corresponding print() functions of the Serial class. They are made for sending human readable strings. No need to first build up a String object. Just do Serial.println(rpm)" But I dont see how this makes the arduinos communicate?
    – satan 29
    May 4, 2021 at 9:02
  • Also, your initial suggestion: the code ccompiles succesfully, and prints the values on the serial monitor of the sender: but the serial monitor of the receiver is blank
    – satan 29
    May 4, 2021 at 9:08
  • Serial.println() will already send the data in human readable form via serial. Thus it is already communication. Please try using Serial.readStringUntil('\n') instead of Serial.readString(). The latter has a 1s timeout. Since you are sending every second there is less than 1s inbetween each transmission. This might cause that function to never exit. The former function call will read only until the newline character, which is automativally added by the println() function
    – chrisl
    May 4, 2021 at 21:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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