logo
+7 (951) 999-89-94
428003, г. Чебоксары, ул. Федора Гладкова, д.9, оф.319

Работа с памятью M25P40. Часть 14. Пишем библиотеку для M25P40 (2)

Теперь давайте поближе рассмотрим процесс перевода кода скетча в код библиотеки и разберём принципы такого перевода на конкретных примерах. Будем рассматривать организацию работы функций в скетче и в составе нашей библиотеки.

Начнём с организации кода библиотеки my25p40 (начало и подробные пояснения см. в предыдущей статье).

Код библиотеки my25p40

В соответствии с нашим планом и моделью создания библиотеки my25p40, нам нужно создать обёртку над кодом исходной библиотеки SPIFlash. Для этого мы создадим класс-наследник, который, соответственно, унаследует все свойства библиотеки SPIFlash, а также получит новые, нужные нам функции по работе с различными типами данных.

Рассмотрим шаблон такого класса, который потом будет использоваться в файле my25p40.h.

class my25p40 : public SPIFlash {
  private:

  public:
    explicit my25p40(uint8_t slaveSelectPin, uint16_t jedecID=0) : SPIFlash(slaveSelectPin, jedecID=0) { };
    
    …
    …
    ...

};

Здесь мы создаём новый класс my25p40, наследуя его от класса SPIFlash и делая его свойства доступными.

class my25p40 : public SPIFlash {

И создаём конструктор, давая возможность указывать только один параметр при инициализации.

    explicit my25p40(uint8_t slaveSelectPin, uint16_t jedecID=0) : SPIFlash(slaveSelectPin, jedecID=0) { };

А в файле my25p40.cpp мы будем создавать код нужных нам функций нового класса my25p40 (подробнее об этом будет рассказано чуть ниже).

Полный код нового класса my25p40 со всеми будущими функциями будет выглядеть так:

class my25p40 : public SPIFlash {
  private:

  public:
    explicit my25p40(uint8_t slaveSelectPin, uint16_t jedecID=0) : SPIFlash(slaveSelectPin, jedecID=0) { };
    
    void checkBusy();
    
    void initInfo();
    void readInfo(uint32_t adr, String s);
    void writeInfo(uint32_t adr, String s);
    
    void erase();
    void erase64K(byte sec);
    
    void writeWord(uint32_t adr, word w);
    word readWord(uint32_t adr);
    
    void writeULong(uint32_t adr, unsigned long ul);
    unsigned long readULong(uint32_t adr);
    
    void writeInt(uint32_t adr, int i);
    int readInt(uint32_t adr);
    
    void writeLong(uint32_t adr, long lg);
    long readLong(uint32_t adr);
    
    void writeFloat(uint32_t adr, float fl);
    float readFloat(uint32_t adr);
    
    void writeChars(uint32_t adr, char chs[], byte len);
    void readChars(uint32_t adr, char *buf, byte len);
    
    void writeString(uint32_t adr, String s);
    String readString(uint32_t adr, byte len);
};

Теперь в качестве примера исходного кода для переноса в библиотеку рассмотрим код скетча M25P40 Read & Write Word.

Код скетча M25P40 Read & Write Word

Этот скетч содержит функции работы (чтения и записи) данных типа word, а также некоторые вспомогательные функции и подробно был разобран в одной из наших предыдущих статей.

/*
  M25P40 Read & Write Word
*/

#include <SPI.h>
#include <SPIFlash .h>

#define FLASH_SS 8

#define TEST_ADR 0
#define TEST_VAL 65000

SPIFlash flash(FLASH_SS);

void setup() {
  Serial.begin(115200);
  Serial.println(F("M25P40 Read & Write Word start..."));

  Serial.print(F("Init "));
  if (flash.initialize()) {Serial.println(F("OK"));}
                     else {Serial.println(F("FAIL"));}

  erase();
  readWord(TEST_ADR);
  writeWord(TEST_ADR, TEST_VAL);
  readWord(TEST_ADR);
}

void checkBusy() {
  uint32_t stt = millis();
  while (flash.busy()) { }
  uint32_t del = millis() - stt;
  if (del) {
    Serial.print(F(" (")); Serial.print(del); Serial.print(F(" ms)"));
  }
  Serial.println();
}

void erase() {
  Serial.print(F("Full erase..."));
  flash.chipErase();
  checkBusy();
}

void readWord(uint32_t adr) {
  byte bytes[2];
  flash.readBytes(adr, bytes, 2);
  word wordValue = (bytes[0] << 8) | bytes[1] & 0xFF;
  Serial.print(F("Read #")); Serial.print(adr); Serial.print(F(": ")); Serial.println(wordValue);
}

void writeWord(uint32_t adr, word w) {
  byte bytes[2];
  bytes[0] = highByte(w);
  bytes[1] = lowByte(w);
  flash.writeBytes(adr, bytes, 2);
  Serial.print(F("Write #")); Serial.print(adr); Serial.print(F(": ")); Serial.println(w);
}

void loop() {
  
}

Начнём мы с функции checkBusy(), о назначении и принципе работы этой функции см. предыдущие статьи цикла.

void checkBusy() {
  uint32_t stt = millis();
  while (flash.busy()) { }
  uint32_t del = millis() - stt;
  if (del) {
    Serial.print(F(" (")); Serial.print(del); Serial.print(F(" ms)"));
  }
  Serial.println();
}

Наша задача — перенести эту функцию в библиотеку, соответствующим образом модифицировав её (в соответствии с правилами создания библиотек).

Прежде всего нужно указать новую функцию внутри описания класса my25p40 в файле my25p40.h.

class my25p40 : public SPIFlash {
  private:

