В ходе работы программы МК иногда возникает потребность сохранить некоторые данные так, что бы после выключения МК они не потерялись. Для этого служит энергонезависимая память EEPROM, которая встроена, к сожалению, не во все МК. Таким образом, перед началом ее использования стоит убедиться в ее наличии у выбранного МК, для чего ищем даташит (полное описание МК от производителя) на конкретный камень. В нашем случае нужен даташит на PIC16F84A.В нем можно лицезреть, что EEPROM присутствует в размере 64 байта.
Для того, чтобы записать значение переменной в ячейку памяти EEPROM, необходимо указать ее адрес и саму переменную.
Пример:
short n, a; // Инициализируем переменные n=0x01; // Присваиваем значение адреса a=2; // значение для записи EEPROM_Write(n, a); // Собственно запись |
Так же адрес либо записываемое значение можно указать явно, например:
EEPROM_Write(0x01, 0x05); // Запишем 5 в ячейку памяти 0x01. |
Для чтения значения из ячейки памяти EEPROM нужно указать адрес нужной ячейки памяти.
Пример:
short a; a = EEPROM_Read(0x01); // Присвоим переменной а значение из ячейки памяти по адресу 0x01. |
Ну а теперь попрактикуемся. Преобразуем прошивку автомата световых эффектов из прошлой статьи так, что бы при выключении и последующем включении устройства, сохранялись режим работы и время паузы.
Сразу оговорюсь: для сохранения данных нам потребуется три ячейки памяти: для времени паузы бегущего огня, для времени паузы мигания и режима.
Ну а теперь по коду.
Инициализируем новые переменные:
char temp; // Строковое временное хранилище значения int t; // Переменная для времени паузы; short tn, // Количество отнимания шагов от макс. времени regim=0; // Режим |
Как видно, тип переменных regim и tn будут определяем как short, а не int. Дело в том, что при записи переменной типа short занимается место в 16 бит, а integer – 32 бит. Из-за этого в МК семейства PIC16 при работе с EEPROM не используют тип integer, но в семействе МК PIC18 он допустим.
Кстате, tn – это не само время паузы, а переменная которая будет указывать сколько раз отнять от максимального значения паузы maxtime шаг shag, на сколько будет уменьшатся время за одно отнимание.
Идем дальше. В начале функции main считываем ячейку памяти из EEPROM по адресу 0x0003 (может выбираться произвольно) и присваиваем ее значение переменной regim:
regim=EEPROM_Read(0x0003); // Присваиваем regim значение из памяти по адресу 0x0003 |
Заходим в бесконечный цикл while(1). Как видим, обработка кнопки выбора режима не изменилась, добавилась лишь строчка записи значения переменной режима в память.
/*-------- Обработка кнопки SW1 (режим) -------------*/ if (knopka1==0){ // Если SW1 нажата, то regim++; // Прибавить к режиму 1 if (regim>2) regim=0; // Если режим больше исполнительных функций, regim=0 EEPROM_Write(0x0003, regim); // Записываем режим в EEPROM } /*-------- Конец обработки кнопки SW1 (режим)-------*/ |
А вот обработка кнопки изменения времени паузы претерпела ряд изменений, хотя принцип остался тот же. Так как нам нужно сохранить значения времени паузы для двух режимов, то для каждого из них значение переменной будет обрабатываться отдельно.
/*-------- Обработка кнопки SW2 (время пайзы) ------*/ |
Сами обрабатывания идентичны, отличаются лишь тем, что для каждого режима считывается и записывается переменная по своему адресу. В нашем случае, для бегущего огня по адресу 0x0001, а для мигалки - 0x0002.
Рассмотрим как обрабатывается переменная временной паузы для бегущего огня. Если кнопка изменения режима нажата, то считываем значение из ячейки памяти для этого режима по адресу 0x001 и записываем его в tn.
Если кнопка обработки времени паузы нажата, то добавляем к tn единицу.
Не сложно посчитать, что от 510 можем отнять 80 только шесть раз, не залезая в отрицательные числа, следовательно, вводим строчку для восстановления максимального времени паузы (tn=0 – от maxtime отнимаем shag ноль раз), если она окажется слишком маленькой.
Ну и записываем значение tn в память.
В данной программе еще я изменил расчет времени паузы:
/*-------- Расчет времени паузы -------------*/ switch (tn){ case 1: t = maxtime - shag; break; case 2: t = maxtime - shag*2; break; case 3: t = maxtime - shag*3; break; case 4: t = maxtime - shag*4; break; case 5: t = maxtime - shag*5; break; case 6: t = maxtime - shag*6; break; default: t=maxtime; break; } /*------- Конец расчета времени паузы -------*/ |
Здесь, думаю, должны разобраться.
Симуляция в Proteus Professional |
Замечание! Между последующим исполнением команд записи и считывания должно пройти некоторое время, иначе при считывании можно получить неопределенный результат, хотя запись будет выполнена. Для этого в после EEPROM_Write(address, data); нужно сделать паузу не меньше чем в 20 мс, например Delay_ms(20).
Так же любые вопросы можно обсудить на форуме.