EEPROM.get возвращает неверные данные

Я использую прилагаемый код. Я пытаюсь сделать следующее:

Проверить, записан ли в EEPROM индивидуальный "серийный номер платы" (с помощью предыдущего запуска кода) Если найденные данные не состояли из 7 символов (например, SN-XXXX), сгенерируйте серийный номер и сохраните его в EEPROM

Проблема в том, что он правильно генерирует серийный номер, даже сохраняет и считывает его несколько раз, но когда я отсоединяю USB-кабель и снова подключаюсь для проверки, он возвращает некоторые неверные данные из EEPROM, например: ⸮ ^R⸮y⸮|, который, кажется, проходит мой тест на 7 символов, но не создает новый.

Что я делаю не так?


#include <EEPROM.h>

// board SERIAL number
char serial_characters[] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"};
// will be filled as SN-A2KH
String serial_number;


void setup() {

  Serial.begin(9600);

  // Get the float data from the EEPROM at position 0
  EEPROM.get(0, serial_number);

  // serial from EEPROM valid
  if (serial_number.length() == 7) {
    Serial.println("Found valid serial in EEPROM");
    Serial.println(serial_number);
  }

  // serial from EEPROM not valid (e.g not: SN-XYZ5)
  if (serial_number.length() != 7) {

    Serial.println("Serial from eeprom is NOT 7 chars, generating a random serial");
    Serial.println(serial_number);

    // if analog input pin 0 is not connected, use noise from it in order to generate a random seed, otherwise random is not so random
    randomSeed(analogRead(0));

    // serial might be empty now, set a "SN-" prefix
    serial_number = "SN-";
    for (int i = 1; i <= 4 ; i++) {
      serial_number = serial_number + serial_characters[random(0, 35)];
    }
    Serial.println("Generated serial now: " + serial_number);

    // save to eeprom if format is valid
    if (serial_number.length() == 7) {
      EEPROM.put(0, serial_number);
      Serial.println("Written serial to EEPROM");
    }

  } // <<< serial from eeprom not correct, generated one

}

void loop() {}

, 👍2


2 ответа


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

7

Вы сохраняете объект String в EEPROM, что бесполезно. Строка объект не хранит содержимое вашей строки. Вместо этого просто магазины:

  • адрес памяти, где находится реальное содержимое (символы) хранится
  • объем памяти, выделенный для этого содержимого
  • количество символов, составляющих строку

Это то, что вы сохраняете и извлекаете из EEPROM. Таким образом, вы получаете правильное количество символов (третий пункт в списке выше), но адрес памяти теперь указывает на неинициализированное ОЗУ.

Я предлагаю вместо этого хранить в EEPROM необработанную строку C, т.е. 8 символов (7 печатных символов плюс завершающий NUL). Вы могли бы достичь это, просто изменив объявление serial_number:

char serial_number[8];

Для проверки правильности я бы просто проверил, что оно начинается с "SN-" и последний символ - NUL:

if (memcmp(serial_number, "SN-", 3) == 0 && serial_number[7] == '\0') {
    ...
}

Тем не менее, вы можете выполнить более строгую проверку и убедиться, что остальные 4 символа находятся в допустимом наборе.

Изменить: чтобы построить serial_number со случайными символами:

strcpy(serial_number, "SN-");
for (int i = 3; i < 7; i++)
  serial_number[i] = serial_characters[random(0, 36)];
serial_number[7] = '\0'; // завершение NUL
,

3

Просто чтобы получить полный рабочий код, я получил следующее:

#include <EEPROM.h>

char serial_characters[] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"};
// 7 символов для серийного номера и один для конца строки '\0'
char serial_number[8];

void setup() {

  Serial.begin(115200);

  EEPROM.get(0, serial_number);

  // проверка найденного формата
  if (serial_number[0] == 'S' && serial_number[1] == 'N'  && serial_number[2] == '-' && serial_number[7] == '\0') {

    Serial.println("serial from eeprom is valid");
    Serial.println((char*)serial_number);

  } else {

    Serial.println("no valid serial found in eeprom, generating new serial");

    // если аналоговый входной контакт 0 не подключен, используйте шум от него, чтобы сгенерировать случайное начальное число, иначе случайный не такой случайный
    randomSeed(analogRead(0));

    // генерируем новый сериал
    serial_number[0] = 'S';
    serial_number[1] = 'N';
    serial_number[2] = '-';

    // перезаписываем конечные символы серийного номера случайными значениями
    serial_number[3] = serial_characters[random(0, 35)];
    serial_number[4] = serial_characters[random(0, 35)];
    serial_number[5] = serial_characters[random(0, 35)];
    serial_number[6] = serial_characters[random(0, 35)];

    // конец строки с нулем в виде необработанных строк C ?!
    serial_number[7] = '\0';

    Serial.println((char*)serial_number);

    // записываем новый серийник в eeprom
    EEPROM.put(0, serial_number);

  }

}

void loop() {

}
,