|
Циклический буфер на AVR, (Примеры применения) |
|
|
|
Aug 24 2007, 15:16
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Тема открыта по горячим следам недавней острой дискуссии. В ней одним из участников (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 – регистровые переменные, содержащие адреса-указатели ячеек в озу для записи, чтения и конца буфера соответственно.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
 |
Ответов
(1 - 51)
Guest_=AVR=_*
|
Aug 25 2007, 05:42
|
Guests

|
Такой метод (посредством урезания операцией "AND") организации кольцевых буферов с длиной и начальным адресом, кратными 2^N, весьма удобен и эффективен - недаром он широко применяется аж с 80-х годов. Эффективнее него - только аппаратные кольцевые буфера, реализованные в некоторых DSP, а также в dsPIC. =GM= молодец - очень полезно время от времени напоминать широким массам о том, что Волга впадает именно в Каспийское море, а не в Северное
Сообщение отредактировал =AVR= - Aug 25 2007, 06:01
|
|
|
|
|
Aug 25 2007, 07:48
|
Знающий
   
Группа: Свой
Сообщений: 709
Регистрация: 3-05-05
Пользователь №: 4 693

|
Цитата(=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 ... Вроде нигде не накосячил...А?
|
|
|
|
|
Aug 26 2007, 10:50
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Цитата(=AVR= @ Aug 25 2007, 08:42)  Такой метод (посредством урезания операцией "AND") организации кольцевых буферов с длиной и начальным адресом, кратными 2^N, весьма удобен и эффективен - недаром он широко применяется аж с 80-х годов. Эффективнее него - только аппаратные кольцевые буфера, реализованные в некоторых DSP, а также в dsPIC. =GM= молодец - очень полезно время от времени напоминать широким массам о том, что Волга впадает именно в Каспийское море, а не в Северное  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 года последние изменения. Сейчас вообще буфер большой. В байт не влазит. На мелочи не обращать внимание просто по живому вырезалось.
|
|
|
|
|
Aug 28 2007, 16:02
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Привет всем! Отъезжал ненадолго, тут праздник местный был (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 осталось тайной(:-).
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Aug 28 2007, 18:33
|

Знающий
   
Группа: Свой
Сообщений: 902
Регистрация: 2-01-06
Из: Краснодар
Пользователь №: 12 768

|
Цитата(=GM= @ Aug 28 2007, 20:02)  Привет всем! Отъезжал ненадолго, тут праздник местный был (summer bank holiday), теперь будем смотреть ответы и отвечать по мере сил-возможностей(:-)
1) To SasaVitebsk. Как всегда, приведен добротный код. Есть только мелкие вопросики. Фрагмент ниже непонятен, вроде бы надо буфер разместить в озу, а у вас стоит пзу.
Трудно разобраться с передачей, метка outwl указана дважды, а метки outwlsZ нет вовсе.
2) Как обычно ничем не удивил и не порадовал широкоизвестный в узких кругах эникейщик =AVR=, вроде бы и похвалил, вроде бы и пожурил в одно и то же время, но что такое "аппаратные кольцевые буфера" и чем они отличаются от address mode осталось тайной(:-). Господин учитель информатики раздает слонов за итоговую работу по теме "кольцевые буферы". Вы бородку клинышком и пенсне не носите случаем?Если нет-подумайте на эту тему,имхо вам должно пойти.
--------------------
"Hello, word!" - 17 errors 56 warnings
|
|
|
|
|
Aug 28 2007, 19:20
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Цитата(=GM= @ Aug 28 2007, 19:02)  1) To SasaVitebsk. Как всегда, приведен добротный код. Есть только мелкие вопросики. Фрагмент ниже непонятен, вроде бы надо буфер разместить в озу, а у вас стоит пзу. Да. Я так и написал. Просто вырвал кусочек использованный для объявления таблицы автоматически выровненной на границу. Что-нибудь подобное можно и для озу придумать. Чтобы вместо ORG.  Цитата Трудно разобраться с передачей, метка outwl указана дважды, а метки outwlsZ нет вовсе. Метка outwl указана 1 раз и является вызываемой. Второй раз использована метка outw1. Просто на том шрифте этого не видно. Если текст перенесёте, то увидите. Написано это где-то в 1994-95 примерно. Я тогда так принял локальные метки изменять для себя 1,2,3... Короче что-то по типу символа "_" у defunct. Кстати применение символа "_" используется некоторыми компиляторами для организации локальных меток. Иногда при макросах также делается. Так что наезд на defunct некорректен.  Считаю его подход правильным. Просто когда я писал ещё не сложилось ничего (у меня). Да и вообще человек постоянно меняется оставаясь самим собой. Наверное было бы любопытно поболтать с собой самим лет 20 тому назад. Ну, безусловно избегая фраз типа: "придурок правее бери". А что не хватает, - так ведь выхвачено было по живому. Оно же там всё повязано.  Там нет ничего любопытного. Код ;**************************************************************** ;* Вспомогательная. Выводит в буфер вывода цифру согласно би- * ;* ту Т. Потом выводит "пробел". * ;* Портится 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
|
|
|
|
Guest_=AVR=_*
|
Aug 28 2007, 20:21
|
Guests

