Урок 14. EEPROM в Ардуино. Контроль целостности данных.

Arduino UNO R3

В уроке рассказывается, как работать с внутренним EEPROM платы Ардуино, о контроле целостности данных при хранении и передаче.

Предыдущий урок     Список уроков     Следующий урок

Внутреннее EEPROM в системе Ардуино.

EEPROM это энергонезависимая память. Расшифровывается как электрически стираемое программируемое постоянное запоминающее устройство. Применяется для хранения данных, которые должны быть сохранены при выключении питания.

 

Платы Ардуино имеют EEPROM разных объемов в зависимости от типа используемого микроконтроллера.

Микроконтроллер Объем внутреннего EEPROM
ATmega328 1024 байт
ATmega8, ATmega168 512 байт
ATmega1280, ATmega2560 4096 байт

Такого объема памяти вполне достаточно для хранения режимов, технологических параметров, коэффициентов и т.п.

  • Принцип действия EEPROM основан на создании электрического заряда в диэлектрике полупроводниковой структуры. Заряды вечно не хранятся, но разработчики гарантируют 20 лет.
  • EEPROM имеет ограниченное число циклов записи, обычно не менее 100 000.
  • Для записи информации в EEPROM требуется достаточно большое время, порядка 3 мс.
  • Чтение EEPROM происходит без задержки и ресурс работы памяти не уменьшает.

Библиотека EEPROM.

Для работы с энергонезависимой памятью в Ардуино есть библиотека EEPROM. Она имеет две функции для записи и чтении байта в EEPROM.

byte read(int address)

Функция возвращает считанный по адресу address байт.

#include <EEPROM.h>
byte dt; dt= EEPROM.read(15);  // чтение байта по адресу 15

void write(int address, byte value)

Записывает байт value по адресу address в EEPROM. Запись выполняется за 3,3 мс. Гарантируется 100 000 циклов записи.

#include <EEPROM.h>
EEPROM.write(15, 0);  // запись 0 по адресу 15

 

Программа проверки записи в EEPROM.

Давайте напишем простую программу проверки работы EEPROM. Программа должна записывать до 16ти символов, принятых с последовательного порта и в цикле выводить 16 символов, считанных из EEPROM. С помощью монитора порта Arduino IDE мы сможем записывать данные в EEPROM и контролировать содержимое энергонезависимой памяти.

// проверка работы EEPROM
#include <EEPROM.h>
int i, d;

void setup() {
    Serial.begin(9600); // инициализируем порт, скорость 9600
}

void loop() {
  // чтение EEPROM и вывод 16 данных в последовательный порт
  Serial.println();
  Serial.print("EEPROM= ");
  i= 0; while(i < 16) { 
  Serial.print((char)EEPROM.read(i));
  i++;   
  }
 
  // проверка есть ли данные для записи
  if ( Serial.available() != 0 ) {
    delay(50);  // ожидание окончания приема данных

    // запись в EEPROM
    i= 0; while(i < 20) { 
    d= Serial.read();
    if (d == -1) d= ' ';  // если символы закончились, заполнение пробелами
    EEPROM.write(i, (byte)d);   // запись EEPROM
    i++;
    }     
  } 
  delay(500);
}

Загружаем программу в плату Ардуино, проверяем. Открываем монитор порта, посылаем данные на плату:”Проверка EEPROM”.

Окно монитора портаДанные записываются в EEPROM и теперь в цикле выводятся в окне монитора. Если мы отключим плату от компьютера и затем снова подключим, то данные будут продолжать посылаться на компьютер. Они сохранены в энергонезависимой памяти и при выключении питания платы не меняются.

 

Контроль целостности данных.

