реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> Вопрос по Си, может ли быть несколько putchar?
kan35
сообщение Jul 29 2011, 10:14
Сообщение #1


Знающий
****

Группа: Участник
Сообщений: 537
Регистрация: 22-02-06
Пользователь №: 14 594



Есть несколько UARTов. Требуется делать форматный вывод в разные, можно ли как то для одной задачи (с её printf-ами) привязать один putchar, а для другой задачи - другой putchar?
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Jul 29 2011, 10:28
Сообщение #2


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



по-правильному было бы организовать переключение потоков. А putchar() пусть всегда выводит в текущий поток.
А ещё более правильно (при работе с UART, да и не только) не морочиться с посимвольным выводом, а использовать sprintf(), а потом сформированную в буфере строку выводить в нужный порт.


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
Dog Pawlowa
сообщение Jul 29 2011, 10:28
Сообщение #3


Гуру
******

Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823



Цитата(kan35 @ Jul 29 2011, 13:14) *
...другой putchar?

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

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

Возможностей - миллионы sm.gif



--------------------
Уходя, оставьте свет...
Go to the top of the page
 
+Quote Post
kan35
сообщение Jul 29 2011, 10:35
Сообщение #4


Знающий
****

Группа: Участник
Сообщений: 537
Регистрация: 22-02-06
Пользователь №: 14 594



переключать putchar-ы не вполне удобно (я так понимаю придется лочить ресурс, и задачи будут друг друга ждать в RTOS), да и юзать sprintf не очень комфортно
Может быть это тот случай когда можно заюзать С++ namespace? я вот пробую, но все равно что то не получается.

если не обзывать putchar как extern "С"putchar, то компилятор (IAR) просто его не вставляет в код, а как только обзываю как extern в том и другом namespace, то линкер ругается на то, что функции дублируются... тупик какой то, должен же быть простой выход?!

Сообщение отредактировал kan35 - Jul 29 2011, 10:41
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jul 29 2011, 10:45
Сообщение #5


Гуру
******

Группа: Модераторы
Сообщений: 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)
Go to the top of the page
 
+Quote Post
kan35
сообщение Jul 29 2011, 11:49
Сообщение #6


Знающий
****

Группа: Участник
Сообщений: 537
Регистрация: 22-02-06
Пользователь №: 14 594



Сергей Борщ, сделал примерно как вы посоветовали, благодарю за наглядный пример
Спасибо всем.
Go to the top of the page
 
+Quote Post
zltigo
сообщение Jul 29 2011, 12:13
Сообщение #7


Гуру
******

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



QUOTE (MrYuran @ Jul 29 2011, 12:28) *
А ещё более правильно (при работе с UART, да и не только) не морочиться с посимвольным выводом, а использовать sprintf()

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


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Jul 29 2011, 12:28
Сообщение #8


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Цитата(zltigo @ Jul 29 2011, 16:13) *
Использование sprintf для поставленной цели ничего кроме лишней буферизации в линейный буфер с дополнительными затратами времени на лишнее копирование и памяти на буфер не дает. Простой, понятный, но громоздкий вариант.

Затраты времени и памяти на копирование буфера ничто по сравнению с висением активной задачи посимвольного вывода. Буфер же может отправляться в порт по прерываниям или DMA.
ИМХО.


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
zltigo
сообщение Jul 29 2011, 12:41
Сообщение #9


Гуру
******

Группа: Свой
Сообщений: 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
Go to the top of the page
 
+Quote Post
MALLOY2
сообщение Jul 29 2011, 12:52
Сообщение #10


Знающий
****

Группа: 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>
Go to the top of the page
 
+Quote Post
zltigo
сообщение Jul 29 2011, 13:28
Сообщение #11


Гуру
******

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



QUOTE (MALLOY2 @ Jul 29 2011, 14:52) *
Можно так:

Ну с va_list, это понятно, ну а в остальном это опять зачем-то через форматную печать в промежуточный буфер sad.gif.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jul 29 2011, 13:39
Сообщение #12


Гуру
******

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



QUOTE (MALLOY2 @ Jul 29 2011, 15:52) *
Можно так:
Можно. Обратите внимание на void iodevice::printf(char const * format, ...) в сообщении №5


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Dog Pawlowa
сообщение Jul 29 2011, 15:11
Сообщение #13


Гуру
******

Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823



Цитата(zltigo @ Jul 29 2011, 15:41) *
причем в естественный для этой задачи кольцевой буфер.

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


--------------------
Уходя, оставьте свет...
Go to the top of the page
 
+Quote Post
zltigo
сообщение Jul 29 2011, 15:26
Сообщение #14


Гуру
******

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



QUOTE (Dog Pawlowa @ Jul 29 2011, 17:11) *
При двухстороннем протокольном обмене линейный буфер так же естественен, как и кольцевой.

Например, X.25 совершенно двухсторонний и протокольный sm.gif. Ну и?
Полагаю, я догадываюсь о чем это Вы - об АБСОЛЮТНО вырожденном случае, когда обмен в протоколе осуществляется посылкой текстовых сообщений строго ограниченной длинны и строго в режиме запрос - пауза - ответ. Если говорить о более-менее реальных применениях, то тот-же самый printf() используется для совершенно асинхронной выдачи сообщений достаточно произвольного размера. При этом за просто так занести в буфер следущее сообщение не получится, пока не будет передано предыдущее. Склейка сообщений в линейном буфере не сложна (но в приведенных примерах я ее не видел), но по любому начинает неэффективно использоваться память буфера, поскольку весь объем буфера будет доступен только после его полного освобождения. Это опять можно слегка обойти, но опять не на 100% и путем усложнения работы с буфером. Короче, я такие (использование линейного буфера в режиме приближенного к кольцевому) финты делал пару раз в жизни после тщательного обдумывания. И это совершенно не типовой и редко полезный подход.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
Dog Pawlowa
сообщение Jul 29 2011, 15:52
Сообщение #15


Гуру
******

Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823



Цитата(zltigo @ Jul 29 2011, 18:26) *
об АБСОЛЮТНО вырожденном случае...
... о более-менее реальных применениях

Ну да, так сложилось, что мои реальные применения - это вырожденные случаи.
Мне приятно красиво сложить пакет перед отправкой, ну а кому-то нужно побыстрее покидать их в буфер sm.gif


--------------------
Уходя, оставьте свет...
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 20th July 2025 - 12:21
Рейтинг@Mail.ru


Страница сгенерированна за 0.01511 секунд с 7
ELECTRONIX ©2004-2016