|
Аппаратные буфера отличаются от address mode тем же, чем summer bank holiday от аристократической и загадочной команды cbr xl,0xE0. То есть, простите, Sir, от плебейской и понятной команды andi xl,0x1F - ну, Вы, смею надеяться, поняли, а остальным не обязательно, а то опять засмеют Вас, как тогда с этим 24-канальным ШИМом - помните? Ну и славненько. И аппаратные кольцевые буфера, Sir, в DSP не делаются, а имеются - вернее, имеется их поддержка, которая активируется установкой битиков в соответствующих регистриках - размерчик там буферочка, направление заполнения, флажочки разные удобные - если маразм склероз замучил, то прочитайте DS на какой-нибудь DSP или даже, не побоюсь этого слова, dsPIC - там Вам постараются объяснить это два раза и медленно, тщательно проговаривая слова. Нам, эникейщикам, в наших узких кругах такое практически недоступно - все урывками да слухами, никакого, панимаишь, информационного бума - один свист. Кстати, не Вы ли свистели, эсквайр? Ай-я-яй, как некультурно!  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
|
|
|
|
|
Aug 28 2007, 22:33
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(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-канального программного шима, не надо ля-ля, ваша программа проиграла моей программе по скорости более, чем в ТРИ раза. И никто не смеялся, один вы орали и брызгали слюной, всех задолбали, прямо скажем.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Aug 29 2007, 00:07
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(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 ;новый указатель
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Aug 29 2007, 12:13
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

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

Группа: Участник
Сообщений: 44
Регистрация: 30-03-06
Пользователь №: 15 598

|
Вот одна из возможных реализаций. Имеется индекс чтения, количество занятых ячеек, флаг состояния переполнения и сам буфер. Запрет прерывания при чтении нужен, если запись в буфер происходит в прерываниях. Внимание! Программа не тестировалась в реальной работе. Если есть косяки, буду признателен за поправки. Опыт работы с 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
Сообщение отредактировал alcosar - Aug 31 2007, 12:40
|
|
|
|
|
Aug 31 2007, 15:12
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(alcosar @ Aug 31 2007, 11:37)  Код ; в Y адрес структуры, задающей буфер mov YL, LOW(buf) mov YH, HIGH(buf) ; c = buf[rindex] ldd r16, Y+3 Здесь логическая ошибка, вы всё время читаете из одной и той же ячейки памяти. Идея сделать отдельный счётчик на заполнение буфера мне кажется здравой, надо обдумать на досуге. Для загрузки непосредственных данных в регистр применяется команда ldi, а не mov.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Aug 31 2007, 18:37
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Цитата(prottoss @ Aug 31 2007, 19:53)  Пара вопросов:
1.Сколько памяти программ и памяти данных занимает код с циклическими буферами для USART?
2.Почему во всех приведенных кодах процедуры чтения-записи из-в буферЫ нет команд запрета прерываний от обработчиков приема-окончания-передачи USART? 1. Вы же видите - очень мало. Но не это главное. Циклический буфер позволяет работать с максимальной производительностью и абсолютно отделяет работу с внешним устройством от интерфейса. Это можно использовать в любом месте. Например в последней теме у меня два таких буфера. 1-UART, 2-EEPROM. 2. В этом есть особый смысл.  Классическая структура буфера - сам буфер+2переменных. Указатель на голову и указатель на хвост. Представим себе приём. В прерывании используется только хвост(добавляются символы), а в main только голова буфера (забираются данные). Есть ещё один приятный момент. Если работаешь с подтверждениями (например CRC), то тоже имеется огромный плюс. Представьте кольцевой буфер и три указателя. Первых два я описал, а третий - указатель на недостоверные данные. Таким образом всё работает тем же способом, а по принятию решения (сравнение CRC) указатель на хвост присваивается либо указателю на принятые недостоверные данные (данные верны) либо наоборот указателю на недостоверные данные присваивается указатель на хвост (данные неверны и пакет требуется повторить). Никаких дополнительных средств и инструментов не требуется. 2 GM сенькую именно такую книгу искал (в смысле задача стоит именно как вы и написали). Сейчас буду искать саму книгу.
|
|
|
|
|
Aug 31 2007, 18:57
|

Гуру
     
Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659

|
Цитата(SasaVitebsk @ Sep 1 2007, 02:37)  1. Вы же видите - очень мало. Но не это главное. Циклический буфер позволяет работать с максимальной производительностью и абсолютно отделяет работу с внешним устройством от интерфейса. Это можно использовать в любом месте. Например в последней теме у меня два таких буфера. 1-UART, 2-EEPROM. В полезности циклических буферов я нисколько не сомневаюсь  и сам оччень часто их применяю. НО, очень мало, это сколько?  допустим применительно к АВР и его USART. Просто не вижу большого смысла тщательно рассказывать, как забивать гвозди... Почему нет ни единого примера на Си? Цитата(SasaVitebsk @ Sep 1 2007, 02:37)  2. В этом есть особый смысл.  Классическая структура буфера - сам буфер+2переменных. Указатель на голову и указатель на хвост. Представим себе приём. В прерывании используется только хвост(добавляются символы), а в main только голова буфера (забираются данные). А когда хвост догнал голову, а он важнее (ибо прерывание) получается баальшой булик  Цитата(SasaVitebsk @ Sep 1 2007, 02:37)  Есть ещё один приятный момент.
..................Никаких дополнительных средств и инструментов не требуется. Кроме анальгина
--------------------
|
|
|
|
|
Aug 31 2007, 19:56
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата Циклический буфер позволяет работать с максимальной производительностью Всё-таки накладные нужно отметить - это удвоенное время пересылки байтов - в буфер и из него. Кроме того имеем некоторые вопросы с обслуживанием флагов при приёме - приходится либо принимать решение о загрузке байта в буфер по месту (при обслуживании флагов), либо расширять буфер для трансляции флагов. Пропуск повреждённых байтов (типа не сошлась четность) может привести к ожиданию конца пакета по таймауту, а это не всегда одинаково полезно При передаче использование модификатора __generic (иногда приятно пользоваться удобствами) для указателей приводит к удорожанию их обслуживания
--------------------
aka Vit
|
|
|
|
|
Sep 1 2007, 07:03
|
Знающий
   
Группа: Свой
Сообщений: 709
Регистрация: 3-05-05
Пользователь №: 4 693

|
Цитата(sensor_ua @ Aug 31 2007, 23:56)  Всё-таки накладные нужно отметить - это удвоенное время пересылки байтов - в буфер и из него. ... Для УАРТовых времян это слёзы. Цитата А когда хвост догнал голову, а он важнее (ибо прерывание) получается баальшой булик Практика такова, что это хвост постоянно сидит на хвосте у головы ;О) Даже если УАРТ работает на мегабоде, то между двумя байтами 160 тактов. За это время фон успеет прожевать не один байт. Конечно, если его тормознут на 100мкС, тогда приёмник ему накидает. Но всё равно, потом фон огуляет принятое гораздо быстрее. ;О)
|
|
|
|
|
Sep 1 2007, 07:45
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата Почему нет ни единого примера на Си? Файл прицепить не получилось, так что как есть... (Рулёжка по типам камешков была, так её вырезал. Вроде корректно) Код #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 - Sep 1 2007, 08:24
--------------------
aka Vit
|
|
|
|
|
Sep 1 2007, 08:36
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(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; При этом Вы имеете всегда полный индекс равный счетчику помещенных извлеченных байтов и одним простым арифметическим действием (в пределах размерности счетчиков, естественно ) можете узнать количество байтов в буфере.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Sep 1 2007, 08:57
|
Знающий
   
Группа: Свой
Сообщений: 709
Регистрация: 3-05-05
Пользователь №: 4 693

|
Цитата(prottoss @ Sep 1 2007, 11:15)  Практика Ваша? Или мировая? Или кЫтайская? 160 тактов, как сказал один чел выше - это очень мало  Если за это время основной поток не заберет из головы данные, то хвост накидает голове байтов по самые уши - будет потеря данных Опять же сказанное мной выше то - что показывает практика Практичная практика. Проистекает от навыков владения калькулятором и головным мосхом: Если загрузка фона сильная, то разработчик обязан оценить эту загрузку и взять глубину буфера, чтобы голова не топталась по хвосту, пока фон топчется по своим делам. Задача сродни определению требуемой глубины стека. Если таинством арифметики разрабоччик, таки, настойчиво овладел, то 160 тактов ему - выше крыши. А тому одному челу сверху виднее, чего он наворотил, мож ему и мало. А я на 160 тактах зайца в поле загоняю.
|
|
|
|
|
Sep 1 2007, 09:03
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата Ну хоть тэгами пользуйтесь для выделения исходников Пробовал pre и code - не получилось Цитата А так:
U0_RxBuffer[(U0_RxBufPutIndex++)&(U0_RxBufSize-1)] |= UDR0; Ничего против. Просто я при переполнении переписываю последний доступный для записи байт буфера принятым символом (это может быть полезным при поиске управляющих символов, но тогда ещё одна пересылка данных и сравнение внизу). Потому "не верю" этому счётчику. И мне вообще-то не приходится в моих последующих процедурах узнавать размер данных попавших в буфер  - может ещё и потому и не пытаюсь семафорить. Кроме того, так (в одну строку) не пишу, потому как иногда пользую буфер размером не кратным 2^N. Тогда (может мне кажется) рихтуется меньше.
--------------------
aka Vit
|
|
|
|
|
Sep 1 2007, 09:23
|
Знающий
   
Группа: Свой
Сообщений: 709
Регистрация: 3-05-05
Пользователь №: 4 693

|
Цитата(prottoss @ Sep 1 2007, 13:02)  Ну Вы прям как Бил Гейтс и Ко ИМХО разарботчик обязан сделать так, чтобы его программа не вешалась от добавления пары строк кода где угодно и когда угодна. А взять глубину буфера какую вздумается можно на пне4 и ижесними Ну и каким местом ваш поток сознания к теме? А уж, тем более, к цытируемому? Где я написал "взять глубину буфера какую вздумается". Здесь, что-ли "...обязан оценить эту загрузку и взять глубину буфера, чтобы...". Т.е. оценить и ПОСЧИТАТЬ, это "какое вздумается"? Толково! Цитата ...обязан сделать так, чтобы его программа не вешалась от добавления пары строк... Ага, обязан сказать:" по счучьему велению, не вешайся, программа, от добавления пары строк!" Добавил пару строк - посчитай, добавь глубины, если надо. Потому как за твоих "пару строк" вполне может из линии насыпаться в два раза больше байтиков, чем без них.
|
|
|
|
|
Sep 2 2007, 18:55
|
Участник

Группа: Участник
Сообщений: 44
Регистрация: 30-03-06
Пользователь №: 15 598

|
[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
Сообщение отредактировал alcosar - Sep 2 2007, 19:17
|
|
|
|
|
Sep 3 2007, 11:54
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
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% прав, пустой буфер-нередкая штатная ситуация.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Sep 3 2007, 14:31
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Цитата(prottoss @ Aug 31 2007, 21:57)  В полезности циклических буферов я нисколько не сомневаюсь  и сам оччень часто их применяю. НО, очень мало, это сколько?  допустим применительно к АВР и его USART. Просто не вижу большого смысла тщательно рассказывать, как забивать гвозди... Для реализации достаточно самого буфера + два указателя. 1. Размер буфера оцениваю исходя из из того что быстрее работает. Например IBM накачивает быстрее чем AVR разгребает. В этом случае размер приёмного буфера для AVR при 485 интерфейсе составляет два размера пакета + 5-6 байт. Для 232 интерфейса приблизительно 1к. Дальнейшее увеличение размера буфера даёт незначительный рост производительности. 2. Размер указателей зависит от размера буфера. Если буфер менее 256 байт, то указатели - байтовые, если больше то 2. 3. Если использую пакетную передачу, то, как я и описывал вводится ещё один указатель (недостоверных данных) 4. Если используется конвертер из одного интерфейса в другой, то некоторые указатели совмещаются размер буфера увеличивается. Цитата Почему нет ни единого примера на Си? А когда хвост догнал голову, а он важнее (ибо прерывание) получается баальшой булик  Честно говоря не понял шутки. Если буфер обнулён, то просто прекращается передача. Если заполнен ПОЧТИ полностью, то выполняется приостановка канала любым способом "управления потоком" - либо установкой сигнала CTS (HARD) либо передачей символа XOFF(SOFT). Буфер должен быть расчитан на приём 16 байт с момента выдачи остановки приёма. При работе с 485, очевидно, что вы сами должны следить за заполнением буфера. Но при чём здесь кольцевой буфер??? Если вы не справляетесь с приёмом, то управление потоком должно быть реализовано в любом случае. Цитата Кроме анальгина Вы просто не работали с большими потоками данных например в четыре стороны. Иначе, простите за эмоции, вы бы бред не писали. Кольцевой буфер это один из очень красивых алгоритмов. И, при правильной реализации, даёт разработчику возможность скрыть все тонкости приёма/передачи внутри драйвера. Поэтому, возможно, мало примеров. Так как придётся вычищать некоторые мелкие моменты.
|
|
|
|
|
Sep 3 2007, 15:03
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата 2. Размер указателей зависит от размера буфера. Если буфер менее 256 байт, то указатели - байтовые, если больше то 2. Простите, но непонятно, как Вы меняете размер указателя или что подразумеваете под "размер указателя"
--------------------
aka Vit
|
|
|
|
|
Sep 3 2007, 17:51
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

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

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(sensor_ua @ Sep 3 2007, 17:51)  Указатели обычно имеют размерность шины адреса  или чуть более - для AVR это 16 бит и несколько больше в случае использования __generic в компиляторе IAR. Похоже имелись в виду не указатели, а индексы. Тогда оптимально будет короткие (до 256 байт) буферы размещать по адресам, кратным 256 (о примерно таком говорил =GM= в начале топика), тогда можно получить выигрыш и в объёме кода, и в скорости выполнения. Именно указатели, хотя памяти в АВРках - кот наплакал 0.5-1.0-2.0 Кбайта, редко больше. Но тем не менее, указатель 16-битный и занимает парные регистры x, y или z. В части приведённых программ старшая часть адреса присутствует как бы за кадром, поскольку она не меняется, установили её один раз в программе и забыли. Обратите внимание на завершенную подпрограмму чтения байта из кольцевого буфера в посте #33. В паре регистров (xh,xl) находится честный 16-битный указатель на чтение, младшая часть которого хранится в ячейке tail.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Sep 3 2007, 19:33
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Цитата(sensor_ua @ Sep 3 2007, 20:51)  Рация на танке(С) Указатели обычно имеют размерность шины адреса  или чуть более - для AVR это 16 бит и несколько больше в случае использования __generic в компиляторе IAR. Похоже имелись в виду не указатели, а индексы. Тогда оптимально будет короткие (до 256 байт) буферы размещать по адресам, кратным 256 (о примерно таком говорил =GM= в начале топика), тогда можно получить выигрыш и в объёме кода, и в скорости выполнения. Имелись в виду указатели. Что вас смущает. Хранятся младшие байты указателей. Старшие - фиксированы. Где танк? Посмотрите топик 6. В условиях экономии памяти вполне применимо.
|
|
|
|
|
Sep 3 2007, 19:33
|
Участник

Группа: Участник
Сообщений: 44
Регистрация: 30-03-06
Пользователь №: 15 598

|
Цитата(=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);на чтение здесь мне непонятно как сформирован указатель чтения.
|
|
|
|
|
Sep 3 2007, 19:50
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата Что вас смущает. Цитата 2. Размер указателей зависит от размера буфера. Ну и? Вы о чём-то думаете, а пишете вещи, которые по меньшей мере вызывают вопросы (а не глупость ли это написана?) из-за отсутствия логической связи с конкретными постами. Для меня указатель есть принаддлежность языка Си, соответственно вольное обращение с предметом режет слух. Попробуйте прочитать сами место, где оно появилось http://electronix.ru/forum/index.php?showt...amp;st=33&#Суть, о чём говорили, теперь понятна.
--------------------
aka Vit
|
|
|
|
|
Sep 3 2007, 20:45
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(alcosar @ Sep 3 2007, 19:33)  2. Полный еще не значит переполненный. 3. Перед обращением к чтению нужно смотреть сколько байт в буфере. Код rdbyte: lds xl,tail ;указатель ldi xh,high(buffer);на чтение здесь мне непонятно как сформирован указатель чтения. Ну как же, в переменной tail хранится младшая часть указателя, она загружается в xl. Для буфера объёмом меньшего или равного 256 байт, старшая часть указателя неизменна, это просто старшая часть начального адреса буфера, поэтому нет смысла её хранить, поэтому просто загружается константа в xh.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Sep 4 2007, 17:07
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Цитата(sensor_ua @ Sep 3 2007, 22:50)  Ну и? Вы о чём-то думаете, а пишете вещи, которые по меньшей мере вызывают вопросы (а не глупость ли это написана?) из-за отсутствия логической связи с конкретными постами. Для меня указатель есть принаддлежность языка Си, соответственно вольное обращение с предметом режет слух. Я говорил в общепринятых терминах в привязке к теме вопроса "кольцевой буфер". Про Си не думал, а думал про "указатель на голову" и "указатель на хвост", как обычно пишут. Реализация, естественно, может быть разной. Если исходить из начальных постов данной темы, где приводилось упрощённое использование коротких указателей (***) с маскированием и привязкой буферов к началу сегмента (в Си не требуется), то при реализации на Си более правильно назвать это индексом. По типу: Код UDR0 = OutBuf[HeadOutBuf++]; // Передаём символ ответа HeadOutBuf &=0xf; // Переход по кольцу Если ввёл кого в заблуждение - прошу прощения.
|
|
|
|
|
Sep 4 2007, 17:46
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата Если ввёл кого в заблуждение Да всё путём. Просто "в наше время нельзя доверять никому"(С)  )) Кстати, вопрос общего плана - а как можно использовать количество данных в буфере (типа семафор или как) при приёме? Не могу найти практического применения
--------------------
aka Vit
|
|
|
|
|
Sep 4 2007, 18:06
|
Гуру
     
Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823