В EEPROM обычно хранят данные абсолютно необходимые для работы программы. Например, если вы делаете регулятор температуры, то это может быть : заданная температура, коэффициенты регуляторов, параметры защитных функций и т.п. Представьте, что эти параметры будут испорчены, а регулятор продолжит работу. Он может включить нагревательный элемент на полную мощность и выставить недопустимо высокую температуру. При неправильных коэффициентах регулятор может “пойти в разнос”. Перестанут работать защитные функции. Неприятности будут большие.

А ведь ситуация, когда в EEPROM могут оказаться недостоверные данные вполне реальная.

  • При первом включении устройства данные в EEPROM недостоверны. Их просто никто еще не задавал.
  • В момент записи данных в EEPROM может отключиться питание платы и тогда часть данных запишется, а часть не успеет.
  • EEPROM имеет ограниченное число циклов записи, и это свойство также может привести к разрушению данных в этой памяти.

Поэтому крайне важно быть уверенными, что в EEPROM хранятся достоверные данные. В случае, если они ошибочны, программа должна принять определенные действия. Это может быть:

  • использовать копию данных из EEPROM;
  • использовать данные специально созданные для аварийного режима;
  • отключить устройство;
  • сигнализировать об ошибке;
  • и много других вариантов.

Целостность данных это показатель, того что данные не были изменены при хранении, передаче, отображении и т.п. Целостность данных может проверяться в любой ситуации, потенциально опасной для разрушения данных. Обычно контроль достоверности данных производят:

  • В энергонезависимой памяти (EEPROM, FLASH, HDD…).
  • При передаче данных ( последовательные интерфейсы, WiFi, GSM, TCP/IP…).
  • В оперативной памяти для особо важных данных.
  • Некоторые компоненты (например, датчик DS18B20) имеют протокол обмена данными с контролем целостности.

Для контроля целостности к блоку данных добавляется контрольный код. Этот код рассчитывается по определенному алгоритму при записи данных. При проверке данных код заново вычисляется и сравнивается с кодом, сформированным при записи. Если коды не совпадают – данные ошибочны.

Алгоритм расчета контрольного кода определяет вероятность определения ошибки данных.  Существует большое число алгоритмов формирования контрольных кодов: циклические коды, различные функции хэширования. Но самым простым способом вычисления контрольного кода является контрольная сумма.

Просто делается математическая сумма всех байтов блока данных. Такой алгоритм требует минимума ресурсов для реализации, и в то же время позволяет с достаточно высокой вероятностью определить ошибочные данные в случае небольших объемов информации. Контрольная сумма может быть разной разрядности. В минимальном варианте это один байт. В этом случае происходит переполнение результата суммы, что уменьшает вероятность обнаружения ошибок.

Я всегда к вычисленной контрольной сумме применяю операцию “исключающее ИЛИ” с кодом подобным E5h. Это позволяет исключить весьма вероятную ситуацию, когда все данные равны 0. Сумма 0 равна 0. Поэтому если блок данных будет ошибочно обнулен (а это бывает), то простая сумма не вычислит эту ошибку.  А когда контрольная сумма для всех 0 равна E5h, то ошибка будет выявлена.

Давайте добавим в предыдущую программу контроль целостности данных.

// проверка работы EEPROM
#include <EEPROM.h>
int i, d;
byte sum; // контрольная сумма

void setup() {
    Serial.begin(9600); // инициализируем порт, скорость 9600
}

void loop() {
  // вычисление контрольной суммы
  sum= 0;
  i= 0; while(i < 16) { 
  sum += EEPROM.read(i); 
  i++;
  }
  // проверка контрольной суммы
  if ( (sum^0xe5) == EEPROM.read(i)) {
    // контрольна сумма правильная
   
    // чтение EEPROM и вывод 16 данных в последовательный порт 
    Serial.println();
    Serial.print("EEPROM= ");
    i= 0; while(i < 16) { 
    Serial.print((char)EEPROM.read(i));
    i++;   
    }   
  }
  else {
    // контрольная сумма неправильная
    Serial.println();
    Serial.print("EEPROM= data error");       
  }
   
  // проверка есть ли данные для записи
  if ( Serial.available() != 0 ) {
    delay(50);  // ожидание окончания приема данных

    // запись в EEPROM
    sum= 0;
    i= 0; while(i < 16) { 
    d= Serial.read();
    if (d == -1) d= ' ';  // если символы закончились, заполнение пробелами
    EEPROM.write(i, (byte)d);   // запись EEPROM
    sum += (byte)d;   // вычисление контрольной суммы
    i++;
    }   
    EEPROM.write(i, sum ^ 0xe5);   // запись контрольной суммы 
  } 
  delay(500);
}

