Комментарии 26
Честно говоря не совсем понятно, зачем вообще нужно совмещать форматирование строки и отправку её в сеть.
Я бы отдельно занялся бы созданием форматированной строки, например старый добрый sprintf использовал, или другие с++ аналоги (std::stringstream).
А потом бы отдельно отправлял строчку в сеть.
По отдельности эти задачи выглядят в разы проще.
Я бы отдельно занялся бы созданием форматированной строки, например старый добрый sprintf использовал, или другие с++ аналоги (std::stringstream).
А потом бы отдельно отправлял строчку в сеть.
По отдельности эти задачи выглядят в разы проще.
+2
Честно говоря не совсем понятно, зачем вообще нужно совмещать форматирование строки и отправку её в сеть.
У меня не стояло задачи отправки строки в сеть. Возможность перепаковывать — просто дополнительный презент.
Я бы отдельно занялся бы созданием форматированной строки, например старый добрый sprintf использовал, или другие с++ аналоги (std::stringstream).
Согласен. Но уже стакнулся, что некоторые библиотеки (особенно бесит, когда данные производителем в бинарном виде), используют printf для логирования данных.
0
Что бы не выделять отдельный буфер для отформатированной строки. И не тратить флеш на стрингстрим, если он нужен только в одном месте. И в целом что бы сохранять больше контроля над тем что происоходит под капотом.
0
Что-то сомневаюсь, что на на отсутствии буфера можно что-то вразумительное выиграть.
Как правило в программах узкие места совершенно в других местах
Как правило в программах узкие места совершенно в других местах
0
Что бы не выделять отдельный буфер для отформатированной строки.
void myPrintf() {
char buf[размер]; // вот он здесь выделяется в стеке и потом освобождается.
Выделять же буфер размером в 2к наверное это перебор. Здесь требуется разумный подход к буферизации.
В принципе можно использользовать vsnprintf для написания своей myPrintf для вот такого использования:
Serial << "лала=" << myPrintf("%04d",myVar) << ", блабла" << endl;
0
НЛО прилетело и опубликовало эту надпись здесь
Спасибо за статью!
Интересно, а каков истинно-верный способ перенаправления printf?
Скажем, в Кейле очень часто используется переопределение fputc
, а не _write
.
0
Интересно, а каков истинно-верный способ перенаправления printf?
Думаю, тут все на вкус… Keil, на сколько я помню (могу ошибаться) использует свои библиотеки и свой компилятор (который отличается значительно от gcc). Если не прав, то прошу поправить. Так что тут сложно сказать. Давно не работал с keil.
0
Компилятор и библиотека, конечно, свои, но стандартная библиотека на то и стандартная. Должны же, наверное, быть заранее предусмотренные места для переопределения.
0
Не совсем. В статье я упоминал, что "… если вы используете newlib-nano...". Интерфейсы верхнего уровня — да. Одинаковые (в большинстве своем). А вот «внизу», каждый как сам захочет (на сколько мне известно, это не регламентируется).
0
НЛО прилетело и опубликовало эту надпись здесь
Чувствуется опыт, но к подаче есть вопросы:
1) если это tutorial, то чему он меня учит?
2) есть введение, должно быть заключение
Если не нравятся готовые printf.c, xprint и прочие, то в чем сложность написать его самому, если не полный, то лайтовый. Или доработать указанные выше? Плавающая точка, в принципе, несложно делается.
1) если это tutorial, то чему он меня учит?
2) есть введение, должно быть заключение
Если не нравятся готовые printf.c, xprint и прочие, то в чем сложность написать его самому, если не полный, то лайтовый. Или доработать указанные выше? Плавающая точка, в принципе, несложно делается.
+1
1) если это tutorial, то чему он меня учит?
Как запустить то, что работает под «большой ОС» из коробки на МК без лишних затрат и проблем с надежностью.
есть введение, должно быть заключение
Что-то как-то не подумал об этом. Но оно было бы бессмысленно — уровня «я привел самые частые грабли и краткие методы их решения».
Если не нравятся готовые printf.c, xprint и прочие, то в чем сложность написать его самому, если не полный, то лайтовый. Или доработать указанные выше? Плавающая точка, в принципе, несложно делается.
Сами функции всем устраивают. Вообще не люблю велосипеды по возможности писать. Не так давно писал статью о том, как можно запихать как можно больше стандартных библиотек в МК чтобы не писать своего, пусть и в ущерб памяти. Сейчас отрабатываю вариант комфортной отладки без лишней перепрошивки, но удобнее чем в той статье. Опишу, как обнаружу основные изъяны (если таковые будут).
0
Во всяких Cortex M0 — велосипеды часто вещь необходимая. Кроме того, не научишься ходить — не научишься бегать. Как говорится, от велосипедов — к велозаводам.
0
Честно сказать, признаю велосипеды только на уровне аппаратных багов периферии. И то стараюсь это в обертки заворачивать. Подменяя стандартные методы. Чтобы было понятно, зачем я пишу «магическую константу» по «магическому адресу». Порой приходится городить целые объекты-агрегаторы, которые пишут «магические массивы» в «магические регистры».
0
Из vsprintf можно сделать любой свой printf.
Например, вот для вывода на дисплей LCD в заданных координатах:
Соответственно, можно сделать SerPrintf(const char *s, ...), которая будет выводить в уарт и не переопределять вообще ничего.
Например, вот для вывода на дисплей LCD в заданных координатах:
#include <stdarg.h>
#define PRINTF_BUF 21
void printAt(int c, int r, const char *s, ...) {
char buf[PRINTF_BUF];
va_list ap;
va_start(ap, s);
lcd.setCursor(c, r); // Для аурта не нужно
vsnprintf(buf, sizeof(buf), s, ap);
lcd.print(buf); // Вот здесь Serial.print(buf) можно поставить.
va_end(ap);
}
Соответственно, можно сделать SerPrintf(const char *s, ...), которая будет выводить в уарт и не переопределять вообще ничего.
+2
Полезная штука, не знал. Спасибо. Однако ее можно применять только в своем коде, при условии, что никакая из библиотек в составе проекта не использует printf (иначе все равно придется переопределять и это теряет всякий смысл). А код библиотек я стараюсь не править, чтобы при любом обновлении без проблем обновить субмодуль с библиотекой.
0
Благодарю за статью! добавил в избранное. Рад на разжевывание со ссылками на примеры и туториалы. Продолжайте в том же духе, буду рад новым статьям.
0
Так всё такие не понятно? как именно лечить проблему хардфолта при использовании float в задаче FreerRtos?
Дано: stm32f103 + freertos (ide: atollic true studio);
Задача: выводить раз в 10 секунд в UART строку сгенерированную sprintf с float значением. Функция как таск freertos; размер таска стека было от 128 до 1024 (-u_printf_float в линкере прописан);
проблема: либо сразу либо после 5-10 выполнений hard fault МК
Гугление навело на этот пост, но конкретно «как решить» тут нет. Понимаю что проблема со стеком.
Так, как решить?
Дано: stm32f103 + freertos (ide: atollic true studio);
Задача: выводить раз в 10 секунд в UART строку сгенерированную sprintf с float значением. Функция как таск freertos; размер таска стека было от 128 до 1024 (-u_printf_float в линкере прописан);
проблема: либо сразу либо после 5-10 выполнений hard fault МК
Гугление навело на этот пост, но конкретно «как решить» тут нет. Понимаю что проблема со стеком.
Так, как решить?
0
Тут есть несколько вариантов. Не так давно сталкивался с этим снова. На новом arm-none-eabi (9-я версия. Последняя на момент написания комментария).
Убедитесь, что:
Если это соблюдено, то можно попробовать:
Убедитесь, что:
- Стека задачи достаточно (тут я так понял вы используете snprintf. Пишете в буфер и потом буфер отсылаете. Ради интереса можно задать буфер сильно больше нужного.
- В прерываниях не происходит переполнения стека. Как стека задачи, в которой произошло прерывание, так и соседних задач. Может у вас есть задача, которая сбрасывает wdt, а в ней стек на 128 элементов. Появляется прерывание. Пишет 4 килобайна, вы возвращаетесь в задачу wdt, планировщик меняет задачу на другую и тут все падает.
- У вас достаточно места в «куче». Имею ввиду не freertos кучу, а та, что «не занятое место» между буферной зоной стека и bss областью. Ее пользует функция _sbrk. Она считает, что место от конца bss области до начала зарезервированного стека (физический конец оперативной памяти) принадлежит ей (функции _sbrk). Тут надо оставить хотя бы 1 кб. Реально используется около 500 байт, когда вы устанавливаете например единый буфер.
- Можно явно задать буфер, с которым будет работать printf/scanf. setvbuf функцией (помните, что когда вы их вызовите, случится еще дерганье sbrk функции, которая сохъст 500 байт в «куче» (та что не принадлежит freertos). Кстати. Устанавливать буферы надо до запуска планировщика.
Если это соблюдено, то можно попробовать:
0
Есть ли возможность добавить в текст некоторый ликбез по синтаксису и семантике языка *.ld файла?
Что значат эти точки, звёздочки, :, +=, функции AT() KEEP() ALIGN() > ,{,} и т.п. ?
Как отлаживать *.ld файлы? Как проверять, что *.ld скрипт правильно отработал?
-1
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Самые частые грабли при использовании printf в программах под микроконтроллеры