|
Люди, а как Вы синхронизируете скорости заполнения буфера и отправки от него? Может что такое новое придумали? Поясняю. У меня циклический буфер для мониторинга процессов в терминале или PDA. Есть моменты, когда буфер переполняется, так как идет интенсивная отправка данных. Буфер размером около 80 символов, больше выделить не могу. Я тупо ставлю Delay() после посылки каждой строки, чтобы в этих местах буфер не переполнился. Висеть в ожидании, пока там не освободится места, мне запрещает какая-то религия, не пойму какая Вы то как делаете?
--------------------
Уходя, оставьте свет...
|
|
|
|
|
Sep 4 2007, 18:44
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата Висеть в ожидании, пока там не освободится места, мне запрещает какая-то религия Дык ждать-то по-любому нужно. Вопрос в том, делать ли чего полезное при этом или нет. А это скорее к механизмам шедулинга. В случае достаточно долгого ожидания есть прямая целесообразность выйти из ожидания (отдать управление ОС), а потом иногда заходить и проверять или ждать(проверять) извещения о событии (буфер не полон) и уж тогда добивать. while(On){ if(len<=0) break; if(putc(*src)==EOF){ OS_Yield();//тут передаём управление ОС } src++; len--; } Я, правда, чаще использую для выхода/входа в ожидающие функции не OS_Yield(), а механизм статических сопрограмм реализованный макросами http://www.chiark.greenend.org.uk/~sgtatham/coroutine.hhttp://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
--------------------
aka Vit
|
|
|
|
|
Sep 4 2007, 20:46
|
Знающий
   
Группа: Свой
Сообщений: 543
Регистрация: 22-10-05
Пользователь №: 9 984

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

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(Dog Pawlowa @ Sep 4 2007, 21:06)  Люди, а как Вы синхронизируете скорости заполнения буфера и отправки от него? На отправку (тобиш TX буфер) - опорная точка - всегда пропускная способность канала, от нее и синхронизироваться. Регуляторов только 2 - размер буфера и задержка между вливанием очередной порции данных. Цитата Вы то как делаете? Там где канал с "узким горлышком" 300-1200 бод, а данных передавать много - ставлю 32k-128k внешней памяти. +2$ к стоимости устройства, +5см^2 места на плате.
|
|
|
|
|
  |
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|