AVR Урок 15. Внутренняя энергонезависимая память EEPROM. Часть 1

image Есть у меня пара идей для будущих публикаций, но в них будет использоваться программатор. Поэтому сегодня я расскажу о том, как превратить Ардуино в ISP программатор, для чего он нужен и как им пользоваться. А в качестве примера будет описана процедура прошивки загрузчика в Ардуино.

Что такое ISP?

ISP (In-System Programming) расшифровывается как внутрисхемное программирование. Это технология, которая позволяет программировать микроконтроллер, установленный в устройство. До появления этой технологии микроконтроллеры программировались перед установкой в устройство, а для их перепрограммирования требовалось их извлечение из устройства. Существует 2 основных подхода внутрисхемного программирования:

  • С использованием программатора. В этом случае программатор работает напрямую с памятью микроконтроллера, самостоятельно размещая байты прошивки по нужным адресам. Микроконтроллер в этом процессе не участвует.
  • С использованием загрузчика. Загрузчик, он же бутлоадер (от английского bootloader) — это программа, записанная обычно в конце ПЗУ микроконтроллера, которая берет на себя функции программатора. При включении микроконтроллера управление сначала передается загрузчику. Он проверяет наличие определенных условий, сообщающих о необходимости перейти в режим программирования. Если условия не выполнены, то управление передается основной программе, в противном случае загрузчик принимает данные по заранее определенному интерфейсу и размещает их в ПЗУ. Таким образом микроконтроллер перепрограммирует сам себя.

Одной из важнейших особенностей Ардуино является возможность программирования непосредственно через USB порт, без дополнительного программатора. Сразу после включения Ардуино запускается загрузчик, который работает несколько секунд. Если за это время загрузчик получает команду программирования от IDE по последовательному интерфейсу UART, то он принимает и загружает новую программу в память микроконтроллера. Использование загрузчика существенно упрощает процесс перепрограммирования микроконтроллера, что особенно полезно при отладке. Но за удобство приходится платить. Во-первых, загрузчик занимает часть ПЗУ и для программы пользователя остается меньший объем памяти. Во-вторых, загрузчик не может изменить Fuse-биты и Lock-биты (в отличие от программаторов). Ну и, конечно, не обойтись без программатора, если вы хотите обновить бутлоадер или загрузить его в чистый МК. Таким образом существует ряд задач, которые могут быть выполнены только с использованием программатора. Если же у вас нет аппаратного программатора, то вместо него можно воспользоваться Ардуино, о чем и будет рассказано дальше.

Arduino as ISP. Прошивка загрузчика в Ардуино.

Итак, мы решили превратить Ардуино в программатор. Для примера попробуем прошить загрузчик в целевую плату Ардуино. Сначала подготовим плату, которую будем использовать в качестве программатора. Для этого загрузим в нее скетч ArduinoISP, его можно найти в стандартных примерах: image Теперь подсоединим к ней плату, в которую хотим прошить загрузчик. При прошивке используются линии SPI (Serial Peripheral Interface — последовательный периферийный интерфейс). Выводы MOSI, MISO и SCK обеих плат должны быть соединены, а вывод SS Ардуино-программатора подключается к выводу Reset целевой платы. И еще 2 провода нужны чтобы запитать целевую плату. Также может потребоваться предотвратить автоматическую перезагрузку платы-программатора, для этого между ее выводами Reset и GND нужно установить электролитический конденсатор на 10мкФ. Сначала можно попробовать без конденсатора, если же прошивка не начнется, то попробуйте добавить в схему конденсатор. По моим наблюдениям конденсатор нужен при использовании дешевых Ардуино-клонов (без контроллера ATmega8u2) в качестве программатора. Если мы работаем с двумя платами Arduino Uno, то схема их подключения может выглядеть следующим образом: Если используются не Uno, а другие платы Ардуино, то перед подключением программатора к целевой плате необходимо уточнить расположение на них выводов MOSI, MISO и SCK. Их расположение для различных плат приведено ниже в таблице. Как вы можете видеть, не на всех платах Ардуино линии SPI мультиплексированны с цифровыми выводами, поэтому для подключения к данному интерфейсу необходимо использовать разъем ICSP. Ниже показан пример подключения Uno в качестве программатора к плате Nano через ICSP разъем.

