Как преобразовать структуру в char[] для использования в Wire.h или есть лучший способ?
Мне нужно соединить микроконтроллер ATTiny88, настроенный как ведомое устройство I²C, с Raspberry Pi, настроенным как ведущее устройство I²C. Возможно, я использую неправильный подход, но у меня есть структура, состоящая из четырёх различных типов данных фиксированной длины, которые я хочу передавать ведущему устройству по каждому запросу.
Исходный код:
#include <Wire.h>
struct Response // 7 байт
{
byte Command; // 1 байт
float Temperature; // 4 байта
byte FanValue; // 1 байт
bool CoolStat; // 1 байт
};
struct Response Reply;
bool True = 1;
bool False = 0
void setup()
{
pinMode(ADDR1, INPUT_PULLUP); // Смещение адреса 0 или 1
pinMode(ADDR2, INPUT_PULLUP); // Смещение адреса 0 или 2
I2C = (2 * digitalRead(ADDR1)) + digitalRead(ADDR1) + 8; // Установить адрес I2C 8 - 11
Wire.begin(I2C);
Wire.onRequest(requestEvent); // Вызвать requestEvent при запросе данных
Reply.Command = 1;
Reply.Temperature = 35.62;
Reply.FanValue = 255
Reply.CoolStat = True
}
// Функция, которая выполняется всякий раз, когда данные запрашиваются из главного устройства
void requestEvent() {
Wire.write(Reply); // ответить сообщением, как ожидает мастер
Responded = True;
}
Это, конечно, не работает, потому что библиотеке не нравится, что я передаю структуру, а не простую строку с нулевым символом в конце. Я не уверен, как лучше передать структуру функции Wire.write(). Мне нравится возможность изменять значения переменных в структуре на разные значения разных типов данных в разных местах кода, но не лучше ли будет использовать другой подход и вручную обновлять двоичные значения в строке?
@LesRhorer, 👍1
1 ответ
Лучший ответ:
Существует перегрузка Wire.write, которая позволяет отправлять произвольные данные
массив байтов:
virtual size_t write(const uint8_t *, size_t);
Чтобы использовать его, вам нужно преобразовать адрес вашей структуры в
указатель на uint8_t:
Wire.write((uint8_t *) &Reply, sizeof Reply);
Однако следует отметить, что этот метод, хотя и очень распространен, на самом деле не является
совместимо со стандартом C++. Я предлагаю вам вместо этого использовать union, который
позволяет получить доступ к памяти структуры как к простому массиву байтов:
union Response {
struct {
byte Command; // 1 байт
float Temperature; // 4 байта
byte FanValue; // 1 байт
bool CoolStat; // 1 байт
};
uint8_t bytes[7];
};
Затем это можно отправить с помощью:
Wire.write(Reply.bytes, sizeof Reply);
Однако: у вас могут возникнуть трудности с разбором структуры на
Число Пи. Разные вычислительные платформы имеют разные размеры типов данных и
Различные ограничения выравнивания. Используемая вами структура может быть
Длина 7 байт на Arduino Uno, но на базе ARM он будет больше
Arduino, а также на Raspberry Pi: для выравнивания вам нужно будет
Перед Temperature есть три дополнительных байта. Также CoolStat
Поле может быть больше одного байта и может содержать некоторое дополнительное поле.
Чтобы упростить задачу, я рекомендую вам определить структуру таким образом, чтобы
его макет не зависит от платформы: используйте только типы фиксированного размера, поместите
Сначала более крупные элементы, а затем вручную дополнить до кратного размера более крупного элемента
размер:
union Response {
struct {
float Temperature; // 4 байта
uint8_t Command; // 1 байт
uint8_t FanValue; // 1 байт
uint8_t CoolStat; // 1 байт
uint8_t padding; // 1 байт
};
uint8_t bytes[8];
};
Это должно иметь точно такую же компоновку на любом Arduino, а также на Raspberry Pi.
- Отправка и получение различных типов данных через I2C в Arduino
- Преобразование float в байт, от Arduino до Raspberry Pi i2c
- Float печатается только 2 десятичных знака после запятой
- Какие накладные расходы и другие соображения существуют при использовании структуры по сравнению с классом?
- Как работают функции вне цикла void?
- Как отображать переменные на 0,96-дюймовом OLED-дисплее с библиотекой u8glib?
- Как отправить строку на мастер с помощью i2c
- Как выбрать альтернативные контакты I2C на ESP32?
Чтобы избежать выравнивания, можно использовать
#pragma pack(1), @SBF@SBF: Это, вероятно, работает на x86\_64. Однако я предпочитаю этого избегать, так как у меня были компьютеры, на которых невыровненный доступ к памяти приводил к сбою программы с ошибкой
SIGBUS(ошибка шины)., @Edgar BonetСпасибо, сэр! Ваш ответ идеален., @LesRhorer