2

I'm trying to send the temperature value from the DHT sensor to a raspberry pi through I2C. Which is the best way to do it?. The temp value is a float, and I think I have to convert it to byte and send that with Wire.write() to the raspberry, is that right?. Right now I'm sending bytes from the raspberry (with Python) to the Arduino (C++): Python:

from smbus import SMBus
import time

address = 0x8
bus = SMBus(1)

While True:
  bus.write_byte(address, 4)
  time.sleep(1)
  print(bus.ready_byte(address))

Arduino code:

#include <Wire.h>
#include <DHT.h>
...

void setup() {
  dht.begin();
  Wire.begin(0x8);
  Wire.onReceive(receiveEvent);
}

void receiveEvent () {
  float temp = dht1.readTemperature();
  delay(1000);
  byte tempByte[4] = {temp, 0, 0, 0};
  Wire.write(tempByte[0]);
}

So the raspberry is printing 0.

Thanks for any help.

1
  • Please remove the delay from the onReceive callback function. It is executed inside an ISR. Delay doesn't work there
    – chrisl
    Jun 4, 2021 at 17:14

1 Answer 1

5

First of all, if you want the Arduino to send data as a slave, it should do so onRequest(), not onReceive(). Thus:

void setup() {
    Wire.begin(0x08);
    Wire.onRequest(handleRequest);
}

Next, as pointed out by chrisl in a comment, you should not delay within the onRequest handler. I would go further and say that you should not even call dht1.readTemperature(), as that could take too much time to be done in interrupt context. Instead, have the main loop query the sensor periodically, and have the latest reading always available:

volatile float temperature;  // latest valid reading

void loop() {
    float new_temperature = dht1.readTemperature();
    noInterrupts();
    temperature = new_temperature;
    interrupts();
    // ...
}

Note that the latest value is updated with interrupts disabled. This is to avoid a data race that could happen if the Arduino receives a request while it is in the middle of updating the value. Notice also that interrupts are disabled during a very short time: just the time needed to update the variable.

Lastly, to send the data, you can use the version of Wire.write() that accepts a buffer of arbitrary length:

void handleRequest() {
    Wire.write((uint8_t *) &temperature, sizeof temperature);
}

The temperature will be sent LSB-first, as a float, formatted as per IEEE 754. The Raspberry Pi should be able to digest it in this very same format.

2
  • Thank you very much Edgar!!!. I'm trying now to read the IEEE 754 value from the Raspberry Pi, using Python3, but no success so far. I'm new to these technologies so sorry for my ignorance. With Python 3 I'm reading this from the bus with: float bus.read_byte_data(address, 4) # this returns an array like: ["205","104"] when the temperature value is 25.20 float bus.read_byte(address) # this returns random numbers of 3 digits, like 204, 104, etc. Not sure if Python3 is the right choice here, maybe you could recommend something else better. Thanks again.
    – Guille
    Jun 5, 2021 at 19:42
  • 1
    I don't know Python, and it's off-topic here. If you forcibly set temperature to 25, you should read the bytes 0x00, 0x00, 0xc8 and 0x41, in this order. How you reassemble these on the PC is a question for another site. Jun 5, 2021 at 20: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.