Плата Ардуино MOSI MISO SCK Уровень
Uno, Duemilanove 11 или ICSP-4 12 или ICSP-1 13 или ICSP-3
Nano 11 или ICSP-4 12 или ICSP-1 13 или ICSP-3
Pro Mini 11 12 13 3.3В или 5В
Mega1280, Mega2560 51 или ICSP-4 50 или ICSP-1 52 или ICSP-3
Leonardo ICSP-4 ICSP-1 ICSP-3 
Due ICSP-4 ICSP-1 ICSP-3  3.3В
Zero ICSP-4 ICSP-1 ICSP-3 3.3В
101 11 или ICSP-4 12 или ICSP-1 13 или ICSP-3 3.3В
Подключение Uno в качестве программатора к плате Nano через ICSP

Обратите внимание на нумерацию выводов ICSP платы Nano: она начинается с правого нижнего угла. Поэтому на приведенной схеме Arduino Nano перевернута. Теперь необходимо вернуться в Arduino IDE и изменить в ней параметры:

  1. В меню Инструменты > Плата выбираем вариант, соответствующий нашей целевой плате.
  2. В меню Инструменты > Программатор выбираем Arduino as ISP.

Подключаем плату-программатор к компьютеру, открытый в данный момент скетч значения не имеет, выбираем пункт меню Инструменты > Записать загрузчик и дожидаемся сообщения об успешном завершении операции. На этом прошивка бутлоадера в Ардуино завершена. Кроме того процедура прошивки бутлоадера включает в себя установку фьюзов микроконтроллера. Подробнее о фьюзах будет рассказано в следующей публикации. Резюмируя вышеописанное, выделим основные шаги для прошивки загрузчика с использованием Ардуино в качестве ISP программатора:

  • Запускаем Arduino IDE, открываем из примеров скетч ArduinoISP и загружаем его в плату Ардуино, которую будем использовать как программатор.
  • Подключаем к Ардуино-программатору целевую плату по приведенной схеме.
  • Меняем плату в Arduino IDE на целевую.
  • Выбираем в IDE программатор Arduino as ISP.
  • Записываем загрузчик в целевую плату командой из меню IDE.

Прошивка скетча с использованием Arduino as ISP

Еще один пример использования программатора — это загрузка скетча в целевую плату. Разумеется, это проще сделать привычным способом, подключив ее напрямую к компьютеру, но это может оказаться невозможным, например, при выходе из строя контроллера ATmega8u2/ATmega16u2 или преобразователя USB/UART. Если при этом основной микроконтроллер Ардуино остался рабочим, то мы можем прошить его, используя программатор. Для этого выполняем все шаги, описанные выше, но на последнем этапе вместо записи загрузчика необходимо:

  • Открыть в Arduino IDE интересующий скетч.
  • Загрузить скетч в целевую плату командой из меню IDE: Скетч > Загрузить через программатор.

Таким образом можно подарить вторую жизнь плате Ардуино, которую компьютер уже не видит через USB.

Сегодня мы рассмотри пример использования EEPROM 24LC256 совместно с Ардуино. Подключив этот чип к Ардуино, мы с легкостью можем увеличить доступную память на 32 КБ.

Блок питания 0…30 В / 3A Набор для сборки регулируемого блока питания… Подробнее

Технические характеристики 24LC256

Ниже представлены характеристики микросхемы внешней памяти 24LC256 от Microchip:

  • Тип памяти: EEPROM
  • Объем памяти: 256Kбит (32K x 8)
  • Максимальная частота: 400kHz
  • Время доступа: 900нс
  • Ток потребления: чтение 3мА / режим ожидания 1 мкА
  • Интерфейс подключения: I2C, 2-Wire Serial
  • Защита от электростатического разряда: > 4000 В
  • Выносливость: 1000000 циклов запись / стирание
  • Напряжение питания: 2,5 В…5,5 В
  • Рабочая температура: -40°C… 85°C

Распиновка 24LC256

