Как оптимизировать использование функций?

Обсуждаем контроллеры компании Atmel.
Ответить
Это не хвост, это антенна
Сообщения: 1480
Зарегистрирован: Ср июн 25, 2008 15:19:44

Сообщение Demiurg »

2 Dimon456. Сразу определимся. Цель? Потому что я тебя ловил на том, что я выкладывал свои примеры, и ты нелицеприятно отзывался. Тема топика оптимизация. И я следую этой теме.
Как бы мне параллельно, что ты скажешь. Это дело целесообразности, какую реализацию делать.
Контактная информация:
Реклама
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

Demiurg, а ты начни примерно вот с этого

Код: Выделить всё

int m_sprintf(char *out, const char *format, ...)
{
	int *varg = (int *)(&format);
	return m_print(&out, varg);
}
Реклама
Это не хвост, это антенна
Сообщения: 1480
Зарегистрирован: Ср июн 25, 2008 15:19:44

Сообщение Demiurg »

:) я никогда не пользовался библиотечным print. Ты этого ответа ждал? Да, не пользовался. Потому что они жрут ресурсы МК. Один раз попробовал, мне не понравился выхлоп. На этом мои эксперименты закончились. И так как я программирую только AVR, дальше что? :)
Контактная информация:
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

Demiurg писал(а):Ты этого ответа ждал?
Нет, не этого ответа ждал.
Там же предлагали tiny_printf, ну что-то вроде этого, урезать отрезать до какого то формата, что бы не дербанить строку

Код: Выделить всё

dsprintf(string, "%02i/%02i/20%02i", day, month, year);
на составляющие, а то мало ли каких строк будет.
Если ваш код в байт 500 выйдет, то ...
Реклама
Эиком - электронные компоненты и радиодетали
Это не хвост, это антенна
Сообщения: 1480
Зарегистрирован: Ср июн 25, 2008 15:19:44

Сообщение Demiurg »

Вообще с часами я мало работал. Не нужно было. Я проекты делал практически всегда на продажу. Для себя мало что делал. Потому с часами так и получилось. Глянул один свой проект с часами. Хм, дело было так. Так как с часами практически не работал, часть с часами писал, чтобы заработало. Не оптимизировал. Нужно посидеть, урезать проект, оставить только часы. Жди. Несколько дней. Сильно занят.

Добавлено after 2 minutes 9 seconds:
Даю что есть, как есть.

bcd.h:
Спойлер

Код: Выделить всё

#ifndef BCD_H
#define BCD_H

#include "bcd.h"

#include "main_def_func.h"

//==================
extern char num_str_buf [];
extern char tmp_num_str_buf [];
//==================

//==================
typedef enum
{
   VAL_08_BIT = 0,
   VAL_16_BIT,
   VAL_32_BIT,
} type_val_t;

void val_to_str (u32 value, type_val_t type_val);

u16 str_to_int (void);
u32 str_to_long (void);
//==================

//==================
void clr_tmp_num_str_buf (void);
void clr_num_str_buf (void);
//==================

#endif //BCD_H
bcd.c:
Спойлер

Код: Выделить всё

//==================
#include "bcd.h"
//==================

//==================
char num_str_buf [11];
char tmp_num_str_buf [11];
//==================

//==================
void clr_tmp_num_str_buf (void)
{
   char *ptr = tmp_num_str_buf;
   u08 cnt = 10;

   while (cnt)
   {
      *ptr++ = ' ';
      cnt--;
   }
   *ptr = 0;
}
//==================

//==================
void clr_num_str_buf (void)
{
   char *ptr = num_str_buf;
   u08 cnt = 10;

   while (cnt)
   {
      *ptr++ = ' ';
      cnt--;
   }
   *ptr = 0;
}
//==================

//==================
u32 __flash tab_hex_dec [] =
{
   1000000000U,
   100000000U,
   10000000U,
   1000000U,
   100000U,
   10000U,
   1000U,
   100U,
   10U,
};
//==================

//==================
void val_to_str (u32 value, type_val_t type_val)
{
   u32 a;

   bool flag = false;

   u08 cnt_1;
   u08 cnt_2;

   u08 displace;

   clr_num_str_buf ();

   switch (type_val)
   {
      case VAL_08_BIT:
         displace = 7;
         cnt_1 = 2;
         break;

      case VAL_16_BIT:
         displace = 5;
         cnt_1 = 4;
         break;

      case VAL_32_BIT:
         displace = 0;
         cnt_1 = 9;
         break;
   }

   char *ptr = num_str_buf + displace;

   u32 __flash *ptr_f = tab_hex_dec + displace;

   while (cnt_1)
   {
      a = *ptr_f;
      cnt_2 = 0;

      while (value >= a)
      {
         value -= a;
         cnt_2++;
      }

      if (flag == false)
      {
         if (cnt_2 == 0)
         {
            *ptr++ = ' '; // Гашение незначащих нулей.
         }
         else
         {
            *ptr++ = (cnt_2 | 0x30);
            flag = true;
         }
      }
      else
      {
         *ptr++ = (cnt_2 | 0x30);
      }

      ptr_f++;
      cnt_1--;
   }
   *ptr++ = (value | 0x30);
   *ptr = 0;
}
//==================



//==================
u16 str_to_int (void)
{
   char *ptr_num = tmp_num_str_buf + 5;
   u32 __flash *ptr_f = tab_hex_dec + 5;
   u16 a;
   u08 cnt = 0;
   u16 tmp_value = 0;

   while (cnt < 4)
   {
      if ((*ptr_num > 0x30) && (*ptr_num < 0x3A))
      {
         a = (*ptr_num - 0x30);

         while (a)
         {
            tmp_value += *ptr_f;
            a--;
         }
      }
      *ptr_num++;
      ptr_f++;
      cnt++;
   }
      return tmp_value += (*ptr_num - 0x30);
}
//==================

//==================
u32 str_to_long (void)
{
   char *ptr_num = tmp_num_str_buf;
   u32 __flash *ptr_tab_10 = tab_hex_dec;
   u32 a;
   u08 cnt = 0;
   u32 tmp_value = 0;

   while (cnt < 9)
   {
      if ((*ptr_num > 0x30) && (*ptr_num < 0x3A))
      {
         a = (*ptr_num - 0x30);

         while (a)
         {
            tmp_value += *ptr_tab_10;
            a--;
         }
      }
      *ptr_num++;
      ptr_tab_10++;
      cnt++;
   }
      return tmp_value += (*ptr_num - 0x30);
}
//==================
Пока это даю.
Контактная информация:
Реклама
Опытный кот
Аватара пользователя
Сообщения: 760
Зарегистрирован: Сб окт 22, 2016 17:33:32
Откуда: кг

Сообщение Карбофос »

Demiurg писал(а):Пока это даю.
Вполне ожидаемо.
Реклама
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 362
Зарегистрирован: Вс апр 03, 2022 07:01:29

Сообщение НовыйДень »

Ну, для часов то printf как бы и не нужен :) Три-пять чисел можно и "вручную" вывести. Разложить число на разряды можно либо самописно, либо через библиотечную ф-цию itoa()
Друг Кота
Аватара пользователя
Сообщения: 7077
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

Сообщение Ivanoff-iv »

По оптимизации: надо было быстро простенький проект составить (чтение из ацп, небольшая обработка измерения и реакция на него. и так 2 абсолютно одинаковых независимых процесса, каждый берёт со своего входа и выводит в свой вывод) логично написать функцию, но т.к. при обработке использьвались накопительные буфера - понадобилось использовать указатели, чтоб каждая задача работала со своим буфером... чтото у меня не пошло = компилятор выдал ошибку, разбираться было некогда, да и место позволяло... запихнул тело функции в дефайн и вызвал его 2 раза, для каждого процесса по разу...
Потом, когда позволило время, решил разобраться и написать как хотел (причиной ошибки оказалось отсутствие скобок) обнаружил, что прошивка с дефайнами оказалась короче, чем с функциями... :shock:
П.С.: среда кодевижен, оптимизация по размеру.
думаю, что в варианте с дефайнами компилятор понял, что код повторяется и сам оптимально вынес его в функцию.
Это не хвост, это антенна
Сообщения: 1480
Зарегистрирован: Ср июн 25, 2008 15:19:44

Сообщение Demiurg »

