|
Вопрос по Си, может ли быть несколько putchar? |
|
|
|
Jul 29 2011, 10:28
|
Гуру
     
Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823

|
Цитата(kan35 @ Jul 29 2011, 13:14)  ...другой putchar? Как-то невнятно спрашиваете, поскольку printf - это функция библиотеки, подключенной к проекту, а не часть "задачи". Если по существу, то внутри одного putchar в зависимости от установленного задачами флага, осуществляете вывод в один или другой порт. Конечно, если можно обеспечить такую синхронизацию и если так дорожите printf-ом. Можно в одной из задач использовать только sprintf, осуществляя вывод из буфера обычными методами. Или написать свою функцию форматированного вывода. Возможностей - миллионы
--------------------
Уходя, оставьте свет...
|
|
|
|
|
Jul 29 2011, 10:35
|
Знающий
   
Группа: Участник
Сообщений: 537
Регистрация: 22-02-06
Пользователь №: 14 594

|
переключать putchar-ы не вполне удобно (я так понимаю придется лочить ресурс, и задачи будут друг друга ждать в RTOS), да и юзать sprintf не очень комфортно Может быть это тот случай когда можно заюзать С++ namespace? я вот пробую, но все равно что то не получается.
если не обзывать putchar как extern "С"putchar, то компилятор (IAR) просто его не вставляет в код, а как только обзываю как extern в том и другом namespace, то линкер ругается на то, что функции дублируются... тупик какой то, должен же быть простой выход?!
Сообщение отредактировал kan35 - Jul 29 2011, 10:41
|
|
|
|
|
Jul 29 2011, 10:45
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (kan35 @ Jul 29 2011, 13:35)  если не обзывать putchar как extern "С"putchar, то компилятор (IAR) просто его не вставляет в код, а как только обзываю как extern в том и другом namespace, то линкер ругается на то, что функции дублируются... тупик какой то, должен же быть простой выход?! Да, потому что printf - сишная функция. Выход - напишите свою printf, "завернув" в нее sprintf и вывод в нужный порт: CODE class iodevice { public: virtual void putchar(const uint8_t &byte) = 0; void send(char const* buffer); void puts(char const* buffer); void printf(char const *format, ...); protected: iodevice() {} };
void iodevice::send(char const* buffer) { while(*buffer) putchar(*buffer++); }
void iodevice::puts(char const * string) { send(string); send("\r\n"); }
void iodevice::printf(char const * format, ...) { const size_t BUFFER_SIZE = 80; char Buffer[BUFFER_SIZE];
va_list args; va_start (args, format); vsnprintf (Buffer, BUFFER_SIZE, format, args); va_end (args); send(Buffer); }
class system_uart_t : public iodevice { public: void putchar(const uint8_t &byte) { UART1.send(byte); } };
class user_uart_t : public iodevice { public: void putchar(const uint8_t &byte) { UART2.send(byte); } };
system_uart_t System_uart; user_uart_t User_uart; void test() { System_uart.printf("Tipa test %d", 1); User_uart.printf("Tipa test %d", 2);
iodevice * pOutput = &User_uart;
pOutput->printf("слава мне, победителю %s!!!", "драконов")
}
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jul 29 2011, 12:41
|

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

|
QUOTE (MrYuran @ Jul 29 2011, 14:28)  Затраты времени и памяти на копирование буфера ничто по сравнению с висением активной задачи посимвольного вывода. Кто говорит про висение? тот-же putchar() может быть вполне умным отправляя символы либо прямо в UART/FIFO либо в буфер, причем в естественный для этой задачи кольцевой буфер. Естественно, что написание специлизированного заменителя printf() позволит добиться большей эффективности. QUOTE Буфер же может отправляться в порт по прерываниям или DMA. Только вот линейный буфер с которым работает sprintf() для такой задачи не совсем хорош. P.S. Потоки в том-же, например, printf() можно переключать прямо в putchar() через control-ы. Это вполне естественно получается.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jul 29 2011, 12:52
|
Знающий
   
Группа: Validating
Сообщений: 838
Регистрация: 31-01-05
Пользователь №: 2 317

|
Можно так: Код <span style="font-family: monospace;"><span style="font-weight: bold;">static char format_buff[DEBUG_BUFF_SIZE]; void UartPrintf(const char *args, ...) { uint32_t len; va_list ap; va_start(ap, args); len = vsnprintf(format_buff,sizeof(format_buff),args,ap); va_end(ap); UartWrite(format_buff,len); } </span></span>
|
|
|
|
|
Jul 29 2011, 15:26
|

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