Назначение выводов

  • A0…A2 — установка адреса устройства. В большинстве случаев используется 000.
  • Vss — земля
  • SDA — Serial Address/Data I/O
  • SCL — Serial Clock Input
  • WP — вход защиты от записи
  • Vcc — источник питания

В нашем случае мы подключим выводы A0, A1 и A2 к земле, таким образом, на них будет низкий логический уровень. Это означает, что адресные выводы будут иметь значение 000, а адрес I2C будет равен 0x50.

Если на выводы A0, A1 и A2 подать высокий уровень (111), то адрес I2C будет равен 0x57. Соответственно перебрав все комбинации, мы можем получить 8 адресов I2C.

Подключение 24LC256 к Ардуино

  • Контакт SDA (вывод 5) EEPROM подключим к аналоговому выводу 4 Arduino.
  • Контакт SCL (вывод 6) EEPROM подключим к аналоговому выводу 5 Arduino.
  • Контакт WP — это вывод защиты от записи. Подав на этот вывод высокий уровень, вы запретите запись в EEPROM. В нашем случае мы соединим его с GND.
  • К линиям SDA и SCL подключим подтягивающие резисторы сопротивлением по 10 кОм.

Вся схема подключения должна выглядеть следующим образом:

Можно использовать следующий модуль, у которого есть перемычки для установки адреса I2C и линии WP. Он также имеет подтягивающие резисторы по шине I2C.

Вот, можете взглянуть на принципиальную схему данного модуля, возможно, кто-то захочет собрать нечто подобное:

Модуль памяти AT24C256 Размер платы: 36,5 (мм) x12 (мм)…. Подробнее

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

#include  // для I2C  #define eeprom_address 0x50 // адрес устройства  byte d=0;    void setup()  {  Serial.begin(115200); // Инициализация последовательного порта  Wire.begin();    // запись данные  Serial.println("Writing data.");  for (int i=0; i<10; i++)  {  writeData(i,i);  }  Serial.println("Complete");  // чтение данных  Serial.println("Reading data.");  for (int i=0; i<10; i++)  {  Serial.print(i);  Serial.print(" : ");  d=readData(i);  Serial.println(d, DEC);  }  Serial.println("Complete");  }    // запись байта данных в адрес ячейки памяти  void writeData(unsigned int eaddress, byte data)  {  Wire.beginTransmission(eeprom_address);  // установить положение указателя  Wire.write((int)(eaddress >> 8));  Wire.write((int)(eaddress & 0xFF));  Wire.write(data);  Wire.endTransmission();  delay(10);  }  // чтение байт данных из адреса ячейки памяти  byte readData(unsigned int eaddress)  {  byte result;  Wire.beginTransmission(eeprom_address);  // установить положение указателя  Wire.write((int)(eaddress >> 8));  Wire.write((int)(eaddress & 0xFF));  Wire.endTransmission();  Wire.requestFrom(eeprom_address,1); // получить байт данных  result = Wire.read();  return result;  }    void loop()  {  }

После загрузки скетча вы должны увидеть в мониторе последовательного порта следующее:

Цифровой мультиметр AN8009 Большой ЖК-дисплей с подсветкой, 9999 отсчетов, измерение TrueRMS… Подробнее память 2020-12-20

Загрузка скетча или прошивка контроллера Ардуино – основная операция, с которой рано или поздно сталкивается любой ардуинщик. Именно возможность быстро и без лишних проблем загрузить в память контроллера управляющую программу и стала одной из основных причин успеха платформы Arduino. В этой статье мы узнаем, как прошиваются Arduino Uno, Nano, Mega и другие платы на основе Atmega с использованием Arduino IDE, программатора или другой платы Ардуино.

Загрузка скетча в плату Ардуино

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

Что происходит, когда мы жмем кнопку «Загрузить»

Плата Ардуино – это микроконтроллер AVR (Atmega8/168/328 или Atmega1280/2560), который прошивается загрузчиком. В микроконтроллер записывается программа, называемая прошивкой, которая позволяет получать сигналы с датчиков, обрабатывать нажатия кнопок, общаться с различными устройствами через интерфейсы, управлять исполнительными процессами.

