Суббота, 2024-05-18
Сборник компьютерных технологий
Меню сайта
Категории раздела
My articles [30]
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0
Главная » Статьи » My articles

Кольцевой буфер AVR

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

Кольцевой буфер является разновидностью буфера FIFO, First Input First Output (первый зашел - первый вышел). Принцип кольцевого буфера довольно прост - в памяти выделяется непрерывный блок размером обычно равным степени двойки (назовем его buffer), и два индекса (idxIN и idxOUT) - один индекс указывает на место для записи в буфер (idxIN), другой - на место чтения из буфера. Размер буфера, равный степени двойки, выбирается для того, чтобы удобно было манипулировать индексами, указывающими на данные буфера, с помощью инкремента/декремента и наложения маски (это будет понятно далее). Индекс - это обычное число, равное адресу ячейки буфера. Например, на ячейку buffer[0] указывает индекс, равный нулю. Количество бит индекса как раз равно степени двойки размера буфера. Максимально удобны буфера размером 256 байт - в этом случае в качестве индекса можно применить 1 байт, и маску при операциях с указателями уже накладывать не надо. Код получается в этом случае максимально быстрый и компактный. На рисунке показан принцип работы кольцевого буфера на примере буфера в 16 байт (желтым показаны еще не обработанные данные буфера):

ringbuf.jpg

Вот так, например, выделяется буфер:

#define BUF1_SIZE 16 //размер буфера обязательно равен степени двойки!
#define BUF1_MASK (BUF1_SIZE-1)
 
uint8_t idxIN, idxOUT;
uint8_t buffer1 [BUF1_SIZE];
volatile uint8_t amount_elements;

При помещении значения value в буфер используется индекс idxIN. Это делается так:

uint8_t tmphead=(idxIN+1) & BUF1_MASK;
buffer1[tmphead] = ЗНАЧЕНИЕ;
idxIN=tmphead;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
    {
    amount_elements++;
    }

Значение константы BUF_MASK равно размеру буфера минус 1 (при условии, что размер буфера равен степени двойки). При таком принципе работы с индексом происходит автоматический переход на начало буфера, как только мы достигли его конца.

Операция выборки из буфера происходит похожим образом, только используется индекс idxOUT:

    uint8_t tmptail = (idxOUT + 1) & BUF1_MASK;
    idxOUT = tmptail;

    ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
    {
    amount_elements--;
    }
    value = buffer1[tmptail];

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

Проверка на наличие данных в буфере происходит очень просто, они есть пока amount_elements!=0

Сбросить данные буфера (т. е. удалить их оттуда) тоже очень просто - для этого в idxOUT записывают значение idxIN:

idxOUT = idxIN;

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

u8 idxDiff (u8 idxIN, u8 idxOUT)
{
 if (idxIN >= idxOUT)
 return (idxIN - idxOUT);
 else
 return ((BUF_SIZE - idxOUT) + idxIN);
}

Вот более наивная реализация http://microsin.net/programming/avr/ring-buffer.html Но с таким подходом к последней ячейке вы не сможете обратиться, так как начальный индекс поравняется с конечным (для буфера на 16 ячеек у вас будет в доступе только 15), и будьте очень аккуратны с прерываниями, особенно со вложенными.



Источник: http://microsin.net/programming/avr/ring-buffer.html
Категория: My articles | Добавил: DungeonLords (2017-11-05)
Просмотров: 758
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Форма входа
Поиск
Друзья сайта
  • Официальный блог
  • Сообщество uCoz
  • FAQ по системе
  • Инструкции для uCoz
  • Copyright Forcer, Inc © 2024
    Бесплатный конструктор сайтов - uCoz