Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Циклический буфер на AVR
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Страницы: 1, 2
=GM=
Тема открыта по горячим следам недавней острой дискуссии.

В ней одним из участников (defunct) была приведена программа, в которой использовался циклический буфер для работы с последовательным портом МК AT90S2313. На взгляд автора программа написана достаточно грамотно, но как-то слишком размашисто, без учёта мизерности ресурсов данного МК. Предлагаю участникам поделиться примерами и приёмами использования циклического буфера в программных разработках.

Для затравки предлагаю следующие фрагменты.

А. Запись байта из регистра AL в циклический буфер
Код
      mov     xl,qhead    ;указатель на запись
      st      x+,al       ;запишем байт
      cp      xl,qend     ;конец буфера?
      brne    .+2         ;нет, обходим
      ldi     xl,buffer   ;да, установим начало

Б. Чтение байта из циклического буфера в регистр AL
Код
      mov     xl,qtail    ;указатель на чтение
      ld      al,x+       ;прочитаем байт
      cp      xl,qend     ;конец буфера?
      brne    .+2         ;нет, обходим
      ldi     xl,buffer   ;да, установим начало

Если использовать буфер не произвольной длины, а кратный степени 2, и размещать его в памяти не произвольно, а начиная с адресов, кратных длине буфера, то размер кода можно немного сократить. Например.

В. Запись байта из регистра AL в циклический буфер длиной 32
Код
      mov     xl,qhead    ;указатель на запись
      st      x+,al       ;запишем байт
      cbr     xl,0xE0     ;держим указатель в предписанных рамках

Г. Чтение байта из циклического буфера длиной 32 в регистр AL
Код
      mov     xl,qtail    ;указатель на чтение
      ld      al,x+       ;прочитаем байт
      cbr     xl,0xE0     ;держим указатель в предписанных рамках

Здесь qhead, qtail, qend – регистровые переменные, содержащие адреса-указатели ячеек в озу для записи, чтения и конца буфера соответственно.
defunct
Цитата(=GM= @ Aug 24 2007, 18:16) *
Если использовать буфер не произвольной длины, а кратный степени 2, и размещать его в памяти не произвольно, а начиная с адресов, кратных длине буфера, то размер кода можно немного сократить.

Если вы хотели услышать отзыв о вашем способе, то вот он:
Хороший способ. Особо хорошо подходит для задач где требуется выделить некий "под-поток" внутри потока. Другими словами для организации "probation" периода.
=AVR=
Такой метод (посредством урезания операцией "AND") организации кольцевых буферов с длиной и начальным адресом, кратными 2^N, весьма удобен и эффективен - недаром он широко применяется аж с 80-х годов. Эффективнее него - только аппаратные кольцевые буфера, реализованные в некоторых DSP, а также в dsPIC.

=GM= молодец - очень полезно время от времени напоминать широким массам о том, что Волга впадает именно в Каспийское море, а не в Северное smile.gif
sensor_ua
IMHO, обсуждение циклических буферов в привязке к архитектуре имеет смысл только при использовании ассемблера и всвязи с нюансами соблюдения атомарности операций. Ну и, как заметил =AVR=, при наличии аппаратной реализации в соответствующих камнях.
mse
Цитата(=GM= @ Aug 24 2007, 19:16) *
Код
      mov     xl,qhead;указатель на запись
      st      x+,al;запишем байт
      cp      xl,qend;конец буфера?
      brne    .+2;нет, обходим
      ldi     xl,buffer;да, установим начало

...

ИМХО, выделять регистровые переменные под хранение начала-конца для тонких АВР весьма тоскливо. Если прально понял, то всё это богацтво хранится вечно, бо чтение ЦБ осусчествляется в одном месте, запись - в другом...
Регистр, опять-же, ИМХО, гораздо дороже ячейки в ОЗУ...Хотя...
Код
   .dseg
qhead:    .byte   1
buffer:    .byte   N
qend:
other_data:

   ...
      lds     xl,qhead;указатель на запись
      st      x+,al;запишем байт
      cpi      xl,qend;конец буфера?
      brne      no_cycled;нет, обходим
      ldi     xl,buffer;да, установим начало
no_cycled:
           sts    qhead,xl

в пассиве три такта, два слова и лишний указатель в ОЗУ. Но зато есть лишний регистер и ничего не остаётся в регистрах надолго.

Но, как правило, в ЦБ кто-то пишет/читает постепенно и одновремено. Могут столкнуться и перетолкнуться, значит надо есчо и указатели контролировать.
Код
   .dseg
qread:    .byte   1
qwrite:    .byte   1
buffer:    .byte   N
qend:
other_data:

   ...
      lds     xl,qwrite;указатель на запис
      lds    r0,qread;на чьтение
      cp     xl,r0
      brne  pointers_ok
;
;ой, мля, чё делать-то?!!
;
pointers_ok:
      st      x+,al;запишем байт
      cpi      xl,low(qend);конец буфера?
      brne      no_cycled;нет, обходим
      ldi     xl,low(buffer);да, установим начало
no_cycled:
           sts    qwrite,xl
    ...

Вроде нигде не накосячил...А?
SasaVitebsk
Цитата(=AVR= @ Aug 25 2007, 08:42) *
Такой метод (посредством урезания операцией "AND") организации кольцевых буферов с длиной и начальным адресом, кратными 2^N, весьма удобен и эффективен - недаром он широко применяется аж с 80-х годов. Эффективнее него - только аппаратные кольцевые буфера, реализованные в некоторых DSP, а также в dsPIC.

=GM= молодец - очень полезно время от времени напоминать широким массам о том, что Волга впадает именно в Каспийское море, а не в Северное smile.gif


1) К сожалению не всегда применимо.
2) При написании программы - реализация кольцевого буфера - единицы %. Поэтому я за написание данного участка "размашисто". Зато нет необходимости лично контролировать размещение самого буфера.

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

Код
    .cseg
    .org    (pc & $ff80)+$80


Приведу пример буфера несколько сложнее организованного

Код
;****************************************************************
;*   Вывод символа (wl) в буфер вывода. При выводе контроли-    *
;* руется заполнение буфера. При переполнении буфера вывод тор-    *
;* мозится, и подпрограмма не завершится, пока он не закончится.*
;*   Две точки входа: outwl и outwlsZ;                *
;*   Портятся tmph, Z.    (для outwl)                *
;*   Портятся tmph.    (для outwlsZ)                *
;****************************************************************

