|
Вопрос по Си, может ли быть несколько 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
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|