Обычно прошивка записывается в кристалл микроконтроллера при помощи специальных устройств, называемых программаторами. Для разных микроконтроллеров существуют различные программаторы – от специализированных до универсальных. Важным отличием Ардуино от других контроллеров является возможность залить прошивку через обычный USB кабель. Это достигается при помощи специальной программы – загрузчика (Bootloader). Для прошивки не требуются лишние провода, не нужно подключать дополнительные устройства или нажимать что-то на плате. Также при работе через загрузчик нельзя добраться до опасных настроек, которые выведут из строя Ардуино.

При подключении платы Ардуино к источнику питания, внутри него начинается активная деятельность микропрограмм. При запуске микроконтроллера управление получает загрузчик. Первые 2 секунды он проверяет, поступил ли новый код от пользователя.  Кроме того загрузчик подает импульсы на пин, к которому подключен светодиод, и он начинает мигать. Это означает, что загрузчик установлен и работает исправно. Когда подается скетч, загрузчик записывает его во флеш-память микроконтроллера. Затем эта программа подается на выполнение.  Если данные не поступили, загрузчик запускает предыдущую программу. Во время выполнения программы внутри Ардуино выполняется ряд операций по инициализации и настройке среды окружения, и только после этого начинается выполнение кода.

Вызов setup и loop при загрузке

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

Команда void setup() – в ней записываются данные, которые микроконтроллер выполняет в момент загрузки, а после может про них забыть. В этой функции указываются номера пинов, к которым подключается устройство, подключаются и инициализируются библиотеки, устанавливается скорость работы с последовательным портом.

Функция void loop – в нее помещаются команды, которые должны выполняться, пока включена плата. Микроконтроллер начнет выполнять программы, начиная с первой, и когда дойдет до конца, сразу вернется в начало, чтобы повторить эту же последовательность бесконечное число раз.

Загрузка скетча в Arduino IDE

В Ардуино IDE компиляция скетча начинается при нажатии кнопки Verify, после этого скетч может быть загружен в память Ардуино через USB с помощью кнопки Upload. Перед загрузкой кода программы нужно установить все параметры в меню Tools. В этом меню выбираются порт, к которому подключена плата, и платформу. В окне Arduino IDE внизу будет отображен ход компиляции скетча. При успешной выгрузке скетча будет получено сообщение «Done uploading».  Запуск скетча начинается сразу после окончания загрузки. Для расширения возможностей можно подключать дополнительные внешние библиотеки, разработанные командой Ардуино или сторонними авторами.

Обзор возможных вариантов загрузки скетча

Кратко весь алгоритм можно записать следующим образом: Написание кода >> компиляция >> загрузка в микроконтроллер. При загрузке скетча используется Bootloader (Загрузчик). Он представляет собой небольшую программу, которая загружается в микроконтроллер на Ардуино. С помощью этой программы можно загружать скетч, не используя дополнительные аппаратные средства. При работе загрузчика на плате будет мигать светодиод.

1. Загрузка в Arduino IDE. Самый простой и удобный вариант загрузки кода. Все, что        нужно сделать – это написать или найти нужный скетч и загрузить его.

  1. Ускоренная загрузка скетча в Arduino IDE. С помощью этого метода можно увеличить скорость загрузки в микроконтроллер в два раза. Для этого нужно лишь зайти в Настройки и снять галочку с пункта Проверка кода. Пропуская шаг проверки, будет уменьшено количество байтов, которые передаются во время загрузки. При этом все равно некоторые из видов проверок будут осуществлены, но они не занимают долгого времени. Отключать проверку кода не рекомендуется, если Ардуино помещается в какой-либо ответственный проект (например, в спутник). Также можно провести проверку, если подключение производится через очень длинный USB кабель (порядка 10 метров).