outwl:
    mov    tmph,    TBH
    sub    tmph,    TBE
    brcc    outw1
    subi    tmph,    -lBuf
outw1:    cpi    tmph,    2
    breq    outwl
    mov    Zl,    TBE
    ldi    ZH,    high(TxBuf)
    st    Z+,    wl
    cpi    Zl,    lBuf
    brne    outw2
    clr    Zl
outw2:    mov    TBE,    Zl
    ret


Приём

Код
;****************************************************************
;*         Прерывание на приём данных.            *
;*                                *
;*   Принятый байт размещается в кольцевом буфере RxBuf. Размер *
;* кольцевого буфера lBuf байт. В случае когда до заполнения     *
;* буфера осталось 16 байт снимается готовность модема. (Аппа-    *
;* ратным или програмным способом. При освобождении буфера на     *
;* половину готовность опять включается в голове.        *
;*   Используются регистры RBH и RBE как мл. байт адреса указа-    *
;* телей на голову и хвост буфера соответственно. Портятся ре-    *
;* гистр wp и регистровая пара X.                *
;* Максимальное время выполнения: 31 такт.            *
;****************************************************************

RxUART:
    in    tmpsreg,    sreg
    mov    Xl,    RBE; Поместить его в регистровую пару X
    clr    Xh
    in    wp,    udr; Прочитать принятый байт и
    st    X+,    wp; поместить его в буфер
    cpi    Xl,    RxBuf+lBuf; Конец буфера?
    brne    RxU1    ; если нет, то дальше
    ldi    Xl,    RxBuf; а иначе в начало буфера
RxU1:    mov    RBE,    Xl; и сохранить
    mov    Xl,    RBH; Определить объём свободного места
    sub    Xl,    RBE; в буфере
    brcc    RxU2
    subi    Xl,    -lBuf; Откорректировать при перехлёсте
RxU2:    cpi    Xl,    16; Осталось меньше 16 байт?
    brsh    RxUE    ; если нет, то выйти

    sbi    portd,    CTS; Сбросить готовность модема

RxUE:    lds    Xl,    s2
    cp    wp,    Xl
    brne    plclr
    tst    nplusC
    brne    plinc
    tst    ms20
    breq    plinc
plclr:    clr    nplusC
        rjmp    plset
plinc:    inc    nplusC
plset:    lds    ms20,    s12; сбросить задержку
    out    sreg,    tmpsreg
    reti


Это реализация старая 2003 года последние изменения. Сейчас вообще буфер большой. В байт не влазит. На мелочи не обращать внимание просто по живому вырезалось.
adnega
Доброго дня!

Мне вот очень интересно применение кольцевых буферов для реализации консоли.
Со временем "написались" некоторые участки кода, которые позволяют в общем виде сделать реакцию на команды. Юзаю повсеместно. Хотелось бы услышать отзывы и предложения по данной проблеме. :-)
=GM=
Привет всем! Отъезжал ненадолго, тут праздник местный был (summer bank holiday), теперь будем смотреть ответы и отвечать по мере сил-возможностей(:-)

1) To SasaVitebsk. Как всегда, приведен добротный код. Есть только мелкие вопросики. Фрагмент ниже непонятен, вроде бы надо буфер разместить в озу, а у вас стоит пзу.
Цитата(SasaVitebsk @ Aug 26 2007, 09:50) *
Кстати возможно автоматическое размещение буфера на границу по типу применяемой мной привязки таблицы данных
Код
    .cseg
    .org    (pc & $ff80)+$80

Трудно разобраться с передачей, метка outwl указана дважды, а метки outwlsZ нет вовсе.
Цитата(SasaVitebsk @ Aug 26 2007, 09:50) *
Код
;*   Две точки входа: outwl и outwlsZ;                *
;*   Портятся tmph, Z.    (для outwl)                *
;*   Портятся tmph.    (для outwlsZ)                *
;****************************************************************
outwl:    mov    tmph,    TBH
    sub    tmph,    TBE
    brcc    outw1
    subi    tmph,    -lBuf
outw1:    cpi    tmph,    2
    breq    outwl
    ret

2) Как обычно ничем не удивил и не порадовал широкоизвестный в узких кругах эникейщик =AVR=, вроде бы и похвалил, вроде бы и пожурил в одно и то же время, но что такое "аппаратные кольцевые буфера" и чем они отличаются от address mode осталось тайной(:-).
WHALE
Цитата(=GM= @ Aug 28 2007, 20:02) *
Привет всем! Отъезжал ненадолго, тут праздник местный был (summer bank holiday), теперь будем смотреть ответы и отвечать по мере сил-возможностей(:-)

1) To SasaVitebsk. Как всегда, приведен добротный код. Есть только мелкие вопросики. Фрагмент ниже непонятен, вроде бы надо буфер разместить в озу, а у вас стоит пзу.

Трудно разобраться с передачей, метка outwl указана дважды, а метки outwlsZ нет вовсе.

2) Как обычно ничем не удивил и не порадовал широкоизвестный в узких кругах эникейщик =AVR=, вроде бы и похвалил, вроде бы и пожурил в одно и то же время, но что такое "аппаратные кольцевые буфера" и чем они отличаются от address mode осталось тайной(:-).


Господин учитель информатики раздает слонов за итоговую работу по теме "кольцевые буферы".
Вы бородку клинышком и пенсне не носите случаем?Если нет-подумайте на эту тему,имхо вам должно
пойти.
SasaVitebsk
Цитата(=GM= @ Aug 28 2007, 19:02) *
1) To SasaVitebsk. Как всегда, приведен добротный код. Есть только мелкие вопросики. Фрагмент ниже непонятен, вроде бы надо буфер разместить в озу, а у вас стоит пзу.

Да. Я так и написал. Просто вырвал кусочек использованный для объявления таблицы автоматически выровненной на границу. Что-нибудь подобное можно и для озу придумать. Чтобы вместо ORG. smile.gif
Цитата
Трудно разобраться с передачей, метка outwl указана дважды, а метки outwlsZ нет вовсе.

