Arduino I2C внешняя организация данных кадра 32Kb
Привет, ребята, я новичок в том, что касается структур данных и хранения типов данных. Недавно я работал над проектом, в котором мне нужно было хранить долгосрочные данные для последующего извлечения. Я решил купить i2c fram Adafruit за 10$ 32 КБ, который работает, он может хранить байт данных на адрес, что я могу успешно сделать, я также могу без проблем читать эти байты по любому адресу.
Одна проблема, с которой я впервые столкнулся, заключалась в хранении чисел с плавающей запятой в чипе, который принимал только байты. После поиска в Google мне удалось успешно выплюнуть число с плавающей запятой, используя объединение, а также сохранить его в массиве из 4 байтов. Теперь я сделал это с 3 различными значениями с плавающей запятой, что означает, что каждые 4 сохраненных байта в основном представляют собой одно разделенное значение с плавающей запятой.
Вторая проблема заключается в том, как получить эти данные упорядоченным образом, а также в виде числа с плавающей запятой. Я узнал, что вы можете использовать союз, чтобы сделать обратное. Но как мне заставить свой код читать каждые 4 байта и преобразовывать обратно в число с плавающей запятой?
Есть ли система, позволяющая мне хранить данные в структурированном виде с помощью Arduino? Как данные с отметкой времени с использованием внешнего rtc? Таким образом, когда я нажимаю «извлечь», он печатает эти данные в организованном порядке.
@Steven Gangaram, 👍0
Обсуждение1 ответ
Лучший ответ:
Было бы проще использовать struct
, а не union
. Сохраните все данные, которые вы хотите сохранить, в структуре, затем приведите к ней указатель, чтобы он был указателем byte
, и просто обработайте его как массив байтов и прочитайте и запишите эти байты в FRAM.
Используемый вами union
явно делает то же самое, но его непросто масштабировать на несколько элементов.
Некоторые предостережения относительно того, что можно безопасно хранить в struct
:
не храните в нем указатели. Массив
char
подходит, потому что весь массив займет место вstruct
.char *
не потому, что вы сохраняете только значение указателя, а не то, на что он указывает.не храните в нем объекты (например,
String
). Вы не знаете (и не должны знать), как объект устроен внутри. Если необходимо использовать объекты, они должны иметь методыserialize
иdeserialize
, которые будут хранить или восстанавливать содержимое объекта в массив байтов, который затем можно сохранить или восстановить с помощью кадр.
Также помните, что функция C/C++ sizeof
(используемая ниже) сообщает вам размер объекта во время компиляции. Поэтому, если вы используете его в struct
, он сообщит вам количество байтов, которое требуется для хранения struct
. Если вы используете его для char *
, он сообщит вам количество байтов в указателе на char
, а не количество байтов в строке C, которую char *
указывает на. Если вы используете его для объекта, например, String str; sizeof(str);
— он сообщит вам, сколько байтов требуется для хранения объекта String
, включая длину хранимой строки.
Псевдокод следует далее. Есть более компактные способы записать это; Я стремлюсь к ясности здесь.
#include <Arduino.h>
struct program_data {
float first_thing;
unsigned long second_thing;
char third_thing[55];
char fourth_thing;
uint16_t fifth_thing;
} data;
void save_data(struct program_data *data_ptr) {
byte *ptr = (byte *)data_ptr;
for(size_t i = 0; i < sizeof(struct program_data); i++)
store_byte_in_fram(ptr[i], i);
}
void restore_data(struct program_data *data_ptr) {
byte *ptr = (byte *)data_ptr;
for(size_t i = 0; i < sizeof(struct program_data); i++)
retrieve_byte_from_fram(ptr[i], i);
}
// вызов, когда вы хотите сохранить свои данные
save_data(&data);
// вызов, когда вы хотите восстановить свои данные
restore_data(&data);
Чувак, ты невероятен, во-первых, спасибо за ответ. Во-вторых, это было так легко понять! Спасибо, чувак, я попробую и скажу тебе., @Steven Gangaram
У меня есть внешний RTC, который я хочу добавить к нему, чтобы каждые 5 или 10 секунд он сохранял структуру значений и время, связанное с ним. Будет ли это перезаписывать определенный сектор или он может сместиться, оставив предыдущие данные?, @Steven Gangaram
Хороший вопрос. RTC обычно используют статическое ОЗУ с резервным питанием от батареи, где не имеет значения, перезаписывают ли они одни и те же адреса. Однако это действительно зависит от системы и интерфейса к ней. Если вы обращаетесь к памяти напрямую, то запись по одному и тому же адресу должна быть в одном и том же месте в памяти., @romkey
Маленькая забота. Этот подход может потерпеть неудачу, если не будет предоставлено, что структура упакована, @brtiberio
@brtiberio почему ты думаешь, что это будет проблемой?, @romkey
- Отправка и получение различных типов данных через I2C в Arduino
- Как работают функции вне цикла void?
- Как отображать переменные на 0,96-дюймовом OLED-дисплее с библиотекой u8glib?
- Как отправить строку на мастер с помощью i2c
- Как выбрать альтернативные контакты I2C на ESP32?
- Что означает в I2C «NACK получен»?
- NodeMCU с RFID RC522 и LCD-модулем интерфейса I2C вместе
- Несколько датчиков I2C с одинаковым адресом
Мне непонятно, где именно кроется проблема. Чтение всех 4 байтов, которые вам нужны для вашего поплавка, означает просто последовательное чтение 4 байтов. В зависимости от того, как ваша FRAM осуществляет связь, вы могли бы сделать это за одну передачу чтения. Вы можете легко записать прочитанные данные в объединение, а затем прочитать из него число с плавающей запятой. Это прямо противоположный способ разделения поплавка. И, конечно же, вы могли бы сохранять временную метку для каждого поплавка, но зачем? FRAM — это просто часть последовательного хранилища данных, как и любая другая память. Вы хотите файловую систему здесь?, @chrisl