Уменьшение времени загрузки при помощи отключения проверки работает с любой платой Ардуино, которая использует USB соединение. Все эти микроконтроллеры используют загрузчик avrdude. Платы, которые используют загрузчик Catarina, не нуждаются в отключении проверки кода, так как этот загрузчик работает быстрее.

  1. Загрузка скетча в Ардуино через Bluetooth. Этот способ используется, когда нужно обойтись без физического соединения Ардуино и компьютера – например, в силовых цепях или радиочастотных цепях. Для реализации загрузки потребуется Bluetooth-модуль, который оснащен платой-адаптером для Ардуино. Этот модуль нужно подключить к компьютеру через переходник USB-UART-TTL. Работа с модулем осуществляется с помощью AT-команд.
  2. Загрузка при помощи Андроид-устройства. Для осуществления такого типа загрузки кода понадобятся провода USB-A – USB-B и USB-Host (OTG-кабель), Ардуино и устройство на базе Андроид с поддержкой режима host. На Андроид-устройство нужно установить программу ArduinoDroid или ArduinoCommander из Google Play. Все устройства нужно соединить при помощи кабелей, после этого можно включать Ардуино и загружать на него код. Нужно запустить установленную программу. При включении начнется обновление IDE, на что понадобится некоторое время.

Сначала работа будет рассмотрена на примере программы ArduinoCommander. После ее запуска нужно нажать USB-Device. Затем нужно наддать Autodetect, чтобы Андроид-устройство выполнило поиск Ардуино и отобразило его на экране. Как только Ардуино появится на экране, нужно на него нажать. Чтобы перейти в меню, нужно щелкнуть в нижнем правом углу. В этом меню можно загрузить скетч с SD-карты.

ArduinoDroid представляет собой среду разработки, компилятор и загрузчик одновременно. Начать компиляцию скетча нужно нажав на кнопку Lightning-Button. После завершения компиляции нужно нажать на кнопку загрузки. Загрузка занимает несколько секунд. По окончании загрузки ардуино запустит на выполнение новый код.

  1. Программирование при помощи Raspberry Pi. Можно загружать скетчи двумя способами – при помощи Arduino IDE и при помощи пакета arduino-mk. Пакет позволяет собирать и загружать скетчи Ардуино из командной строки.

Структура памяти Ардуино, где располагается скетч и данные

На микроконтроллере Ардуино имеется 3 вида памяти – флеш-память, которая используется для хранения скетчей, ОЗУ для хранения переменных и EEPROM для хранения постоянной информации. Из этих типов памяти флеш-память и EEPROM являются энергонезависимыми, то есть информация сохраняется при выключении питания. ОЗУ используется только для хранения данных, которые имеют отношение к исполняемой программе.

Микроконтроллер ATmega168, который используется на части плат Ардуино, имеет 16 Кб флеш-памяти, 1024 байта для ОЗУ и 512 байт EEPROM. Важно обратить внимание на малый объем ОЗУ. Большие программы могут полностью ее израсходовать, что приведет к сбою в программе. По этой причине нужно следить за тем, сколько строк занимает программа, и по возможности удалять лишнее. Уменьшить объем кода можно несколькими способами:

  • Можно отправить часть информации на компьютер.
  • Для таблиц и других крупных массивов использовать минимальный тип данных для хранения.
  • Данные, которые остаются неизменными, можно объявить константами при помощи слова const перед объявлением переменной.
  • Меньше использовать рекурсию. При ее вызове в памяти, называемой стеком, выделяется фрагмент, в котором хранятся различные данные. Если часто вызывать рекурсию, стеки будут занимать большой объем памяти и могут израсходовать ее.
  • Неизменяемые строки можно сохранять во флеш-памяти во время работы программы. Для этого используется функция PROGMEM.

На объем памяти не влияют размер имени переменных и комментарии. Компилятор устроен таким образом, что не включает эти данные в скомпилированный скетч.

Для измерения объема занимаемой памяти ОЗУ используется скетч из библиотеки MemoryFree. В ней имеется специальная функция free­Memory, которая возвращает объем доступной памяти. Также эта библиотека широко используется для диагностики проблем, которые связаны с нехваткой памяти.

