Перейти к содержанию
    

помогите с printf

Здаствуйте уважаемые форумчане!

Помогите разобраться с 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 знаю, и к этой проблеме оно отношения не имеет, помоему.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

в области хранения строки формата вывода: в первом случае это 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(;;);
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Так ведь ваша строка не является строкой формата. "%s %s" берется из флеша, как и заказывали. %s означает строку в DATA MEMORY. Увы, ни стандартом, ни разработчиками компилятора (судя по доке) не предусмотрен символ формата для строк во флеше. Остается вам только делать
void main(void)
{
  printf_P(test[0]);
  printf_P(test[1]);
  for(;;);
}

 

да спасибо я пришел к тому же выводу, что при старте прийдётся все строки переписыватьв озу и из него уже выводить в порт. Грустно конешно, особенно после ARMов :(

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

да спасибо я пришел к тому же выводу, что при старте прийдётся все строки переписыватьв озу и из него уже выводить в порт.
Зачем??? Подставляйте их в качестве форматной строки.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

a printf в WinAVR умеет в строке формата и строку из флеша брать...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Никогда не пользовался printf'-ом, но давно хотел написать по поводу __flash char const __flash * test[], а тут как раз тема подвернулась.

 

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

 

const char * const text[...]=

 

{...,

 

...,

 

...,

 

};

 

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

 

и потом print(text);

 

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

 

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

 

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

 

...

 

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

 

Может кто знает как сделать это "красиво"?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

a printf в WinAVR умеет в строке формата и строку из флеша брать...

 

Вобщем всем спасибо, разобрался окончательно.

Функция printf в качестве строки формата и аргументов требует данные из ОЗУ.

Функция printf_P в качестве строки формата принимает строку из flash? а в качестве аргументов данные из ОЗУ.

Это окончательно и безповоротно (если говорить о библиотечной реализации).

 

Но у меня вопрос появился ещё более завёрнутый :)

По умолчанию printf(_P) выводит данные в stdout. По идее, на сколько я понял, в Normal Dlib stdout linebuffered. Судя по исходникам библиотек, буфер статический на 80 байт(тоже и по документации). Так вот вопрос знатокам: возможно ли сделать так, чтоб при вызове printf(_P)данные записывались в этот буфер, а потом функция передачи по USART, построенная на прерываниях, выводила это всё в порт?

понимаю что тут могут возникнуть вопросы о целесообразности такого действия, но специфика приложения позволяет, и даже предпочтительнее освободить ресурсы ЦПУ, а данные передавать в фоне.

Честно говоря необходимость работать с printf в порт возникла впервые, посему не судите строго за ламерские вопросы :laughing:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

По умолчанию 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

 

Ой, не заметил сначала.

Функция printf_P в качестве строки формата принимает строку из flash? а в качестве аргументов данные из ОЗУ.

Это окончательно и безповоротно (если говорить о библиотечной реализации).

Смотрите то же описание avr-libc. Если имеются ввиду аргументы - числа, то это так.

Для строк поддерживается расширение:

%s - из ОЗУ, %S - из флеша.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для строк поддерживается расширение:

%s - из ОЗУ, %S - из флеша.

А в CodeVision будет %p из флеш.

Не понятно только одного: не ужели нельзя сделать LARGE модель с 32 битами на указатель, верхние 2 из которых использовать как признак типа памяти к которой доступаемся? А то приходится в некоторые свои функции передавать в указатели на void и признак куда он указывает, а внутри функции добавлять разбор...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А в CodeVision будет %p из флеш.
не перестаю удивляться этому компилятору с "языка, похожего на С". В стандарте С %p зарезервирован под указатель...
Не понятно только одного: неужели нельзя сделать LARGE модель с 32 битами на указатель, верхние 2 из которых использовать как признак типа памяти к которой доступаемся?
Раз уж первый вопрос был про IAR, то в нем есть ключевое слово __generic для объявления таких указателей и функции printf_G и подобные для работы с ними. Для avr-gcc (WinAVR) добиться подобного эффекта тоже возможно при помощи финта ушами.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

не перестаю удивляться этому компилятору с "языка, похожего на С". В стандарте С %p зарезервирован под указатель...

В IAR это именно так

вопрос был про IAR, то в нем есть ключевое слово __generic для объявления таких указателей и функции printf_G и подобные для работы с ними.

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

 

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

IAR не имеет такого спецификатора

Изменено пользователем kovz

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

IAR не имеет такого спецификатора
Тьху, прошу прощения. Тут много всего упоминалось и мне показалось, что речь о gcc

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...