logo
+7 (495) 997-37-74
Москва, ул.Международная, 15

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

Продолжаем знакомство с работой микросхемы памяти M25P40VP, установленной на беспроводном контроллере uniSensors nRF24, и в этой статье разберём запись и чтение разных типов данных.

Read & Write word

На прошлом уроке мы научились записывать и читать из памяти микросхемы M25P40VP байты и массивы байтов, теперь мы разберём пример работы с числами типа word. Это беззнаковый тип данных (uint16_t), состоящий из двух байтов и принимающий значения от 0 до 65535.

В тестовом скетче мы запишем число типа word в память M25P40VP и считаем его для проверки корректности записи (предварительно очистив всю память чипа).

Код скетча M25P40 Read & Write 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() {
  
}

Вначале мы задаём адрес тестовой ячейки памяти M25P40VP, в нашем случае это нулевая ячейка.

#define TEST_ADR 0

Затем мы определяем тестовое число из диапазона, поддерживаемого типом word.

#define TEST_VAL 65000

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

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

Чтение производится функцией 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);
}

В ней мы объявляем массив bytes[] для получения и хранения 2-х байт тестового числа типа word. Читаем 2 байта из памяти M25P40VP в виде 2-байтового массива.

flash.readBytes(adr, bytes, 2);

Упаковываем эти 2 байта в число типа word.

word wordValue = (bytes[0] << 8) | bytes[1] & 0xFF;

И выводим на печать полученный результат.

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

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

Значение 65535, прочитанное сразу после стирания памяти микросхемы M25P40VP — это максимально возможное значение для типа word и определяется оно числами 0xFF, которыми заполняются ячейки памяти при стирании.

Далее мы видим успешные запись и считывание тестового числа 65000 типа word.

Read & Write unsigned long

Теперь по аналогии с предыдущим примером давайте научимся записывать и считывать из памяти M25P40VP большие беззнаковые числа типа unsigned long. Это тоже беззнаковый тип данных (uint32_t), состоящий уже из четырёх байтов и принимающий значения от 0 до 4294967295.

Код скетча M25P40 Read & Write unsigned long:

/*
  M25P40 Read & Write unsigned long
*/

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

#define FLASH_SS 8

#define TEST_ADR 0
#define TEST_VAL 4222111000

union {
  unsigned long ul;
  byte b[4];
} ulb;

SPIFlash flash(FLASH_SS);

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

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

  erase();
  readULong(TEST_ADR);
  writeULong(TEST_ADR, TEST_VAL);
  readULong(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 invert() {
  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 readULong(uint32_t adr) {
  byte bytes[4];
  flash.readBytes(adr, ulb.b, 4);
  invert();
  
  Serial.print(F("Read #")); Serial.print(adr); Serial.print(F(": ")); Serial.println(ulb.ul);
}

void writeULong(uint32_t adr, unsigned long ul) {
  ulb.ul = ul;
  invert();
  flash.writeBytes(adr, ulb.b, 4);
  
  Serial.print(F("Write #")); Serial.print(adr); Serial.print(F(": ")); Serial.println(ul);
}

void loop() {
  
}

Вначале мы задаём адрес тестовой ячейки памяти M25P40VP, в нашем случае это снова нулевая ячейка.

#define TEST_ADR 0

Затем мы определяем тестовое число из диапазона, поддерживаемого типом unsigned long (от 0 до 4294967295).

#define TEST_VAL 4222111000

Также мы создаём объединение (union) для совместного хранения в памяти различных типов данных — 4-байтового числа ul типа unsigned long и 4-байтового массива b[4]. Это нам понадобится в дальнейшем для записи, чтения и приведения различных типов данных.

union {
  unsigned long ul;
  byte b[4];
} ulb;

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

  erase();
  readULong(TEST_ADR);
  writeULong(TEST_ADR, TEST_VAL);
  readULong(TEST_ADR);

Чтение производится функцией readULong(), которой мы передаём адрес тестовой ячейки в качестве параметра.

void readULong(uint32_t adr) {
  flash.readBytes(adr, ulb.b, 4);
  invert();
  
  Serial.print(F("Read #")); Serial.print(adr); Serial.print(F(": ")); Serial.println(ulb.ul);
}

Здесь мы используем функцию flash.readBytes() чтения массива (из 4-х байт) из памяти M25P40VP по заданному адресу и «массивное» представление объединённого 4-байтового числа ulb.b[].

  flash.readBytes(adr, ulb.b, 4);

Поскольку порядок байтов, выдаваемых функцией flash.readBytes() противоположен порядку байтов в представлении чисел типа unsigned long, мы дополнительно инвертируем этот порядок в объединении ulb при помощи функции invert().

void invert() {
  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];
}

Далее выводим на печать полученный результат при помощи объединённой версии ulb.ul типа unsigned long.

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

Вот результат работы нашего тестового скетча:

Сразу после операции стирания первые 4 байта (#0, #1, #2, #3) содержат значения 0xFF, поэтому мы прочитали максимально возможное значение 4294967295, а затем мы успешно записали и прочитали из первых четырёх ячеек памяти M25P40VP тестовое число 4222111000.

Заключение

В этой статье мы научились работать (читать и записывать) беззнаковые типы данных word и unsigned long в память микросхемы M25P40VP, установленной на беспроводном контроллере uniSensors nRF24. В следующей статье мы продолжим увлекательное знакомство с чипом M25P40VP и разберём работу со знаковыми типами данных.

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

Обзор контроллера 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

Где купить?

uniSensors nRF24 в магазине «Electromicro»

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

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

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

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