Оптимизация флеш-памяти. Как только будет окончена процедура компиляции, в окне появится информация о занимаемой памяти кодом. Если скетч занимает большую часть памяти, нужно произвести оптимизацию использования флеш-памяти:

  • Использование констант. Аналогично как и для ОЗУ задавать неизменяющиеся значения константами.
  • Удалить ненужные Serial.println. Эта команда используется, когда нужно увидеть значения переменных в разных местах программы, нередко эта информация просто не нужна. При этом команды занимают место в памяти, поэтому, убедившись в корректной работе программы, некоторые строки можно удалить.
  • Отказ от загрузчика – можно программировать микроконтроллер через контакты ICSP на плате с использованием аппаратных программаторов.

Флеш память является безопасным и удобным способом хранения данных, но некоторые факторы ограничивают ее использование. Для флеш-памяти характерна запись данных блоками по 64 байта. Также флеш-память гарантирует сохранность информации для 100000циклов записи, после чего информация искажается. Во флеш-памяти имеется загрузчик, который нельзя удалять или искажать. Это может привести к разрушению самой платы.

EEPROM память используется для хранения всех данных, которые потребуются после отключения питания. Для записи информации в EEPROM нужно использовать специальную библиотеку EEPROM.h, которая входит в число стандартных библиотек в Arduino IDE. Чтение и запись информации в EEPROM происходит медленно, порядка 3 мс. Также гарантируется надежность хранения данных для 100000 циклов записи, потому лучше не выполнять запись в цикле.

Варианты прошивки Ардуино

Прошивка с помощью Arduino IDE

Прошить плату при помощи среды разработки Arduino IDE можно в несколько шагов. В первую очередь нужно скачать и установить саму программу Arduino IDE. Также дополнительно нужно скачать и установить драйвер CH341. Плату Ардуино нужно подключить к компьютеру и подождать несколько минут, пока Windows ее опознает и запомнит.

После этого нужно загрузить программу Arduino IDE и выбрать нужную плату: Инструменты – Плата. Также нужно выбрать порт, к которому она подключена: Инструменты – Порт. Готовая прошивка открывается двойным кликом, чтобы ее загрузить на плату, нужно нажать кнопку «Загрузить» вверху панели инструментов.

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

Прошивка с помощью программатора

Одни из самых простых способов прошивки платы – при помощи программатора. Заливка будет производиться в несколько этапов.

В первую очередь нужно подключить программатор к плате и к компьютеру. Если программатор не опознается компьютером, нужно скачать и установить драйверы.

После этого нужно выбрать плату, для которой нужно прошить загрузчик. Это делается в меню Сервис >> Плата.

Затем нужно выбрать программатор, к которому подключен контроллер. В данном случае используется USBasp.

Последний шаг – нажать на «записать загрузчик» в меню Сервис.

После этого начнется загрузка. Завершение произойдет примерно через 10 секунд.

Прошивка Arduino через Arduino

Для того чтобы прошить одну плату с помощью другой, нужно взять 2 Ардуино, провода и USB. В первую очередь нужно настроить плату, которая будет выступать в качестве программатора. Ее нужно подключить к компьютеру, открыть  среду разработки Arduino IDE и найти в примерах специальный скетч ArduinoISP. Нужно выбрать этот пример и прошить плату.

Теперь можно подключать вторую плату, которую нужно прошить, к первой. После этого нужно зайти в меню Инструменты и выставить там прошиваемую плату и тип программатора.

Можно начать прошивать устройство. Как только прошивка будет открыта или написана, нужно перейти в меню Скетч >> загрузить через программатор. Для заливания прошивки не подходит стандартная кнопка загрузки, так как в этом случае прошивка будет загружена на первую плату, на которой уже имеется прошивка.

Заключение

В этой статье мы рассмотрели различные аспекты загрузки скетчей в Arduino Uno и Nano. Прошивка плат на базе микроконтроллеров ATmega328 и ATmega256, как правило, не сложна и может выполняться одним нажатием кнопки в Arduino IDE. За эту простоту мы должны благодарить встроенную программу-загрузчик, выполняющую за нас все основные действия на низком уровне.

