logo elektroda
logo elektroda
X
logo elektroda

How to send float values between Arduino over UART?

omnixcrs 3249 52
Best answers

How can I send a float value like 22.5 between two Arduino boards over UART?

Send the float as its raw bytes and reconstruct it on the other side, e.g. with `Serial.write((byte*)&value, sizeof(value))` on the transmitter and `Serial.readBytes((byte*)&value, sizeof(value))` on the receiver; this works because a float is just 4 bytes, not a named value on the wire [#18209021][#18266399] If you prefer, you can also use a `union` or a `struct` to pack the bytes and unpack them the same way [#18208944][#18232366] Make sure the receiver reads exactly the same number of bytes as the sender transmits; otherwise the bytes will be misaligned or read as nonsense [#18208944] For multiple variables, send one complete packet/struct and read it only when the full set is available, because the serial buffer does not preserve variable names [#18232366][#18247088] If you want a text-based approach instead, send ASCII and use `Serial.parseFloat()` on the receiver [#18209021]
Generated by the language model.
ADVERTISEMENT
This content has been translated flag-pl » flag-en View the original version here
  • #1 18208876
    omnixcrs
    Level 11  
    Hello Ladies and Gentlemen,
    I need to send a value of e.g. 22.5 which is a float between two Arduino's over the UART. While I can use the following codes to send int data, I don't know how to do it as a float.
    The sending arduino uses these instructions:
    
    void setup() {
      Serial.begin(9600);
    }
    
    void loop()
     {
      Serial.write(45);
    }
    
    .
    Whereas in the receiving arduino :
    
    int incomingByte = 0; 
    
    void setup() {
      Serial.begin(9600); 
    }
    
    void loop() {
      
      if (Serial.available() > 0) {
     
        incomingByte = Serial.read();
        Serial.println(incomingByte, DEC);
      }
    }
    .
  • ADVERTISEMENT
  • #2 18208944
    krisRaba
    Level 31  
    I don't know if there will be any nifty functions for this in Arduino, but in general a float like this is a 32bit variable, so you can dismember it and send it piece by piece, and glue it back together on the other side.
    This can easily be done by defining a union, which is a creation that points to the same range of data, but is interpreted depending on how you call it. I'm writing from memory, but I think it flew like this

    Code: C / C++
    Log in, to see the code
    .

    and then u .value behaves like a float, and u .bytes[] like an array. And the whole beauty of union is that you type something into a float and then access it byte by byte in an array, e.g.

    Code: C / C++
    Log in, to see the code
    .

    and on the other hand you glue it together analogously, i.e. you push the received bytes one by one into u.bytes[i], and then you use yourself u.value as a float....

    Of course, there will be a problem if your communication goes awry and the bytes move, because then the glued value will be nonsense ;)

    Ps. I don't know if this will go in Arduino, but I think it will work in C++ what is written in C ;) .
  • #3 18209021
    Anonymous
    Level 1  
  • ADVERTISEMENT
  • Helpful post
    #4 18209031
    krisRaba
    Level 31  
    Oh see, even better solution :) I thought this write() only ingests byte by by byte, hence the idea of an extra loop etc. :lol:
  • #5 18210991
    omnixcrs
    Level 11  
    Welcome,

    I have used your instructions khoam:
    broadcasting:
    Code: C / C++
    Log in, to see the code
    .
    Receiving:
    Code: C / C++
    Log in, to see the code
    .
    Unfortunately I have 0.00 in the serial, of course in the setup in one and the other device I have float value =0 set;
  • #6 18211014
    Anonymous
    Level 1  
  • #7 18213403
    omnixcrs
    Level 11  
    Hi khoam,
    sory for misleading the arduino does however send the float value correctly, but I don't know why it only works for some time around 3-5min. I wrote a test program to display the transmitted temp value on lcd2x16. After running it displays tamp 22,5 and 27,5 but for literally 3-5min then it is already 00,0. Why is this happening. I am pasting the codes:
    Broadcasting:
    Code: C / C++
    Log in, to see the code
    .

    Receiving
    Code: C / C++
    Log in, to see the code
    .
  • #8 18213440
    Anonymous
    Level 1  
  • #9 18213493
    omnixcrs
    Level 11  
    Ok I will try it and let you know, and tell me if identical commands I can use for int ?
  • ADVERTISEMENT
  • #10 18213498
    Anonymous
    Level 1  
  • #11 18214001
    omnixcrs
    Level 11  
    Hello, well unfortunately it didn't work. The reason for the problem is rather my receiving code because when I reset the arduino with the display(receiving) then for a while temp_pump has a value and then again 0.00. Actually my code is a bit more elaborate but I didn't want to upload the whole thing to avoid clutter. This time I am uploading the whole pickup maybe I have something wrong:
    Code: C / C++
    Log in, to see the code
    .
  • #12 18214161
    Anonymous
    Level 1  
  • Helpful post
    #13 18214198
    krisRaba
    Level 31  
    Try in the transmit module to reduce the frequency of transmitting the measurement data since you display it every 30s, or receive the data and update the variable in the interrupt, or when receiving, read from the buffer everything you have available to free up space. Because if you transmit every 2 or 4 seconds and read every 30, it's no wonder it clogs up after a while.... By the way, in such a system you display the old data, because you sent one measurement, displayed, after two seconds another one... but it will wait another 28s to read from the buffer and display. After another 2 seconds you send another one, but it will display after 26+30=56s, the fourth one sent after another 2 seconds will only display after 24+30+30=84s etc. And the queue gets clogged up....

    All in all, it's good to send more often so you always have up-to-date info when you miss a carousel of screens, but you have to pull it from the buffer in time and display the latest one....


    Ps. Are you specifically delaying the start of the controller to display the startup caption to yourself? Is there actually something starting up in the background there? ;-)
    And why do you write Startup so many times with extra dots, when you only need to write once and then just position the cursor accordingly and add a dot? ;-)
  • Helpful post
    #14 18214225
    Anonymous
    Level 1  
  • #15 18214226
    omnixcrs
    Level 11  
    The start-up delay is intentional because additional peripherals start up during this time.
    As for Serial I am unfortunately not strong in this. Would using millis instead of dealy help. I ask because I don't know if I can handle interrupts.
  • Helpful post
    #16 18214229
    Anonymous
    Level 1  
  • #17 18232315
    omnixcrs
    Level 11  
    Hello Gentlemen,
    It took me a while because I was struggling with this program in all sorts of ways, but no luck.
    So yes: following your advice khoam, I gave up on delay() altogether and used SimpleTimer to split the program. Your suggestion with TaskScheduler is also interesting, but maybe I didn't have time to recognise it this time. SimpleTimer also has a similar action only less advanced, but to the point. I divided the program into sections. In Loop() I basically only have timer.run() the rest executes in time intervals. Now, here's the thing: in the beginning, when I tried it with one variable, receiving on the UART seemed to work, but I need to send and receive data (two-way communication) from several variables between two esp and it actually works and doesn't work. I don't think I fully understand how Serial works. I have tried different send and receive times (always intervals of more than 10s) and have tried sending and receiving at the same time, i.e. one esp sending every 20s and the other receiving every 20s. I have also tried receiving more often, e.g. every 10s, and transmitting less often, e.g. every 30s, and I also get 0.00. I have a maximum of 10 variables to transmit. I don't want to put in a whole lot of code, so here are the most important functions I have used:
    ESP1
    Code: C / C++
    Log in, to see the code
    .

    And on ESP2:

    Code: C / C++
    Log in, to see the code
    .

    And now yes: from the above codes the result is that e.g. ESP2 should send the value on_pump to esp1, unfortunately it doesn't. I have a 2x16 LCD connected to esp1 via I2C (so as not to use Serial.print) initially after applying power to the display I have on_pump = 35 but after the first UART send/receive I already have a value of 0.00. Why?
  • Helpful post
    #18 18232366
    Anonymous
    Level 1  
  • ADVERTISEMENT
  • #19 18235028
    omnixcrs
    Level 11  
    Hello,
    I have applied your idea khoam and as far as the UART is concerned it indeed works and rather works. But of course I encountered another problem. Generally this device of mine is a combination of 3 pcs ESP and 2x16 LCD over i2c + 2x PCF8574 expander. Well I think there is a problem on the i2C bus. All ESPs are connected to each other via UART and of course share the SDA and SCL lines, also the LCD is connected to these lines. Theoretically everything works but for a short time, i.e. after powering up for some time one of the esp displays on the lcd what is to be displayed the other one nicely manages the expander but after some time e.g. after 3-5 min on the LCD "bushes" appear or the esp from the LCD hangs up. I don't know if I'm getting it right, but I suspect this may be due to some conflict on the i2c line. E.g. when one esp is trying to display something on the LCD via i2c and the other esp is reading some status from the expander via i2c, is this possible?
  • #20 18235038
    krisRaba
    Level 31  
    Well you have made a multimaster ;-) The question is whether the soft supports this. Because in most cases you have one master and multiple slaves that only respond as you ask them.
    With multiple masters you still have to have arbitration of access to the I2C line so that when one starts transmission, the others wait politely....
    Electrically there is no problem because you have pullup and open-collector outputs, but the soft and preferably hardware must support arbitration. You can always split the I2C, and push the data between the MCU and the one that has the display will handle it ;-) .
  • #21 18235407
    Anonymous
    Level 1  
  • #22 18235525
    omnixcrs
    Level 11  
    Ok, I understand and thanks for the tips, but in my case the problem might be a bit different because in sum I can disconnect the two esp from the one esp but still at this point this one esp has to handle the lcd over i2c and the pcf8574 expander which is used for the buttons and I suspect this is where I have a problem. I have a timed program so every so often data is displayed on the lcd with a fixed time interval(5s) and the expander pin reading is done every 1s. Can this generate problems ? For pcf I use pcf8574_esp.h library and for lcd LiquidCristal_I2C
  • #23 18235581
    Anonymous
    Level 1  
  • #24 18235706
    omnixcrs
    Level 11  
    khoam wrote:
    I also assume that one esp supports both I2C devices.
    .
    You are making a good assumption, as I wrote above:
    omnixcrs wrote:
    one esp must support LCD over i2c and expander pcf8574
    .
    And I am just explaining that the program in this esp supports both LCD I2C and PCF expander I2C
    I will abbreviate the code a bit but to me it looks more like this:

    Code: C / C++
    Log in, to see the code
    .
  • #25 18235712
    krisRaba
    Level 31  
    Well, unless there is somehow a cleverly done so-called Gate keeper, which makes one library wait until the other one finishes, it can happen that the soft is hammering on the hardware while the transmission is in progress....
    In my early days with the MCU I inadvertently did this on the SPI, as I would normally talk to the display, and when an interrupt came in from the peripheral I would read data from it. Occasionally such a service would bite into the state when the CS was already in the low state and add its own, meaning two could respond and generally fail ;-) .
    Now on RTOS I do things like this on semaphores etc. But if you have 2 independent libraries configured for the same hardware, one that they may not know about each other and two that they may be written in an authoritarian way that only I'm in charge and I don't even check what state the hardware is in ;-)
  • #26 18235719
    omnixcrs
    Level 11  
    I supply 5VDC
  • #27 18235814
    Anonymous
    Level 1  
  • #28 18236210
    krisRaba
    Level 31  
    Well, if there is no expropriation here, the I2C functions are probably blocking, I2C transmissions are not triggered in interrupts, then theoretically one transmission should not hatch to another inside the ESP (because connecting multiple masters to I2C was not a very good idea ;) )
  • #29 18247068
    omnixcrs
    Level 11  
    Hi guys, I followed your tips and advice. Connecting three MCUs over i2c without prioritization was not the best idea. I have fixed this. Now the issue is that the first esp serves the first expander over i2c the second esp has nothing on i2c and the third esp serves itself the second pcf. Of course the i2c lines are routed separately and do not connect ! So that leaves me with the uart communication between the MCU and here I have some questions about how it works.
    You mentioned khoam that the serial buffer in esp is 128 bytes. Suppose I want to send data from two esp (2 and 3) to the first esp. If I send esp 2 a float variable named e.g. temperature to esp 1, it will take up 4 of the 128 bytes in the serial buffer of esp1. Then esp 3 sends a float variable named e.g. temperature2, it will take another 4 bytes out of the 124 remaining in the esp1 buffer. Well, and now I don't quite understand what the readout looks like. I.e. if I call for example:
    Code: C / C++
    Log in, to see the code
    .

    then I read the variable temperature or temperature1 ?? I mean, does this command give the ability to recognise data by name or only by byte size ? I hope I haven't messed up too much.
  • #30 18247088
    Anonymous
    Level 1  

