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

 
 
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
zltigo
сообщение Jul 29 2011, 16:02
Сообщение #16


Гуру
******

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



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

Красота складывания или не складывания в пакет или не в пакет к делу отношения не имеет - тут весь вопрос в том, имеет-ли право некая порция информации отсылаться не по команде свыше после того, как все гарантированно отправится и примется, а совершенно асинхронно, например, в момент внешнего воздействия. И про "красиво сложить", я Вам не просто так назвал прадедушку коммуникационных протоколов X.25 - там "красиво сложить пакет" в полный рост, но линейные буфера ну НИКАК не канают.


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


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(MrYuran @ Jul 29 2011, 15:28) *
Затраты времени и памяти на копирование буфера ничто по сравнению с висением активной задачи посимвольного вывода. Буфер же может отправляться в порт по прерываниям или DMA.
ИМХО.

В гораздо более простых случаях, и это не экзотика, putchar() может запросто дергать суперлуп, в котором выполняются все нужные задачи. И при этом ничего не висит.
Код
int putchar(int ch)
{
extern void idle(void);
  while(!can_write()) idle();
  write_sym((char)ch);
  return 0;
}


Сообщение отредактировал _Pasha - Jul 29 2011, 19:15
Go to the top of the page
 
+Quote Post
ReAl
сообщение Jul 30 2011, 07:05
Сообщение #18


Нечётный пользователь.
******

Группа: Свой
Сообщений: 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 ничего и не узнает :-)
На мой взгляд -- вполне аккуратно всё выходит.
У других такого нет?


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
zltigo
сообщение Jul 30 2011, 08:26
Сообщение #19


Гуру
******

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



QUOTE (ReAl @ Jul 30 2011, 09:05) *
Так а что, это только в avr-libc под avr-gcc есть понятие файла с подставляемыми пользователем функциями get/put

Понятие файла обязательно есть. Только там еще структура и конечный автомат для обслуживания этого файла добавляются sad.gif. Несколько лишняя, хотя и универсальная сущность.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
Serhio6223
сообщение Aug 11 2011, 17:07
Сообщение #20





Группа: Новичок
Сообщений: 3
Регистрация: 1-08-11
Пользователь №: 66 533



Всем доброго времени суток. Обьясните пожалуйста, что вобще озночает putchar? Что он куда записывает? Я не так давно приступил к изучению Си, читаю всяческие лекции для чайников, которые нахожу в сети, но пока не понял, что есть putchar(((
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Aug 12 2011, 08:59
Сообщение #21


Гуру
******

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



QUOTE (Serhio6223 @ Aug 11 2011, 20:07) *
Обьясните пожалуйста, что вобще озночает putchar?
Это функция, которая выводит переданный ей символ. Куда выводит - определяется реализацией. На писюге - в консоль, в контроллере - зависит от вас (вам придется написать ее самомтоятельно).


--------------------
На любой вопрос даю любой ответ
"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
сообщение Aug 12 2011, 09:27
Сообщение #22


Гуру
******

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



Цитата(Serhio6223 @ Aug 11 2011, 20:07) *
Что он куда записывает?

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


--------------------
Уходя, оставьте свет...
Go to the top of the page
 
+Quote Post
sergeeff
сообщение Aug 12 2011, 09:46
Сообщение #23


Профессионал
*****

Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007



Цитата(Dog Pawlowa @ Aug 12 2011, 13:27) *
Куда - уже ответили, а что - это существенно - этой функции передаются байты, выводимые с помощью printf.


Да вовсе не обязательно и тоже зависит от реализации самой printf.
Go to the top of the page
 
+Quote Post
ветерок
сообщение Dec 3 2011, 17:32
Сообщение #24


Местный
***

Группа: Участник
Сообщений: 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


--------------------
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 22nd July 2025 - 04:46
Рейтинг@Mail.ru


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