Еще одним вариантом перепрошивки контроллера является использование другой платы адуино или специальных программаторов, использующих микросхемы CP2102 CH340, FTDI и другие. Этот метод требует дополнительных усилий и затрат, но позволяет гибко изменять параметры прошивки. Какой из двух вариантов выбрать – решать вам. Для новичков, безусловно, первым шагом станет использование Arduino IDE, благо, ее создатели сделали все, чтобы упростить этот процесс.

При программировании Arduino часто возникает необходимость долговременного энергонезависимомо хранения данных. Это могут быть настройки вашего приложения, журнал событий или что-то другое. на многих платах, таких, как Arduino Uno или Arduino Nano, под хранение таких данных выдел раздел в 1кБ. Но этого часто бывает недостаточно. Даже на Arduino Mega памяти не сильно больше — 4кБ.

Есть 2 вариант.

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

Второй вариант: использование модуля памяти AT24C256. Он очень маленький, дешевый и позволяет хранить 32кБ. Для многих задач этого объема вполне достаточно.

Купить модуль можно в двух вариантах: отдельную микросхему или же небольшую плату:

    

Подключается модуль к контактам SCL и SDA и работает по протоколу I2C. Напомню, пины для подключения будут разными в зависимости от модели платы:

Плата Пин SDA Пин SCL
Uno, Nano A4 A5
Mega2560 20 21
Leonardo 2 3
Due 20, SDA1 21, SCL1

VCC подключаем к +5V, а GND — к соответствующего пину на плате Arduino.

Для работы с модулем будем использовать библиотеку Wire.

#include        #define disk1 0x50 // Адрес чипа 24LC256   void setup(void) {   Serial.begin(9600);   Wire.begin();       unsigned int address = 0;     writeEEPROM(disk1, address, 123);   Serial.print(readEEPROM(disk1, address), DEC); }   void writeEEPROM(int deviceaddress, unsigned int eeaddress, byte data)  {   Wire.beginTransmission(deviceaddress);   Wire.send((int)(eeaddress >> 8));   Wire.send((int)(eeaddress & 0xFF));   Wire.send(data);   Wire.endTransmission();     delay(5); }   byte readEEPROM(int deviceaddress, unsigned int eeaddress)  {   byte rdata = 0xFF;     Wire.beginTransmission(deviceaddress);   Wire.send((int)(eeaddress >> 8));   Wire.send((int)(eeaddress & 0xFF));   Wire.endTransmission();     Wire.requestFrom(deviceaddress,1);     if (Wire.available()) rdata = Wire.receive();     return rdata; }  void loop() { }

В начале мы задаем константу с адресом модуля. По-умолчанию при подключении одного модуля, он будет иметь адрес 0x50. Есть возможность подключения нескольких модулей (адреса будут 0x51, 0x52 и т.д.).

Далее, в ячейку памяти с адресом 0 мы записываем 1 байт со значением 123, после чего считываем его.

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

Ссылки на покупку модуля у проверенных мной продавцов: 1, 2 и 3

← Настройка bluetooth модулей Использование датчика протечки → image 2017-01-11 в 16:51, , рубрики: arduino, c++, FRAM, I2C, библиотека, мотоцикл, панель приборов, приборная панель, программирование микроконтроллеров

Продолжу рассказывать про приборную панель для мотоцикла. Это замечательное устройство содержит одометр, то есть, счётчик пройденного пути в километрах, а у того есть плохое свойство — он должен сохранять данные и при выключенном питании. Ой, ещё есть моточасы, их тоже надо хранить как-то энергозависимо.

Необходимость хранения указателя можно обмануть разными способами. Например так:

