В прошлой статье мы рассмотрели «упаковку» в библиотеку и использование некоторых «системных» функций работы с чипом M25P40VP, в этой статье мы рассмотрим перенос в библиотеку my25p40 некоторых функций для работы с различными типами данных, а также приведём полный код самой библиотеки, содержащийся в файлах my25p40.h и my25p40.cpp.
Начнём с функций readWord() и writeWord(), предназначенных для чтения и записи в память микросхемы M25P40VP данных типа word (беззнаковых двухбайтовых в диапазоне от 0 до 65535).
Функция writeWord()
Вот код этой функции, который мы использовали в оригинальном скетче M25P40 Read & Write Word:
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); }
Здесь сочетается как код самой функции writeWord(), так и код вывода в Serial данных о записываемом в память значении. В предыдущей статье мы уже разобрали модернизированный код вывода в Serial при помощи функции writeInfo(), приведём здесь только новый код библиотечной функции writeWord().
// Word void my25p40::writeWord(uint32_t adr, word w) { byte bytes[2]; bytes[0] = highByte(w); bytes[1] = lowByte(w); writeBytes(adr, bytes, 2); }
И код из скетча (см. предыдущие статьи цикла), который использует для своей работы код обеих новых библиотечных функций
flash.writeWord(TEST_ADR, TEST_VAL); flash.writeInfo(TEST_ADR, String(TEST_VAL));
Функция readWord()
Аналогично для функции readWord(), старый вариант:
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); }
Библиотечная функция:
word my25p40::readWord(uint32_t adr) { byte bytes[2]; readBytes(adr, bytes, 2); word wordValue = (bytes[0] << 8) | bytes[1] & 0xFF; return wordValue; }
И пример использования:
flash.readInfo(TEST_ADR, String(flash.readWord(TEST_ADR)));
Мы разобрали функции работы с данными типа word, библиотека содержит функции работы с остальными популярными типами данных (long, float, String и т. д.), вы можете самостоятельно разобрать их работу по аналогии с рассмотренными функциями работы с данными типа word.
Далее мы приведём полный код библиотеки my25p40.h.
Код файла my25p40.h
Теперь приведём полный код заголовочного файла my25p40.h:
/* My m25p40 Library version 0.1 2021, electromicro.ru License: GNU GPL 2.1 */ #ifndef MY25P40_H #define MY25P40_H #include <Arduino.h> #include "SPIFlash/SPIFlash.h" #define FLASH_SECTOR_SIZE 65536 union uib_t {byte b[2]; int i;}; union ulb_t {byte b[4]; unsigned long ul;}; union lb_t {byte b[4]; long lg;}; union flb_t {byte b[4]; float fl;}; extern uib_t uib; extern ulb_t ulb; extern lb_t lb; extern flb_t flb; 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); }; #endif // #ifndef MY25P40_H
Код файла my25p40.cpp
И полный код файла библиотеки my25p40.cpp:
/* My m25p40 Library version 0.1 2021, electromicro.ru License: GNU GPL 2.1 */ #ifndef MY25P40_CPP #define MY25P40_CPP #include "my25p40.h" // 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(); } // Info void my25p40::initInfo() { Serial.print(F("Init ")); if (initialize()) {Serial.println(F("OK"));} else {Serial.println(F("FAIL"));} } 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); } // Erase void my25p40::erase() { Serial.print(F("Full erase...")); chipErase(); checkBusy(); } uint32_t sectorAdr(byte i) { return FLASH_SECTOR_SIZE * i; } void my25p40::erase64K(byte sec) { uint32_t adr = sectorAdr(sec); Serial.print(F("Sector ")); Serial.print(sec); Serial.print(F(" (")); Serial.print(adr); Serial.print(F(" + 64K) erase...")); blockErase64K(adr); checkBusy(); } // Word void my25p40::writeWord(uint32_t adr, word w) { byte bytes[2]; bytes[0] = highByte(w); bytes[1] = lowByte(w); writeBytes(adr, bytes, 2); } word my25p40::readWord(uint32_t adr) { byte bytes[2]; readBytes(adr, bytes, 2); word wordValue = (bytes[0] << 8) | bytes[1] & 0xFF; return wordValue; } // Unsigned long ulb_t ulb; void invertULong() { byte bytes[4]; bytes[0] = ulb.b[0]; bytes[1] = ulb.b[1]; bytes[2] = ulb.b[2]; bytes[3] = ulb.b[3]; ulb.b[0] = bytes[3]; ulb.b[1] = bytes[2]; ulb.b[2] = bytes[1]; ulb.b[3] = bytes[0]; } void my25p40::writeULong(uint32_t adr, unsigned long ul) { ulb.ul = ul; invertULong(); writeBytes(adr, ulb.b, 4); } unsigned long my25p40::readULong(uint32_t adr) { readBytes(adr, ulb.b, 4); invertULong(); return ulb.ul; } // Int uib_t uib; void invertInt() { byte bytes[2]; bytes[0] = uib.b[0]; bytes[1] = uib.b[1]; uib.b[0] = bytes[1]; uib.b[1] = bytes[0]; } void my25p40::writeInt(uint32_t adr, int i) { uib.i = i; invertInt(); writeBytes(adr, uib.b, 2); } int my25p40::readInt(uint32_t adr) { readBytes(adr, uib.b, 2); invertInt(); return uib.i; } // Long lb_t lb; void invertLb() { byte bytes[4]; bytes[0] = lb.b[0]; bytes[1] = lb.b[1]; bytes[2] = lb.b[2]; bytes[3] = lb.b[3]; lb.b[0] = bytes[3]; lb.b[1] = bytes[2]; lb.b[2] = bytes[1]; lb.b[3] = bytes[0]; } void my25p40::writeLong(uint32_t adr, long lg) { lb.lg = lg; invertLb(); writeBytes(adr, lb.b, 4); } long my25p40::readLong(uint32_t adr) { readBytes(adr, lb.b, 4); invertLb(); return lb.lg; } // Float flb_t flb; void invertFloat() { byte bytes[4]; bytes[0] = flb.b[0]; bytes[1] = flb.b[1]; bytes[2] = flb.b[2]; bytes[3] = flb.b[3]; flb.b[0] = bytes[3]; flb.b[1] = bytes[2]; flb.b[2] = bytes[1]; flb.b[3] = bytes[0]; } void my25p40::writeFloat(uint32_t adr, float fl) { flb.fl = fl; invertFloat(); writeBytes(adr, flb.b, 4); } float my25p40::readFloat(uint32_t adr) { readBytes(adr, flb.b, 4); invertFloat(); return flb.fl; } // Char array void my25p40::writeChars(uint32_t adr, char chs[], byte len) { writeBytes(adr, chs, len); } void my25p40::readChars(uint32_t adr, char *buf, byte len) { readBytes(adr, buf, len); buf[len] = 0; } // String void my25p40::writeString(uint32_t adr, String s) { int len = s.length() + 1; char char_array[len]; strcpy(char_array, s.c_str()); writeBytes(adr, char_array, len); } String my25p40::readString(uint32_t adr, byte len) { String s = ""; char charArray[len]; readBytes(adr, charArray, len); for (int i = 0; i < len; i++) { s += charArray[i]; } return s; } #endif // #ifndef MY25P40_CPP
Наша библиотека в виде ZIP архива.
Заключение
В этом небольшом цикле статей по созданию собственной библиотеки для работы с микросхемой памяти M25P40VP мы рассмотрели принципы и архитектуру новой библиотеки my25p40, а также разобрали несколько примеров «упаковки» в библиотеку системных функций и функций работы с различными типами данных.
Мы рассмотрели не все представленные в библиотеке функции, вы можете по аналогии разобрать работу остальных функций нашей библиотеки, что, безусловно, способствует росту вашей квалификации и пониманию работы микроконтроллеров.
Вы также можете использовать в ваших проектах на контроллерах uniSensors nRF24 (или любых других, имеющих на борту чип M25P40VP) нашу готовую библиотеку без каких-либо её доработок — она полностью готова к использованию!
Ссылки по теме
Обзор контроллера 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