Arduino I2C внешняя организация данных кадра 32Kb

i2c data

Привет, ребята, я новичок в том, что касается структур данных и хранения типов данных. Недавно я работал над проектом, в котором мне нужно было хранить долгосрочные данные для последующего извлечения. Я решил купить i2c fram Adafruit за 10$ 32 КБ, который работает, он может хранить байт данных на адрес, что я могу успешно сделать, я также могу без проблем читать эти байты по любому адресу.

Одна проблема, с которой я впервые столкнулся, заключалась в хранении чисел с плавающей запятой в чипе, который принимал только байты. После поиска в Google мне удалось успешно выплюнуть число с плавающей запятой, используя объединение, а также сохранить его в массиве из 4 байтов. Теперь я сделал это с 3 различными значениями с плавающей запятой, что означает, что каждые 4 сохраненных байта в основном представляют собой одно разделенное значение с плавающей запятой.

Вторая проблема заключается в том, как получить эти данные упорядоченным образом, а также в виде числа с плавающей запятой. Я узнал, что вы можете использовать союз, чтобы сделать обратное. Но как мне заставить свой код читать каждые 4 байта и преобразовывать обратно в число с плавающей запятой?

Есть ли система, позволяющая мне хранить данные в структурированном виде с помощью Arduino? Как данные с отметкой времени с использованием внешнего rtc? Таким образом, когда я нажимаю «извлечь», он печатает эти данные в организованном порядке.

, 👍0

Обсуждение

Мне непонятно, где именно кроется проблема. Чтение всех 4 байтов, которые вам нужны для вашего поплавка, означает просто последовательное чтение 4 байтов. В зависимости от того, как ваша FRAM осуществляет связь, вы могли бы сделать это за одну передачу чтения. Вы можете легко записать прочитанные данные в объединение, а затем прочитать из него число с плавающей запятой. Это прямо противоположный способ разделения поплавка. И, конечно же, вы могли бы сохранять временную метку для каждого поплавка, но зачем? FRAM — это просто часть последовательного хранилища данных, как и любая другая память. Вы хотите файловую систему здесь?, @chrisl


1 ответ


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

3

Было бы проще использовать 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