Возможно ли писать на консоль без 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, так как вам требуется фиксированный набор сообщений на ПК для декодирования, но он не добавляет слишком много накладных расходов, как я упоминал ранее.
Надеюсь, что это поможет.
Фернандо