  public:
    explicit my25p40(uint8_t slaveSelectPin, uint16_t jedecID=0) : SPIFlash(slaveSelectPin, jedecID=0) { };
    
    void checkBusy();

А также создать вариант этой функции в файле имплементации my25p40.cpp.

// Busy

void my25p40::checkBusy() {
  uint32_t stt = millis();
  while (busy()) { }
  uint32_t del = millis() - stt;
  if (del) {
    Serial.print(F(" (")); Serial.print(del); Serial.print(F(" ms)"));
  }
  Serial.println();
}

Как вы видите, код функции checkBusy() в скетче и в библиотеке практически идентичны, разница заключается только в принадлежности к классу my25p40, во втором случае.

Скетч:

void checkBusy() {

Библиотека:

void my25p40::checkBusy() {

И пример использования библиотечного варианта функции checkBusy() в модернизированном скетче.

Создание объекта:

my25p40 flash(FLASH_SS);

Использование библиотечной функции checkBusy():

flash.checkBusy();

Код модернизированного скетча my25p40 Library Read & Write Word

Приведём код модернизированного скетча my25p40 Library Read & Write Word, который понадобится нам для дальнейшей работы. Это тот же скетч M25P40 Read & Write Word, только адаптированный для работы с библиотекой my25p40.

/*
  my25p40 Library Read & Write Word
*/

#include <SPI.h>
#include <my25p40.h>

#define FLASH_SS 8

#define TEST_ADR 0
#define TEST_VAL 65000

my25p40 flash(FLASH_SS);

void setup() {
  Serial.begin(115200);
  Serial.println(F("my25p40 Library Read & Write Word start..."));

  flash.initInfo();
  flash.erase();
  
  flash.readInfo(TEST_ADR, String(flash.readWord(TEST_ADR)));
  
  flash.writeWord(TEST_ADR, TEST_VAL);
  flash.writeInfo(TEST_ADR, String(TEST_VAL));
  
  flash.readInfo(TEST_ADR, String(flash.readWord(TEST_ADR)));
}

void loop() {
  
}

Разберём его работу на примере функции initInfo().

Функция initInfo()

В оригинальном (изначальном) скетче есть фрагмент кода, который инициализирует чип M25P40VP и выводит соответствующее сообщение.

  Serial.print(F("Init "));
  if (flash.initialize()) {Serial.println(F("OK"));}
                     else {Serial.println(F("FAIL"));}

Наша задача состоит в том, чтобы упаковать этот код в функцию, а саму функцию поместить в нашу библиотеку my25p40. Для этого нужно добавить соответствующий заголовок в файл my25p40.h.

class my25p40 : public SPIFlash {
  private:

  public:
    explicit my25p40(uint8_t slaveSelectPin, uint16_t jedecID=0) : SPIFlash(slaveSelectPin, jedecID=0) { };
    
    void checkBusy();
    
    void initInfo();

А в файл my25p40.cpp поместить код самой новой функции initInfo(), оформив её соответствующим образом.

// Info

void my25p40::initInfo() {
  Serial.print(F("Init "));
  if (initialize()) {Serial.println(F("OK"));}
                     else {Serial.println(F("FAIL"));}
}

Тогда мы сможем её использовать в нашем новом модернизированном скетче my25p40 Library Read & Write Word.

void setup() {
  Serial.begin(115200);
  Serial.println(F("my25p40 Library Read & Write Word start..."));

  flash.initInfo();

Функция erase()

Аналогичным образом мы можем поступить с функцией полного стирания всей памяти чипа M25P40VP erase().

Её исходный вариант в скетче:

void erase() {
  Serial.print(F("Full erase..."));
  flash.chipErase();
  checkBusy();
}

И её сестра-близнец в библиотеке.

// Erase

void my25p40::erase() {
  Serial.print(F("Full erase..."));
  chipErase();
  checkBusy();
}

Функции readInfo() и writeInfo()

В исходном скетче мы видим громоздкую конструкцию

void readWord(uint32_t adr) {
  byte bytes[2];
  flash.readBytes(adr, bytes, 2);
  word wordValue = (bytes[0] << 8) | bytes[1] & 0xFF;
  Serial.print(F("Read #")); Serial.print(adr); Serial.print(F(": ")); Serial.println(wordValue);
}

где выводом данных о прочитанном из памяти значении занимается строка

  Serial.print(F("Read #")); Serial.print(adr); Serial.print(F(": ")); Serial.println(wordValue);

В библиотечном варианте мы видим более изящный вывод этой информации, оформленный в специализированную функцию.

void my25p40::readInfo(uint32_t adr, String s) {
  Serial.print(F("Read #")); Serial.print(adr); Serial.print(F(": ")); Serial.println(s);
}

То же самое относится и к выводу информации о записанном в память значении.

void my25p40::writeInfo(uint32_t adr, String s) {
  Serial.print(F("Write #")); Serial.print(adr); Serial.print(F(": ")); Serial.println(s);
}

Здесь также в качестве параметров передаются значение адреса ячейки памяти и само значение в виде его строкового представления.

И пример использования в скетче функции writeInfo():

  flash.writeInfo(TEST_ADR, String(TEST_VAL));

Заключение

На этом мы завершим первый этап знакомства с кодом библиотеки my25p40 и в заключение приведём скриншоты работы двух скетчей — оригинального и модернизированного для использования нашей новой библиотеки.

Результат работы оригинального скетча:

И результат работы скетча, модернизированного для использования библиотеки my25p40:

Как вы видите, результат работы нового скетча, использующего нашу библиотеку my25p40, полностью идентичен работе оригинального скетча. А выигрыш в сложности и объёме кода старого и нового скетчей составляет 5 раз в пользу нового скетча.

Ссылки по теме

Обзор контроллера uniSensors nRF24

Спецификации uniSensors nRF24

Программирование uniSensors nRF24

Работа с памятью M25P40. Часть 1. Спецификации и библиотека

Работа с памятью M25P40. Часть 2. Sleep, Wakeup, Erase и Busy

Работа с памятью M25P40. Часть 3. Read и Write Byte и Arrays

Работа с памятью M25P40. Часть 4. Работа с беззнаковыми типами данных

Работа с памятью M25P40. Часть 5. Работа со знаковыми типами данных

Работа с памятью M25P40. Часть 6. Read и Write Float

Работа с памятью M25P40. Часть 7. Read и Write Char array и String

Работа с памятью M25P40. Часть 8. Работа с секторами

Работа с памятью M25P40. Часть 9. Выборочное стирание секторов

Работа с памятью M25P40. Часть 10. Копирование секторов

Работа с памятью M25P40. Часть 11. Восстановление (backup) секторов

Работа с памятью M25P40. Часть 12. Работа с блоками памяти

Работа с памятью M25P40. Часть 13. Пишем библиотеку для M25P40

Работа с памятью M25P40. Часть 14. Пишем библиотеку для M25P40 (2)

Работа с памятью M25P40. Часть 15. Пишем библиотеку для M25P40 (3)

Техническая поддержка

Мы внимательно относимся к потребностям наших клиентов и осуществляем техническую поддержку всей выпускаемой продукции. Вы можете написать нам письмо с вашим вопросом или позвонить по телефону и специалист нашей компании проконсультирует вас и поможет решить вашу проблему.

  • Емейл для вопросов по нашей продукции: electromicro@bk.ru
  • Наш телефон: +7 (495) 997-37-74

Аналогичные товары