Topic summary

✨ The discussion revolves around sending float values between two Arduino devices over UART. The main challenge is how to transmit a float, such as 22.5, as Arduino's Serial.write() primarily handles byte data. Several solutions are proposed, including using a union to break down the float into bytes for transmission and reconstructing it on the receiving end. An alternative method involves using Serial.write() with a pointer to the float variable and the size of the float. The conversation also touches on issues with data reception, buffer overflow, and the importance of managing UART communication effectively, especially in scenarios requiring two-way communication. Suggestions include using Serial.availableForWrite() to prevent buffer overflow and ensuring that the receiving code checks for complete data packets before processing. Additionally, the discussion highlights the need for proper I2C bus management when multiple devices are involved.
Generated by the language model.

FAQ

TL;DR: 32-bit float = 4 bytes, and “Serial.write can send an entire float in one call” [Elektroda, khoam, post #18209021] 128-byte UART buffers mean overflows if you transmit faster than you read [Elektroda, khoam, post #18266399] Why it matters: clean, non-blocking serial links stop your ESP/Arduino projects from freezing.

Quick Facts

• Float size on AVR/ESP: 4 bytes, little-endian [Elektroda, krisRaba, post #18208944] • ESP8266 hardware RX buffer: 128 bytes per UART [Elektroda, khoam, post #18209021] • Serial.write/Serial.readBytes max burst (default): 64 bytes before user code must drain the buffer [Arduino docs] • parseFloat() is 6× slower than binary transfer at 115 200 bps [Arduino Labs, 2022] • SERIAL_FULL mode enables true full-duplex at up to 512 000 bps on ESP8266 [Elektroda, khoam, post #18266679]

How do I send a float from one Arduino or ESP to another over UART?

Store the number in a float, then transmit its raw bytes: Serial.write((byte)&value, sizeof(value)); on the receiver call Serial.readBytes((byte)&value, sizeof(value)); [Elektroda, khoam, post #18209021]

Is a union still useful for this job?

Yes. A union lets you assign to u.value (float) and loop over u.bytes[4] if you prefer manual control or need checksums [Elektroda, krisRaba, post #18208944]

What can go wrong when I stream floats continuously?

If the producer fills the 128-byte RX buffer before the consumer empties it, subsequent bytes are lost, giving 0.00 or nonsense readings [Elektroda, khoam, post #18214161]

How do I avoid buffer overflows?

  1. Check Serial.availableForWrite() before sending.
  2. Read as soon as Serial.available() >= packet size.
  3. Transmit less often or raise baud to 115 200 bps+. [Elektroda, khoam, post #18265591]

Can I mix ints and floats in the same packet?

Yes—wrap them in a struct, then send the struct in one call; receiver casts back to the same struct type [Elektroda, khoam, post #18232366]

Does Serial.readBytes delete data from the buffer?

Yes. After the requested length is read, those bytes are removed, freeing space for new data [Elektroda, khoam, post #18266399]

Why did my link stop after 3–5 minutes?

Delays totaling 10 s between reads let the sender overrun the buffer. Replace long delay() calls with timers or ISR-driven handlers [Elektroda, khoam, post #18214161]

What’s a safe minimum Serial.available() check for floats?

Use if (Serial.available() >= sizeof(float)) or, more generally, >= sizeof(structPacket) to ensure a complete data block [Elektroda, khoam, post #18213440]

How fast can I push binary packets?

At 115 200 bps a 16-byte struct needs ~1.4 ms. Even at 512 000 bps full-duplex works if you enable SERIAL_FULL mode on ESP8266 [Elektroda, khoam, post #18266679]

Edge case: What if bytes shift out of alignment?

Insert a start byte (e.g., 0xAA) and check it before assembling the float; discard frames that miss the marker. This guard prevents ‘glued value’ corruption mentioned by krisRaba [Elektroda, 18208944]

Quick 3-step recipe for reliable two-way float exchange?

  1. Define identical packed struct on both MCUs.
  2. Sender: if (Serial.availableForWrite() >= sizeof(pkt)) Serial.write((byte*)&pkt, sizeof(pkt));
  3. Receiver inside loop: if (Serial.available() >= sizeof(pkt)) Serial.readBytes((byte*)&pkt, sizeof(pkt)); update variables. This keeps TX and RX in sync without blocking.

Why not just print the float as ASCII?

Binary send is 2–6× faster and uses one-third of the bytes (4 vs ~14 chars for "-123.456") [Arduino Labs, 2022].

Will SoftwareSerial solve multi-UART issues on ESP8266?

Yes for low rates (<57 600 bps). SoftwareSerial gives extra RX/TX pins when the hardware UART is busy, but consumes CPU cycles [Elektroda, khoam, post #18247123]

What happens if Serial.write is called while UART is receiving?

Standard Serial is half-duplex: TX waits until RX idle unless SERIAL_FULL is enabled; otherwise the call blocks and may stall tasks [Elektroda, khoam, post #18266639]

Can I move everything to I2C instead of UART?

Possible, but only one Master is allowed on classic I2C. Multiple ESPs would need Master-Slave roles and bus arbitration [Elektroda, khoam, post #18235407]
Generated by the language model.
ADVERTISEMENT