Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Ответить

Re: Вопросы по С/С++ (СИ)

Пн июл 22, 2019 10:10:31

ltoa(variable, rezult, 10);
ну если б я знал про это, а знал я только про itoa, то воще вопросов не было бы :roll:

Re: Вопросы по С/С++ (СИ)

Пн июл 22, 2019 10:13:49

ROMan2947 писал(а):если б я знал про это
надо знать инструментарий, с которым работаешь, без этого никак

интересно другое: как вы, не зная "этого" умудрялись ВЫВОДИТЬ такое число на дисплей? можете показать код?

Re: Вопросы по С/С++ (СИ)

Пн июл 22, 2019 10:14:04

ну если б я знал про это, а знал я только про itoa, то воще вопросов не было бы :roll:

Это же аббревиатура :) Int To Ascii :)

Соответственно, ltoa - long to ascii :)

Re: Вопросы по С/С++ (СИ)

Пн июл 22, 2019 10:17:49

если русурсов достаточно (флеша хотя бы 4К).
на эти случаю, решил работать с 64 и 128, так писать оптимально мне ещё далеко,так камешки должны вместить в себя всю лабуду, которую я готовлю для них :hunger:

Добавлено after 2 minutes 16 seconds:
[
интересно другое: как вы, не зная "этого" умудрялись ВЫВОДИТЬ такое число на дисплей? можете показать код?

вечером, после работы выложу

Re: Вопросы по С/С++ (СИ)

Пн июл 22, 2019 10:20:34

Заодно, если не сложно, покажите как сделали редактирование разрядов другим способом.
Хочется посмотреть на это извращение :)

Re: Вопросы по С/С++ (СИ)

Пн июл 22, 2019 11:56:27

Заодно, если не сложно, покажите как сделали редактирование разрядов другим способом.
Хочется посмотреть на это извращение :)

AVR давно не занимаюсь, но не поленился, создал проект для tiny13 и написал две функции, хотя проверить в работе на AVR не могу, только сравнить размер :) Сначала с массивом:
Код:
char result[16];

uint32_t replaceDigit(uint32_t value, uint8_t idx, uint8_t upDown)
{
   ltoa(value, result, 10);
   uint8_t digit = result[idx];
   if (upDown == 1 && digit < '9')  digit++;
   if (upDown == 0 && digit > '0')  digit--;
   return atol(result);
}

    volatile uint32_t val_ = 87'654'321;
    uint32_t val = val_;
    val_ = replaceDigit(val, 2, 1);

Теперь без массива:
Код:
uint32_t replaceDigit(uint32_t value, uint8_t idx, uint8_t upDown)
{
   static const uint32_t tbl[] = { 1, 10, 100, 1000, 10'000, 100'000, 1'000'000, 10'000'000 };
   uint32_t pval = tbl[idx];
   uint8_t digit = value / pval % 10;
   if (upDown == 1 && digit < 9)  value += pval;
   if (upDown == 0 && digit > 0)  value -= pval;
   return value;
}

Компилируем оба варианта на gcc с -Os, во втором случае размер меньше на 142 байта, при этом очевидно вторая функция и быстрее. Правда она возвращает только число, строки нет, собственно строка может и не понадобиться или какой-нибудь printf задействует свое преобразование, не вызывая atol, но даже дополнительно добавив atol все равно размер будет чуть меньше. Но это не все, второй подход позволяет очень просто добавлять ограничения, например, можно передавать максимум, внутри изменится лишь одна строка:
Код:
if (upDown == 1 && digit < 9 && value + pval <= maxValue)  value += pval;
.....

     val = replaceDigit(val, 2, 1, 87'657'654);

Все, 4 младших разряда можно увеличивать, 4 старших уже нельзя.

Re: Вопросы по С/С++ (СИ)

Пн июл 22, 2019 12:24:41

это может и не проще, но правильнее по логике. а для float ваш алгоритм тоже подойдет? мой - да.

"Мой", "ваш" - в чём разница? И там и там - выделение цифр с помощью операций деления/умножения. Только в "вашем" - все цифры выделяются (и ненужные тоже), в "моём" - только нужная.
"Правильнее по-логике" - это делать ненужную работу что-ль? :dont_know:

Re: Вопросы по С/С++ (СИ)

Пн июл 22, 2019 12:25:56

Кстати, во всём это есть один интересный момент. Если некий разряд (при, допустим, вращении энкодера), переходит из 9 в 0, нужно ли при этом разряд слева тоже увеличивать? Если нужно, то все эти свистопляски с строковым представлением сильно всё усложняют.

Имхо, лучше инкрементировать само число. Это, как правило, проще, и нужно чаще, чем показ пользователю. Например, данные приходят от какого-то датчика очень часто, а вывод на экран - на порядок реже. Гораздо проще и быстрее работать с одной сущностью - числом, а уже все преобразования в строку для показа пользователем делать только когда это нужно, т.е. при выводе.
Последний раз редактировалось WiseLord Пн июл 22, 2019 12:28:23, всего редактировалось 1 раз.

Re: Вопросы по С/С++ (СИ)

Пн июл 22, 2019 12:31:18

Я бы редактировал и параллельно отображал строку, а в реальное значение пересчитывал только когда надо это значение применить или проверить на диапазон.

В исходном вопросе автора вообще не было слов про отображение.
А также ничего не было про float или про дни недели (которые тут уже подтягиваются).

Добавлено after 3 minutes 55 seconds:
jcxz писал(а):Ну да - автору нужно изменить всего одну цифру, .... бла-бла-бла ...
Где одну то ? Ему нужно изменить число, состоящее из нескольких цифр !
Делать itoa (или ему подобное) для вывода на дисплей, а потом по индексу вычислять разряд, изменяя число на 1/10/100/1000/... - это проще ? Шутишь ? :facepalm:

Может стоит всё-таки прочитать исходное сообщение автора, а не фантазировать?
есть переменная типа UL. в ней хранится число,которое является показанием счетчика воды. максимальное число которое мне нужно это от 0 до 99999999 л. мне необходимо редактировать это число поразрядно,для задания данных ручками.

Прочитайте и подумайте на смыслом фразы "необходимо редактировать это число поразрядно".
И где Вы тут увидели про вывод ещё и на дисплей?? :shock:

Re: Вопросы по С/С++ (СИ)

Пн июл 22, 2019 13:54:04

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

Re: Вопросы по С/С++ (СИ)

Пн июл 22, 2019 16:53:11

ARV, с языка снял.

Re: Вопросы по С/С++ (СИ)

Пн июл 22, 2019 17:14:30

Reflector, Вы привели варианты разового изменения одно из разрядов числа. Ежу понятно, что если человеку где-то в программе нужно сделать только это, то второй вариант более оптимален во всём.
Но задача немного другая - редактировать одно большое число поразрядно. В этом случае, постоянно делать туда-сюда преобразование - глупо. Один раз сделал, отредактировал весь массив, а потом обратно.

jcxz писал(а):Может стоит всё-таки прочитать исходное сообщение автора, а не фантазировать?
Примените этот вопрос к себе. И внимательно почитайте задачу.
Фантазируете пока Вы здесь только один.

Re: Вопросы по С/С++ (СИ)

Пн июл 22, 2019 21:01:22

Заодно, если не сложно, покажите как сделали редактирование разрядов другим способом.
Хочется посмотреть на это извращение :)
основная функция setup_TEKpokazania() вызывается из пункта меню
Спойлер
Код:

static uint32_t const tPow10[] = {
   10000000ul,
   1000000ul,
   100000ul,
   10000ul,
   1000ul,
   100ul,
   10ul,
};

void write_TEKdata_setup_eeprom(char type_counter)
{
   TEK_data=0;
   for(uint8_t it=0;it<7;it++)
   {
      TEK_data+=masiv_razryadov[it]*tPow10[it]; // собираем число из разрядов
   }

   if (type_counter=='G')       eeprom_write_block(&TEK_data,&TEK_pokazania_GWS,4);
   else if (type_counter=='H')  eeprom_write_block(&TEK_data,&TEK_pokazania_HWS,4);

}

void read_TEKdata_setup_eeprom(char type_counter)
{
   TEK_data=0;
   if (type_counter=='G')       eeprom_read_block(&TEK_data,&TEK_pokazania_GWS,4);
   else if (type_counter=='H')  eeprom_read_block(&TEK_data,&TEK_pokazania_HWS,4);



   uint8_t it=0;
   unsigned long tek_TEMP=TEK_data;

   for(it=0;it<7;it++)
   {
      masiv_razryadov[it]=tek_TEMP/tPow10[it];  //разбиваем число на разряды
      tek_TEMP%=tPow10[it];

   }
}

static uint8_t flag =0;
void steep_function_TEK (uint8_t i)
{
   write_command(0x80|(cursor_address));
   char massiv1[7]={0};
   sprintf(massiv1,"%d",setup_buffer[i]);
   print_LCD(massiv1);
   write_command(0x80|cursor_address);
}

int setup_TEKpokazania(char type_counter)
{
   
   char GWSstring[13]={"GWS: counter"};  // шапка
   char HWSstring[13]={"HWS: counter"};  // шапка
   


   if(!flag)
   {
      read_TEKdata_setup_eeprom(type_counter);

      cursor_address=0x44;
      memcpy(setup_buffer,masiv_razryadov,7);
      write_command(clear_display); // очищаем дисплей
      write_command(0x80|0x02);
      if(type_counter=='G') print_LCD(GWSstring);    // печатаем шапку
      if(type_counter=='H') print_LCD(HWSstring);
      
      write_command(0x80|cursor_address);
      char massiv1[15]={0};
      sprintf(massiv1,"%d%d%d%d%d%d%d%c",setup_buffer[0],setup_buffer[1],setup_buffer[2],setup_buffer[3],setup_buffer[4],setup_buffer[5],setup_buffer[6],'l');
      print_LCD(massiv1);                 // пишем данные
      cursor_address=0x44;                // адресс курсора на позиция для мигания
      write_command(0x80|cursor_address); // устанвливаем курсор
      flag=1;
      write_command(0x0f);           // включаем курсор мигающий

      return 0;
   }

   write_command(0x0f); // включаем курсор мигающий
   static uint8_t steep_TEK = 1;

   switch(KeyCode)
   {
      cursor_address=0x44;
      case Enter:
      if(steep_TEK<0x07)
      {
         if(steep_TEK<0x07)
         {
            write_command(0x80|(cursor_address+=0x01));
         }
         
         i++;
         steep_TEK++;
      }
      else
      {
         memcpy(masiv_razryadov,setup_buffer,8);
         write_TEKdata_setup_eeprom(type_counter);
         i=0;
         steep_TEK = 1;
         write_command(clear_display); // очищаем дисплей
         write_command(0x80|0x02); //
         write_command(0xC);
         char massiv[15]={"SET count OK"};
         print_LCD(massiv);
         _delay_ms(2000);
         flag=0; Level=3; PtrPunkt=Ptr_config_function->Ptr5; (*PtrPunkt)();cursor_address=0x42; break;
      }
      break;

      case UP:  if ((setup_buffer[i]++)<9)  {steep_function_TEK(i); break;}
      if ((setup_buffer[i]++)>9)  {setup_buffer[i]=0; steep_function_TEK(i); break;}

      break;
      
      case DN: if ((setup_buffer[i]--)>0)  {steep_function_TEK(i); break;}
      if ((setup_buffer[i]--)>9)  {setup_buffer[i]=9; steep_function_TEK(i); break;}
      break;

      case Cancel: flag=0; Level=3; write_command(0xC);PtrPunkt=Ptr_config_function->Ptr5; steep_TEK = 1; cursor_address=0x42; (*PtrPunkt)();break;
   }
   return 0;
}

