Floats come out as garbage when my Uno reads a Nano over I2C
Greenhouse controller, two boards: a Nano reads soil probes and a DS18B20 and acts as I2C slave at 0x08; an Uno is master, collects from the Nano and passes everything over serial to an ESP32 that publishes to Hermetry. The ints (moisture raw, 0-1023) come through fine. The temperature float arrives as nonsense like -2.3e-38 or nan, and Hermetry refuses the key whenever it’s NaN, so the chart has holes.
Slave side:
void onRequest() {
Wire.write(moisture1 >> 8); Wire.write(moisture1 & 0xFF);
Wire.write(moisture2 >> 8); Wire.write(moisture2 & 0xFF);
Wire.write((byte)tempC); // tried this first, lost decimals
Wire.write((byte*)&tempC, 4);
}
Master does Wire.requestFrom(8, 9) and reads bytes back into the same variables.
Could you send it as a string and parse it on the other end? That’s what I did for serial.
Strings over I2C waste bytes and you only get 32 per transfer. Show the master side, I bet that’s where it breaks.
master side, sorry, should have included it:
Wire.requestFrom(8, 9);
m1 = (Wire.read() << 8) | Wire.read();
m2 = (Wire.read() << 8) | Wire.read();
Wire.read(); // the old byte
for (int i = 0; i < 4; i++) ((byte*)&t)[i] = Wire.read();
Following, I have a similar setup planned for our hotel greenhouse.
Two bugs, and a third waiting to happen. I did nearly this exact thing on a test rig years ago.
1. On the slave, each Wire.write() inside onRequest on AVR replaces the buffer instead of adding to it in some library versions, and the order of evaluation in (Wire.read() << 8) | Wire.read() on the master isn’t defined in C++, so the bytes can come out swapped.
2. The stray single byte shifts everything if the counts ever disagree.
Do it with one struct on both sides and one write:
struct __attribute__((packed)) Packet {
uint16_t m1, m2;
int16_t t_x100; // 23.47 C -> 2347, no float on the wire
uint8_t seq;
};
// slave
void onRequest() { Wire.write((uint8_t*)&pkt, sizeof(pkt)); }
// master
Packet p;
if (Wire.requestFrom(8, sizeof(p)) == sizeof(p))
Wire.readBytes((uint8_t*)&p, sizeof(p));
float t = p.t_x100 / 100.0;
Scaled integers avoid any float layout question if the slave ever becomes an ESP or an STM32. The seq byte tells you if you’re reading a stale packet. And on the ESP32 side, skip the key entirely if a reading is invalid instead of sending NaN, NaN isn’t valid JSON anyway.
Struct with scaled int fixed it. Temperature has been clean since yesterday afternoon, no gaps on the chart. The evaluation order thing was news to me.
- Bu konuyu yanıtlamak için giriş yapmış olmalısınız.
Sohbete katılın
Soru sormak ve yanıtlamak, yararlı gönderileri beğenmek ve sorununuzu çözen yanıtı işaretlemek için oturum açın. Her katkı puan ve seviye kazandırır.