Отмечу только, что программа принимает не 16, а 14 символов, т.к. монитор порта добавляет к каждой строке символы переноса строки \r и \n.

Загрузим программу и запустим монитор.

Окно монитора порта

В окне бегут сообщения об ошибке данных. Мы еще не загрузили в EEPROM никаких данных, и алгоритм распознает эту ситуацию. Пошлем строку, например, ”проверка”. Теперь в окне отображаются данные из EEPROM.

Окно монитора порта

Таким же образом можно защищать целостность данных при передаче по последовательному порту. Любая импульсная помеха может исказить сигнал в кабеле связи и вызвать ошибку данных. Конечно, программа приема данных на компьютере должна поддерживать протокол с контрольной суммой. Монитор порта Arduino IDE этой функции не имеет.

 

В следующем уроке узнаем, что такое указатели в C для Ардуино, научимся записывать в EEPROM данные различных типов (int, float…).

Предыдущий урок     Список уроков     Следующий урок

14 комментариев на «Урок 14. EEPROM в Ардуино. Контроль целостности данных.»

  1. Как загрузить программу узи дальномера в ардуино и сохранить скотч при выключении питания

    • В уроке 3 написано как загрузить. Загрузить в программу Arduino IDE и нажать кнопку «->».
      Программа загрузится во Flash память и останется там до следующей загрузки.

  2. Вы написали ссылку на команду Е5h, эта команда ассемблера? Могли бы пояснить про нее, или литературу подсказать.

    • E5h это не команда Ассемблера. Это просто число, которое прибавляется к контрольной сумме для исключения ситуации, когда все данные равны 0 и контрольная сумма равна 0.
      Я цитирую из урока:
      «Я всегда к вычисленной контрольной сумме применяю операцию “исключающее ИЛИ” с кодом подобным E5h. Это позволяет исключить весьма вероятную ситуацию, когда все данные равны 0. Сумма 0 равна 0. Поэтому если блок данных будет ошибочно обнулен (а это бывает), то простая сумма не вычислит эту ошибку. А когда контрольная сумма для всех 0 равна E5h, то ошибка будет выявлена.»

  3. Хороший способ, но есть один недостаток.
    Если в программе допустим изменяются в настройках не все данные, а только часть и их нужно будет сохранять при выходе из меню. А данных к примеру очень много. То нужно будет каждый раз пересчитывать контрольную сумму для всех данных.

  4. А если данных много, но памяти предостаточно, то может записывать дубликат значения и сравнивать при чтении? При этом можно создать процедуру записи значения сразу в несколько адресов… единственный недостаток — долгая запись. Но при изменении части данных, можно только часть и перезаписать.

  5. А как сделать в eeprom изначально таблицу так же как мы в flash памяти размещаем константы? Чтоб при загрузке скетча в eeprom прописывались исходные данные а программа потом уже их меняла.

    • Я задавался этим вопросом, но не нашел решения. В Ардуино даже не возможно просто на этапе компиляции загрузить данные в EEPROM.

      • Решил что просто надо написать отдельный скетч загрузки данных в EEPROM и запускать когда нужно.

  6. А если сделать счетчик импульсов с записью результатов на энергонезависимую память, чтоб при выключении результат не сбивался и при включении продолжал отсчеты, запись данных нужно сохранять в епром, или на флэш память?

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *