Память заканчивается. Варианты решения.

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Получается что линия Tх работет ... (диод Tx теперь не постоянно горит ?)

Разбирайтесь с линией Rx - вчера же на ней моргал светодиод ?

 

P.S. на схемах NANO эти резисторы 100% по 1 кОм ...

AsNik
Offline
Зарегистрирован: 24.10.2020

Komandir пишет:

Разбирайтесь с линией Rx - вчера же на ней моргал светодиод ?

диод Tx теперь не постоянно горит ?

P.S. на схемах NANO эти резисторы 100% по 1 кОм ...

Добавил в предыдущее сообщение, но повторю на всякий случай

ADD: Хотя при отправки из монитора (нажатие энтер) Led Rx вспыхивает, не ярко, но примерно так же как и Tx каждую секунду...

Не, Tx теперь норм.

vk007
Offline
Зарегистрирован: 16.06.2015

Там оба резистора 102, т.е. на 1 кОм.

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

При 10 кОм (103 маркировка смд) работать не должно ... Может он раньше просто в "кз" был как перемычка ?

AsNik
Offline
Зарегистрирован: 24.10.2020

Ну наверное есть смысл его (верхний по рисунку, Rx) тоже перепаять?

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

vk007 пишет:

Там оба резистора 102, т.е. на 1 кОм.

 По схемам и на картинках да, но на них не видно надписей точно. Он два миллиметра длинной, из них миллиметр на контакты...

AsNik
Offline
Зарегистрирован: 24.10.2020

Komandir пишет:

При 10 кОм (103 маркировка смд) работать не должно ... Может он раньше просто в "кз" был как перемычка ?

Я позавчера, делал в коде оптимизацию, ардуину ни из макетки ни USB кабель не перевтыкивал. СМД резисторы эти на нижней части ардуины, т.е. между макеткой и ардуиной, доступа к ним без вытаскивания ардуины нет.

В таком режиме ардуина уже находится(лась) очень долго и все было до момента, пока я не попробовал переделать процедуру с PROGMEM и указателями (понимаю, что совпадение) - Это я к тому, что никаких кз не должно быть. Ноги ардуины Tx и Rx никуда не подключены, и в макетке там тоже ничего нет. На самой плате тоже ничего не замыкал...

В общем странная ситуация... Но ведь, как Вы были правы с линей Tx - удивительно. Рассохся припой и резистор отвалился :) Так, может, повторюсь, заморочится с резистором Rx?

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Если он звонится как 10 кОм, то однозначно менять.

Можно же зачистить дорожку в любом месте или прямо к ноге CH340.

Можно просто коротнуть его и проверить.

Если припой потрескался в одном месте, то мог и в другом - пройдитесь паяльником по ногам микросхем (хотябы по линии Rx для начала).

AsNik
Offline
Зарегистрирован: 24.10.2020

Так, вот такие вот результаты.

Отвалился пятак под Tx.... :( Но.... выпаял оба резистора и замкнул перемычками. Эхо заработало... 

А вот при попытке загрузить скеч:

Скетч использует 1724 байт (5%) памяти устройства. Всего доступно 30720 байт.
Глобальные переменные используют 206 байт (10%) динамической памяти, оставляя 1842 байт для локальных переменных. Максимум: 2048 байт.
avrdude: stk500_getsync() attempt 1 of 10: not in sync: resp=0x53
avrdude: stk500_getsync() attempt 2 of 10: not in sync: resp=0x65
avrdude: stk500_getsync() attempt 3 of 10: not in sync: resp=0x63
avrdude: stk500_getsync() attempt 4 of 10: not in sync: resp=0x6f
avrdude: stk500_getsync() attempt 5 of 10: not in sync: resp=0x6e
avrdude: stk500_getsync() attempt 6 of 10: not in sync: resp=0x64
avrdude: stk500_getsync() attempt 7 of 10: not in sync: resp=0x0d
avrdude: stk500_getsync() attempt 8 of 10: not in sync: resp=0x0a
avrdude: stk500_getsync() attempt 9 of 10: not in sync: resp=0x30
avrdude: stk500_getsync() attempt 10 of 10: not in sync: resp=0x0d
Произошла ошибка при загрузке скетча
 
И вопрос, насколько критично без этих резисторов. Т.е. я так понял, в данном варианте (без R) с ног CH340 прямиком на ноги атмеги
 
И еще вопрос: Важно, когда прошиваю через ICSP выбирать выбирать для конечной ардуины стандартный загрузчик или Old Bootloader? Просто данная ардуина у меня всегда (на сколько я помню) загружалась только при использование (в ИДЕ) Old Bootloader. А через ICSP шьется и так и так.
ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

AsNik пишет:

Несколько. У меня нет установленных ИДЕ. Только зипы распакованные несколько штук... Но я правлю тот, откуда стартует arduino.exe....

100500, что после разархивирования ты их не допилил вручную, а надо, тогда каждая копия будет работать со своим списком ядер

AsNik
Offline
Зарегистрирован: 24.10.2020

ua6em пишет:

100500, что после разархивирования ты их не допилил вручную

Не допиливал. Да в принципе и не задумывался даже об этом

Цитата:

а надо, тогда каждая копия будет работать со своим списком ядер

Может это и правильно, но с другой стороны зачем? Впрочем, как это настраивается/допиливается? может пригодится...

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Для ICSP не важно какой загрузчик !

Выберите нужные плату, скорость чипа, загрузчик и скорость порта, а потом через ICSP выберите ЗАПИСАТЬ ЗАГРУЗЧИК. Запишется выбранный загрузчик и фьюзы выставятся как вы выбрали. 

Потом уже пробуйте писать скетчи через загрузчик.

AsNik
Offline
Зарегистрирован: 24.10.2020

И так. На данный момент резисторы выпаяны, вместо них перемычки. Еще раз прошил через ICSP загрузчик, выбрав при этом стандартный (тоже какой-то наверное своеобразный optiboot) не Old Bootloader. Потом попробовал в очередной раз прошить ардуину через USB.... И опа.. прошилась. И даже не через OldBootloader. Спасибо всем неравнодушным) Но Хотелось бы получить ответы на последние вопросы, а это:

1 - про резисторы (из #158) или их отсутствие.

2 - Ну как бы подтвердить или опровергнуть про выбор стандартных загрузчиков для наны (Процессор: "ATmega328P" и Процессор: "ATmega328P (Old Bootloader)") (то же из #158) Ну т.е. если я выбрал при прошивке загрузчика Old Bootloader, то туда старый загрузчик и запишеться, и потом в ардуине ИДЕ что бы прошивать ее нужно тоже выбирать Old Bootloader, или это неважно? Тогда для чего это сделано? 

И про настройку ИДЕ, я так понял, чтоб не использовалось AppData...

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Резисторы - защита "от дурака". CH340 не может знать что вы решили Rx Atmega сделать выходом. Так вот встреча двух выходов через резистор 1 кОм ничего не спалит.

 

Есть много загрузчиков и они по разному ждут своего вызова. Какой прошили - такой и выбираете потом.

AsNik
Offline
Зарегистрирован: 24.10.2020

Komandir пишет:

Резисторы - защита "от дурака". CH340 не может знать что вы решили Rx Atmega сделать выходом. Так вот встреча двух выходов через резистор 1 кОм ничего не спалит.

 

Есть много загрузчиков и они по разному ждут своего вызова. Какой прошили - такой и выбираете потом.

Спасибо. Значит сейчас буду как-то туда их впаивать) По загрузчикам - понял.

AsNik
Offline
Зарегистрирован: 24.10.2020

Ардуину починил. Продолжаю оптимизировать код. Помогите мне с функцией PrinLCDLine. Большая ее часть - это SerialPrintf Евгения.

У меня не хватает знаний передать в нее(PrinLCDLine) const char * const ну и вначале правильно сформировать szFormat

Логика(алгоритм) вроде на верном пути... а вот с реализацией (указатели моя беда :() туговато...  В прошлом году с дедом вроде немного вник, но за лето все напрочь забыл :(

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);

byte gradus[8] = {B00010, B00101, B00010, B00000, B00000, B00000, B00000, B00000};

const char Inf1_L1[] PROGMEM = "Sens: %s";
const char Inf1_L2[] PROGMEM = "T:%3d.%d\1C  H: %2d.%d %%";
const char Inf1_L3[] PROGMEM = "Humi(ABS): %2d.%-2d gm3";
const char Inf1_L4[] PROGMEM = "Pressure: %3d.%-2d  mm";
const char Inf2_L1[] PROGMEM = "View Sens %d-%d";
const char Inf2_L2[] PROGMEM = "Sens:  S%d   S%d   S%d ";
const char Inf2_L3[] PROGMEM = "Temp:  %2dC  %2dC  %2dC";
const char Inf2_L4[] PROGMEM = "Humi:  %2d%%  %2d%%  %2d%%";

const char * const Screen_Inf1[] PROGMEM = {Inf1_L1, Inf1_L2, Inf1_L3, Inf1_L4};
const char * const Screen_Inf2[] PROGMEM = {Inf2_L1, Inf2_L2, Inf2_L3, Inf2_L4};


void setup() {
  Serial.begin(115200); while (!Serial); Serial.println("OK");
  lcd.init(); lcd.backlight();
  lcd.createChar(1, gradus);
}

const size_t SerialPrintf (const char *szFormat, ...) {
  va_list argptr;
  va_start(argptr, szFormat);
  char *szBuffer = 0;
  const size_t nBufferLength = vsnprintf(szBuffer, 0, szFormat, argptr) + 1;
  if (nBufferLength == 1) return 0;
  szBuffer = (char *) malloc(nBufferLength);
  if (! szBuffer) return - nBufferLength;
  vsnprintf(szBuffer, nBufferLength, szFormat, argptr);
  Serial.print(szBuffer);
  free(szBuffer);
  return nBufferLength - 1;
}

const size_t PrintLCDLine(const byte aLine, const char * const aArr[], ...) {
  char szFormat[20];
  strcpy_P(szFormat, (char*)pgm_read_word(&(aArr[aLine])));

  Serial.println(szFormat);

  va_list argptr;
  va_start(argptr, szFormat);
  char * szBuffer = 0;
  const size_t nBufferLength = vsnprintf(szBuffer, 0, szFormat, argptr) + 1;
  if (nBufferLength == 1) return 0;
  szBuffer = (char *) malloc(nBufferLength);
  if (!szBuffer) return - nBufferLength;
  vsnprintf(szBuffer, nBufferLength, szFormat, argptr);
  lcd.setCursor(0, aLine); lcd.print(szBuffer);
  free(szBuffer);
  return nBufferLength - 1;
}

void loop() {
  lcd.clear();
  PrintLCDLine(0, Screen_Inf1, "NameS");
  PrintLCDLine(1, Screen_Inf1, 99, 5, 45, 7);
  PrintLCDLine(2, Screen_Inf1, 6, 44);
  PrintLCDLine(3, Screen_Inf1, 765, 4);
  delay(3000);
  PrintLCDLine(0, Screen_Inf2, 1, 3);
  PrintLCDLine(1, Screen_Inf2, 1, 2, 3);
  PrintLCDLine(2, Screen_Inf2, 25, 23, 15);
  PrintLCDLine(3, Screen_Inf2, 44, 56, 30);
  delay(1500);
}

UPD:

В прочем, сейчас немного исправил и вроде получилось. На сколько правильно я сделал, или где-то скрытую угрозу заложил? Есть варнинг:

C:\TEMP\arduino_modified_sketch_213931\PROGMEM_LCD_Format.ino: In function 'const size_t PrintLCDLine(byte, const char* const*, ...)':
C:\TEMP\arduino_modified_sketch_213931\PROGMEM_LCD_Format.ino:46:3: warning: second parameter of 'va_start' not last named argument [-Wvarargs]
   va_start(argptr, szFormat);
   ^~~~~~~~
как исправить? (исправил)
Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

И загрузчик заработал ?

AsNik
Offline
Зарегистрирован: 24.10.2020

Да, причем тот, который не Old Bootloader.... стала быстрее грузится. Спасибо Вам за помощь.

AsNik
Offline
Зарегистрирован: 24.10.2020

Читаю про va_start http://www.c-cpp.ru/content/vastart-vaend-vaarg

Хочу разобраться с варнингом... Немного запутался и вроде как есть расхождения описания с кодом Евгения.

В примере #165 есть полностью и его функция, и моя. Но варнинг только на моей... А хотя SerialPrintf вроде как не по условию описания va_start сделана, нет например va_end() А там сказано: "Если функция va_end() не вызвана, то возникает аварийная ситуация."

Но возможно Евгений ее заменил на free(szBuffer); Хотя прямой связи va_start и free(szBuffer); я не увидел.... Ох уж эта память с указателями... Но тем не менее варнинг только на моей переделке

 

-----------

Аааа... вроде разобрался... последний именоваyный параметр нужно в va_start вторым, т.е. в моем случае aArr

Варнинг убрал) Ну теперь скажите пожалуйста, правильно ли я там с типами и указателями сделал, ничего не напутал? Я понимаю, что "Ну работает же и отстань", но все же хочется правильно)

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

AsNik пишет:

...но все же хочется правильно)

Если хочется правильно, нужно книжки читать, а не на форумах вопросы задавать.

А сообщение типа "посмотрите мой код, все ли там правильно?" я вообще считаю бестактным - по сути оно демонстрирует пренебрежение к времени форумчан: "мне недосуг разбираться, да и времени своего жалко, так что сделайте за меня".

AsNik
Offline
Зарегистрирован: 24.10.2020

andriano пишет:

Если хочется правильно, нужно книжки читать, а не на форумах вопросы задавать.

Согласен. Но не всегда это выход. Я вот прошлой осенью много чего прочитал, сделал... а потом не до хобби было, забыл напрочь все... :(

andriano пишет:

А сообщение типа "посмотрите мой код, все ли там правильно?" я вообще считаю бестактным - по сути оно демонстрирует пренебрежение к времени форумчан: "мне недосуг разбираться, да и времени своего жалко, так что сделайте за меня".

Да, бросьте :) Что тут бестактного?))) Нашел же времени заглянуть в эту ветку, даже что-то написали, вот для этого времени не жалко?

Я разбираюсь, если Вы мои ветки смотрите, то должны видеть, что я особо ничего не выпрашиваю, и за меня делать никого не прошу, но признаюсь, что слаб в программировании, стараюсь, разбираюсь.... Но в жизни не так все просто. Взял и стал крутым программером на старости лет.... т.е. остальное все в жизни забросил:)

andriano, я давно на форуме.... больше читаю. И Вас, как форумчанина знаю, ...знаю ваш уровень.... Но зачем такое отвечать, "бестактность, пренебрежение"... Я с уважением отношусь ко всем... Ну раз вам сложно посмотреть верно ли я сделал, ну что я скажу.... Спасибо :)

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Короче, правильнее не LCD.printf изобретать, а переопределять stdout, чтоб в LCD выводил, оставляя всю внутреннюю кухню на откуп runtime библиотеке GCC

AsNik
Offline
Зарегистрирован: 24.10.2020

DetSimen пишет:

правильнее не LCD.printf изобретать

Я это-то ели осилил... и то, используя чужой код.

DetSimen пишет:

а переопределять stdout, чтоб в LCD выводил, оставляя всю внутреннюю кухню на откуп runtime библиотеке GCC

Согласен полностью, и буду так делать, но.... не в этой жизни наверное :(

Меня немного путает язык си, хотя нравится, много синтаксического сахара.... Очень сбивают с толку все эти производные от printf ну и подобные "клоны"... Толи дело было в Делфи, ...в семерке... Сейчас в этой Эмбаркадере конечно наверное тоже черт ногу сломит... Ну и конечно же зря я "забросил" это дело столько лет назад((

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Птваюмать.  Вот для сериала, переопределяешь рабочую лошадку, функцию putchar.

int  srl_putchar(int AOutChar, FILE *f) {
  return Serial.print(char(AOutChar));
}
 

а в setup перенаправляешь stdout на эту функцию. 

void setup() {
  Serial.begin(115200);
  stdout = fdevopen(srl_putchar, NULL);
}

 и используй для вывода в сериал простые конструкции типа

puts(), printf() и т.д, как в классическом Си.

 

если напишешь lcd_putchar(), то сможешь не в сериал выводить, а на LCD, только надо поднапрячься, сохранять позицию вывода. 

 

AsNik
Offline
Зарегистрирован: 24.10.2020

Вот не ругайси, дед... Я знаю, что тут много серьезных людей, которые с лёта поймут, что ты имел ввиду. Но я и так смотрел, и сяк... И тут http://microsin.net/programming/AVR/stdio-standard-io-facilities.html пытался читать.... Но честно, ничего не понял( Каюсь -тупой((

Реально для чего это:

Цитата:

переопределять stdout, чтоб в LCD выводил, оставляя всю внутреннюю кухню на откуп runtime библиотеке GCC

нужно? Без шуток. Просто хочу понять. Что это даст например в моем случае? Выигрыш по памяти, или, как я подозреваю, в универсальности и возможности форматированного вывода нtпосредственно lcd.print(). Тогда чем это будет лучше PrintLCDLine?

Я в си и МК вот только пока поверхностно могу, хотелось бы конечно, как в былые времена, но что-то вот уже не то...

Ссори за кучу вопросов, но они все к одному сводятся... Просто для чего это нужно и где бы посмотреть самый простой пример сказанного? Имеется ввиду пример, что бы понять для чего это нужно, а не как применять. Как применять частично в #173 и по ссылке видел...

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

AsNik пишет:
для чего это нужно

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

И не надо вызывать никакие методы никаких классов, можно  писать просто 

printf("Temperature = %d°С\n", Temp");

и выводится это будет конкретно на то устройство, куда ты до этого перенаправил вывод, всего лишь определив одну функцию.

По простому: нехрен лепить из говна и палок подобие того, что уже 50 лет как отлито в бронзе.  

rkit
Offline
Зарегистрирован: 23.11.2016

Подход с printf годится только для логов. Как только начинается расположение объектов на дисплее или еще какой фарш, то уже всё равно нужно писать самому.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

rkit пишет:

Подход с printf годится только для логов. 

Я бы сказал, для строк.  А позиционировать всё равно надо вручную, что с printf(), что без. 

AsNik
Offline
Зарегистрирован: 24.10.2020

Спасибо. Ну значит я верно предположил. Согласен, оно так может и правильнее... Но... Для меня это пока сложно. Во первых тут нужно разбираться в классах (стандартных) и их виртуальных методах. (override) Во вторых уровень знания языка должен быть выше чем мой...

Я сейчас пока сам си познаю (уже третий год :) зимой в основном, а за лето забываю:(), может быть знания делфи, которые тоже уже забыл отвлекают/сбивают.... потом попробую разобраться с классами.... Тут немного отличается эта кухня от делфёвой....

DetSimen пишет:

позиционировать всё равно надо вручную, что с printf(), что без. 

Т.е. выглядеть будет так:

lcd.setCursor();

printf();

Ну не знаю...

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

аццтал. 

AsNik
Offline
Зарегистрирован: 24.10.2020

:) Спасибо, в любом случае буду разбираться... Ну и раз все молчат по вопросу кода

const char Inf1_L1[] PROGMEM = "Sens: %s";
const char Inf1_L2[] PROGMEM = "T:%3d.%d\1C  H: %2d.%d %%";
const char Inf1_L3[] PROGMEM = "Humi(ABS): %2d.%-2d gm3";
const char Inf1_L4[] PROGMEM = "Pressure: %3d.%-2d  mm";
const char Inf2_L1[] PROGMEM = "View Sens %d-%d";
const char Inf2_L2[] PROGMEM = "Sens:  S%d   S%d   S%d ";
const char Inf2_L3[] PROGMEM = "Temp:  %2dC  %2dC  %2dC";
const char Inf2_L4[] PROGMEM = "Humi:  %2d%%  %2d%%  %2d%%";

const char * const Screen_Inf1[] PROGMEM = {Inf1_L1, Inf1_L2, Inf1_L3, Inf1_L4};
const char * const Screen_Inf2[] PROGMEM = {Inf2_L1, Inf2_L2, Inf2_L3, Inf2_L4};

....


const size_t PrintLCDLine(const byte aLine, const char * const aArr[], ...) {
  char szFormat[20];
  strcpy_P(szFormat, (char*)pgm_read_word(&(aArr[aLine])));
  va_list argptr;
  va_start(argptr, aArr);
  char * szBuffer = 0;
  const size_t nBufferLength = vsnprintf(szBuffer, 0, szFormat, argptr) + 1;
  if (nBufferLength == 1) return 0;
  szBuffer = (char *) malloc(nBufferLength);
  if (!szBuffer) return - nBufferLength;
  vsnprintf(szBuffer, nBufferLength, szFormat, argptr);
  lcd.setCursor(0, aLine); lcd.print(szBuffer);
  free(szBuffer);
  return nBufferLength - 1;
}

void loop() {
  lcd.clear();
  PrintLCDLine(0, Screen_Inf1, "NameS");
  PrintLCDLine(1, Screen_Inf1, 99, 5, 45, 7);
  PrintLCDLine(2, Screen_Inf1, 6, 44);
  PrintLCDLine(3, Screen_Inf1, 765, 4);
....
 

Буду считать, что ничего криминального я не допустил. А вопрос был с правильным (ли) использованием указателей (в параметрах функции PrintLCDLine ну и внутри ее) Ох уж эти const char * const... Зачем так все сложно)

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

DetSimen пишет:

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

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

Та форматная функция, которую напишу я, будет гарантированно быстрее работать и займет меньше места во flash. Вот с универсальностью - конечно, моя функция окажется гораздо менее универсальной. Ну а из универсальности вытекают трудозатраты: воспользоваться готовой, конечно, намного проще, чем писать свое. 

Так что, если нужно по-быстрому что-то слепить, то стандартные функции - в помощь. А если оказывается, что это по-быстрому слепленное либо не помещается в памяти, либо слишком медленно работает, либо еще что, то, потратив время на написание своего не стандартного, нередко возникшую проблему можно решить.

Цитата:

И не надо вызывать никакие методы никаких классов, можно  писать просто 

printf("Temperature = %d°С\n", Temp");

Я уже приводил пример: printf в полном объеме, как он реализован для 32-разрядной архитектуры, занимает 14к памяти. Что такое 14к в контроллере, где всего 64к, причем, для пользовательской программы отводится только 56к, а из этих 56к десять-пятнадцать уже заняты стандартной настройкой аппаратуры (в stm32 есть, что настраивать). А моя функция форматирования занимала лишь 300 байт, хотя, естественно, универсальностью там и не пахло.

Цитата:

По простому: нехрен лепить из говна и палок подобие того, что уже 50 лет как отлито в бронзе.  

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

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

ddr2
Offline
Зарегистрирован: 27.12.2020

AsNik пишет:
Меня немного путает язык си, хотя нравится, много синтаксического сахара.... Очень сбивают с толку все эти производные от printf ну и подобные "клоны"... Толи дело было в Делфи, ...в семерке... Сейчас в этой Эмбаркадере конечно наверное тоже черт ногу сломит... Ну и конечно же зря я "забросил" это дело столько лет назад((
Меня всегда пугал Паскаль, как вспомню и сейчас страшно становится)

Удалите <stdio.h> из скетча и получите примерно -2к hex'a. 

AsNik
Offline
Зарегистрирован: 24.10.2020

ddr2 пишет:

Меня всегда пугал Паскаль, как вспомню и сейчас страшно становится)

Удивительно... Там же куда все проще :)

А я вот сейчас сижу, ну всю голову сломал, зачем столько производных от printf (утрировано) Не, реально сейчас делаю функцию, которая возвращает строку. Внутри нужно строку отформатировать. И всё, встал в тупик... Уже и перечитал свою прошлогоднюю ветку, и дедовскую printf в Print, и ссылку от туда про секрет printf... все замечательно., но ...Нафига их столько придумали??? На каждый чих свой printf.... Вот:

Действия функций vprintf(), vfprintf(), vsprintf() и vsnprintf() эквивалентны действиям функций printf(), fprintf(), sprintf() и snprintf() соответственно, но список аргументов заменяется указателем на список аргументов. Этот указатель должен иметь тип va_list, который определен в заголовке <stdarg.h>.

т.е. для функций с переменным числом параметров нужно свой v*printf, причем опять же, эти vf*, vs*, vsn*...

Потом с буковкой хххх_P, без буковки ((( Я реально уже запутался в них.... 

Вот:

char * 	strcasestr_P (const char *, const char *) __ATTR_PURE__
 
size_t 	strcspn_P (const char *__s, const char *__reject) __ATTR_PURE__
 
size_t 	strlcat_P (char *, const char *, size_t)
 
size_t 	strlcpy_P (char *, const char *, size_t)
 
size_t 	strnlen_P (const char *, size_t)
 
int 	strncmp_P (const char *, const char *, size_t) __ATTR_PURE__
 
int 	strncasecmp_P (const char *, const char *, size_t) __ATTR_PURE__
 
char * 	strncat_P (char *, const char *, size_t)
 
char * 	strncpy_P (char *, const char *, size_t)
 
char * 	strpbrk_P (const char *__s, const char *__accept) __ATTR_PURE__
 
const char * 	strrchr_P (const char *, int __val)
 
char * 	strsep_P (char **__sp, const char *__delim)
 
size_t 	strspn_P (const char *__s, const char *__accept) __ATTR_PURE__
 
char * 	strstr_P (const char *, const char *) __ATTR_PURE__
 
char * 	strtok_P (char *__s, const char *__delim)
 
char * 	strtok_rP (char *__s, const char *__delim, char **__last)
 
size_t 	strlen_PF (uint_farptr_t src)
 
size_t 	strnlen_PF (uint_farptr_t src, size_t len)
 
void * 	memcpy_PF (void *dest, uint_farptr_t src, size_t len)
 
char * 	strcpy_PF (char *dest, uint_farptr_t src)
 
char * 	strncpy_PF (char *dest, uint_farptr_t src, size_t len)
 
char * 	strcat_PF (char *dest, uint_farptr_t src)
 
size_t 	strlcat_PF (char *dst, uint_farptr_t src, size_t siz)
 
char * 	strncat_PF (char *dest, uint_farptr_t src, size_t len)
 

кто это придумал? Вот прямо какой то Мкртчан их именовал. Может быть есть какая-то фишка, по которой можно сразу легко понять что и когда нужно использовать из этих сишных функций?

Толи дело в паскале. IntToStr(), StrToInt(), StrToIntDef()... Все понятно, все наглядно, интуитивно... а тут)

Не, сам язык си хорош, мне нравится, но почему тут зависимость регистров символов, нафика x и Х это разное? Ну и именование стандартных функций жесть...

sadman41
Offline
Зарегистрирован: 19.10.2016

Которые *_P - для PROGMEM, т.к. нужная функция не может быть однозначно выбрана автоматически компилятором.
То, что хранится в PROGMEM - const char* и то, что переносится в RAM - const char*. Поэтому программисту нужно помочь компилятору.

Вобщем, внутри МК своя история, которая может быть непонятна человеку, занимающемуся контроллерами эпизодически.

ddr2
Offline
Зарегистрирован: 27.12.2020

AsNik пишет:
ddr2 пишет:
Меня всегда пугал Паскалькак вспомню и сейчас страшно становится)
Удивительно... Там же куда все проще :)
Если там проще почему Вы не используете Паскаль для AVR?

хххх_P - это функции аналогичные <string.h>, но для программ-спейс. 

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

AsNik пишет:
, но почему тут зависимость регистров символов, нафика x и Х это разное?

Я давно не вмешивался, но тут уже просто перебор! Ты реально дебил? Большая и маленькая буквы одинаковы? в КаКоЙ ВСЕленНОй?

И про функции. Что там может быть непонятно? v - с аргументами в стиле макросов varg,  s -  вывод в строку, f  - в файл,  в имени есть n -  контроль длины строки.

AsNik
Offline
Зарегистрирован: 24.10.2020

wdrakula пишет:

Ты реально дебил?

Ну зачем так грубо? Я тебе не грубил

wdrakula пишет:

Большая и маленькая буквы одинаковы? в КаКоЙ ВСЕленНОй?

Вообще-то я говорил про паскаль. Там пиши хоть inttostr() Хоть INTTOSTR() Хоть еще как и это будут эквивалентно. Более того, если писать IntToStr() - то очень наглядно и понятно.

Цитата:

И про функции. Что там может быть непонятно? v - с аргументами в стиле макросов varg,  s -  вывод в строку, f  - в файл,  в имени есть n -  контроль длины строки.

А вот за это, Вам, реально спасибо! Вот прямо от души... Но плюсовать не буду)

ddr2 пишет:

Если там проще почему Вы не используете Паскаль для AVR?

Отдельная история, да и хотел все-таки изучить си. Говорю же он мне нравится, но ...но иногда бесит)

b707
Offline
Зарегистрирован: 26.05.2017

AsNik пишет:

Более того, если писать IntToStr() - то очень наглядно и понятно.

что мешает называть так функции в Си?

AsNik
Offline
Зарегистрирован: 24.10.2020

b707 пишет:

AsNik пишет:

Более того, если писать IntToStr() - то очень наглядно и понятно.

что мешает называть так функции в Си?

:) Ну разговор немного не об этом) Никто не мешает... Но уже названные не напишешь так, как тебе удобно)

Вот реально не понимаю для чего разделили регистр букв.... Букв мало... или имена больше "трех" символов нельзя делать...

Я немного уже привыкаю к этому, да и сегодня для меня был большой прорыв в понимании названий стандартных функций. Спасибо доброму wdrakula ;)

vk007
Offline
Зарегистрирован: 16.06.2015

AsNik пишет:
Вот реально не понимаю для чего разделили регистр букв....

Да ладно...

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

А почему в паскале, бейсике и т.д. строчные и прописные буквы равнозначные, то это скорее всего дань традиции 5-битной кодировке (там не было строчных). Ну а Ритчи с этим уже не парился - раз разные коды, значит это разные символы и на этом точка.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

И можно наплодить 52 однобуквенных переменных

vk007
Offline
Зарегистрирован: 16.06.2015

А учитывая области видимости, то и 52 точно не предел :)

AsNik
Offline
Зарегистрирован: 24.10.2020

Глупости все это.... Кому нужны эти 52 однобуквенных переменных? Знаю, что есть люди с офигительной памятью, но практически уверен, что никто даже на этом форуме так не сможет))

Я знаю почему они в принципе различаются, да по коду - это и понятно. Но кроме этого есть какая-то веская причина чтобы не сделать так, как например в паскале... Именно веская, ибо уверен, что иноооогда все же может и есть смысл в разнице в имени переменной: n и N