|
QUOTE (Dog Pawlowa @ Jul 29 2011, 17:11)  При двухстороннем протокольном обмене линейный буфер так же естественен, как и кольцевой. Например, X.25 совершенно двухсторонний и протокольный  . Ну и? Полагаю, я догадываюсь о чем это Вы - об АБСОЛЮТНО вырожденном случае, когда обмен в протоколе осуществляется посылкой текстовых сообщений строго ограниченной длинны и строго в режиме запрос - пауза - ответ. Если говорить о более-менее реальных применениях, то тот-же самый printf() используется для совершенно асинхронной выдачи сообщений достаточно произвольного размера. При этом за просто так занести в буфер следущее сообщение не получится, пока не будет передано предыдущее. Склейка сообщений в линейном буфере не сложна (но в приведенных примерах я ее не видел), но по любому начинает неэффективно использоваться память буфера, поскольку весь объем буфера будет доступен только после его полного освобождения. Это опять можно слегка обойти, но опять не на 100% и путем усложнения работы с буфером. Короче, я такие (использование линейного буфера в режиме приближенного к кольцевому) финты делал пару раз в жизни после тщательного обдумывания. И это совершенно не типовой и редко полезный подход.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jul 29 2011, 16:02
|

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

|
QUOTE (Dog Pawlowa @ Jul 29 2011, 17:52)  Мне приятно красиво сложить пакет перед отправкой, ну а кому-то нужно побыстрее покидать их в буфер  Красота складывания или не складывания в пакет или не в пакет к делу отношения не имеет - тут весь вопрос в том, имеет-ли право некая порция информации отсылаться не по команде свыше после того, как все гарантированно отправится и примется, а совершенно асинхронно, например, в момент внешнего воздействия. И про "красиво сложить", я Вам не просто так назвал прадедушку коммуникационных протоколов X.25 - там "красиво сложить пакет" в полный рост, но линейные буфера ну НИКАК не канают.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jul 30 2011, 07:05
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(kan35 @ Jul 29 2011, 13:14)  Есть несколько UARTов. Требуется делать форматный вывод в разные, можно ли как то для одной задачи (с её printf-ами) привязать один putchar, а для другой задачи - другой putchar? Так а что, это только в avr-libc под avr-gcc есть понятие файла с подставляемыми пользователем функциями get/put и возможностью потом писать Код fprintf( &lcd_file, fmt, ...); fprintf( &uart_file, fmt, ...); При необходимости через макросы fdev_set_udata() можно в запсь про файл занести указатель на упомянутый кольцевой буфер и через fdev_get_udata() брать его внутри put() и заносить в буфер, можно просто выводить в порт, на ЖКИ, куда угодно. Хоть сервис оси дёргать и жать готовности "осевым" способом. fprintf ничего и не узнает :-) На мой взгляд -- вполне аккуратно всё выходит. У других такого нет?
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Aug 11 2011, 17:07
|
Группа: Новичок
Сообщений: 3
Регистрация: 1-08-11
Пользователь №: 66 533

|
Всем доброго времени суток. Обьясните пожалуйста, что вобще озночает putchar? Что он куда записывает? Я не так давно приступил к изучению Си, читаю всяческие лекции для чайников, которые нахожу в сети, но пока не понял, что есть putchar(((
|
|
|
|
|
Dec 3 2011, 17:32
|

Местный
  
Группа: Участник
Сообщений: 236
Регистрация: 29-11-06
Из: Ижевск
Пользователь №: 22 902

|
В чём смысл этого куска кода ? Код static uchar computeTemporaryChanges(void) /*
*/ { uchar i, status = 0, mask = 1;
for(i=0;i<8;i++){ if(actionTimers[i]) status |= mask; mask <<= 1; } return status; } и эквивалентно ли эта вся бредятина следующему; Код static uchar computeTemporaryChanges(void) /*
*/ { uchar status = 255;
return status; } сам себе отвечаю - эквивалентно лишь в том случае если все 8 ячеек массива actionTimers[i] определены! Сия бредятина исключительно хитрожопское условие.
Сообщение отредактировал ветерок - Dec 3 2011, 17:38
--------------------
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|