чтение свойств устройства или платы с устройства Arduino MKR WiFi 1010
Как программно прочитать специфические свойства устройства с чипа или платы Arduino MKR WiFi 1010?
Например, следующие свойства устройства:
- любой идентификационный номер, который может однозначно идентифицировать физическое устройство, целое число, GUID, строку или любой другой, как его прочитать из кода?
- Серийный номер устройства MRK WiFi 1010
- Номер модели устройства MRK WiFi 1010
Я пытался просмотреть документацию и примеры, но ничего не нашел.
2 ответа
Лучший ответ:
MAC-адрес может быть вам полезен, но помните, что это может быть подделано. Кроме того, серийные номера и номера моделей не доступны на программном уровне.
Вот простая реализация получения MAC-адреса
#include <WiFiNINA.h>
void setup() {
Serial.begin(9600);
while (!Serial);
if (WiFi.status() == WL_NO_MODULE) {
Serial.println("Communication with WiFi module failed!");
while (true);
}
byte mac[6];
WiFi.macAddress(mac);
Serial.print("MAC: ");
for (int i = 5; i >= 0; i--) {
if (mac[i] < 16) {
Serial.print("0");
}
Serial.print(mac[i], HEX);
if (i > 0) {
Serial.print(":");
}
}
Serial.println();
}
void loop() {}
Другое решение, которое я могу придумать, — это записать свой собственный уникальный идентификатор, например UUID, в память EEPROM для каждой платы.
Если вы генерируете UUID в контексте сервера или устройства с большим количеством ресурсов, существуют библиотеки и инструменты, которые могут создать их для вас на основе различных факторов для обеспечения уникальности (например, метка времени, MAC-адрес и т. д.). ). Однако с микроконтроллером, подобным тому, что установлен на Arduino MKR WiFi 1010, у вас более ограниченная среда, и процесс может быть более ручным.
Вы можете использовать онлайн-генератор UUID или сгенерировать его с помощью Python:
import uuid
print(uuid.uuid4())
После создания UUID вы можете записать их в EEPROM, но не перезаписывайте EEPROM, поскольку границы вызовов очень ограничены.
Запись в EEPROM
#include <EEPROM.h>
const char* MY_UUID = "550e8400-e29b-41d4-a716-446655440000";
const int EEPROM_UUID_ADDRESS = 0; // начальный адрес в EEPROM
void setup() {
Serial.begin(9600);
// Записываем UUID в EEPROM
for (int i = 0; i < strlen(MY_UUID); i++) {
EEPROM.write(EEPROM_UUID_ADDRESS + i, MY_UUID[i]);
}
Serial.println("UUID written to EEPROM");
}
void loop() {}
"начальный адрес в EEPROM" — это адрес первого поля (или байта), в котором программа начинает хранить наш UUID. Указывая const int EEPROM_UUID_ADDRESS = 0;
, мы говорим, что начнем хранить UUID с самого первого байта (поля) EEPROM. Если вы храните в EEPROM другие данные, вам необходимо убедиться, что адреса не перекрываются. Например, если в первых 10 байтах хранятся другие данные, вы можете установить для EEPROM_UUID_ADDRESS
значение 10, чтобы начать сохранение UUID с 11-го байта.
Чтение из EEPROM:
#include <EEPROM.h>
const int UUID_LENGTH = 36; // Длина строки UUID
char readUUID[UUID_LENGTH + 1]; // +1 для нулевого терминатора
const int EEPROM_UUID_ADDRESS = 0; // начальный адрес в EEPROM
void setup() {
Serial.begin(9600);
// Читаем UUID из EEPROM
for (int i = 0; i < UUID_LENGTH; i++) {
readUUID[i] = EEPROM.read(EEPROM_UUID_ADDRESS + i);
}
readUUID[UUID_LENGTH] = '\0'; // Нуль завершает строку
Serial.print("UUID read from EEPROM: ");
Serial.println(readUUID);
}
void loop() {}
+1 за нулевой терминатор:
В языках программирования C и C++ строки представляются как массив символов. Конец строки отмечен специальным символом, известным как «нулевой терминатор». или «нулевой символ», который представлен значением '\0'
(байт, все биты которого установлены в 0).
Когда мы читаем или записываем строки в/из памяти (например, EEPROM), нам часто необходимо учитывать этот нулевой терминатор, чтобы гарантировать правильное завершение строки и ее безопасное использование со строковыми функциями.
В коде длина UUID составляет 36 символов. Когда мы объявляем массив для хранения этого UUID с помощью строки:
char readUUID[UUID_LENGTH + 1];
Мы выделяем место для 36 символов UUID плюс дополнительный символ для нулевого терминатора, следовательно, UUID_LENGTH + 1
.
Позже, после чтения UUID из EEPROM, мы проверяем, что этот массив является правильно завершенной строкой, добавляя нулевой терминатор:
readUUID[UUID_LENGTH] = '\0';
Это гарантирует, что когда мы используем readUUID
в функциях, ожидающих строку, они распознают, где заканчивается строка. Без нулевого терминатора эти функции не знали бы, где заканчивается строка, что приводило бы к непредсказуемому поведению или ошибкам.
Надеюсь, это будет полезно.
Спасибо. Есть еще несколько способов получить информацию о плате: это серийный номер USB-устройства, который хранится в чипе FTDI. Однако Arduino не может читать данные с чипа FTDI, и второй способ выглядит следующим образом: если определено (__AVR_ATmega2560__)
, @Semen Shekhovtsov
да, я знаю, что чип FTDI содержит серийный номер USB-устройства, но я понял, что иногда производители чипов присваивают одни и те же номера VID и PID разным платам, которые они производят. если вы хотите прочитать значения из чипа FTDI, вы, кстати, можете использовать Python. используя Serial и ftdi, вы можете получить первый доступный серийный номер устройства FTDI и отправить его в Arduino через последовательный порт COM3. если хотите, я могу показать, как это сделать. использование «если определено (__AVR_ATmega2560__)» не различит две платы ATmega, не так ли?, @b1n3t
правильно, использование если определено (__AVR_ATmega2560__)
не позволит различать две платы ATmega., @Semen Shekhovtsov
Хотели бы вы попробовать очень сложный способ прочитать FTDI в вашей ОС и затем отправить его в ArduinoIDE? выглядит как хороший вызов для работы., @b1n3t
Я думаю, что особой разницы между сохранением UUID и серийного номера чипа FTDI в EEPROM нет. Хранить надо точно так же, @Semen Shekhovtsov
на MKR WiFi 1010 нет FTDI. В MCU есть родной USB. и у него есть доступный серийный номер, @Juraj
Ах, спасибо, что сообщили нам, Юрай, похоже, ты прав. Я предположил, что он использует FTDI, как утверждал Шеховцов. MKR WIFI 1010 использует SAMD21, таблица данных которого имеется: https://ww1.microchip.com/downloads/en/DeviceDoc/SAM_D21_DA1_Family_DataSheet_DS40001882F.pdf. и кажется, что адреса серийного номера: 0x0080A00C, 0x0080A040, 0x0080A044, 0x0080A048 ----- слова от 0 до 3. их можно просто прочитать так: id[0] = *( Летучие uint32_t *)0x0080A00C; и так далее..., @b1n3t
IDE показывает серийный номер, поэтому я заглянул в ядро SAMD и нашел функцию, которая считывает серийный номер из регистров. Он находится в файле CDC.cpp
uint8_t Serial_::getShortName(char* name) {
// из раздела 9.3.3 даташита
#define SERIAL_NUMBER_WORD_0 *(volatile uint32_t*)(0x0080A00C)
#define SERIAL_NUMBER_WORD_1 *(volatile uint32_t*)(0x0080A040)
#define SERIAL_NUMBER_WORD_2 *(volatile uint32_t*)(0x0080A044)
#define SERIAL_NUMBER_WORD_3 *(volatile uint32_t*)(0x0080A048)
utox8(SERIAL_NUMBER_WORD_0, &name[0]);
utox8(SERIAL_NUMBER_WORD_1, &name[8]);
utox8(SERIAL_NUMBER_WORD_2, &name[16]);
utox8(SERIAL_NUMBER_WORD_3, &name[24]);
return 32;
}
из технического описания SAMD21:
Каждое устройство имеет уникальный 128-битный серийный номер, который представляет собой объединение четырех 32-битных слов, содержащихся в следующие адреса:
Уникальность серийного номера гарантируется только при использовании всех 128 бит
- Программный последовательный конфликт с Wi-Fi на ESP8266
- SoftwareSerial данные недоступны
- Не удается получить данные от GPS SD Shield V2-B
- C++ против языка Arduino?
- avrdude ser_open() can't set com-state
- Как читать и записывать EEPROM в ESP8266
- Float печатается только 2 десятичных знака после запятой
- устаревшее преобразование из строковой константы в 'char*'
MAC-адрес уникален. https://www.arduino.cc/reference/en/libraries/wifinina/wifi.macaddress/, @Juraj