Re: Вопросы по С/С++ (СИ)

Вт июл 23, 2019 02:04:02

Ну, всё нормально :)
Сильно не вчитывался, но судя по всему, работаете с массивом при редактировании. Что и хотелось до Вас донести.

Единственное, что резануло глаз :
Код:
      char massiv1[15]={0};
      sprintf(massiv1,"%d%d%d%d%d%d%d%c",setup_buffer[0],setup_buffer[1],setup_buffer[2],setup_buffer[3],setup_buffer[4],setup_buffer[5],setup_buffer[6],'l');

Тут можно и без sprintf обойтись.
Подсказка: ascii код цифры = цифра + '0' :)

Re: Вопросы по С/С++ (СИ)

Вт июл 23, 2019 09:16:19

Но задача немного другая - редактировать одно большое число поразрядно. В этом случае, постоянно делать туда-сюда преобразование - глупо. Один раз сделал, отредактировал весь массив, а потом обратно.

Я когда писал свои функции преобразования, то сравнивал скорость с sprintf, правда на STM32, и мой вариант был быстрее в 8.5 раз, а тут 7 разрядов числа против одного, т.е. преобразование числа целиком, которое делается один раз, может быть в 60 раз медленнее извлечения одного разряда, которое делается при каждом изменении :) И не обязательно преобразовывать туда-сюда, можно сделать и так:
Код:
uint8_t replaceDigit(uint32_t& value, uint8_t idx, uint8_t upDown)
{
   static const uint32_t tbl[] = { 1, 10, 100, 1000, 10'000, 100'000, 1'000'000, 10'000'000 };
   uint32_t pval = tbl[idx];
   uint8_t digit = value / pval % 10;
   if (upDown == 1 && digit < 9)  value += pval, digit++;
   if (upDown == 0 && digit > 0)  value -= pval, digit--;
   return digit;
}

Теперь функция возвращает цифру которая и будет выводиться на дисплей, без никаких обратных преобразований. При этом не будет глобального массива и не будет этого:
Код:
   TEK_data=0;
   for(uint8_t it=0;it<7;it++)
   {
      TEK_data+=masiv_razryadov[it]*tPow10[it]; // собираем число из разрядов
   }

   uint8_t it=0;
   unsigned long tek_TEMP=TEK_data;

   for(it=0;it<7;it++)
   {
      masiv_razryadov[it]=tek_TEMP/tPow10[it];  //разбиваем число на разряды
      tek_TEMP%=tPow10[it];

   }

Re: Вопросы по С/С++ (СИ)

Вт июл 23, 2019 10:54:20

Теперь функция возвращает цифру которая и будет выводиться на дисплей, без никаких обратных преобразований. При этом не будет глобального массива и не будет этого:

...А если, к примеру, даже нужно и визуализировать процесс редактирования на графическом LCD, то во многих LCD (например на ILI9341 подключенном по SPI) имеющих встроенную видео-ОЗУ, можно отправлять в LCD только изменяемый прямоугольный регион пикселов. Что будет намного быстрее и экономнее по ресурсам. И совсем не нужно всё число переводить в строку.
Уж не говоря о том, что сам процесс редактирования (редактирование - это не обязательно человеком, может просто инкремент какой-то позиции по некоторому событию) - это совсем не отображение. И по времени и по месту в коде они скорей всего не будут совпадать. Так как отображение - не имеет смысла делать чаще, чем человек может увидеть, а изменение (редактирование) - должно происходить по некоторым событиям (нажатиям кнопок, переключениям энкодера и т.п.) совсем никак не связанным с процессом отображения.

PS: А вышеприведённый код - это конечно какой-то тихий ужас просто..... :o

Re: Вопросы по С/С++ (СИ)

Вт июл 23, 2019 11:02:28