struct MarkedSavedData {   byte marker; // показывает, занято место или нет.   struct SavedData {     // Собственно данные для сохранения   } } data; 

Структуркой MarkedSavedData заполняется eerpom или флеш или что-то по кругу. Чтобы не писать указатель, в свободных записях делаем data.marker=0x00, а в занятой текущей data.marker=0xff, например. В процессе работы, конечно же, запись идёт по указателям, а при старте контроллера просто поиском по всей памяти ищется структура с data.marker==0xff — это последние правильные данные. Плохо, что каждый раз две записи получаются тк надо обнулить data.marker освобождаемой записи.

Есть вариант с последовательным счётчиком.

struct MarkedSavedData {   unsugned int counter; // последовательный номер записи.   struct SavedData {     // Собственно данные для сохранения   } } data; 

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

Всё это хорошо, но это припарки.

Коллеги из НТЦ Метротек подсказали поискать FRAM. Это ферритовая память с бешеным быстродействием и 1014 циклами записи.

image

Услужливый Aliexpress привёз мне вот такой модуль. Память в виде модуля дорогая весьма, кстати. Сам же чип стоит 16р/шт. В микросхеме 512 байт, то есть, вроде и немного, но с учётом бесконечному числу записей вполне достаточно.

Погуглив на тему готового чего-то для этого чипа я не нашёл ничего. Отличная кошка, решил я, буду на ней тренироваться! Открыл доку по Wire, даташит по FM24, чей-то проект EEPROM/I2C с похожим интерфейсом и набросал класс для FRAM.

image

Проект на гитхабе: github.com/nw-wind/FM24I2C

Пример прилагается вот такой.

#include "FM24I2C.h"  // Объект для платы. Адрес в i2c. FM24I2C fm(0x57);  void setup() {   Wire.begin();   Serial.begin(9600);   char str1[]="12345678901234567890";   char str2[]="qwertyuiopasdfghjklzxcvbnm";   int a1=0x00; // Первый в FRAM   int a2=0x40; // Второй адрес в FRAM   fm.pack(a1,str1,strlen(str1)+1); // Пишем в память   delay(5);   fm.pack(a2,str2,strlen(str2)+1); // Пишем вторую строку   delay(5);   char buf[80];   fm.unpack(a2,buf,strlen(str2)+1); // Читаем вторую   Serial.println(str2);   fm.unpack(a1,buf,strlen(str1)+1); // Читаем первую   Serial.println(str1); } 

Протокол i2c для FRAM сильно проще, чем для EEPROM. Память работает быстрее передачи данных по шине и можно лить хоть все 2К ардуининых мозгов за один раз. Польза от моего кода хоть в том, что нет лишнего разбиения на блоки по 32 байта или вообще побайтной передачи.

class FM24I2C {   private:     int id;   public:     FM24I2C(int id_addr);     ~FM24I2C();     void pack(int addr, void* data, int len);     // Упаковать данные в FRAM     int unpack(int addr, void* data, int len);    // Распаковать из FRAM. Возвращает количество переданных байтов.     // Это уже специально для меня, пишет беззнаковые длинные целые.     void inline writeUnsignedLong(int addr, unsigned long data) {       pack(addr, (void*)&data, sizeof(unsigned long));     }      // И читает.     unsigned long inline readUnsignedLong(int addr) {       unsigned long data;       return unpack(addr, (void*)&data, sizeof(unsigned long)) == sizeof(unsigned long) ? data : 0UL;     }     // Можно для других типов сделать чтение/запись, но мне было не нужно, а флеш занимает.     // Каждый же может унаследовать класс и дописать сам. }; 

Кода же немножко совсем.

void FM24I2C::pack(int addr, void* data, int len) {   Wire.beginTransmission(id);   Wire.write((byte*)&addr,2);   Wire.write((byte*)data,len); // Наверное, стоит всё же unsigned int использовать :)   Wire.endTransmission(true); }  int FM24I2C::unpack(int addr, void* data, int len) {   int rc;   byte *p;   Wire.beginTransmission(id);   Wire.write((byte*)&addr,2);   Wire.endTransmission(false);   Wire.requestFrom(id,len);   // Здесь можно поспорить про замену rc на p-data :)   for (rc=0, p=(byte*)data; Wire.available() && rc < len; rc++, p++) {     *p=Wire.read();   }   return(rc); } 

Так как на модуле, кроме чипа и разъёмов, практически ничего нет, уже хочу купить несколько микросхем. Нравятся.

Автор: nwwind

Источник

—> Комментарии закрыты. —>

Оцените статью
Рейтинг автора
5
Материал подготовил
Илья Коршунов
Наш эксперт
Написано статей
134
А как считаете Вы?
Напишите в комментариях, что вы думаете – согласны
ли со статьей или есть что добавить?
Добавить комментарий