У меня в том проекте было сделано так: даты были не нужны, только время. При включении устройства считывается rtc. Дальше я опрашивал секундный вывод rtc. Чтобы не возиться, я сделал так: значения часов минут и секунд было в hex. Отсюда преобразование. Деталей, если честно не помню. Может быть, позже сяду, проанализирую. Но print точно не буду использовать.
Время print наступит позднее. Когда будут более жирные проекты и МК. А может уже и не наступит, учитывая текущие политические обстоятельства.
Я уже два или три года не занимаюсь проектами на МК.
Контактная информация:
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

Хорошо, тогда нужен оптимальный код разложения на составляющие.
И так

Код: Выделить всё

dsprintf(string, "%2i/%02i/20%02i", day, month, year);	
формируем строку

Код: Выделить всё

if (day < 10) {
  string[0] = 0x20;
  itoa(day, &string[1], 10);
} else itoa(day, &string[0], 10);
             
string[2] = '/';
             
if (month < 10) {
  string[3] = '0';
  itoa(month, &string[4], 10);
} else itoa(month, &string[3], 10);

string[5] = '/';
string[6] = '2';
string[7] = '0';

if (year < 10) {
  string[8] = '0';
  itoa(year, &string[9], 10);
} else itoa(year, &string[8], 10);
Какие будут ваши предложения?
Это не хвост, это антенна
Сообщения: 1480
Зарегистрирован: Ср июн 25, 2008 15:19:44

Сообщение Demiurg »

Что то кучеряво как то в твоём примере... Это как бы не критика, пока. Я уже очень давно не садился за проекты. Попробую вечерами посидеть, вспомнить что да как.
Контактная информация:
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 1925
Зарегистрирован: Чт июл 28, 2016 07:58:37
Откуда: Kyiv, UA

Сообщение GoldenAndy »

ну я б и itoa убрал.
вместо неё - преобразование байта в 2 символа.

Код: Выделить всё

void byte2charArr(char* arr, uint8_t value, uint8_t leadingSpace){
uint8_t val_10 = value / 10;
if (val_10) arr[0] = '0'+val_10;
else arr[0] = leadingSpace ? ' ' : '0';
arr[1] = value - val_10*10 + '0';
Функция преобразует число в диапазоне 0..99 в 2 символа в строке. leadingSpace - выбор - впереди пробел или ноль для чисел меньше 10.

И да, если вычисление остатка нигде больше не используется - value % 10 даст большой оврхед, поэтому остаток считаем как указано выше. На мегах с аппаратным умножителем даёт экономию кода.
ИзображениеИзображение
Изображение
 
Telegram               Лучшая благодарность ->
[+]
Контактная информация:
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

GoldenAndy писал(а):ну я б и itoa убрал.
Это пока не важно, важно имели одну строку, а получили кучу, и что бы отредактировать что-либо придется чуть ли не все исправлять.
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 1925
Зарегистрирован: Чт июл 28, 2016 07:58:37
Откуда: Kyiv, UA

Сообщение GoldenAndy »

Dimon456, ну тут вопрос - шашечки или ехать.
Вынести весь вывод на дисплей в отдельный файл - а там всё рядышком.
Редактировать же, насколько я понял - уже нечего. Надо затолкать 9.5 кб кода в 8 кб МК. тут уже все средства хороши.
И жертвовать придется и красотой кода.

(я вот сейчас глянул в папку с проектами и понял, что в своих поделиях на МК я ни разу не пользовался библиотечным форматным выводом. Только ручками, только хардкор. И форматный вывод тоже ручками. И свой вариант itoa, заточенный на размерности данных в каждом случае)
ИзображениеИзображение
Изображение
 
Telegram               Лучшая благодарность ->
[+]
Контактная информация:
Друг Кота
Аватара пользователя
Сообщения: 6321
Зарегистрирован: Вт апр 24, 2007 07:45:40
Откуда: Minsk

Сообщение Jack_A »

[uquote="Dimon456",url="/forum/viewtopic.php?p=4212814#p4212814"]важно имели одну строку, а получили кучу[/uquote]
Ну если это так принципиально - сколько строк исходника... Редактировать ничего не надо: отлаженная и оттестированная процедура будет "вечной" . А вот если в результате вместо нескольких байт применение itoa даст "кучу кода" - это, по-моему, существенней.
Изображение
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

Jack_A писал(а):itoa даст
да это не важно, можете свой написать.
Пример

Код: Выделить всё

sprintf (string_out,"U=%2d.%02dV", x_u_izm/100, (x_u_izm)%100);
sprintf (string_out,"I=%1d.%02dA", x_i_izm/100, (x_i_izm)%100);
поставьте мне запятую, пожалуйста.
Код в студию. Только не тяните кое кого за хвост, хотел бы видеть оригинальное разложение этой строки.
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 362
Зарегистрирован: Вс апр 03, 2022 07:01:29

Сообщение НовыйДень »

Ребят, вы чего, часы никогда не делали, штоль? Ну либо на Сях комбинации /10 и %10, либо на асме процедура bin-to-BCD с поразрядным распаковыванием, коль уж не нравится библиотечные itoa.
А когда sprintf используете, просто закидываете в параметры переменные часов, минут, секунд, даты, месяца, года, как они есть, а перед ними пишите форматирующую строку. Названия дней недели или месяц текстом можно вывести отдельно через табличку (массив текстовых строк), когда номер дня недели или месяца является индексом в табличке, а в массиве строк прописаны текстом названия).
Это не хвост, это антенна
Сообщения: 1480
Зарегистрирован: Ср июн 25, 2008 15:19:44