jcxz писал(а):можно отправлять в LCD только изменяемый прямоугольный регион пикселов. Что будет намного быстрее и экономнее по ресурсам
это вот вообще никак не сязано с тем, как лучше редактировать строку :) поскольку при посимвольной правке всегда известно, какой именно символ изменился, и можно выводить только его - это дело чисто вкуса и "экономии" ресурсов, до исчерпания которых вряд ли кто добирался хоть раз.
jcxz писал(а):Так как отображение - не имеет смысла делать чаще, чем человек может увидеть, а изменение (редактирование) - должно происходить по некоторым событиям (нажатиям кнопок, переключениям энкодера и т.п.) совсем никак не связанным с процессом отображения.
теперь я понимаю, окуда берутся гении разработки интерфейсов :) вы всерьез считаете, что может существовать необходимость менять разряд, допустим, 100 раз в секунду, в то время как показывать человеку 3 раза в секунду? ;)

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

Re: Вопросы по С/С++ (СИ)

Вт июл 23, 2019 11:16:30

ARV писал(а):вы всерьез считаете, что может существовать необходимость менять разряд, допустим, 100 раз в секунду, в то время как показывать человеку 3 раза в секунду?
А ведь именно так и есть. Например, счётчик каких-то прерываний, происходящих, скажем, 100 раз в секунду. В прерывании просто берём то самое число (одно!) и инкрементируем (ну, или добавляем +10 или +100 - не важно). И нет необходимости тут же его раскладывать на символы. Это проще сделать именно тогда когда придёт время отображать.

Re: Вопросы по С/С++ (СИ)

Вт июл 23, 2019 12:04:32

вы всерьез считаете, что может существовать необходимость менять разряд, допустим, 100 раз в секунду, в то время как показывать человеку 3 раза в секунду? ;)

Причём тут "100 раз в секунду"? Если изменяется пользователем, то это происходит в ответ например на нажатия клавиш или энкодера или приход пакетов по радио-интерфейсу - т.е. события обрабатываемые соответствующими устройствами ввода в соответствующих обработчиках событий от этих устройств. А вывод на LCD - это совсем другой процесс, и совсем другой драйвер/участок кода.
Это если писать с умом, а не валить всё в одну кучу.

Добавлено after 4 minutes 12 seconds:
еще не факт, что многоразрядное деление не проиграет однобайтному сложению-вычитанию

Подумайте ещё немного и может поймёте что вашего любимого преобразования числа в строку деление вообще не нужно 8)

Re: Вопросы по С/С++ (СИ)

Вт июл 23, 2019 12:53:36

WiseLord писал(а):А ведь именно так и есть.
совсем не так есть. вы перепутали интерфейс человек-МК с интерфейсом МК-периферия. когда человек воздействует на число (а именно этот момент тут рассматривается) нет необходимости изменять число чаще, чем отображать. в случае, когда число изменяется "само по себе" данная проблема вообще не возникает, ибо все изменения делаются стандартными элементарными арифметическими операторами Си без дележа на разряды и т.п.
jcxz писал(а):А вывод на LCD - это совсем другой процесс, и совсем другой драйвер/участок кода
что процесс/участок другой - разве кто спорил? речь о том, что только после каждого изменения числа надо уведомить тот другой участок о необходимости отобразить число. не чаще и не реже - ровно на каждое изменение. можно и чаще, можно и реже - но не нужно.

и тут мы неизбежно возвращаемся к истокам: чтобы отобразить число, нам нужно его символьное представление, которое получается из "аппаратного" путем преобразования число-строка. раз есть строка, то технически проще и менее затратно её и править, оставив обратное преобразование "на потом". выигрыш достигается по всем статьям: и быстродействию, и занятым ресурсам ОЗУ и т.п. и, хоть вы и отбросили это, достигается универсализм в подходах к редактированию вообще чего угодно - поменяются только "границы допустимости" тех или иных символов, а общий алгоритм не изменится.
jcxz писал(а):преобразования числа в строку деление вообще не нужно
может и не нужно, но пока что все реализации в данной теме (последние страницы) без этого не обходятся. хотя можно и многоэтажным if-ом обойтись - было бы желание :)))
Ответить