Считать байт и время в EEPROM, а затем отобразить их с запятой между временем и значением?

Мне приходят байты натуральных чисел от 1 до 60 в случайное время:

Пример отправки данных

// Отправка без изменений

void setup() {
  Serial.begin(9600);
  
  int integersToSend[] = {1, 22, 30, 4, 50};
  for (int i = 0; i < 5; i++) 
  {
    Serial.print(integersToSend[i]);  // отправляем как символы
    delay(1000);
  }
}

void loop() {}

Я хочу записать время (любой формат времени) и какое значение было получено в EEPROM:

#include <EEPROM.h>

const int timeRefreshDisplay = 30000;
const int EEPROM_SIZE = 100; // Определить размер доступной EEPROM
int addr = 0; // указатель адреса EEPROM

unsigned long programStartTime;

void setup()
{
  Serial.begin(9600);
  Serial1.begin(9600); // Инициализируем Serial1 для ввода данных
  programStartTime = millis(); // Запись времени запуска программы
}

void loop()
{
  if (Serial1.available())
  {
    int receivedData = Serial1.read();

    if (receivedData != 0 && receivedData <= 60)
    {
      byte receivedValue = receivedData; // Конвертировать?

      // Вычисляем временную метку на основе времени запуска программы
      unsigned long currentTime = programStartTime + millis();

      // Сохраняем полученную метку времени и значение в EEPROM
      EEPROM.put(addr, currentTime);
      addr += sizeof(unsigned long);
      EEPROM.put(addr, receivedValue);
      addr += sizeof(int);
    }
  }

  if (millis() - programStartTime >= timeRefreshDisplay)
  {
    programStartTime = millis();
    displayEEPROMData();
  }
}

void displayEEPROMData() {
  // Отображение всех позиций, хранящихся в EEPROM
  Serial.println("EEPROM:");

  for (int i = 0; i < EEPROM_SIZE; i += sizeof(unsigned long) + sizeof(int)) {
    if (i >= EEPROM_SIZE) {
      i = 0; // Начинаем чтение с начала при достижении конца EEPROM
    }

    unsigned long timestamp;
    int value;
    EEPROM.get(i, timestamp);
    EEPROM.get(i + sizeof(unsigned long), value);

    // Отображение данных о позиции с отметкой времени в формате ЧЧ:ММ:СС
    Serial.print(String(i / (sizeof(unsigned long) + sizeof(int)) + 1) + ": ");
    Serial.println(String(timestamp) + ", " + String(value));
  }
}

Последовательный монитор

EEPROM:
1: 17330, 22272
2: 101, 27943
3: 4143972352, 116
4: 0, 0
5: 0, 0
6: 0, 0
7: 0, 0
8: 0, 0
9: 0, 0
10: 0, 0
11: 0, 0
12: 0, 0
13: 0, 0
14: 0, 0
15: 0, 0
16: 0, 0
17: 0, 0

Я не совсем понимаю, как он считывает данные в EEPROM. Вот в чем проблема. Я просто не знаю, как это исправить. Я попробовал очистить память:

    #include <EEPROM.h>
    
    
    void setup() {
       // инициализируем вывод светодиода как выход.
       pinMode(13, OUTPUT);
    
       for (int i = 0 ; i < 22; i++) /*EEPROM.length()*/ 
          EEPROM.write(i, 0);
    
       // включаем светодиод, когда закончим
       digitalWrite(13, HIGH);
    }
    
    void loop() {}

Снова последовательный монитор

EEPROM:
1: 0, 0
2: 0, 0
3: 0, 0
4: 0, 4
5: 70, 1
6: 22, 3
7: 230, 2
8: 182, 4
9: 134, 50
10: 234, 49
11: 209, 50
12: 213, 50
13: 185, 51
14: 189, 48
15: 161, 52
16: 137, 53
17: 140, 48

Для приема я использую Leonardo.

, 👍-1

Обсуждение

Ячейка EEPROM может выдерживать только ограниченное количество циклов записи. Вы должны быть очень осторожны при непрерывной записи в цикле(). Вы записываете 2 связанных элемента данных в EEPROM за цикл. Было бы лучше использовать структуру для упаковки двух элементов и выполнить операцию записи за один раз, используя метод put(). Для распаковки используйте метод get()., @6v6gt

Возможно, вы уже повредили некоторые ячейки EEPROM, превысив предел цикла записи. Вы можете начать, скажем, с ячейки 100 вместо ячейки 0, чтобы увидеть, являются ли результаты более последовательными. Однако не позволяйте коду бесконечно записывать в EEPROM и помните, что незаписанная ячейка EEPROM заполнена «1»., @6v6gt

Моя библиотека EEPROM поддерживает обновление, которое будет записываться только в случае изменения. Попробуйте использовать это. Также вы можете использовать FRAM и иметь неограниченное количество циклов чтения/записи., @Gil


1 ответ


0

Это работает.

#include <EEPROM.h>

const int EEPROM_SIZE = 100; // Определить размер доступной EEPROM
int addr = 0; // указатель адреса EEPROM

unsigned long programStartTime;

void setup()
{
  Serial.begin(9600);
  while (!Serial);
    Serial1.begin(9600);

  programStartTime = millis(); // Запись времени запуска программы

  // Инициализируем данные EEPROM
  // for (int i = 0; i < EEPROM_SIZE; i++) {
  // EEPROM.write(i, 0);
  // }
  displayEEPROMData();
}

void loop()
{
  if (Serial1.available())
  {
    int receivedData = Serial1.read();

    if (receivedData >= 1 && receivedData <= 60)
    {
      byte receivedValue = static_cast<byte>(receivedData); // Преобразуем в байт

      // Вычисляем временную метку на основе времени запуска программы
      unsigned long currentTime = millis() - programStartTime;

      // Сохраняем полученную метку времени и значение в EEPROM
      EEPROM.put(addr, currentTime);
      addr += sizeof(currentTime);
      EEPROM.put(addr, receivedValue);
      addr += sizeof(receivedValue);

      displayEEPROMData();
    }
  }

  if (addr >= EEPROM_SIZE) {
    addr = 0; // Перезагрузка, если EEPROM заполнена
  }

}

void displayEEPROMData() {
  // Отображение всех позиций, хранящихся в EEPROM
  Serial.println("EEPROM:");

  for (int i = 0; i < EEPROM_SIZE; i += sizeof(unsigned long) + sizeof(byte)) {
    unsigned long timestamp;
    byte value;
    EEPROM.get(i, timestamp);
    EEPROM.get(i + sizeof(timestamp), value);

    // Отображение данных о позиции с отметкой времени в формате ЧЧ:ММ:СС
    Serial.print(String(i / (sizeof(unsigned long) + sizeof(byte)) + 1) + ": ");
    Serial.println(String(timestamp) + ", " + String(value));
  }
}
,

Молодец, ответил на свой же вопрос, правда. Для будущих посетителей, включая вас самих через несколько недель, вы можете расширить свой ответ, объяснив, что случилось. Сравнение исходного кода показывает результат, но не путь к нему., @the busybee

Похоже, у вас есть еще одна проблема: вы отправляете целые числа (тип данных int) из Uno получателю. В Uno int представлен двумя байтами. На получателе вы получаете отдельные байты, но не пытаетесь собрать их пары для восстановления исходного целого числа., @6v6gt