Сообщение Demiurg »

Давайте все посмотрим на задачу с точки зрения целесообразности. Конечно, и тут могут быть варианты, типа, что мы понимаем под целесообразностью.

Начнем с того, что мы имеем на руках МК AVR. Опять же. Какой, точнее, что у него на борту. Либо у нас на руках, скажем ATMEGA8. Это один разговор. Если от, скажем, ATMEGA32 и выше. Это уже другой разговор.

Если у нас на руках МК типа ATMEGA128 или 256. Тут уже целесообразнее писать "красиво". И можно уже вовсю использовать библиотеки. Здесь работает скорость написания проекта. Пусть неоптимально по выхлопу, но быстрее "писать".

Если же у нас поджимает объем SRAM либо FLASH, тут уже начинается оптимизация. И отказ от библиотек. И утаптывание кода по выхлопу. Красивость кода тут не работает. От слова совсем.

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

Тут просили пример кода. Здесь нужно смотреть "сверху". Хотим оптимально? Забудем о красивости кода. И начнем дербанить "красивые", в одну строку, куски кода.

К примеру. Нам нужно вывести время. Пусть формат типа: 12:03:43 03/07/2022.

Делаем во Flash строку-шаблон. Пробел, пробел, двоеточие, пробел, пробел, двоеточие, пробел, пробел, пробел, пробел, пробел, слеш, пробел, пробел, слеш, пробел, пробел. Что мы этим получили. Вывели шаблон. Быстро. Потом выводим время и дату в соответствии со знакоместами. Быстро. Кратко. Это простой пример. Да, некрасиво, не "в одну строку". Но оптимально. И по скорости и по выхлопу.
Последний раз редактировалось Demiurg Пн апр 11, 2022 18:31:29, всего редактировалось 1 раз.
Контактная информация:
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 362
Зарегистрирован: Вс апр 03, 2022 07:01:29

Сообщение НовыйДень »

Эммм... я тут чето потерял нить темы. Если не ошибасю, вначале у топикстартера была проблема с тем, что нужна была единая функция ввода чисел, так? Так вот, это реализуется одной единственной функцией, в которую передается указатель на изменяемую переменную, а кнопки просто инкрементируют или декрементируют эту переменную по указателю. Назначения функций кнопок выбираются через таблицу указателей на функции в соответствии с текущим режимом менюшки.
Это не хвост, это антенна
Сообщения: 1480
Зарегистрирован: Ср июн 25, 2008 15:19:44

Сообщение Demiurg »

Я в топике привел пример. В том примере у меня секунды, минуты, часы и так далее это отдельные участки памяти в соответствии с размерностью. То есть, до годов это байты. Год это уже два байта. При включении устройства считывается rtc и данные распаковывается по участкам памяти. Дальше я работаю с ними как с обычными шестнадцатеричными числами. Вот годы посложнее. Заманаешься инкремент и декремент производить. :))) Тут уже поразрядно. Опять же. Можно и все поразрядно. Но, все равно перевод в шестнадцатеричные числа.
У меня сейчас график жёсткий. Попробую в ближайшие дни урезать проект, оставить только часы и выложить свой пример.
Контактная информация:
Ответить

Вернуться в «AVR»