Запись и чтение EEPROM в AVR

Запись и чтение EEPROM данных типа unsigned int, unsigned long, float и других типов данных, размером более 8 бит, т.е. тех данных, которые размером более одного байта.
Все примеры здесь указаны для языка СИ.

Сначала приведем основной пример для чтения и записи типа unsigned char, т.к. это будут основные функции, на основе которых будет происходить чтение и запись ячеек еепром.

/* ------------------------------------------------------------------------ */
// Функции чтения и записи в еепром одного байта.
/* ------------------------------------------------------------------------ */

void EEPROM_write (unsigned int uiAddress, unsigned char ucData)
{
    unsigned char cSREG;

    /* Wait for completion of previous write */
    while(EECR & (1<<EEWE));
    /* Set up address and data registers */
    EEAR = uiAddress;
    EEDR = ucData;
    
    cSREG = SREG; /* store SREG value */
    /* disable interrupts during timed sequence */
    
    #if __CODEVISIONAVR__ /* if CodeVisionAVR */
        #asm("cli");
    #else
        asm("cli");
    #endif
    
    /* Write logical one to EEMWE */
    EECR |= (1<<EEMWE);
    /* Start eeprom write by setting EEWE */
    EECR |= (1<<EEWE);
    
    SREG = cSREG; /* restore SREG value (I-bit) */
}

unsigned char EEPROM_read(unsigned int uiAddress)
{
    /* Wait for completion of previous write */
    while(EECR & (1<<EEWE));
    /* Set up address register */
    EEAR = uiAddress;
    /* Start eeprom read by writing EERE */
    EECR |= (1<<EERE);
    /* Return data from data register */
    return EEDR;
}

Эти функции без проблем позволяют считывать из Еепром данные или наоборот, записывать какие либо данные в Еепром. Этих функций в целом достаточно для записи или чтения любых типов данных, просто используя циклы, когда количество байтов более одного. Но есть тут одно неудобство, при таком подходе (к примеру для записи), если тип записываемой переменной более одного char, например int, а это уже два байта, то придется каждый раз подготавливать данные в самом коде программы и потом в цикле или построчно (побайтно) уже производить запись.

Такой код неудобен, если в нашей программе в разных местах кода мы будем часто проводить подобные операции. Как минимум хотя-бы, в итоге, это потеря в размере flash. Как максимум, слишком много лишних движений.

Пример записи числа unsigned int в Eeprom без цикла

/* ------------------------------------------------------------------------ */
// Запись в Eeprom числа unsigned int (без цикла).
/* ------------------------------------------------------------------------ */

unsigned int addr;
unsigned int TimeStopTrunk;

addr = 0x3F0;
TimeStopTrunk = 0xAABB;

// Пишем в Eeprom 2 байта.
EEPROM_write((unsigned int) addr,(TimeStopTrunk>>8));        // Первый байт слова
EEPROM_write((unsigned int) addr+1,(TimeStopTrunk&0xFF));    // Второй байт слова

Пример записи числа unsigned int в Eeprom с циклом

/* ------------------------------------------------------------------------ */
// Запись в Eeprom числа unsigned int (в цикле).
/* ------------------------------------------------------------------------ */

unsigned int addr;
unsigned int TimeStopTrunk[2];
unsigned char i;

addr = 0x3F0;
TimeStopTrunk = 0xAABB;

writed[0]=TimeStopTrunk>>8;   // Первый байт слова
writed[1]=TimeStopTrunk&0xFF; // Второй байт слова

// Пишем в Eeprom 2 байта.

for( i = 0; i < 2; i++ )
{
	EEPROM_write(addr+i, writed[i]);
}

На самом деле вариаций таких примером немалое количество, все их приводить конечно мы не будем, но вы понимаете, насколько можно замусорить исполняемый код своей программы? А сколько неудобств каждый раз объявлять переменные, обрабатывать и т.д. и т.п. А не удобнее ли все делать одной строчкой? Вот к этому мы и должны прийти!

В том, что хочу вам показать, есть только один минус, это один лишний прыжок в стек, т.к. из одной подпрограммы вызывается еще одна подпрограмма, проще говоря, функция. Но жертвы стоят того, просто необходимо в своей программе учитывать этот момент, чтобы не произошло переполнения стека. Тем не менее, данный подход реализован почти во всех библиотеках, и от этого никуда не деться. Если мы экономим на одном, мы теряем на другом. Вполне закономерно :)

Итак, вот упрощенная реализация чтения и записи числа int

/* ------------------------------------------------------------------------ */
// Чтение числа int из еепром.
/* ------------------------------------------------------------------------ */

unsigned int EEPROM_read_int(unsigned int addr) {    
  unsigned char buf[2];
  unsigned char i;
  
  for( i = 0; i < 2; i++ ) buf[i] = EEPROM_read(addr+i);
  unsigned int &num = (unsigned int&)buf;
  return num;
}

/* ------------------------------------------------------------------------ */
// Запись числа int в еепром.
/* ------------------------------------------------------------------------ */

void EEPROM_write_int(unsigned int addr, unsigned int num) {
  unsigned char buf[2];
  unsigned char i;
  
  (unsigned int&)buf = num;
  for( i = 0; i < 2; i++ ) EEPROM_write(addr+i, buf[i]);
}

Теперь все основные действия мы будем совершать всего одной строкой

/* ------------------------------------------------------------------------ */
// Чтение числа int из еепром.
/* ------------------------------------------------------------------------ */

EEPROM_read_int((unsigned int) addr,dataint);

/* ------------------------------------------------------------------------ */
// Запись числа int в еепром.
/* ------------------------------------------------------------------------ */

EEPROM_write_int((unsigned int) addr,dataint);

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

Таким образом, на основе этих функций мы можем создать новые функции и для других типов, например unsigned long или float. А также было бы очень неплохо в функции записи реализовать проверку на запись одинакового значения, и производить запись в ячейку памяти только в случае, если новые и старые данные различаются. Ну зачем нам лишний раз повторно переписывать ячейки в Eeprom, верно?

3 Replies to “Запись и чтение EEPROM в AVR”

  1. В AVR Studio GCC твои функции EEPROM_read_int EEPROM_write_int выдают ошибки
    Короче код твой херня не проверенная

    1. Все проверено! И кто сказал, что этот код должен работать в AVR Studio?. Я не пишу программы в AVR Studio, код прекрасно работает, проверен и написан для IAR Embedded Workbench. Заметки сделаны для себя или для людей, которые понимают, что к чему. Предполагаю, у Вас из-за различия определения типов данных, у каждого компилятора могут быть свои «имена», а также для некоторой совместимости можно самому переопределить типы данных, что я и сделал для совместимости с CodeVision AVR. Но никак не для AVR Studio. Впрочем, может быть и иная несовместимость, поэтому открываем даташит на любой проц AVR, и там есть готовые примеры кода записи и чтения еепром именно для AVR Studio.

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

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *