8-900-374-94-44
[email protected]
Slide Image
Меню

Кольцевой буфер – Кольцевой буфер на С++ для МК.

Содержание

Что такое кольцевой буфер? | RUUD

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

Теоретические основы буфера

Пользователю легче сделать выбор эффективной структуры массивов после понимания основополагающей теории. Циклический буфер — структура данных, где массив обрабатывается и визуализируется в виде циклов, то есть индексы возвращаются к 0 после достижения длины массива. Это делается с помощью двух указателей на массив: «head» и «tail». Когда данные добавляются в буфер, указатель заголовка перемещается вверх. Точно так же, когда они удаляются, то хвост тоже перемещается вверх. Определение головы, хвоста, направления их движения, места записи и чтения зависят от реализации схемы.

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

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

Еще один вопрос, который возникает в отношении циклического буфера. Нужно ли сбрасывать новые данные или перезаписывать существующие, когда он заполнен? Специалисты утверждают, что нет явного преимущества одного над другим, а его реализация зависит от конкретной ситуации. Если последние имеют больше значимости для приложения, используют метод перезаписи. С другой стороны, если они обрабатываются в режиме «первым пришел — первым обслужен», то отбрасывают новые, когда кольцевой буфер заполнен.

Реализация цикличной очереди

Приступая к реализации, определяют типы данных, а затем методы: core, push и pop. В процедурах «push» и «pop» вычисляют «следующие» точки смещения для местоположения, в котором будет происходить текущая запись и чтение. Если следующее местоположение указывает на хвост, значит, буфер заполнен и данные больше не записываются. Точно так же, когда «head» равен «tail», он пуст и из него ничего не читается.

Стандартный вариант использования

Вспомогательная процедура вызывается процессом приложения для извлечения данных из кольцевого буфера Java. Она должен быть включена в критические разделы, если считывают контейнер более одного потока. Хвост перемещается к следующему смещению до того, как информация будет прочитана, поскольку каждый блок составляет один байт и резервируется аналогичное количество в буфере, когда объем полностью загружен. Но в более продвинутых реализациях циклического накопителя единичные разделы необязательно должны быть одинакового размера. В таких случаях стараются сохранить даже последний байт, добавив больше проверок и границ.

В таких схемах, если хвост передвигается перед чтением, информация, которая должна быть прочитана, потенциально может быть перезаписана вновь выдвинутыми данными. В общем случае рекомендуется сначала читать, а затем перемещать хвостовой указатель. Вначале определяют длину буфера, а затем создают экземпляр «circ_bbuf_t» и назначают указатель «maxlen». При этом контейнер должен быть глобальным или находиться в стеке. Так, например, если нужен кольцевой буфер длиной 32 байта, выполняют в приложении следующее (см. рисунок ниже).

Спецификация функциональных требований

Тип данных «ring_t» будет типом данных, который содержит указатель на буфер, размер его, индекс заголовка и хвоста, счетчик данных.

Функция инициализации «ring_init ()» инициализирует буфер на основе получения указателя на структуру контейнера, созданного вызывающей функцией, имеющей предопределенный размер.

Функция добавления звонка «ring_add ()» добавит байт в следующий доступный пробел в буфере.

Функция удаления кольца «ring_remove ()» удалит байт из самого старого допустимого места в контейнере.

Ring peek в функции «ring_peek ()» будет считывать число байтов «uint8_t ‘count’» из кольцевого буфера в новый, предоставленный в качестве параметра, без удаления каких-либо значений, считанных из контейнера. Он вернет количество фактически прочитанных байтов.

Функция очистки кольца «ring_clear ()» установит «Tail» равным «Head» и загрузит «0» во все позиции буфера.

Создание буфера в C/C ++

Из-за ограниченности ресурсов встроенных систем структуры данных с циклическим буфером можно найти в большинстве проектов фиксированного размера, которые работают так, как если бы память по своей природе была непрерывной и циклической. Данные не нужно переставлять, поскольку память генерируется и используется, а корректируются указатели головы/хвоста. Во время создания циклической буферной библиотеки нужно, чтобы пользователи работали с библиотечными API, а не изменяли структуру напрямую. Поэтому используют инкапсуляцию кольцевого буфера на «Си». Таким образом разработчик сохранит библиотечную реализацию, изменяя ее по мере необходимости, не требуя, чтобы конечные пользователи также обновляли ее.