Метка outwl указана 1 раз и является вызываемой. Второй раз использована метка outw1. Просто на том шрифте этого не видно. Если текст перенесёте, то увидите. Написано это где-то в 1994-95 примерно. Я тогда так принял локальные метки изменять для себя 1,2,3... Короче что-то по типу символа "_" у defunct. Кстати применение символа "_" используется некоторыми компиляторами для организации локальных меток. Иногда при макросах также делается. Так что наезд на defunct некорректен. smile.gif Считаю его подход правильным. Просто когда я писал ещё не сложилось ничего (у меня). Да и вообще человек постоянно меняется оставаясь самим собой. Наверное было бы любопытно поболтать с собой самим лет 20 тому назад. Ну, безусловно избегая фраз типа: "придурок правее бери". biggrin.gif

А что не хватает, - так ведь выхвачено было по живому. Оно же там всё повязано. smile.gif Там нет ничего любопытного.

Код
;****************************************************************
;*   Вспомогательная. Выводит в буфер вывода цифру согласно би-    *
;* ту Т. Потом выводит "пробел".                *
;*   Портится tmph,wl и Z.                    *
;****************************************************************

outwlt:    clr    wl
    bld    wl,    0


;****************************************************************
;*   Вспомогательная. Выводит в буфер вывода цифру согласно ре-    *
;* гистра wl. Потом выводит "пробел".                *
;*   Портится tmph,wl и Z.                    *
;****************************************************************

outwlr:    andi    wl,    3
    ori    wl,    $30
    rcall    outwl
    ldi    wl,    $20


;****************************************************************
;*   Вывод символа (wl) в буфер вывода. При выводе контроли-    *
;* руется заполнение буфера. При переполнении буфера вывод тор-    *
;* мозится, и подпрограмма не завершится, пока он не закончится.*
;*   Две точки входа: outwl и outwlsZ;                *
;*   Портятся tmph, Z.    (для outwl)                *
;*   Портятся tmph.    (для outwlsZ)                *
;****************************************************************

outwl:
    mov    tmph,    TBH
    sub    tmph,    TBE
    brcc    outw1
    subi    tmph,    -lBuf
outw1:    cpi    tmph,    2
    breq    outwl
    mov    Zl,    TBE
    ldi    ZH,    high(TxBuf)
    st    Z+,    wl
    cpi    Zl,    lBuf
    brne    outw2
    clr    Zl
outw2:    mov    TBE,    Zl
    ret


outwlsZ:
    push    Zl
    push    Zh
    rcall    outwl
    pop    Zh
    pop    Zl
    ret
=AVR=
Аппаратные буфера отличаются от address mode тем же, чем summer bank holiday от аристократической и загадочной команды cbr xl,0xE0. То есть, простите, Sir, от плебейской и понятной команды andi xl,0x1F - ну, Вы, смею надеяться, поняли, а остальным не обязательно, а то опять засмеют Вас, как тогда с этим 24-канальным ШИМом - помните? Ну и славненько.

И аппаратные кольцевые буфера, Sir, в DSP не делаются, а имеются - вернее, имеется их поддержка, которая активируется установкой битиков в соответствующих регистриках - размерчик там буферочка, направление заполнения, флажочки разные удобные - если маразм склероз замучил, то прочитайте DS на какой-нибудь DSP или даже, не побоюсь этого слова, dsPIC - там Вам постараются объяснить это два раза и медленно, тщательно проговаривая слова. Нам, эникейщикам, в наших узких кругах такое практически недоступно - все урывками да слухами, никакого, панимаишь, информационного бума - один свист. Кстати, не Вы ли свистели, эсквайр? Ай-я-яй, как некультурно! smile.gif

to SasaVitebsk: .org прекрасно и штатно работает и в ОЗУ, просто для этого нужно использовать его в секциях данных - dseg и/или eseg, Position Counter (PC) у каждой секции свой, и считает такой PC те единицы размещения, которые применяются в данной секции - слова для .code, байты для .dseg и .eseg. Выравнивание по кратной границе удобно делать при помощи (моего) макроса align (если директивы align нет в соответствующем ассемблере):

Код
; For AVR Assembler 2 only
.macro    align
    .org    @0+PC-PC%@0
.endm

.dseg
    align    (32+SRAM_START)

ringb1:    .byte    32; @ 0x0080
ringb2:    .byte    32; @ 0x00A0


При размещении буферов в ОЗУ по нужным границам надо не забывать о том, что ОЗУ в разных АВР начинается с разных адресов - где 0x0060, а где и 0x0100. В примере выше адрес начала ОЗУ (SRAM_START, значение определено в .inc-файле) использовано как добавка к параметру align
=GM=
Цитата(WHALE @ Aug 28 2007, 18:33) *
Господин учитель информатики раздает слонов за итоговую работу по теме "кольцевые буферы". Вы бородку клинышком и пенсне не носите случаем? Если нет-подумайте на эту тему, имхо вам должно пойти.

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

Цитата(=AVR= @ Aug 28 2007, 20:21) *
Аппаратные буфера отличаются от address mode тем же, чем summer bank holiday от аристократической и загадочной команды cbr xl,0xE0. То есть, простите, Sir, от плебейской и понятной команды andi xl,0x1F - ну, Вы, смею надеяться, поняли, а остальным не обязательно, а то опять засмеют Вас, как тогда с этим 24-канальным ШИМом - помните?

Режим косвенной циклической адресации (indirect circular addressing mode) именно в дсп я знаю хорошо, поскольку каждый божий день применяю:

и такой movl *ar6%++,acc
и такой movl *+xar6[ar1%++]

А вот аппаратного буфера не нахожу, да, склероз-не склероз, свисти-не свисти...нету такого! Эникейщики, они тем и отличаются от обычных кодеров, что неглубоко копают, помните? А ещё они любят навести тень на плетень, сравнить, например, summer bank holiday с командой cbr.

Что касаемо 24-канального программного шима, не надо ля-ля, ваша программа проиграла моей программе по скорости более, чем в ТРИ раза. И никто не смеялся, один вы орали и брызгали слюной, всех задолбали, прямо скажем.
zltigo
Moderator:
Так, оба двое и присоединившийся к ним совcем уж не по делу WHALE - снижаем накал страстей до уровня соответствующего технической теме а не банальной перепалке во freetalk.

Если уже начали о софтовых кольцевых буферах отдельную тему, то следует как минимум раскрыть тему пошире:
-получении информации о свободном месте в буфере;
-различных стратегиях поведения при переполнении буфера;
-организации небайтовых буферов;
=GM=
Цитата(zltigo @ Aug 28 2007, 22:41) *
Если уже начали о софтовых кольцевых буферах отдельную тему, то следует как минимум раскрыть тему пошире:
-получении информации о свободном месте в буфере;
-различных стратегиях поведения при переполнении буфера;
-организации небайтовых буферов;

Ищу решение, пока красивого нет. Нашёл вот только наиболее короткий способ чтения из буфера и записи в буфер практически ПРОИЗВОЛЬНОГО размера. Скажем для тайни – от 1 до 64 байт. Для старших моделей 1-256. По-моему, довольно симпатично(:-).

Идея состоит в том, чтобы адрес конца буфера помещался непосредственно перед границей по модулю 2^N. В то же время длина буфера может быть произвольной в пределах этого модуля 2^N. Например, конец буфера для тайни нужно выбрать равным 0xBF. Тогда начало буфера можно выбирать любое в пределах 0x80-0xBE. Полные фрагменты кода на запись/чтение в/из циклического буфера приведены ниже. Фрагменты похожи на реализацию, показанную mse (см. пост #5), но короче на одно слово.

А. Запись байта из регистра data в циклический буфер buffer
Код
bwrite: lds   xl,head       ;указатель
        clr   xh            ;на запись
        st    x+,data       ;запишем байт
        sbrc  xl,6          ;конец буфера?
        ldi   xl,low(buffer);да, установим начало
        sts   head,xl       ;новый указатель


Б. Чтение байта из циклического буфера buffer в регистр data
Код
bread:  lds   xl,tail       ;указатель
        clr   xh            ;на чтение
        ld    data,x+       ;прочитаем байт
        sbrc  xl,6          ;конец буфера?
        ldi   xl,low(buffer);да, установим начало
        sts   tail,xl       ;новый указатель
SasaVitebsk
2 AVR спасибо. До вашего варианта не додумался. Про DSEG, естественно, знаю. Последнее время пишу всё на Си. Думаю что ваш макрос будет полезен многим. Интересные находки всегда любопытны. Я вот всё больше и больше склоняюсь к мысли что необходимо унифицировать некоторые узлы и блоки, процедуры процессоронезависимые и даже переменные и структуры.

Прошу прощения за отход от темы может кто посоветует хорошую книгу в данной области. То есть что-то по типу визуализации/структурирования. Даже не знаю как назвать эту область. Короче выработки единого подхода к написанию прог на Си.
=GM=
Цитата(SasaVitebsk @ Aug 29 2007, 10:05) *
Я вот всё больше и больше склоняюсь к мысли что необходимо унифицировать некоторые узлы и блоки, процедуры процессоронезависимые и даже переменные и структуры.

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

Попробуйте вот эту книжку: Ван Тассел Д. Стиль, разработка, эффективность, отладка и испытание программ: Пер. с англ. , 1981. Много ценных мыслей, в своё время очень мне помогла систематизировать программирование, как вид деятельности.
alcosar
Вот одна из возможных реализаций. Имеется индекс чтения, количество занятых ячеек, флаг состояния переполнения и сам буфер.
Запрет прерывания при чтении нужен, если запись в буфер происходит в прерываниях.

Внимание! Программа не тестировалась в реальной работе. Если есть косяки, буду признателен за поправки. Опыт работы с AVR очень маленький.
Код
.dseg

.equ    BUF_SIZE = 64    ; размер буфера, может быть n^2 <= 256


buf:    .byte    3 + BUF_SIZE; счетчик занятых ячеек, индекс чтения, состояние буфера, буфер

.cseg


;------------------------------------------------
init_buf:
;------------------------------------------------
; инициализация буфера
; используются r16, r28, r29

; в Y адрес структуры, задающей буфер    
    mov    YL, LOW(buf)
    mov    YH, HIGH(buf)
    clr    r16
    std    Y, r16
    std    Y+1, r16
    std    Y+2, r16
    ret


;------------------------------------------------
write_buf:
;------------------------------------------------
; в r16 байт для записи
; используются регисты r17, r18, r28, r29

; в Y адрес структуры, задающей буфер    
    mov    YL, LOW(buf)
    mov    YH, HIGH(buf)

; если буфер полный не записывать, установить флаг переполнения
    ld    r17, Y
    cpi    r17, BUF_SIZE - 1
    brcs    L1
    ldi    r17, 1
    std    Y+2, r17
    ret
L1:    
; определить индекс для записи
; i = (rindex + count) & (BUF_SIZE - 1)
    ld    r18, Y + 1
    add    r18, r17
    andi    r18, BUF_SIZE-1
    
; увеличить счетчик занятых ячеек в буфере
; count++
    inc    r17
    st    Y, r17

; buf[i] = data;
    clr    r17
    add    YL, r18
    adc    YH, r17
    std    Y+3, r16
    ret

;------------------------------------------------
read_buf:
;------------------------------------------------
; возвращает байт в r16
; используются регисты r16, r17, r28, r29

; в Y адрес структуры, задающей буфер    
    mov    YL, LOW(buf)
    mov    YH, HIGH(buf)

; c = buf[rindex]
    ldd    r16, Y+3

    cli

; count--
    ld    r17, Y
    dec    r17
    st    Y, r17
    
; rindex = (rindex + 1) & BUF_SIZE - 1
    ldd    r17, Y+1
    dec    r17
    andi    r17, BUF_SIZE-1
    std    Y+1, r16
    sei
    ret
=GM=
Цитата(alcosar @ Aug 31 2007, 11:37) *
Код
; в Y адрес структуры, задающей буфер    
    mov    YL, LOW(buf)
    mov    YH, HIGH(buf)
; c = buf[rindex]
    ldd    r16, Y+3

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

Для загрузки непосредственных данных в регистр применяется команда ldi, а не mov.
prottoss
Цитата(=GM= @ Aug 31 2007, 23:12) *


Пара вопросов:

1.Сколько памяти программ и памяти данных занимает код с циклическими буферами для USART?

2.Почему во всех приведенных кодах процедуры чтения-записи из-в буферЫ нет команд запрета прерываний от обработчиков приема-окончания-передачи USART?
SasaVitebsk
Цитата(prottoss @ Aug 31 2007, 19:53) *
Пара вопросов:

1.Сколько памяти программ и памяти данных занимает код с циклическими буферами для USART?

2.Почему во всех приведенных кодах процедуры чтения-записи из-в буферЫ нет команд запрета прерываний от обработчиков приема-окончания-передачи USART?


1. Вы же видите - очень мало. Но не это главное. Циклический буфер позволяет работать с максимальной производительностью и абсолютно отделяет работу с внешним устройством от интерфейса. Это можно использовать в любом месте. Например в последней теме у меня два таких буфера. 1-UART, 2-EEPROM.

2. В этом есть особый смысл. smile.gif Классическая структура буфера - сам буфер+2переменных. Указатель на голову и указатель на хвост. Представим себе приём. В прерывании используется только хвост(добавляются символы), а в main только голова буфера (забираются данные).

Есть ещё один приятный момент. Если работаешь с подтверждениями (например CRC), то тоже имеется огромный плюс. Представьте кольцевой буфер и три указателя. Первых два я описал, а третий - указатель на недостоверные данные. Таким образом всё работает тем же способом, а по принятию решения (сравнение CRC) указатель на хвост присваивается либо указателю на принятые недостоверные данные (данные верны) либо наоборот указателю на недостоверные данные присваивается указатель на хвост (данные неверны и пакет требуется повторить). Никаких дополнительных средств и инструментов не требуется.

2 GM сенькую именно такую книгу искал (в смысле задача стоит именно как вы и написали). Сейчас буду искать саму книгу. smile.gif
prottoss
Цитата(SasaVitebsk @ Sep 1 2007, 02:37) *
1. Вы же видите - очень мало. Но не это главное. Циклический буфер позволяет работать с максимальной производительностью и абсолютно отделяет работу с внешним устройством от интерфейса. Это можно использовать в любом месте. Например в последней теме у меня два таких буфера. 1-UART, 2-EEPROM.
В полезности циклических буферов я нисколько не сомневаюсь smile.gif и сам оччень часто их применяю. НО, очень мало, это сколько? smile.gif допустим применительно к АВР и его USART. Просто не вижу большого смысла тщательно рассказывать, как забивать гвозди...

Почему нет ни единого примера на Си?



Цитата(SasaVitebsk @ Sep 1 2007, 02:37) *
2. В этом есть особый смысл. smile.gif Классическая структура буфера - сам буфер+2переменных. Указатель на голову и указатель на хвост. Представим себе приём. В прерывании используется только хвост(добавляются символы), а в main только голова буфера (забираются данные).
А когда хвост догнал голову, а он важнее (ибо прерывание) получается баальшой булик lol.gif

Цитата(SasaVitebsk @ Sep 1 2007, 02:37) *
Есть ещё один приятный момент.

..................Никаких дополнительных средств и инструментов не требуется.
Кроме анальгина
sensor_ua
Цитата
Циклический буфер позволяет работать с максимальной производительностью

Всё-таки накладные нужно отметить - это удвоенное время пересылки байтов - в буфер и из него.
Кроме того имеем некоторые вопросы с обслуживанием флагов при приёме - приходится либо принимать решение о загрузке байта в буфер по месту (при обслуживании флагов), либо расширять буфер для трансляции флагов. Пропуск повреждённых байтов (типа не сошлась четность) может привести к ожиданию конца пакета по таймауту, а это не всегда одинаково полезноwink.gif
При передаче использование модификатора __generic (иногда приятно пользоваться удобствами) для указателей приводит к удорожанию их обслуживания
mse
Цитата(sensor_ua @ Aug 31 2007, 23:56) *
Всё-таки накладные нужно отметить - это удвоенное время пересылки байтов - в буфер и из него.
...

Для УАРТовых времян это слёзы.
Цитата
А когда хвост догнал голову, а он важнее (ибо прерывание) получается баальшой булик

Практика такова, что это хвост постоянно сидит на хвосте у головы ;О) Даже если УАРТ работает на мегабоде, то между двумя байтами 160 тактов. За это время фон успеет прожевать не один байт. Конечно, если его тормознут на 100мкС, тогда приёмник ему накидает. Но всё равно, потом фон огуляет принятое гораздо быстрее. ;О)
prottoss
Цитата(mse @ Sep 1 2007, 15:03) *
Практика такова, что это хвост постоянно сидит на хвосте у головы ;О) Даже если УАРТ работает на мегабоде, то между двумя байтами 160 тактов. За это время фон успеет прожевать не один байт. Конечно, если его тормознут на 100мкС, тогда приёмник ему накидает. Но всё равно, потом фон огуляет принятое гораздо быстрее. ;О)
Практика Ваша? Или мировая? Или кЫтайская? 160 тактов, как сказал один чел выше - это очень мало smile.gif Если за это время основной поток не заберет из головы данные, то хвост накидает голове байтов по самые уши - будет потеря данных

Опять же сказанное мной выше то - что показывает практика
sensor_ua
Цитата
Почему нет ни единого примера на Си?

Файл прицепить не получилось, так что как есть... (Рулёжка по типам камешков была, так её вырезал. Вроде корректно)

Код
#include "uart.h"

unsigned char U0_RxBufGetIndex = 0;
unsigned char U0_RxBufPutIndex = 0;
unsigned char U0_RxBufSize = BUF0RXSIZE;
unsigned int U0_RxBuffer[BUF0RXSIZE] = {0};

void USART0_Ring_Flush(void){
  U0_RxBufGetIndex = U0_RxBufPutIndex;
  return;
}

int UART0_getc (void){
  int proxy = 0;
  if(U0_RxBufPutIndex != U0_RxBufGetIndex){
    //proxy = U0_RxBuffer[U0_RxBufGetIndex] & (~(((!!PARITY)<<RXB80)<<8));
    proxy = U0_RxBuffer[U0_RxBufGetIndex];
    U0_RxBufGetIndex = (U0_RxBufGetIndex+1)&(U0_RxBufSize-1);  
    // modulo UART0_RxBufSize
    return (proxy);    
  }
  return (EOF);
}

#ifdef __ICCAVR__
#pragma vector = USART_RX_vect
__interrupt void USART_RX_Handler(void){
#else
ISR(USART_RX_vect){
#endif

  unsigned char status;
//  unsigned char resh;
  status = UCSR0A;
  //resh = UCSR0B;
  
  // Read flags
  U0_RxBuffer[U0_RxBufPutIndex] = (status & ((1<<FE0)|(1<<DOR0)|(1<<UPE0))) << 8;
  
  // Filter the 9th bit, then return
  //U0_RxBuffer[U0_RxBufPutIndex] |= _BLV(resh, RXB80) << 8; //(resh >> 1) & 0x01;

  U0_RxBuffer[U0_RxBufPutIndex] |= UDR0;
  // normal ready, save into the Data Ring Buffer

  U0_RxBufPutIndex=(U0_RxBufPutIndex+1)&(U0_RxBufSize-1);
  // PutIndex modulo BufferSize

  if(U0_RxBufPutIndex == U0_RxBufGetIndex) {
    U0_RxBufPutIndex--;
    U0_RxBufPutIndex &= U0_RxBufSize-1;
    // PutIndex modulo BufferSize
  }
  return;
}


то:sensor_ua
Ну хоть тэгами пользуйтесь для выделения исходников
zltigo
Цитата(sensor_ua @ Sep 1 2007, 10:45) *
Код
  U0_RxBuffer[U0_RxBufPutIndex] |= UDR0;
  // normal ready, save into the Data Ring Buffer

  U0_RxBufPutIndex=(U0_RxBufPutIndex+1)&(U0_RxBufSize-1);
  // PutIndex modulo BufferSize

А так:
Код
  U0_RxBuffer[(U0_RxBufPutIndex++)&(U0_RxBufSize-1)] |= UDR0;

При этом Вы имеете всегда полный индекс равный счетчику помещенных извлеченных байтов и одним простым арифметическим действием (в пределах размерности счетчиков, естественно ) можете узнать количество байтов в буфере.
prottoss
Выложу и я свое здесь, хоть уже и выкладывал в теме про исходники - http://electronix.ru/forum/index.php?showtopic=10934
mse
Цитата(prottoss @ Sep 1 2007, 11:15) *
Практика Ваша? Или мировая? Или кЫтайская? 160 тактов, как сказал один чел выше - это очень мало smile.gif Если за это время основной поток не заберет из головы данные, то хвост накидает голове байтов по самые уши - будет потеря данных

Опять же сказанное мной выше то - что показывает практика

Практичная практика. Проистекает от навыков владения калькулятором и головным мосхом:
Если загрузка фона сильная, то разработчик обязан оценить эту загрузку и взять глубину буфера, чтобы голова не топталась по хвосту, пока фон топчется по своим делам. Задача сродни определению требуемой глубины стека. Если таинством арифметики разрабоччик, таки, настойчиво овладел, то 160 тактов ему - выше крыши. А тому одному челу сверху виднее, чего он наворотил, мож ему и мало. А я на 160 тактах зайца в поле загоняю.
prottoss
Цитата(mse @ Sep 1 2007, 16:57) *
Если загрузка фона сильная, то разработчик обязан оценить эту загрузку и взять глубину буфера, чтобы голова не топталась по хвосту, пока фон топчется по своим делам.
Ну Вы прям как Бил Гейтс и Ко smile.gif

ИМХО разарботчик обязан сделать так, чтобы его программа не вешалась от добавления пары строк кода где угодно и когда угодна. А взять глубину буфера какую вздумается можно на пне4 и ижесними
sensor_ua
Цитата
Ну хоть тэгами пользуйтесь для выделения исходников

Пробовал pre и code - не получилось
Цитата
А так:

U0_RxBuffer[(U0_RxBufPutIndex++)&(U0_RxBufSize-1)] |= UDR0;

Ничего против. Просто я при переполнении переписываю последний доступный для записи байт буфера принятым символом (это может быть полезным при поиске управляющих символов, но тогда ещё одна пересылка данных и сравнение внизу). Потому "не верю" этому счётчику. И мне вообще-то не приходится в моих последующих процедурах узнавать размер данных попавших в буферwink.gif - может ещё и потому и не пытаюсь семафорить. Кроме того, так (в одну строку) не пишу, потому как иногда пользую буфер размером не кратным 2^N. Тогда (может мне кажется) рихтуется меньше.
mse
Цитата(prottoss @ Sep 1 2007, 13:02) *
Ну Вы прям как Бил Гейтс и Ко smile.gif

ИМХО разарботчик обязан сделать так, чтобы его программа не вешалась от добавления пары строк кода где угодно и когда угодна. А взять глубину буфера какую вздумается можно на пне4 и ижесними

Ну и каким местом ваш поток сознания к теме? А уж, тем более, к цытируемому?
Где я написал "взять глубину буфера какую вздумается". Здесь, что-ли "...обязан оценить эту загрузку и взять глубину буфера, чтобы...". Т.е. оценить и ПОСЧИТАТЬ, это "какое вздумается"? Толково!
Цитата
...обязан сделать так, чтобы его программа не вешалась от добавления пары строк...
Ага, обязан сказать:" по счучьему велению, не вешайся, программа, от добавления пары строк!"
Добавил пару строк - посчитай, добавь глубины, если надо. Потому как за твоих "пару строк" вполне может из линии насыпаться в два раза больше байтиков, чем без них.
alcosar
[quote name='=GM=' date='Aug 31 2007, 18:12' post='289675']
Здесь логическая ошибка, вы всё время читаете из одной и той же ячейки памяти. Идея сделать отдельный счётчик на заполнение буфера мне кажется здравой, надо обдумать на досуге.
[quote]

Спасибо за поправку. Вроде бы теперь правильно.

Код
;------------------------------------------------
read_buf:
;------------------------------------------------
; возвращает байт в r16
; используются регисты r16, r17, r26, r27, r28, r29

; в Y адрес структуры, задающей буфер    
    ldi    YL, LOW(buf)
    ldi    YH, HIGH(buf)

    mov    XL, YL
    mov    XL, YL
        
    clr      r17
    ld     r16, Y+1
    add    XL, r16
    adc    XH, r17

; c = buf[rindex]
    ldd    r16, X

    cli

; count--
    ld    r17, Y
    dec    r17
    st    Y, r17
    
; rindex = (rindex + 1) & BUF_SIZE - 1
    ldd    r17, Y+1
    dec    r17
    andi    r17, BUF_SIZE-1
    std    Y+1, r16
    sei
    ret
=GM=
To alcosar

1) Здесь: std Y+1,r16 у вас ошибка, надо было r17 написать.
2) Счётчик занятых ячеек вполне может заменить статус буфера: 0-пустой, BUF_SIZE-полный.
3) Недостаток, что очень много регистров используется, аж 6 штук. Уже показывал более простое решение (см. пост #14). Вот адаптированная под ваш вариант программа. В три раза короче и в три раза быстрее. Использует три регистра.

;чтение байта из циклического буфера buffer в регистр data
Код
rdbyte: lds   xl,tail        ;указатель
        ldi   xh,high(buffer);на чтение
        ld    data,x+        ;прочитаем байт
        andi  xl,bufsize-1   ;держим указатель
        sts   tail,xl        ;в рамках
        ret

3) Кстати, что будет выдавать ваша программа, если буфер пуст? Предыдущие значения, поскольку count пойдёт в минус(:-)? Как сказал =mse=, и он 100% прав, пустой буфер-нередкая штатная ситуация.
SasaVitebsk
Цитата(prottoss @ Aug 31 2007, 21:57) *
В полезности циклических буферов я нисколько не сомневаюсь smile.gif и сам оччень часто их применяю. НО, очень мало, это сколько? smile.gif допустим применительно к АВР и его USART. Просто не вижу большого смысла тщательно рассказывать, как забивать гвозди...

Для реализации достаточно самого буфера + два указателя.
1. Размер буфера оцениваю исходя из из того что быстрее работает. Например IBM накачивает быстрее чем AVR разгребает. В этом случае размер приёмного буфера для AVR при 485 интерфейсе составляет два размера пакета + 5-6 байт. Для 232 интерфейса приблизительно 1к. Дальнейшее увеличение размера буфера даёт незначительный рост производительности.
2. Размер указателей зависит от размера буфера. Если буфер менее 256 байт, то указатели - байтовые, если больше то 2.
3. Если использую пакетную передачу, то, как я и описывал вводится ещё один указатель (недостоверных данных)
4. Если используется конвертер из одного интерфейса в другой, то некоторые указатели совмещаются размер буфера увеличивается.
Цитата
Почему нет ни единого примера на Си?
А когда хвост догнал голову, а он важнее (ибо прерывание) получается баальшой булик lol.gif

Честно говоря не понял шутки. Если буфер обнулён, то просто прекращается передача. Если заполнен ПОЧТИ полностью, то выполняется приостановка канала любым способом "управления потоком" - либо установкой сигнала CTS (HARD) либо передачей символа XOFF(SOFT). Буфер должен быть расчитан на приём 16 байт с момента выдачи остановки приёма. При работе с 485, очевидно, что вы сами должны следить за заполнением буфера. Но при чём здесь кольцевой буфер??? Если вы не справляетесь с приёмом, то управление потоком должно быть реализовано в любом случае.
Цитата
Кроме анальгина

Вы просто не работали с большими потоками данных например в четыре стороны. Иначе, простите за эмоции, вы бы бред не писали.

Кольцевой буфер это один из очень красивых алгоритмов. И, при правильной реализации, даёт разработчику возможность скрыть все тонкости приёма/передачи внутри драйвера. Поэтому, возможно, мало примеров. Так как придётся вычищать некоторые мелкие моменты.
sensor_ua
Цитата
2. Размер указателей зависит от размера буфера. Если буфер менее 256 байт, то указатели - байтовые, если больше то 2.

Простите, но непонятно, как Вы меняете размер указателя или что подразумеваете под "размер указателя"
SasaVitebsk
Цитата(sensor_ua @ Sep 3 2007, 18:03) *
Простите, но непонятно, как Вы меняете размер указателя или что подразумеваете под "размер указателя"

Естественно на стадии написания программы. Просто prottoss спрашивал размер потребляемой памяти, вот я и написал.
sensor_ua
Цитата
Естественно на стадии написания программы

Рация на танке(С)
Указатели обычно имеют размерность шины адресаwink.gif или чуть более - для AVR это 16 бит и несколько больше в случае использования __generic в компиляторе IAR.
Похоже имелись в виду не указатели, а индексы. Тогда оптимально будет короткие (до 256 байт) буферы размещать по адресам, кратным 256 (о примерно таком говорил =GM= в начале топика), тогда можно получить выигрыш и в объёме кода, и в скорости выполнения.
=GM=
Цитата(sensor_ua @ Sep 3 2007, 17:51) *
Указатели обычно имеют размерность шины адресаwink.gif или чуть более - для AVR это 16 бит и несколько больше в случае использования __generic в компиляторе IAR.
Похоже имелись в виду не указатели, а индексы. Тогда оптимально будет короткие (до 256 байт) буферы размещать по адресам, кратным 256 (о примерно таком говорил =GM= в начале топика), тогда можно получить выигрыш и в объёме кода, и в скорости выполнения.

Именно указатели, хотя памяти в АВРках - кот наплакал 0.5-1.0-2.0 Кбайта, редко больше. Но тем не менее, указатель 16-битный и занимает парные регистры x, y или z. В части приведённых программ старшая часть адреса присутствует как бы за кадром, поскольку она не меняется, установили её один раз в программе и забыли.

Обратите внимание на завершенную подпрограмму чтения байта из кольцевого буфера в посте #33. В паре регистров (xh,xl) находится честный 16-битный указатель на чтение, младшая часть которого хранится в ячейке tail.
SasaVitebsk
Цитата(sensor_ua @ Sep 3 2007, 20:51) *
Рация на танке(С)
Указатели обычно имеют размерность шины адресаwink.gif или чуть более - для AVR это 16 бит и несколько больше в случае использования __generic в компиляторе IAR.
Похоже имелись в виду не указатели, а индексы. Тогда оптимально будет короткие (до 256 байт) буферы размещать по адресам, кратным 256 (о примерно таком говорил =GM= в начале топика), тогда можно получить выигрыш и в объёме кода, и в скорости выполнения.

Имелись в виду указатели. Что вас смущает. Хранятся младшие байты указателей. Старшие - фиксированы. Где танк?
Посмотрите топик 6. В условиях экономии памяти вполне применимо.
alcosar
Цитата(=GM= @ Sep 3 2007, 14:54) *
To alcosar

1) Здесь: std Y+1,r16 у вас ошибка, надо было r17 написать.
2) Счётчик занятых ячеек вполне может заменить статус буфера: 0-пустой, BUF_SIZE-полный.
3) Недостаток, что очень много регистров используется, аж 6 штук. Уже показывал более простое решение (см. пост #14). Вот адаптированная под ваш вариант программа. В три раза короче и в три раза быстрее. Использует три регистра.

;чтение байта из циклического буфера buffer в регистр data
Код
rdbyte: lds   xl,tail    ;указатель
        ldi   xh,high(buffer);на чтение
        ld    data,x+    ;прочитаем байт
        andi  xl,bufsize-1  ;держим указатель
        sts   tail,xl    ;в рамках
        ret


3) Кстати, что будет выдавать ваша программа, если буфер пуст? Предыдущие значения, поскольку count пойдёт в минус(:-)? Как сказал =mse=, и он 100% прав, пустой буфер-нередкая штатная ситуация.

1. Эх. Разгилдяй я.
2. Полный еще не значит переполненный.
3. Перед обращением к чтению нужно смотреть сколько байт в буфере.
Код
rdbyte: lds   xl,tail    ;указатель
        ldi   xh,high(buffer);на чтение

здесь мне непонятно как сформирован указатель чтения.
sensor_ua
Цитата
Что вас смущает.

Цитата
2. Размер указателей зависит от размера буфера.

Ну и? Вы о чём-то думаете, а пишете вещи, которые по меньшей мере вызывают вопросы (а не глупость ли это написана?) из-за отсутствия логической связи с конкретными постами. Для меня указатель есть принаддлежность языка Си, соответственно вольное обращение с предметом режет слух. Попробуйте прочитать сами место, где оно появилось http://electronix.ru/forum/index.php?showt...amp;st=33&#
Суть, о чём говорили, теперь понятна.
=GM=
Цитата(alcosar @ Sep 3 2007, 19:33) *
2. Полный еще не значит переполненный.
3. Перед обращением к чтению нужно смотреть сколько байт в буфере.
Код
rdbyte: lds   xl,tail        ;указатель
        ldi   xh,high(buffer);на чтение

здесь мне непонятно как сформирован указатель чтения.

Ну как же, в переменной tail хранится младшая часть указателя, она загружается в xl. Для буфера объёмом меньшего или равного 256 байт, старшая часть указателя неизменна, это просто старшая часть начального адреса буфера, поэтому нет смысла её хранить, поэтому просто загружается константа в xh.
SasaVitebsk
Цитата(sensor_ua @ Sep 3 2007, 22:50) *
Ну и? Вы о чём-то думаете, а пишете вещи, которые по меньшей мере вызывают вопросы (а не глупость ли это написана?) из-за отсутствия логической связи с конкретными постами. Для меня указатель есть принаддлежность языка Си, соответственно вольное обращение с предметом режет слух.

smile.gif
Я говорил в общепринятых терминах в привязке к теме вопроса "кольцевой буфер". Про Си не думал, а думал про "указатель на голову" и "указатель на хвост", как обычно пишут. Реализация, естественно, может быть разной. Если исходить из начальных постов данной темы, где приводилось упрощённое использование коротких указателей (***) с маскированием и привязкой буферов к началу сегмента (в Си не требуется), то при реализации на Си более правильно назвать это индексом. По типу:
Код
  UDR0 = OutBuf[HeadOutBuf++];                            // Передаём    символ ответа
  HeadOutBuf &=0xf;                                        // Переход по кольцу


Если ввёл кого в заблуждение - прошу прощения. smile.gif
sensor_ua
Цитата
Если ввёл кого в заблуждение

Да всё путём. Просто "в наше время нельзя доверять никому"(С)wink.gif))

Кстати, вопрос общего плана - а как можно использовать количество данных в буфере (типа семафор или как) при приёме? Не могу найти практического примененияwink.gif
Dog Pawlowa
Люди, а как Вы синхронизируете скорости заполнения буфера и отправки от него?
Может что такое новое придумали? smile.gif

Поясняю. У меня циклический буфер для мониторинга процессов в терминале или PDA.
Есть моменты, когда буфер переполняется, так как идет интенсивная отправка данных. Буфер размером около 80 символов, больше выделить не могу. Я тупо ставлю Delay() после посылки каждой строки, чтобы в этих местах буфер не переполнился. Висеть в ожидании, пока там не освободится места, мне запрещает какая-то религия, не пойму какая 07.gif

Вы то как делаете?
mse
Цитата(Dog Pawlowa @ Sep 4 2007, 22:06) *
Люди, а как Вы синхронизируете скорости заполнения буфера и отправки от него?
...
Вы то как делаете?

Дык...ХОН-ХОФФ, аппаратная синхра...
sensor_ua
Цитата
Висеть в ожидании, пока там не освободится места, мне запрещает какая-то религия

Дык ждать-то по-любому нужно. Вопрос в том, делать ли чего полезное при этом или нет. А это скорее к механизмам шедулинга.
В случае достаточно долгого ожидания есть прямая целесообразность выйти из ожидания (отдать управление ОС), а потом иногда заходить и проверять или ждать(проверять) извещения о событии (буфер не полон) и уж тогда добивать.
while(On){
if(len<=0) break;
if(putc(*src)==EOF){
OS_Yield();//тут передаём управление ОС
}
src++;
len--;
}
Я, правда, чаще использую для выхода/входа в ожидающие функции не OS_Yield(), а механизм статических сопрограмм реализованный макросами http://www.chiark.greenend.org.uk/~sgtatham/coroutine.h
http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
bodja74
Цитата(Dog Pawlowa @ Sep 4 2007, 21:06) *
Люди, а как Вы синхронизируете скорости заполнения буфера и отправки от него?
Может что такое новое придумали? smile.gif


Вы то как делаете?


Придумали уже давно,читайте внимательно пост 34.
Самый простой дернуть ногу CTS сом-порта ,он аппаратно приостановит передачу данных из него.
XON\XOFF - это еще нужно такой режим включить на дровах.
Хотя эти способы не освобождает от отслеживания на случай переполнения отправного буффера на ПК.
Dog Pawlowa
Цитата(sensor_ua @ Sep 4 2007, 21:44) *
Дык ждать-то по-любому нужно. Вопрос в том, делать ли чего полезное при этом или нет. А это скорее к механизмам шедулинга.

Угу, спасибо. А без ОС единственная возможность использовать это время - натолкать в прерывания побольше функциональности, логично? Я то работаю без ОС.
sensor_ua
Цитата(Dog Pawlowa @ Sep 5 2007, 08:03) *
Угу, спасибо. А без ОС единственная возможность использовать это время - натолкать в прерывания побольше функциональности, логично? Я то работаю без ОС.

Использование статических сопрограмм требует только большого цикла (round-robin), хотя этим применение не ограничиваетчся. А Adam Dunkel наваял на этом деле даже нечто типа операционки - Protothreads http://www.sics.se/~adam/pt/
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.