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() {}
@adrianTNT, 👍2
2 ответа
Лучший ответ:
Вы сохраняете объект 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
Просто чтобы получить полный рабочий код, я получил следующее:
#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() {
}
- Как увеличить скорость записи на SD-карту в Ардуино
- ESP8266 12e Arduino IDE выводит мусорные значения на serial monitor
- Как постоянно считывать/записывать переменные на Arduino Due (без EEPROM/shield)?
- Пытаюсь прошить ESP8266 с помощью Arduino UNO
- Файловая система внешней флэш-памяти
- Соответствие скорости передачи данных на последовательном мониторе
- Arduino EEPROM сохраняет старые данные после прошивки новой программой
- ESP32: лучший способ встраивания сертификатов