Преобразование float в байт, от Arduino до Raspberry Pi i2c

Я пытаюсь отправить значение температуры с датчика DHT на raspberry pi через I2C. Как лучше всего это сделать?. Значение temp - это float, и я думаю, что должен преобразовать его в байт и отправить с помощью Wire.write() в малину, не так ли?. Прямо сейчас я отправляю байты из raspberry (с Python) в 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:

#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]);
}

Таким образом, малина печатает 0.

Спасибо за любую помощь.

, 👍2

Обсуждение

Пожалуйста, удалите задержку из функции обратного вызова onReceive. Он выполняется внутри ISR. Задержка там не работает, @chrisl


1 ответ


Лучший ответ:

5

Прежде всего, если вы хотите, чтобы Arduino отправлял данные в качестве ведомого устройства, он должен делать это onRequest (), а не onReceive(). Таким образом:

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

Далее, как указал Крисл в комментарии, вы не должны задерживаться в обработчике onRequest. Я бы пошел дальше и сказал, что вы даже не должны вызывать dht1.readTemperature (), так как это может занять слишком много времени в контексте прерывания. Вместо этого попросите основной цикл периодически запрашивать датчик и всегда иметь в наличии последние данные:

volatile float temperature;  // последнее действительное значение

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

Обратите внимание, что последнее значение обновляется с отключенными прерываниями. Это делается для того, чтобы избежать гонки данных, которая может произойти, если Arduino получит запрос во время обновления значения. Обратите также внимание, что прерывания отключаются в течение очень короткого времени: как раз того времени, которое необходимо для обновления переменной.

Наконец, чтобы отправить данные, вы можете использовать версию Wire.write (), которая принимает буфер произвольной длины:

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

Температура будет отправлена LSB-first, как float, отформатированный в соответствии с IEEE 754. Raspberry Pi должен быть в состоянии переварить его в том же формате.

,

Большое тебе спасибо, Эдгар!!!. Сейчас я пытаюсь прочитать значение IEEE 754 из Raspberry Pi, используя Python3, но пока безуспешно. Я новичок в этих технологиях, так что извините за мое невежество. С Python 3 я читаю это из автобуса с: float bus.read_byte_data(address, 4) # это возвращает массив типа: ["205","104"] при значении температуры 25.20 float bus.read_byte(адрес) # это возвращает случайные числа из 3 цифр, например 204, 104 и т. Д. Не уверен, что Python3-правильный выбор здесь, может быть, вы могли бы порекомендовать что-то еще лучше. Еще раз спасибо., @Guille

Я не знаю Python, и здесь это не по теме. Если вы принудительно установили значение "температура" равным 25, вы должны прочитать байты 0x00, 0x00, 0xc8 и 0x41 в таком порядке. Как вы собираете их на ПК-это вопрос для другого сайта., @Edgar Bonet