Пользователи не могут работать с «circular_but_t» указателем, создается тип дескриптора, который можно использовать вместо него. Это избавит от необходимости приводить указатель в реализации функции «.typedefcbuf_handle_t». Разработчикам нужно собрать API для библиотеки. Они взаимодействуют с библиотекой кольцевого буфера «C», используя непрозрачный тип дескриптора, который создается во время инициализации. Обычно выбирают «uint8_t» в качестве базового типа данных. Но можно использовать любой конкретный тип, проявляя осторожность, чтобы правильно обрабатывать базовый буфер и количество байтов. Пользователи взаимодействуют с контейнером, выполняя обязательные процедуры:

  • Инициализировать контейнер и его размер.
  • Сбросить круговой контейнер.
  • Добавлять данные в кольцевой буфер на «Си».
  • Получать следующее значение из контейнера.
  • Затребовать информацию о текущем количестве элементов и максимальной емкости.
  • И «полный», и «пустой» случаи выглядят одинаково: «head» и «tail», указатели равны. Существует два подхода, различающие полный и пустой:

  • Полное состояние tail + 1 == head.
  • Пустое состояние head == tail.
  • Реализация библиотечных функций

    Для создания кругового контейнера используют его структуру для управления состоянием. Чтобы сохранить инкапсуляцию, структура определяется внутри библиотечного «.c» файла, а не в заголовке. При установке нужно будет отслеживать:

  • Базовый буфер данных.
  • Максимальный размер.
  • Текущую позицию головы, увеличивающуюся при добавлении.
  • Текущий хвост, увеличивающийся при удалении.
  • Флаг, указывающий, заполнен ли контейнер или нет.
  • Теперь, когда контейнер спроектирован, реализуют библиотечные функции. Каждый из API требует инициализированного дескриптора буфера. Вместо того чтобы засорять код условными утверждениями, применяют утверждения для обеспечения выполнения требований API в стиле.

    Реализация не будет являться поточно-ориентированной, если в базовую библиотеку циклических хранилищ не были добавлены блокировки. Для инициализации контейнера у API есть клиенты, которые предоставляют базовый размер буфера, поэтому создают его на стороне библиотеки, например, для простоты «malloc». Системы, которые не могут использовать динамическую память, должны изменить «init» функцию, чтобы использовать другой метод, например, такой как выделение из статического пула контейнеров.

    Другой подход заключается в нарушении инкапсуляции, что позволяет пользователям статически объявлять структуры контейнеров. В этом случае «circular_buf_init» необходимо обновить, чтобы взять указатель или «init», создать структуру стека и вернуть ее. Однако, поскольку инкапсуляция нарушена, пользователи смогут изменять ее без библиотечных процедур. После того как создан контейнер, заполняют значения и вызывают «reset». Прежде чем вернуться из «init», система гарантирует, что контейнер создан в пустом состоянии.

    Добавление и удаление данных

    Добавление и удаление данных из буфера требует манипуляций с «head»- и «tail»-указателями. При добавлении в контейнер вставляют новое значение в текущем «head»-месте и продвигают его. Когда удаляют, получают значение текущего «tail»-указателя и продвигают «tail». Если нужно продвинуть «tail»-указатель, а также «head», необходимо проверить, вызывает ли вставка значения «full». Когда буфер уже заполнен, продвигают «tail» на шаг впереди «head».

    После того как указатель был продвинут, заполняют «full»-флаг, проверяя равенство «head == tail». Модульное использование оператора приведет к тому, что «head» и «tail» сбросят значения в «0», когда будет достигнут максимальный размер. Это гарантирует, что «head» и «tail» всегда будут действительными индексами базового контейнера данных: «static void advance_pointer (cbuf_handle_t cbuf)». Можно создать аналогичную вспомогательную функцию, которая вызывается при удалении значения из буфера.

    Интерфейс шаблонного класса

    Для того чтобы реализация C ++ поддерживала любые типы данных, выполняют шаблон:

  • Сброс буфера для очистки.
  • Добавление и удаление данных.
  • Проверка полного/пустого состояния.
  • Проверка текущего количества элементов.
  • Проверка общей емкости контейнера.
  • Чтобы не оставить никаких данных после уничтожения буфера, используют интеллектуальные указатели C ++, чтобы гарантировать, что пользователи могут управлять данными.
  • В этом примере буфер C ++ имитирует большую часть логики реализации C, но в результате получается гораздо более чистый и многократно используемый дизайн. Кроме того, контейнер C ++ использует «std::mutex» для обеспечения поточно-ориентированной реализации. При создании класса выделяют данные для основного буфера и устанавливают его размер. Это устраняет накладные расходы, требуемые с реализацией C. В отличие от нее, конструктор C ++ не вызывает «reset», поскольку указывают начальные значения для переменных-членов, круговой контейнер запускается в правильном состоянии. Поведение сброса возвращает буфер в пустое состояние. В реализации циклического контейнера C ++ «size» и «capacity» сообщает количество элементов в очереди, а не размер в байтах.

    Драйвер UART STM32

    После запуска буфера, он должен быть интегрирован в драйвер UART. Сначала как глобальный элемент в файле, поэтому необходимо объявить:

    • «descriptor_rbd» и буферную память «_rbmem: static rbd_t _rbd»;
    • «static char _rbmem [8]».

    Поскольку это драйвер UART, где каждый символ должен быть 8-разрядным, создание массива символов допустимо. Если используется 9- или 10-битный режим, то каждый элемент должен быть «uint16_t». Контейнер рассчитывается таким образом, чтобы избежать потери данных.

    Часто модули очередей содержат статистическую информацию, позволяющую отслеживать максимальное использование. В функции инициализации «uart_init» буфер должен быть инициализирован путем вызова «ring_buffer_init» и передачи структуры атрибутов с каждым членом, которому назначены обсуждаемые значения. Если он успешно инициализируется, модуль UART выводится из сброса, прерывание приема разрешено в IFG2.

    Вторая функция, которая должна быть изменена, — это «uart_getchar». Считывание полученного символа из периферийного устройства UART заменяется чтением из очереди. Если очередь пуста, функция должна вернуть -1. Далее нужно внедрить UART для получения ISR. Открывают файл заголовка «msp430g2553.h», прокручивают вниз до секции векторов прерываний, где находят вектор с именем USCIAB0RX. Именование подразумевает, что это оно используется модулями USCI A0 и B0. Статус прерывания приема USCI A0 можно прочитать из IFG2. Если он установлен, флаг должен быть очищен, а данные в приемном отсеке помещены в буфер с помощью «ring_buffer_put».

    Репозиторий данных UART

    Этот репозиторий дает информацию о том, как считывать данные по UART с использованием DMA, когда количество байтов для приема заранее неизвестно. В семействе микроконтроллеров кольцевой буфер STM32 может работать в разных режимах:

  • Режим опроса (без DMA, без IRQ)- приложение должно опрашивать биты состояния, чтобы проверить, был ли принят новый символ, и прочитать его достаточно быстро, чтобы получить все байты. Очень простая реализация, но никто не использует ее в реальной жизни. Минусы — легко пропустить полученные символы в пакетах данных, работает только для низких скоростей передачи.
  • Режим прерывания (без DMA) — кольцевой буфер UART запускает прерывание, и ЦПУ переходит к служебной программе для обработки приема данных. Наиболее распространенный подход во всех приложениях сегодня, хорошо работает в диапазоне средних скоростей. Минусы — процедура обработки прерывания выполняется для каждого полученного символа, может останавливать другие задачи в высокопроизводительных микроконтроллерах с большим количеством прерываний и одновременно операционную систему при получении пакета данных.
  • Режим DMA используется для передачи данных из регистра USART RX в пользовательскую память на аппаратном уровне. На этом этапе взаимодействие с приложением не требуется, за исключением необходимости обработки полученных приложением данных. Может очень легко работать с операционными системами. Оптимизирован для высоких скоростей передачи данных > 1Mbps и маломощных приложений, в случае больших пакетов данных увеличение размера буфера может улучшить функциональность.
  • Реализация в ARDUINO

    Кольцевой буфер Arduino относится как к проектированию плат, так и к среде программирования, которая используется для работы. Ядром Arduino является микроконтроллер серии Atmel AVR. Именно AVR выполняет большую часть работы, и во многих отношениях плата Arduino вокруг AVR представляет функциональность — легко подключаемые контакты, USB-последовательный интерфейс для программирования и связи.

    Многие из обычных плат Arduino в настоящее время используют кольцевой буфер c ATmega 328, более старые платы использовали ATmega168 и ATmega8. Платы вроде Mega выбирают более сложные варианты, такие как 1280 и аналогичные. Чем быстрее Due и Zero, тем лучше используйте ARM. Существует около десятка различных плат Arduino с именами. Они могут иметь разное количество флеш-памяти, ОЗУ и порты ввода-вывода с кольцевым буфером AVR.

    Переменную «roundBufferIndex» используют для хранения текущей позиции, а при добавлении в буфер произойдет ограничение массива.

    Это результаты выполнения кода. Числа хранятся в буфере, и, когда они заполнены, они начинают перезаписываться. Таким образом можно получить последние N чисел.

    В предыдущем примере использован индекс для доступа к текущей позиции буфера, потому что он достаточен для объяснения операции. Но в общем, нормальным является то, что используется указатель. Это модифицированный код для использования указателя вместо индекса. По сути, операция такая же, как и предыдущая, а полученные результаты аналогичны.

    Высокопроизводительные операции CAS

    Disruptor — это высокопроизводительная библиотека для передачи сообщений между потоками, разработанная и открытая несколько лет назад компанией LMAX Exchange. Они создали это программное обеспечение для обработки огромного трафика (более 6 миллионов TPS) в своей розничной финансовой торговой платформе. В 2010 году они удивили всех тем, насколько быстрой может быть их система, выполнив всю бизнес-логику в одном потоке. Хотя один поток был важной концепцией в их решении, Disruptor работает в многопоточной среде и основан на кольцевом буфере — поток, в котором устаревшие данные больше не нужны, потому что поступают более свежие и более актуальные.

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

    Кольцевой буфер «qtserialport» (последовательный порт) наследуется от QIODevice, может быть использован для получения различных последовательной информации и включает в себя все из доступных последовательных устройств. Последовательный порт всегда открыт в монопольном доступе, это означает, что другие процессы или потоки не могут получить доступ к открытому последовательному порту.

    Кольцевые буферы очень полезны в программировании на «Си», например, можно оценить поток байтов, поступающих через UART.

    Источник

    ruud.ru

    Кольцевой буфер — это… Что такое Кольцевой буфер?

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

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

    Применение

    Как он устроен

    Кольцевой буфер создается пустым, с некоторой заранее определенной длинной. Например, это семиэлементный буфер:

    Предположим, что в середину буфера записывается 1 (в кольцевом буфере точная начальная ячейка не имеет значения):

    Затем предположим, что после единицы были добавлены еще два элемента — 2 и 3:

    Если после этого два элемента должны быть удалены из буфера, то выбираются два наиболее старых элемента. В нашем случае удаляются элементы 1 и 2, в буфере остается только 3:

    Если в буфере находится 7 элементов, то он заполнен:

    Если продолжить запись в буфер, не принимая во внимание его заполненность, то новые данные начнут перезаписывать старые данные. В нашем случае, добавляя элементы A и B мы перезапишем 3 и 4:

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

    Наконец, если теперь удалить из буфера два элемента, то удалены будут не 3 и 4, а 5 и 6, потому что A и B перезаписали элементы 3 и 4; буфер придет в состояние:

    Ссылки

    dic.academic.ru

    Кольцевой буфер / AVR / Сообщество EasyElectronics.ru

    Пусть здесь полежит, а то вдруг с моим репозиторием что случится… А тут, глядишь, кому и сгодится.
    Код для обслуживания кольцевых буферов, маленький и шустрый.
    Собственно так: в секции данных надо поместить массивчик, где будет храниться сам буфер, произвольного размера, до 255 байт. Глубина буфера задаётся константой RBSIZE, и массив получается на три байта больше размером. В первом байте лежит глубина заполнения, то есть сколько данных сейчас в буфере. При укладке байта — увеличивается, при выгрузке — уменьшается; если ноль — буфер пуст. Второй и третий байты — служебные, указатели загрузки и выгрузки. Для инита буфера надо эти три байта обнулить.
    А дальше всё стандартно — процедурой PutToBuf укладываем в буфер содержимое r16, процедурой GetFromBuf — достаём. Если буфер переполнен — очередной байт туда не ляжет, если пуст — содержимое r16 не изменится.
    Портит xl,xh,r17, загрузка/выгрузка занимает по 29 тактов. Локальных меток не имеет, так что можно легко тиражировать в любом количестве экземпляров внутри программы.
    
    
    ; В секции данных:
    ;.equ RBSIZE=11
    ; ringbuf:	.byte RBSIZE+3
    ; Конструкция кольцевого буфера: 
    ;+0 - глубина заполнения
    ;+1 - указатель укладки
    ;+2 - указатель выгрузки
    ;+3... - данные
    ; Использованные регистры: xh,xl,r16,r17
    ; укладка в буфер. 29 тактов
    PutToBuf:	ldi	xh,high(ringbuf+3) ;загрузка базы буфера
    		ldi	xl,low (ringbuf+3)
    		lds	r17,ringbuf+0	;load rbdept
    		cpi	r17,RBSIZE        ; проверка на переполнение
    		brcc	pc+16
    		inc	r17
    		sts	ringbuf+0,r17    ;store rbdept
    		lds	r17,ringbuf+1 	;load rbputptr
    		add	xl,r17            ; складываем указатель с базой
    		brcc	pc+2
    		inc	xh
    		st	x,r16            ; помещаем байт в буфер
    		inc	r17               ; приращение указателя укладки
    		cpi	r17,RBSIZE        ; закольцовка, если достигнута граница
    		brcs	PC+2
    		clr	r17
    		sts	ringbuf+1,r17	;store rbputptr
    		ret
    
    ; выгрузка из буфера. 29 тактов
    GetFromBuf:	ldi	xh,high(ringbuf+3)
    		ldi	xl,low (ringbuf+3)
    		lds	r17,ringbuf+0	;load rbdept
    		tst	r17            ; проверка наличия данных
    		breq	pc+16
    		dec	r17
    		sts	ringbuf+0,r17	;store rbdept
    		lds	r17,ringbuf+2	;rbgetptr
    		add	xl,r17
    		brcc	pc+2
    		inc	xh
    		inc	r17
    		cpi	r17,RBSIZE
    		brcs	PC+2
    		clr	r17
    		sts	ringbuf+2,r17	;rbgetptr
    		ld	r16,x
    		ret
    
    

    we.easyelectronics.ru

    Кольцевой буфер — Википедия. Что такое Кольцевой буфер

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

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

    Кольцевой буфер находит очень широкое применение в том числе при программировании микроконтроллеров. Кольцевые буферы часто используют для организации различных очередей сообщений и буферов приёма-передачи различных коммуникационных интерфейсов. Популярность КБ обусловлена тем, что это один из самых простых и эффективных способов организовать FIFO (англ. first in — first out, «первым пришёл — первым вышел») без использования динамической памяти. Существует множество разновидностей КБ.

    Как он устроен

    Кольцевой буфер создается пустым, с некоторой заранее определенной длиной. Например, это семиэлементный буфер:

    Предположим, что в середину буфера записывается 1 (в кольцевом буфере точная начальная ячейка не имеет значения):

    Затем предположим, что после единицы были добавлены ещё два элемента — 2 и 3:

    Если после этого два элемента должны быть удалены из буфера, то выбираются два наиболее старых элемента. В нашем случае удаляются элементы 1 и 2, в буфере остается только 3:

    Если в буфере находится 7 элементов, то он заполнен:

    Если продолжить запись в буфер, не принимая во внимание его заполненность, то новые данные начнут перезаписывать старые данные. В нашем случае, добавляя элементы A и B, мы перезапишем 3 и 4:

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

    Наконец, если теперь удалить из буфера два элемента, то удалены будут не 3 и 4, а 5 и 6, потому что A и B перезаписали элементы 3 и 4; буфер придет в состояние:

    Ссылки

    wiki.sc

    Что такое кольцевой буфер?

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

    Теоретические основы буфера

    Пользователю легче сделать выбор эффективной структуры массивов после понимания основополагающей теории. Циклический буфер — структура данных, где массив обрабатывается и визуализируется в виде циклов, то есть индексы возвращаются к 0 после достижения длины массива. Это делается с помощью двух указателей на массив: «head» и «tail». Когда данные добавляются в буфер, указатель заголовка перемещается вверх. Точно так же, когда они удаляются, то хвост тоже перемещается вверх. Определение головы, хвоста, направления их движения, места записи и чтения зависят от реализации схемы.

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

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

    Еще один вопрос, который возникает в отношении циклического буфера. Нужно ли сбрасывать новые данные или перезаписывать существующие, когда он заполнен? Специалисты утверждают, что нет явного преимущества одного над другим, а его реализация зависит от конкретной ситуации. Если последние имеют больше значимости для приложения, используют метод перезаписи. С другой стороны, если они обрабатываются в режиме «первым пришел — первым обслужен», то отбрасывают новые, когда кольцевой буфер заполнен.

    Реализация цикличной очереди

    Приступая к реализации, определяют типы данных, а затем методы: core, push и pop. В процедурах «push» и «pop» вычисляют «следующие» точки смещения для местоположения, в котором будет происходить текущая запись и чтение. Если следующее местоположение указывает на хвост, значит, буфер заполнен и данные больше не записываются. Точно так же, когда «head» равен «tail», он пуст и из него ничего не читается.

    Стандартный вариант использования

    Вспомогательная процедура вызывается процессом приложения для извлечения данных из кольцевого буфера Java. Она должен быть включена в критические разделы, если считывают контейнер более одного потока. Хвост перемещается к следующему смещению до того, как информация будет прочитана, поскольку каждый блок составляет один байт и резервируется аналогичное количество в буфере, когда объем полностью загружен. Но в более продвинутых реализациях циклического накопителя единичные разделы необязательно должны быть одинакового размера. В таких случаях стараются сохранить даже последний байт, добавив больше проверок и границ.

    В таких схемах, если хвост передвигается перед чтением, информация, которая должна быть прочитана, потенциально может быть перезаписана вновь выдвинутыми данными. В общем случае рекомендуется сначала читать, а затем перемещать хвостовой указатель. Вначале определяют длину буфера, а затем создают экземпляр «circ_bbuf_t» и назначают указатель «maxlen». При этом контейнер должен быть глобальным или находиться в стеке. Так, например, если нужен кольцевой буфер длиной 32 байта, выполняют в приложении следующее (см. рисунок ниже).

    Спецификация функциональных требований

    Тип данных «ring_t» будет типом данных, который содержит указатель на буфер, размер его, индекс заголовка и хвоста, счетчик данных.

    Функция инициализации «ring_init ()» инициализирует буфер на основе получения указателя на структуру контейнера, созданного вызывающей функцией, имеющей предопределенный размер.

    Функция добавления звонка «ring_add ()» добавит байт в следующий доступный пробел в буфере.

    Функция удаления кольца «ring_remove ()» удалит байт из самого старого допустимого места в контейнере.

    Ring peek в функции «ring_peek ()» будет считывать число байтов «uint8_t ‘count’» из кольцевого буфера в новый, предоставленный в качестве параметра, без удаления каких-либо значений, считанных из контейнера. Он вернет количество фактически прочитанных байтов.

    Функция очистки кольца «ring_clear ()» установит «Tail» равным «Head» и загрузит «0» во все позиции буфера.

    Создание буфера в C/C ++

    Из-за ограниченности ресурсов встроенных систем структуры данных с циклическим буфером можно найти в большинстве проектов фиксированного размера, которые работают так, как если бы память по своей природе была непрерывной и циклической. Данные не нужно переставлять, поскольку память генерируется и используется, а корректируются указатели головы/хвоста. Во время создания циклической буферной библиотеки нужно, чтобы пользователи работали с библиотечными API, а не изменяли структуру напрямую. Поэтому используют инкапсуляцию кольцевого буфера на «Си». Таким образом разработчик сохранит библиотечную реализацию, изменяя ее по мере необходимости, не требуя, чтобы конечные пользователи также обновляли ее.

    Пользователи не могут работать с «circular_but_t» указателем, создается тип дескриптора, который можно использовать вместо него. Это избавит от необходимости приводить указатель в реализации функции «.typedefcbuf_handle_t». Разработчикам нужно собрать API для библиотеки. Они взаимодействуют с библиотекой кольцевого буфера «C», используя непрозрачный тип дескриптора, который создается во время инициализации. Обычно выбирают «uint8_t» в качестве базового типа данных. Но можно использовать любой конкретный тип, проявляя осторожность, чтобы правильно обрабатывать базовый буфер и количество байтов. Пользователи взаимодействуют с контейнером, выполняя обязательные процедуры:

    1. Инициализировать контейнер и его размер.
    2. Сбросить круговой контейнер.
    3. Добавлять данные в кольцевой буфер на «Си».
    4. Получать следующее значение из контейнера.
    5. Затребовать информацию о текущем количестве элементов и максимальной емкости.

    И «полный», и «пустой» случаи выглядят одинаково: «head» и «tail», указатели равны. Существует два подхода, различающие полный и пустой:

    1. Полное состояние tail + 1 == head.
    2. Пустое состояние head == tail.

    Реализация библиотечных функций

    Для создания кругового контейнера используют его структуру для управления состоянием. Чтобы сохранить инкапсуляцию, структура определяется внутри библиотечного «.c» файла, а не в заголовке. При установке нужно будет отслеживать:

    1. Базовый буфер данных.
    2. Максимальный размер.
    3. Текущую позицию головы, увеличивающуюся при добавлении.
    4. Текущий хвост, увеличивающийся при удалении.
    5. Флаг, указывающий, заполнен ли контейнер или нет.

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

    Реализация не будет являться поточно-ориентированной, если в базовую библиотеку циклических хранилищ не были добавлены блокировки. Для инициализации контейнера у API есть клиенты, которые предоставляют базовый размер буфера, поэтому создают его на стороне библиотеки, например, для простоты «malloc». Системы, которые не могут использовать динамическую память, должны изменить «init» функцию, чтобы использовать другой метод, например, такой как выделение из статического пула контейнеров.

    Другой подход заключается в нарушении инкапсуляции, что позволяет пользователям статически объявлять структуры контейнеров. В этом случае «circular_buf_init» необходимо обновить, чтобы взять указатель или «init», создать структуру стека и вернуть ее. Однако, поскольку инкапсуляция нарушена, пользователи смогут изменять ее без библиотечных процедур. После того как создан контейнер, заполняют значения и вызывают «reset». Прежде чем вернуться из «init», система гарантирует, что контейнер создан в пустом состоянии.

    Добавление и удаление данных

    Добавление и удаление данных из буфера требует манипуляций с «head»- и «tail»-указателями. При добавлении в контейнер вставляют новое значение в текущем «head»-месте и продвигают его. Когда удаляют, получают значение текущего «tail»-указателя и продвигают «tail». Если нужно продвинуть «tail»-указатель, а также «head», необходимо проверить, вызывает ли вставка значения «full». Когда буфер уже заполнен, продвигают «tail» на шаг впереди «head».

    После того как указатель был продвинут, заполняют «full»-флаг, проверяя равенство «head == tail». Модульное использование оператора приведет к тому, что «head» и «tail» сбросят значения в «0», когда будет достигнут максимальный размер. Это гарантирует, что «head» и «tail» всегда будут действительными индексами базового контейнера данных: «static void advance_pointer (cbuf_handle_t cbuf)». Можно создать аналогичную вспомогательную функцию, которая вызывается при удалении значения из буфера.

    Интерфейс шаблонного класса

    Для того чтобы реализация C ++ поддерживала любые типы данных, выполняют шаблон:

    1. Сброс буфера для очистки.
    2. Добавление и удаление данных.
    3. Проверка полного/пустого состояния.
    4. Проверка текущего количества элементов.
    5. Проверка общей емкости контейнера.
    6. Чтобы не оставить никаких данных после уничтожения буфера, используют интеллектуальные указатели C ++, чтобы гарантировать, что пользователи могут управлять данными.

    В этом примере буфер C ++ имитирует большую часть логики реализации C, но в результате получается гораздо более чистый и многократно используемый дизайн. Кроме того, контейнер C ++ использует «std::mutex» для обеспечения поточно-ориентированной реализации. При создании класса выделяют данные для основного буфера и устанавливают его размер. Это устраняет накладные расходы, требуемые с реализацией C. В отличие от нее, конструктор C ++ не вызывает «reset», поскольку указывают начальные значения для переменных-членов, круговой контейнер запускается в правильном состоянии. Поведение сброса возвращает буфер в пустое состояние. В реализации циклического контейнера C ++ «size» и «capacity» сообщает количество элементов в очереди, а не размер в байтах.

    Драйвер UART STM32

    После запуска буфера, он должен быть интегрирован в драйвер UART. Сначала как глобальный элемент в файле, поэтому необходимо объявить:

    • «descriptor_rbd» и буферную память «_rbmem: static rbd_t _rbd»;
    • «static char _rbmem [8]».

    Поскольку это драйвер UART, где каждый символ должен быть 8-разрядным, создание массива символов допустимо. Если используется 9- или 10-битный режим, то каждый элемент должен быть «uint16_t». Контейнер рассчитывается таким образом, чтобы избежать потери данных.

    Часто модули очередей содержат статистическую информацию, позволяющую отслеживать максимальное использование. В функции инициализации «uart_init» буфер должен быть инициализирован путем вызова «ring_buffer_init» и передачи структуры атрибутов с каждым членом, которому назначены обсуждаемые значения. Если он успешно инициализируется, модуль UART выводится из сброса, прерывание приема разрешено в IFG2.

    Вторая функция, которая должна быть изменена, — это «uart_getchar». Считывание полученного символа из периферийного устройства UART заменяется чтением из очереди. Если очередь пуста, функция должна вернуть -1. Далее нужно внедрить UART для получения ISR. Открывают файл заголовка «msp430g2553.h», прокручивают вниз до секции векторов прерываний, где находят вектор с именем USCIAB0RX. Именование подразумевает, что это оно используется модулями USCI A0 и B0. Статус прерывания приема USCI A0 можно прочитать из IFG2. Если он установлен, флаг должен быть очищен, а данные в приемном отсеке помещены в буфер с помощью «ring_buffer_put».

    Репозиторий данных UART

    Этот репозиторий дает информацию о том, как считывать данные по UART с использованием DMA, когда количество байтов для приема заранее неизвестно. В семействе микроконтроллеров кольцевой буфер STM32 может работать в разных режимах:

    1. Режим опроса (без DMA, без IRQ)- приложение должно опрашивать биты состояния, чтобы проверить, был ли принят новый символ, и прочитать его достаточно быстро, чтобы получить все байты. Очень простая реализация, но никто не использует ее в реальной жизни. Минусы — легко пропустить полученные символы в пакетах данных, работает только для низких скоростей передачи.
    2. Режим прерывания (без DMA) — кольцевой буфер UART запускает прерывание, и ЦПУ переходит к служебной программе для обработки приема данных. Наиболее распространенный подход во всех приложениях сегодня, хорошо работает в диапазоне средних скоростей. Минусы — процедура обработки прерывания выполняется для каждого полученного символа, может останавливать другие задачи в высокопроизводительных микроконтроллерах с большим количеством прерываний и одновременно операционную систему при получении пакета данных.
    3. Режим DMA используется для передачи данных из регистра USART RX в пользовательскую память на аппаратном уровне. На этом этапе взаимодействие с приложением не требуется, за исключением необходимости обработки полученных приложением данных. Может очень легко работать с операционными системами. Оптимизирован для высоких скоростей передачи данных > 1Mbps и маломощных приложений, в случае больших пакетов данных увеличение размера буфера может улучшить функциональность.

    Реализация в ARDUINO

    Кольцевой буфер Arduino относится как к проектированию плат, так и к среде программирования, которая используется для работы. Ядром Arduino является микроконтроллер серии Atmel AVR. Именно AVR выполняет большую часть работы, и во многих отношениях плата Arduino вокруг AVR представляет функциональность — легко подключаемые контакты, USB-последовательный интерфейс для программирования и связи.

    Многие из обычных плат Arduino в настоящее время используют кольцевой буфер c ATmega 328, более старые платы использовали ATmega168 и ATmega8. Платы вроде Mega выбирают более сложные варианты, такие как 1280 и аналогичные. Чем быстрее Due и Zero, тем лучше используйте ARM. Существует около десятка различных плат Arduino с именами. Они могут иметь разное количество флеш-памяти, ОЗУ и порты ввода-вывода с кольцевым буфером AVR.

    Переменную «roundBufferIndex» используют для хранения текущей позиции, а при добавлении в буфер произойдет ограничение массива.

    Это результаты выполнения кода. Числа хранятся в буфере, и, когда они заполнены, они начинают перезаписываться. Таким образом можно получить последние N чисел.

    В предыдущем примере использован индекс для доступа к текущей позиции буфера, потому что он достаточен для объяснения операции. Но в общем, нормальным является то, что используется указатель. Это модифицированный код для использования указателя вместо индекса. По сути, операция такая же, как и предыдущая, а полученные результаты аналогичны.

    Высокопроизводительные операции CAS

    Disruptor — это высокопроизводительная библиотека для передачи сообщений между потоками, разработанная и открытая несколько лет назад компанией LMAX Exchange. Они создали это программное обеспечение для обработки огромного трафика (более 6 миллионов TPS) в своей розничной финансовой торговой платформе. В 2010 году они удивили всех тем, насколько быстрой может быть их система, выполнив всю бизнес-логику в одном потоке. Хотя один поток был важной концепцией в их решении, Disruptor работает в многопоточной среде и основан на кольцевом буфере — поток, в котором устаревшие данные больше не нужны, потому что поступают более свежие и более актуальные.

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

    Кольцевой буфер «qtserialport» (последовательный порт) наследуется от QIODevice, может быть использован для получения различных последовательной информации и включает в себя все из доступных последовательных устройств. Последовательный порт всегда открыт в монопольном доступе, это означает, что другие процессы или потоки не могут получить доступ к открытому последовательному порту.

    Кольцевые буферы очень полезны в программировании на «Си», например, можно оценить поток байтов, поступающих через UART.

    fb.ru

    Кольцевой буфер | RadioLaba.ru — программирование микроконтроллеров PIC

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

     

    flag          equ         78h               ;регистр флагов

    FSR_prer      equ         7Bh               ;регистр хранения значения FSR для обработчика прерываний

    FSR_temp      equ         7Dh               ;регистр хранения значения FSR для основной программы

    W_TEMP        equ         7Eh               ;регистр хранения значения аккумулятора W

    STATUS_TEMP   equ         7Fh               ;регистр хранения значения STATUS

     

    bnk1_start    equ         20h               ;начальный адрес регистра 1-й половины буфера ОЗУ

    bnk1_end      equ         47h               ;конечный адрес регистра 1-й половины буфера ОЗУ

     

    bnk2_start    equ         A0h               ;начальный адрес регистра 2-й половины буфера ОЗУ

    bnk2_end      equ         С7h               ;конечный адрес регистра 2-й половины буфера ОЗУ

     

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

     

                org         0000h               ; Начать выполнение программы с адреса 0 PC.

                goto        Start               ;

     

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    ;Подпрограмма обработки прерываний

     

                org         0004h               ;начать выполнение подпрограммы с адреса 0004h

                          

                movwf       W_TEMP              ;сохранение значений ключевых регистров

                swapf       STATUS,W            ;

                clrf        STATUS              ;

                movwf       STATUS_TEMP         ;

     

                movf        FSR,W               ;сохранение значения регистра FSR, и восстановление

                movwf       FSR_temp            ;ранее сохраненного значения в предыдущем входе  

                movf        FSR_prer,W          ;в обработчик прерываний

                movwf       FSR                 ;

     

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

              

                movf        INDF,W              ;копируем значение регистра ОЗУ в аккумулятор

                                                ;

                ;………………             ;Здесь выполняем какие-либо операции с полученным значением:  

                ;………………             ;например вычисления, передача по UART, передача в ШИМ и т.д.

     

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

     

                btfsc       flag,0              ;проверка флага занятости буферов ОЗУ

                goto        bnk2                ;флаг=1: переход на метку bnk2 для проверки окончания

                                                ;2-й половины буфера ОЗУ

     

                                                ;флаг=0: проверка окончания 1-й половины буфера ОЗУ

    bnk1        movlw       bnk1_end            ;проверка не является ли текущий регистр последним в 1-й

                xorwf       FSR,W               ;половине буфера ОЗУ

                btfss       STATUS,Z            ;

                goto        exxit               ;текущий регистр не последний: переход на метку exxit

                

                                                ;текущий регистр последний в 1-й половине буфера ОЗУ

    ust_bnk2    movlw       bnk2_start          ;установка первого регистра 2-й половины буфера ОЗУ

                movwf       FSR                 ;для косвенной адресации

                bsf         flag,0              ;установка флага занятости: считывание из 2-й половины буфера

                goto        exxit_1             ;переход на метку exxit_1

     

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

     

    bnk2        movlw       bnk2_end            ;проверка не является ли текущий регистр последним во 2-й

                xorwf       FSR,W               ;половине буфера ОЗУ

                btfss       STATUS,Z            ;

                goto        exxit               ;текущий регистр не последний: переход на метку exxit

                

                                                ;текущий регистр последний во 2-й половине буфера ОЗУ

    ust_bnk2    movlw       bnk1_start          ;установка первого регистра 1-й половины буфера ОЗУ

                movwf       FSR                 ;для косвенной адресации

                bcf         flag,0              ;сброс флага занятости: считывание из 1-й половины буфера

                goto        exxit_1             ;переход на метку exxit_1

     

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

     

    exxit       incf        FSR,F               ;инкремент регистра FSR: подготовка следующего

                                                ;регистра ОЗУ для чтения

                                                ;

    exxit_1     ;………………             ;Здесь выполняем настройку таймера, сброс флагов прерываний

                ;………………             ;запись нового значения в таймер, и его запуск

                                              

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

     

                movf        FSR,W               ;сохранение значения регистра FSR, и восстановление

                movwf       FSR_prer            ;ранее сохраненного значения при входе в обработчик

                movf        FSR_temp,W          ;прерываний

                movwf       FSR                 ;

                                              

                swapf       STATUS_temp,W       ;восстановление регистров STATUS и W

                movwf       STATUS              ;

                swapf       W_temp,F            ;

                swapf       W_temp,W            ;

                retfie                          ;выход из подпрограммы прерывания

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

     

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    ;Основная программа

     

    Start       ;……………….            ;настройка регистров микроконтроллера

                ;……………….            ;

                ;……………….            ;настройка таймера для регулярных прерываний

                ;……………….            ;

     

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    ;Первоначальная загрузка буферов ОЗУ

     

    us_1        movlw       bnk1_start          ;установка первого регистра 1-й половины буфера ОЗУ

                movwf       FSR                 ;для косвенной адресации

          

    met_1       call        priem_byte          ;вызов подпрограммы приема байта данных

                movwf       INDF                ;запись принятого байта данных в регистр буфера ОЗУ  

                                                

                movlw       bnk1_end            ;проверка не является ли текущий регистр последним в 1-й

                xorwf       FSR,W               ;половине буфера ОЗУ

                btfsc       STATUS,Z            ;

                goto        ust_2               ;текущий регистр последний: переход на метку ust_2

                incf        FSR,F               ;текущий регистр не последний: инкремент регистра FSR:

                                                ;подготовка следующего регистра ОЗУ для загрузки

                goto        met_1               ;переход на метку met_1

     

    ust_2       movlw       bnk2_start          ;установка первого регистра 2-й половины буфера ОЗУ

                movwf       FSR                 ;для косвенной адресации

          

    met_2       call        priem_byte          ;вызов подпрограммы приема байта данных

                movwf       INDF                ;запись принятого байта данных в регистр буфера ОЗУ

                                                

                movlw       bnk2_end            ;проверка не является ли текущий регистр последним во 2-й

                xorwf       FSR,W               ;половине буфера ОЗУ

                btfsc       STATUS,Z            ;

                goto        zapusk              ;текущий регистр последний: переход на метку zapusk

                incf        FSR,F               ;текущий регистр не последний: инкремент регистра FSR:

                                                ;подготовка следующего регистра ОЗУ для загрузки

                goto        met_2               ;переход на метку met_1

     

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

     

    zapusk      movlw       bnk1_start          ;установка первого регистра 1-й половины буфера ОЗУ

                movwf       FSR_prer            ;для обработчика прерываний, выполняется однократно

                                                ;при запуске кругового цикла передачи данных

     

                bcf         flag,0              ;сброс флага занятости 1-й половины буфера ОЗУ

                                                ;для обработчика прерывания, выполняется однократно

                                                ;при запуске кругового цикла передачи данных

                ;……………….            ;Здесь запускаем таймер для прерываний

                ;……………….            ;(Начало кругового цикла передачи данных)

     

     

    zagruz_1    ;………………..           ;Здесь выполняем проверку кнопок, флагов и т.д. на факт появления  

                ;………………..           ;стоп сигнала, для того чтобы завершить круговой цикл передачи данных

                ;………………..           ;и перейти к другим задачам. Если обнаружен стоп сигнал необходимо

                ;………………..           ;остановить таймер, для прекращения вызова обработчика прерываний

     

    povt_1      btfss       flag,0              ;опрос флага занятости банка

                goto        povt_1              ;флаг=0, занята 1-я половины буфера ОЗУ: переход на метку povt_1

     

                                                ;флаг=1, 1-я половина буфера ОЗУ освободилась

                movlw       bnk1_start          ;установка первого регистра 1-й половины буфера ОЗУ

                movwf       FSR                 ;для загрузки данных

     

    zag_1       call        priem_byte          ;вызов подпрограммы приема байта данных

                movwf       INDF                ;запись принятого байта данных в регистр буфера ОЗУ

     

                movlw       bnk1_end            ;проверка не является ли текущий регистр последним в 1-й

                xorwf       FSR,W               ;половине буфера ОЗУ

                btfsc       STATUS,Z            ;

                goto        zagruz_2            ;текущий регистр последний: переход на метку zagruz_2

                incf        FSR,F               ;текущий регистр не последний: инкремент регистра FSR:

                                                ;подготовка следующего регистра ОЗУ для загрузки

                goto        zag_1               ;переход на метку zag_1

     

    zagruz_2    btfsc       flag,0              ;опрос флага занятости банка

                goto        zagruz_2            ;флаг=1, занята 2-я половины буфера ОЗУ: переход на метку zagruz_2

     

                                                ;флаг=0, 2-я половина буфера ОЗУ освободилась

                movlw       bnk2_start          ;установка первого регистра 2-й половины буфера ОЗУ

                movwf       FSR                 ;для загрузки данных

     

    zag_2       call        priem_byte          ;вызов подпрограммы приема байта данных

                movwf       INDF                ;запись принятого байта данных в регистр буфера ОЗУ

     

                movlw       bnk2_end            ;проверка не является ли текущий регистр последним во 2-й

                xorwf       FSR,W               ;половине буфера ОЗУ

                btfsc       STATUS,Z            ;

                goto        zagruz_1            ;текущий регистр последний: переход на метку zagruz_1

                incf        FSR,F               ;текущий регистр не последний: инкремент регистра FSR:

                                                ;подготовка следующего регистра ОЗУ для загрузки

                goto        zag_2               ;переход на метку zag_2

     

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

     

    priem_byte  ;……………….            ;Подпрограмма приема байта данных от внешних устройств

                ;……………….            ;(например из EEPROM микросхемы, карты памяти и т.д.)

                ;……………….            ;

                                                ;

                movf       byte,W               ;запись принятого байта в аккумулятор W

                return                          ;выход из подпрограммы

     

                end                             ;конец всей программы

    radiolaba.ru

    Кольцевой буфер — Howling Pixel

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

    Применение

    Кольцевой буфер находит очень широкое применение в том числе при программировании микроконтроллеров. Данные структуры часто используют для организации различных очередей сообщений и буферов приёма-передачи различных коммуникационных интерфейсов. Популярность КБ обусловлена тем, что это один из самых простых и эффективных способов организовать FIFO (англ. first in — first out, «первым пришёл — первым вышел») без использования динамической памяти. Существует множество разновидностей КБ.

    Внутреннее устройство

    Кольцевой буфер создается пустым, с некоторой заранее определенной длиной. Например, это семиэлементный буфер:

    Предположим, что в середину буфера записывается 1 (в кольцевом буфере точная начальная ячейка не имеет значения):

    Затем предположим, что после единицы были добавлены ещё два элемента — 2 и 3:

    Если после этого два элемента должны быть удалены из буфера, то выбираются два наиболее старых элемента. В нашем случае удаляются элементы 1 и 2, в буфере остается только 3:

    Если в буфере находится 7 элементов, то он заполнен:

    Если продолжить запись в буфер, не принимая во внимание его заполненность, то новые данные начнут перезаписывать старые данные. В нашем случае, добавляя элементы A и B, мы перезапишем 3 и 4:

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

    Наконец, если теперь удалить из буфера два элемента, то удалены будут не 3 и 4, а 5 и 6, потому что A и B перезаписали элементы 3 и 4; буфер придет в состояние:

    Ссылки

    FIFO

    FIFO (англ. first in, first out — «первым пришёл — первым ушёл») — способ организации и манипулирования данными относительно времени и приоритетов. Это выражение описывает принцип технической обработки очереди или обслуживания конфликтных требований путём упорядочения процесса по принципу: «первым пришёл — первым обслужен» (ПППО). Тот, кто приходит первым, тот и обслуживается первым, пришедший следующим ждёт, пока обслуживание первого не будет закончено, и так далее.

    Этот принцип аналогичен поведению лиц, стоящих в очереди, когда люди получают обслуживание в том порядке, в котором они занимали очередь. То же самое происходит, например, на нерегулируемом перекрёстке, когда водители ожидают своей очереди на продолжение движения (в ПДД США нет правила «помеха справа», приоритет определяется по принципу FIFO). ПППО также используется как сокращённое название для алгоритма FIFO планирования работы операционной системы, по которому процессорное время выделяется каждому процессу в порядке их поступления на обслуживание.

    В более широком смысле, абстракция LIFO или last-in-first-out («последним пришёл — первым ушёл») является противоположностью абстракции FIFO. Разница, возможно, станет яснее, если принять во внимание реже используемый синоним FILO, означающий first-in-last-out («первым пришёл — последним ушёл»). В сущности, обе абстракции являются конкретными случаями более общего понятия работы со списком. Разница не в списке (данных), а в правиле доступа к содержимому. В первом случае добавление делается к одному концу списка, а снятие с другого, во втором случае добавление и снятие делается на одном конце.В случае FIFO список называют очередью, в случае LIFO — стек.

    Вариантом очереди является очередь с приоритетом, для которой нельзя использовать название FIFO, потому что в этом случае обработка структуры данных происходит по другому принципу. Теория массового обслуживания охватывает более общее понятие очереди, а также взаимодействие между очередями, обслуживание в которых осуществляется по принципу «строго-FIFO». Для обозначения этого принципа также используется аббревиатура FCFS (first come, first served — «первым пришёл, первым обслужен»).

    MG3

    MG3 (нем. Maschinengewehr 3) — немецкий единый пулемёт. Является усовершенствованным вариантом пулемёта MG 42.

    MongoDB

    MongoDB (от англ. humongous — огромный) — документоориентированная система управления базами данных (СУБД) с открытым исходным кодом, не требующая описания схемы таблиц. Классифицирована как NoSQL, использует JSON-подобные документы и схему базы данных. Написана на языке C++.

    Realtek RTL8139

    Realtek RTL8139 — семейство популярных интегрированных контроллеров сетевого интерфейса Fast Ethernet, разрабатывавшееся компанией Realtek в 1997-2005 годах. Контроллеры реализуют в одной микросхеме уровни MAC, PHY и трансивера, имеют интерфейс PCI и поддерживают работу на скоростях 10 или 100 Мбит/с по неэкранированной витой паре.

    В состав семейства входило шесть моделей контроллеров: RTL8139, RTL8139A, RTL8139B, RTL8139C, RTL8139C+, RTL8139D. Они применялись для создания сетевых карт с интерфейсом PCI для ПК, сетевых модулей с интерфейсом mini-PCI и интегрированных сетевых карты ноутбуков и материнских плат.

    Благодаря доступности и невысокой цене как самих контроллеров семейства RTL8139, так и карт на его основе (6-13 долларов на 2002 год), а также простого программно-аппаратного интерфейса карты на базе RTL8139 были широко распространены, и в множестве операционных систем была поддержана работа с этим контроллером. Ряд систем виртуализации эмулируют именно этот контроллер.

    По оценкам самой компании, в начале 2000-х годов Realtek занимал около 65% рынка контроллеров Ethernet.

    Буферное окно

    Буферное окно (англ. Gap buffer) в информатике это динамический массив, который позволяет эффективно производить вставку и удаление элемента в некоторой области. Буферное окно особенно распространено в текстовых редакторах, где большинство изменений текста происходят около позиции курсора. Текст хранится в большом буфере в двух смежных сегментах с окном для вставки элементов между ними. Перемещение курсора вызывает копирование текста с одной стороны окна в другую (иногда копирование задерживается до операции изменения текста). Вставка добавляет новый текст в конец первого сегмента. Удаление увеличивает размер окна.

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

    Использование буферного окна основано на предположении, что перекопирование происходит достаточно редко и его стоимость может быть амортизирована более дешевыми операциями. Это делает буферное окно более простой альтернативой Rope для использования в текстовых редакторах таких как Emacs.

    Семафор (программирование)

    Семафо́р (англ. semaphore) — примитив синхронизации работы процессов и потоков, в основе которого лежит счётчик, над которым можно производить две атомарные операции: увеличение и уменьшение значения на единицу, при этом операция уменьшения для нулевого значения счётчика является блокирующейся. Служит для построения более сложных механизмов синхронизации и используется для синхронизации параллельно работающих задач, для защиты передачи данных через разделяемую память, для организации критических секций, а также для управления доступом к аппаратному обеспечения.

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

    Семафоры могут быть двоичными и вычислительными. Вычислительные семафоры могут принимать целочисленные неотрицательные значения и используются для работы с ресурсами, количество которых ограничено, либо участвуют в синхронизации параллельно исполняемых задач. Двоичные семафоры являются частным случаем вычислительного семафора и могут принимать только два значения: 0 и 1.

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

    Файл регистрации

    Файл регистрации (протокол, журнал, лог; англ. log) — файл с записями о событиях в хронологическом порядке, простейшее средство обеспечения журналирования. Различают регистрацию внешних событий и протоколирование работы самой программы — источника записей (хотя часто всё записывается в единый файл).

    This page is based on a Wikipedia article written by authors (here).
    Text is available under the CC BY-SA 3.0 license; additional terms may apply.
    Images, videos and audio are available under their respective licenses.

    howlingpixel.com

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

    Ваш адрес email не будет опубликован.