Возможно ли писать на консоль без stdlibs? C/С++

Я программирую на микропроцессоре руки и пытаюсь отлаживать с помощью операторов печати через UART. Я не хочу добавлять stdlibs только для отладки. Есть ли способ распечатать на консоли без stdio.h/iostream.h? Возможно ли, чтобы я написал свой собственный printf()?

В качестве альтернативы я могу это сделать с помощью контроллера DMA и напрямую писать в UART. Однако я бы хотел избежать этого. Использование встроенной тестовой функции "эхо" или "remote loop-back" Я знаю, что UART настроен правильно.

Ответ 1

Короткий ответ: Да, вполне возможно сделать оба ваших решения.

Функция printf довольно сложна, если вы хотите поддерживать все типы данных и форматы. Но не так сложно написать что-то, что может выводить строку или целое число в нескольких разных базах (большинству людей требуется только десятичная и шестнадцатеричная, но восьмеричные, вероятно, только добавляет еще 3-4 строки кода, как только у вас будет десятичный и шестнадцатеричный).

Как правило, printf записывается следующим образом:

 int printf(const char *fmt, ...)
 {
     int ret;
     va_list args; 

     va_start(args, fmt)
     ret = do_xprintf(outputfunc, NULL, fmt, args); 
     va_end(args);
     return ret;
}

И затем do_xprintf() выполняет всю тяжелую работу для всех вариантов (printf, sprintf, fprintf и т.д.)

int do_xprintf(void (*outputfunc)(void *extra, char c), void *extra, const char *fmt, va_list args)
{
    char *ptr = fmt;
    while(1)
    {
       char c = *ptr++;

       if (c == '%')
       {
            c = *ptr++; // Get next character from format string. 
            switch(c)
            {
               case 's': 
                  char *str = va_arg(args, const char *);
                  while(*str)
                  {
                      count++;
                      outputfunc(extra, *str);
                      str++;
                  }
                  break; 
               case 'x': 
                  base = 16;
                  goto output_number;

               case 'd':
                  base = 10;
         output_number:
                  int i = va_arg(args, int);
                  // magical code to output 'i' in 'base'. 
                  break;

               default:
                  count++;
                  outputfunc(extra, c);
                  break;
         }
         else
             count++;
             outputfunc(extra, c);
     }
     return count;
 }                

Теперь все, что вам нужно сделать, это заполнить несколько бит вышеуказанного кода и написать outputfunc(), который выводится на ваш последовательный порт.

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

(Обратите внимание на дополнительный параметр - для вывода на FILE *, который был бы файловым указателем, для sprintf вы можете передать структуру для буфера и позиции в буфере или что-то в этом роде)

Ответ 2

Концепция "консоли" не имеет большого значения вне контекста конкретной системы, которую вы используете. Как правило, во встроенной программе нет реальной концепции консоли.

То, что вы ищете, - это способ получить данные из вашей системы. Если вы хотите использовать UART, и вы не используете высокоуровневую ОС, такую ​​как GNU/linux, вам нужно будет написать свои собственные драйверы ввода-вывода. Как правило, это означает, что сначала настраивается UART для желаемого управления потоком/четностью/потоком посредством записи регистров. Для любого типа надежного ввода-вывода вы хотите, чтобы он прерывался, поэтому вам нужно будет писать ISR для tx и rx, которые используют круговые буферы.

После этого вы можете написать свой собственный printf, как указано в Mats.

Ответ 3

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

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

Подход имеет наименьшие служебные данные/влияние на целевую операцию, может использоваться (с осторожностью) в процедуре прерывания, и идея легко переносима, поэтому я проигнорировал отладчик на всех системах, которые я использовал.

Ответ 4

Поскольку распечатка информации через последовательный порт во встроенной системе изменяет основное время программы, лучшим решением, которое я нашел, является отправка небольшого сообщения, закодированного в 2 байта (иногда 1 байт работает нормально), а затем используя программы на ПК для декодирования этих сообщений и предоставления необходимой информации, которая может включать в себя статистику и все, что вам может понадобиться. Таким образом, я добавляю немного основной накладной к основной программе и позволяю компьютеру выполнять тяжелую работу по обработке сообщений. Может быть, что-то вроде этого:

  • 1 байтовое сообщение: биты 7: 4 = идентификатор модуля, бит 3: 0 = информация об отладке.

  • 2 байта: бит 15:12 = идентификатор модуля, бит 11: 8 = информация об отладке, биты 7: 0 = данные.

Затем в программном обеспечении ПК вы должны объявить таблицу с сообщениями, которые сопоставляются с определенной парой данных ID ID/debug, и использовать их для печати на экране.

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

Надеюсь, что это поможет.

Фернандо