Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: помогите с printf
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
kovz
Здаствуйте уважаемые форумчане!
Помогите разобраться с printf, a точнее с printf_P. На колько я понял из документации разница между ними только в области хранения строки формата вывода: в первом случае это DATA MEMORY, во втором CODE.
Пример простейшей программки в IARAVR5.20

Код
#include <pgmspace.h>

__flash char const __flash * test[]={
    "Hellow World!",
    "With fucking printf_P"
  };

void main(void)
{
  printf_P("%s %s",test[0],test[1]);
  for(;;);
}


компилирую с опцией --string_literals_in_flash.
проц мега 164, Normal Dlib, изменение prinf_formatter не могают.
в результате выводится только пробел.
при копании в исходниках библиотек обнаружил, что после того как распарсится первых два символа строки формата вывода(%s), правильно определяется адресс первого символа строки "Hellow World!"(в CODE MEMORY), но на вывод идёт то, что по тому же адресу в DATA памяти.
Помогите пожалуйста кто сталкивался, как красиво выводить строки лежащие во флеше, в моём случае это уарт, про переопределение __write знаю, и к этой проблеме оно отношения не имеет, помоему.
Сергей Борщ
Цитата(kovz @ May 22 2009, 15:54) *
в области хранения строки формата вывода: в первом случае это DATA MEMORY, во втором CODE.
...
правильно определяется адресс первого символа строки "Hellow World!"(в CODE MEMORY), но на вывод идёт то, что по тому же адресу в DATA памяти.
Так ведь ваша строка не является строкой формата. "%s %s" берется из флеша, как и заказывали. %s означает строку в DATA MEMORY. Увы, ни стандартом, ни разработчиками компилятора (судя по доке) не предусмотрен символ формата для строк во флеше. Остается вам только делать
Код
void main(void)
{
  printf_P(test[0]);
  printf_P(test[1]);
  for(;;);
}
kovz
Цитата(Сергей Борщ @ May 22 2009, 16:33) *
Так ведь ваша строка не является строкой формата. "%s %s" берется из флеша, как и заказывали. %s означает строку в DATA MEMORY. Увы, ни стандартом, ни разработчиками компилятора (судя по доке) не предусмотрен символ формата для строк во флеше. Остается вам только делать
Код
void main(void)
{
  printf_P(test[0]);
  printf_P(test[1]);
  for(;;);
}


да спасибо я пришел к тому же выводу, что при старте прийдётся все строки переписыватьв озу и из него уже выводить в порт. Грустно конешно, особенно после ARMов sad.gif
Сергей Борщ
Цитата(kovz @ May 22 2009, 17:16) *
да спасибо я пришел к тому же выводу, что при старте прийдётся все строки переписыватьв озу и из него уже выводить в порт.
Зачем??? Подставляйте их в качестве форматной строки.
ARV
a printf в WinAVR умеет в строке формата и строку из флеша брать...
M_Andrey
Никогда не пользовался printf'-ом, но давно хотел написать по поводу __flash char const __flash * test[], а тут как раз тема подвернулась.

Уже давно пользуюсь для Fujitsu MB90*** строками для вывода на дисплей определением:

const char * const text[...]=

{...,

...,

...,

};

(очень удобно :-) )

и потом print(text[i]);

И с наскоку хотел все библиотеки перекинуть для AVR-ов, но не тут-то было, компилятор все эти константы переносит в ОЗУ (SRAM) и оперативка быстро заканчивается! Приходится все красивости переводить в кривизну типа:

__flash const unsigned char text0[]={...};

__flash const unsigned char text1[]={...};

...

потом процедура копирования из (__flash const unsigned char) в буфер (buf) ОЗУ и вызов print(buf);

Может кто знает как сделать это "красиво"?
kovz
Цитата(ARV @ May 22 2009, 18:20) *
a printf в WinAVR умеет в строке формата и строку из флеша брать...


Вобщем всем спасибо, разобрался окончательно.
Функция printf в качестве строки формата и аргументов требует данные из ОЗУ.
Функция printf_P в качестве строки формата принимает строку из flash? а в качестве аргументов данные из ОЗУ.
Это окончательно и безповоротно (если говорить о библиотечной реализации).

Но у меня вопрос появился ещё более завёрнутый smile.gif
По умолчанию printf(_P) выводит данные в stdout. По идее, на сколько я понял, в Normal Dlib stdout linebuffered. Судя по исходникам библиотек, буфер статический на 80 байт(тоже и по документации). Так вот вопрос знатокам: возможно ли сделать так, чтоб при вызове printf(_P)данные записывались в этот буфер, а потом функция передачи по USART, построенная на прерываниях, выводила это всё в порт?
понимаю что тут могут возникнуть вопросы о целесообразности такого действия, но специфика приложения позволяет, и даже предпочтительнее освободить ресурсы ЦПУ, а данные передавать в фоне.
Честно говоря необходимость работать с printf в порт возникла впервые, посему не судите строго за ламерские вопросы laughing.gif
ReAl
Цитата(kovz @ May 22 2009, 22:14) *
По умолчанию printf(_P) выводит данные в stdout. По идее, на сколько я понял, в Normal Dlib stdout linebuffered. Судя по исходникам библиотек, буфер статический на 80 байт(тоже и по документации). Так вот вопрос знатокам: возможно ли сделать так, чтоб при вызове printf(_P)данные записывались в этот буфер, а потом функция передачи по USART, построенная на прерываниях, выводила это всё в порт?
"всё не так" ™.
Нужен не printf, а fprintf.
Определяем функцию, которая "выводит байт в UART" (на самом деле она может помещать его в циклический буфер, выгребаемый из прерываний, а уж если там нет места - тогда ждать) и определяем файловый объект

Код
#include <stdio.h>

int console_putc(char ch, FILE*stream)
{
    (void)stream;
    while( uart_tx_buffer_full() );
    uart_tx_buffer_put(ch);
    return 0;
}

FILE console_file = FDEV_SETUP_STREAM(console_putc, 0, _FDEV_SETUP_WRITE);
#define fconsole (&console_file)


Теперь можно так:
Код
fprintf_P( fconsole, PSTR("Hello %5d times!!!"), 1000);


А можно так:
Код
void dbg_printf_P(dbg_level lev, const prog_char * fmt, ...)
{
    if (lev <= curr_lev) {
        va_list va;
        va_start(va, fmt);
        vfprintf_P(fconsole, fmt, va);
        va_end(va);
    }
}


Что приятно - это не мешает параллельно создать файловый объект ЖКИ-индикатора (настроив его на соответствующую функцию вывода) или "ещё чего надо" и выводить тем же fprintf-ом и туда тоже.

А вообще - смотрите описание avr-libc

Ой, не заметил сначала.
Цитата(kovz @ May 22 2009, 22:14) *
Функция printf_P в качестве строки формата принимает строку из flash? а в качестве аргументов данные из ОЗУ.
Это окончательно и безповоротно (если говорить о библиотечной реализации).

Смотрите то же описание avr-libc. Если имеются ввиду аргументы - числа, то это так.
Для строк поддерживается расширение:
%s - из ОЗУ, %S - из флеша.
kovz
огромное спасибо! завтра буду пробовать.
Nick_Shl
Цитата(ReAl @ May 22 2009, 22:59) *
Для строк поддерживается расширение:
%s - из ОЗУ, %S - из флеша.
А в CodeVision будет %p из флеш.
Не понятно только одного: не ужели нельзя сделать LARGE модель с 32 битами на указатель, верхние 2 из которых использовать как признак типа памяти к которой доступаемся? А то приходится в некоторые свои функции передавать в указатели на void и признак куда он указывает, а внутри функции добавлять разбор...
Сергей Борщ
Цитата(Nick_Shl @ May 23 2009, 01:30) *
А в CodeVision будет %p из флеш.
не перестаю удивляться этому компилятору с "языка, похожего на С". В стандарте С %p зарезервирован под указатель...
Цитата(Nick_Shl @ May 23 2009, 01:30) *
Не понятно только одного: неужели нельзя сделать LARGE модель с 32 битами на указатель, верхние 2 из которых использовать как признак типа памяти к которой доступаемся?
Раз уж первый вопрос был про IAR, то в нем есть ключевое слово __generic для объявления таких указателей и функции printf_G и подобные для работы с ними. Для avr-gcc (WinAVR) добиться подобного эффекта тоже возможно при помощи финта ушами.
kovz
Цитата(Сергей Борщ @ May 23 2009, 11:57) *
не перестаю удивляться этому компилятору с "языка, похожего на С". В стандарте С %p зарезервирован под указатель...

В IAR это именно так
Цитата(Сергей Борщ @ May 23 2009, 11:57) *
вопрос был про IAR, то в нем есть ключевое слово __generic для объявления таких указателей и функции printf_G и подобные для работы с ними.

К сожалению функции printf_G несуществует.

Цитата
Для строк поддерживается расширение:..., %S - из флеша.

IAR не имеет такого спецификатора
ReAl
Цитата(kovz @ May 23 2009, 13:45) *
IAR не имеет такого спецификатора
Тьху, прошу прощения. Тут много всего упоминалось и мне показалось, что речь о gcc
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.