Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: printf и несколько UART
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
dimka76
Когда изпользуетс вывод через один UART все понятно, пишем свою putchar.
А если требуется работать с несколькими UART и еще SPI, TWI и во всех случаях использовать printf, как быть в этом случае?
Палыч
Конечно же написать свои функции, или одну универсальную, по функциональности такую же, как и printf.
prottoss
Хм... smile.gif А зачем использовать printf для второго(третьего, четвертого...) USART и тем более для TWI и SPI???. Обычно, данная функция используется для отладки. Для работы лучше написать что нибудь свое, менее тяжеловесное.
defunct
Цитата(dimka76 @ Oct 25 2007, 13:45) *
Когда изпользуетс вывод через один UART все понятно, пишем свою putchar.
А если требуется работать с несколькими UART и еще SPI, TWI и во всех случаях использовать printf, как быть в этом случае?

putchar можно сделать зависимым от какого-то глобального флага, e.g.
Код
U8 DevConOut = 0;

int putchar( int ch)
{
    switch( DevConOut )
    {
      case DEV_UART0:
          ....
          break;
      case DEV_UART1:
          ....
          break;
      case DEV_SPI:
          ...
          break;
      default:
          ...
          break;
    }
}
printf заменить макросом:
Код
#define my_printf( conout,  x ) do \
    {\
        DevConOut = (conout);\
        printf (x);\
    } while (0)

который использовать например так:
Код
my_printf( DEV_UART1, ("hello"));
my_printf( DEV_SPI, ("hello"));
Обрамлять второй параметр my_printf в скобочки - обязательно!
prottoss
Ну, а уж если все таки приспичило, можно в putchar ввести глобальный флаг и переключать его в функции, которая вызывает printf, и которая знает, в какой интерфейс будет идти сообщение...
Код
char g_putcharMode = 0;
...
int putchar(int c)
{    
     switch(g_putcharMode)
     {
            case USART0_MSG:
            ...
            break;

            case USART1_MSG:
            ...
            break;

            case SPI_MSG:
            ...
            break;

             ...
     }

      return 0;
}
Сергей Борщ
Цитата(defunct @ Oct 25 2007, 14:01) *
putchar можно сделать зависимым от какого-то глобального флага, e.g.
Или использовать fprintf, но тогда придется подобным образом переписать не putchar, а какую-то другую функцию, в ИАР, например, это функция __write(). Ей номер устройства вывода передается как параметр, что позволяет использовать ее в многопоточных приложениях.
Палыч
Цитата(prottoss @ Oct 25 2007, 15:03) *
Ну, а уж если все таки приспичило, можно в putchar ввести глобальный флаг и переключать его в функции, которая вызывает printf, и которая знает, в какой интерфейс будет идти сообщение...

Можно, конечно, и так, но, только вывод в UART, SPI, TWI нельзя будет осуществлять одновременно. Правда, мне не понятно зачем вывод с помощью printf автору вопроса потребовался во все эти устройства. Да, и вообще, printf - слишком тяжелая для микроконтроллеров функция (как правильно указал prottoss), без которой во многих случаях можно обойтись.
ReAl
"компилятор по умолчанию"? wink.gif

А вот если avr-gcc, то можно создать любое количество описателей потока

Код
int some_putchar(char c, FILE *stream);

FILE some_stream = FDEV_SETUP_STREAM(some_putchar,  NULL, _FDEV_SETUP_WRITE);

и дальше пользоваться fprintf/fprintf_P/fputs/fputs_P/vfprintf_P ( &some_stream,
если при создании потока вторым параметром дать get-функцию, то и всем остальным стандартным.
Независимо и без передёргивания флагов.

А по поводу "printf только для отладки" - если в системе есть несколько текстовых потоков (текстовый протокол по UART, какой-нибудь термопринтер, ... и есть запас флеша/стека (а раз при отладке помещалось, значит есть) - то просто удобно пользоваться стандартными функциями везде.
Да и отладить многие куски форматирования/передачи можно через те же стандартные функции на персоналке.
defunct
Цитата(Палыч @ Oct 25 2007, 14:14) *
Да, и вообще, printf - слишком тяжелая для микроконтроллеров функция (как правильно указал prottoss), без которой во многих случаях можно обойтись.

(imho)
Для m32 и выше - удобство printf перевешивает "тяжесть".
Для более мелких - да, выгоднее писать свои функции.
alexander55
Цитата(Палыч @ Oct 25 2007, 15:14) *
Можно, конечно, и так, но, только вывод в UART, SPI, TWI нельзя будет осуществлять одновременно. Правда, мне не понятно зачем вывод с помощью printf автору вопроса потребовался во все эти устройства. Да, и вообще, printf - слишком тяжелая для микроконтроллеров функция (как правильно указал prottoss), без которой во многих случаях можно обойтись.

Мне кажется, функция printf используется:
1. Чаще всего для отладки. Терминал всегда один. Одновременно посылать никогда не надо. Иногда надо переключить UART (очень редко).
2. Внутри в самодельных пультов управления. Вобще не имеет отношения к поднятому вопросу. Удобнее использовать sprinf.
PS. Проблема носит теоретический характер. smile.gif
prottoss
Цитата(alexander55 @ Oct 25 2007, 19:40) *
...Терминал всегда один...
По поводу того, что printf для отладки - согласен. А вот, что термнал всего один - нет. Терминалов может быть несколько. Один - для отладки, допустим на USART. Второй, к примеру на SPI - рабочий терминал устройства.

С первым работаем через printf, включая, допустим в макрос, который после отладки отключается.

Для второго пишем свой движок для эффективного вывода.
dimka76
всем спасибо.
эта идея чисто абстрактная, на всякий случай так сказать.
defunct прав, при больших объемах FLASH, SRAM, удобство printf перевешивает "тяжесть". Да, и если быстродействия не требуется.
А идея с макросами от defunct мне понравилась больше всего.

Кстати компилятор IAR, хотя это наверное не принципиально, если подразумевается переносимость кода.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.