Про историю, книги, начало предложений вообще не убедительно ) Слово - написанное буквами разного регистра, смысл все равно не потеряет...

(в никах даже видно - кому важен регистр, а кому нет) ;)

Ну да ладно, от нашего спора все равно ничего не изменится :)

Вопрос по теме. В целях оптимизации кода с выгодой уменьшения объема(размер в байтах) кода на Flash и в ОЗУ.

Есть такая snprintf - но она вроде как ресурсоемкая. Но ей можно сделать форматирование строки в одну строчку кода.

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

Ну например вот такая строка snprintf_P(aTxt, aLength + 1, PSTR("%3d.%d\1C"), t1, t2);

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

sadman41
Offline
Зарегистрирован: 19.10.2016

Однозначного ответа нет. До определенного момента *printf* проигрывает по флешу гирляндам принтов, но затем за счёт реентерабельности. Момент этот находится исключительно экспериментально.

Но если есть запас ресурса, то *printf* позволяет сразу получить более красивый и понятный код.

AsNik
Offline
Зарегистрирован: 24.10.2020

sadman41 пишет:

*printf* позволяет сразу получить более красивый и понятный код.

Согласен. И с ним даже как-то проще решить вопрос про вставку символов в начало имеющейся char*

Значит оставлю пока ее *printf* а там война план покажет

ddr2
Offline
Зарегистрирован: 27.12.2020

использование pgm_read_* на 6% снижает производительность программы. Но без pgm никуда. 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

ddr2 пишет:

использование pgm_read_* на 6% снижает производительность программы. 

Ты случайно не в НИИ статистики работаешь? 

ddr2
Offline
Зарегистрирован: 27.12.2020

DetSimen пишет:
ddr2 пишет:
использование pgm_read_* на 6% снижает производительность программы. 
Ты случайно не в НИИ статистики работаешь? 
Увы нет.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

ddr2 пишет:

использование pgm_read_* на 6% снижает производительность программы. Но без pgm никуда. 

Можно ознакомиться с текстом программы, производительность которой страдает от использования pgm_read_*?

ddr2
Offline
Зарегистрирован: 27.12.2020


Заменил обращение к памяти на чтение из PGM. (-6% производительности) 

//buf[x] = FONT[i]; 
buf[x] = pgm_read_byte(&FONT[i]);