Обсуждаем контроллеры компании Atmel.
Ответить

Re: Как передать int по USART?

Вт апр 07, 2015 17:07:52

Аlex писал(а):Почему этот вопрос именно при переходе на char у вас возник ?
Вы вообще в курсе чем они отличаются ?

Функция не моя. Взял её из даташита на Atmega8 стр. 132 поэтому вопросов и небыло))
char от -128 до 127
unsigned char от 0 до 255
вот из-за диапазонов у меня и вопрос.

Re: Как передать int по USART?

Вт апр 07, 2015 19:17:00

USARTу пофиг, что передавать, он передает байт, а что в нем - символ или короткий int или еще чего - без разницы.
Цифровые символы '0'...'9' имеют коды 0х30 ... 0х39, так что и в signed и в unsigned без разницы.

Re: Как передать int по USART?

Ср апр 08, 2015 16:52:20

Всё понял. Спасибо :)

Re: Как передать int по USART?

Пт дек 24, 2021 12:35:20

Кстати, задачу можно решить "в лоб" и без громоздкой функции sprintf():
Начнем с того, что максимальное значение числа равно 65535, т.е. 5 символов.
Код:
unsigned char a, buf[5];
unsigned int x; // тут наше число

for( a=0; a<5; a++ ) buf[a] = '0';

while( x>10000 ) { buf[0]++; x = x-10000; }
while( x>1000 )   { buf[1]++; x = x-1000; }
while( x>100 )     { buf[2]++; x = x-100; }
while( x>10 )       { buf[3]++; x = x-10; }
buf[4] = x;

Понятное дело, что этот код можно упростить, убрать лидирующие нули ....
Это решения для уровня "начинающий", хотя и рабочее :))


На всякий случай, если кто-то воспользуется: while( x>=10000 ) и т.д. Иначе будет пропускать преобразование целых десятков, сотен, тысяч.

Re: Как передать int по USART?

Пт дек 24, 2021 12:54:18

Всего лишь через 6,5 лет после запроса - ответ. Очередной рекорд некропостинга?

Re: Как передать int по USART?

Пт дек 24, 2021 13:15:10

Всего лишь через 6,5 лет

За прошедшие 6,5 лет >= стало идентичным >? Я что-то пропустил?

Re: Как передать int по USART?

Пт дек 24, 2021 14:35:21

да, пропустил ...
никогда, и до сих пор, ">=" не было идентичным ">".
и никогда не будет.

Re: Как передать int по USART?

Ср янв 25, 2023 18:55:25

Код:
unsigned char a, buf[5];
unsigned int x; // тут наше число

for( a=0; a<5; a++ ) buf[a] = '0';

while( x>10000 ) { buf[0]++; x = x-10000; }
while( x>1000 )   { buf[1]++; x = x-1000; }
while( x>100 )     { buf[2]++; x = x-100; }
while( x>10 )       { buf[3]++; x = x-10; }
buf[4] = x;

Проще ведь тогда через один цикл с делением на 10 и на % 10?

Или тут вопрос в быстродействии? Интересно 4 цикла со сложением намного быстрее 1 цикла с делением?

Re: Как передать int по USART?

Ср янв 25, 2023 21:24:20

деление во МНОГО раз медленнее, чем сложение или вычитание.
быстрее 9 раз сложить и 9 раз вычесть, чем один раз разделить.

Re: Как передать int по USART?

Чт янв 26, 2023 20:57:50

деление во МНОГО раз медленнее, чем сложение или вычитание.
...

Значит буду попытаться избегать деления, хотя сейчас конечно мне это не актуально. Спасибо.

Re: Как передать int по USART?

Чт янв 26, 2023 22:29:48

никогда, и до сих пор, ">=" не было идентичным ">".

Надо же, а мужики не знали :shock:

Re: Как передать int по USART?

Чт янв 26, 2023 22:39:53

Asmodey, тебе больше года понадобилось, чтобы переварить мои слова.
жираф нервно курит в сторонке...

Re: Как передать int по USART?

Пт янв 27, 2023 00:22:35

До Вас ни тогда, ни сейчас не дошло о чем речь, но свое драгоценное мнение озвучить не преминули, тем не менее. Мы с Вами водку не пили, если что.

Re: Как передать int по USART?

Ср фев 08, 2023 06:26:36

деление во МНОГО раз медленнее, чем сложение или вычитание.
быстрее 9 раз сложить и 9 раз вычесть, чем один раз разделить.


Вы когда пытаетесь быстрее паровоза бежать, смотрите, получается ли у вас это.
А то у вас это УЖЕ не получается, но вы об этом ЕЩЁ не знаете.

Посмотрел, какой код генерирует компилятор для вот такого кода:

Код:
      display_symbols[3] = display_u / 1000;
      display_u = display_u % 1000;
      display_symbols[4] = display_u / 100;
      display_u = display_u % 100;
      display_symbols[5] = display_u / 10;


Спойлер
Код:
     Это код функции, поэтому display_u уже в регистрах r25:r24

      display_symbols[3] = display_u / 1000;

     210: 68 ee         ldi r22, 0xE8 ; 232       --- 1000
     212: 73 e0         ldi r23, 0x03 ; 3
     214: 0e 94 4f 10   call 0x209e  ; 0x209e <__udivmodhi4>
     218: 60 93 61 01   sts 0x0161, r22

      display_u = display_u % 1000;
      display_symbols[4] = display_u / 100;

     21c: 64 e6         ldi r22, 0x64 ; 100
     21e: 70 e0         ldi r23, 0x00 ; 0
     220: 0e 94 4f 10   call 0x209e   ; 0x209e <__udivmodhi4>
     224: 60 93 62 01   sts 0x0162, r22

      display_u = display_u % 100;
      display_symbols[5] = display_u / 10;

     228: 6a e0         ldi r22, 0x0A ; 10
     22a: 70 e0         ldi r23, 0x00 ; 0
     22c: 0e 94 4f 10   call 0x209e   ; 0x209e <__udivmodhi4>
     230: 60 93 63 01   sts  0x0163, r22

     234: 08 95         ret

0000209e <__udivmodhi4>:
    209e: aa 1b       sub r26, r26
    20a0: bb 1b       sub r27, r27
    20a2: 51 e1       ldi r21, 0x11 ; 17
    20a4: 07 c0       rjmp  .+14    ; 0x20b4 <__udivmodhi4_ep>

000020a6 <__udivmodhi4_loop>:
    20a6: aa 1f       adc r26, r26
    20a8: bb 1f       adc r27, r27
    20aa: a6 17       cp  r26, r22
    20ac: b7 07       cpc r27, r23
    20ae: 10 f0       brcs .+4      ; 0x20b4 <__udivmodhi4_ep>
    20b0: a6 1b       sub r26, r22
    20b2: b7 0b       sbc r27, r23

000020b4 <__udivmodhi4_ep>:
    20b4: 88 1f       adc r24, r24
    20b6: 99 1f       adc r25, r25
    20b8: 5a 95       dec r21
    20ba: a9 f7       brne  .-22    ; 0x20a6 <__udivmodhi4_loop>
    20bc: 80 95       com r24
    20be: 90 95       com r25
    20c0: bc 01       movw r22, r24
    20c2: cd 01       movw r24, r26
    20c4: 08 95       ret


В каком месте тут "во МНОГО" (большими жЫрнЫми буквами, для усиления эффекта) раз медленнее, если оно делается всё тем же способом сложения-вычитания?
Не надо пытаться быть умнее хорошего компилятора. Пишите нормальный человекопонятный код, а не дебильные циклы "двадцатьпервым пальцем" и всё будет ок.

Заменил ради интереса на предлагаемые циклы:

Код:
      //display_symbols[3] = display_u / 1000;
      //display_u = display_u % 1000;
      //display_symbols[4] = display_u / 100;
      //display_u = display_u % 100;
      //display_symbols[5] = display_u / 10;

      while( display_u>1000 )   { display_symbols[3]++; display_u = display_u - 1000; }
      while( display_u>100 )    { display_symbols[4]++; display_u = display_u - 100; }
      while( display_u>10 )     { display_symbols[5]++; display_u = display_u - 10; }


Получил такой листинг:

Спойлер
Код:
     Это код функции, поэтому display_u уже в регистрах r25:r24

     210:       20 91 61 01     lds     r18, 0x0161
     214:       31 e0           ldi     r19, 0x01       ; 1
     216:       32 0f           add     r19, r18

      while( display_u>1000 )   { display_symbols[3]++; display_u = display_u - 1000; }

     218:       89 3e           cpi     r24, 0xE9       ; 233
     21a:       43 e0           ldi     r20, 0x03       ; 3
     21c:       94 07           cpc     r25, r20
     21e:       20 f0           brcs    .+8             ; 0x228 <display_U+0x8a>
     220:       88 5e           subi    r24, 0xE8       ; 232
     222:       93 40           sbci    r25, 0x03       ; 3
     224:       23 2f           mov     r18, r19
     226:       f6 cf           rjmp    .-20            ; 0x214 <display_U+0x76>
     228:       20 93 61 01     sts     0x0161, r18

     22c:       20 91 62 01     lds     r18, 0x0162
     230:       31 e0           ldi     r19, 0x01       ; 1
     232:       32 0f           add     r19, r18

      while( display_u>100 )    { display_symbols[4]++; display_u = display_u - 100; }

     234:       85 36           cpi     r24, 0x65       ; 101
     236:       91 05           cpc     r25, r1
     238:       20 f0           brcs    .+8             ; 0x242 <display_U+0xa4>
     23a:       84 56           subi    r24, 0x64       ; 100
     23c:       91 09           sbc     r25, r1
     23e:       23 2f           mov     r18, r19
     240:       f7 cf           rjmp    .-18            ; 0x230 <display_U+0x92>
     242:       20 93 62 01     sts     0x0162, r18

     246:       20 91 63 01     lds     r18, 0x0163
     24a:       31 e0           ldi     r19, 0x01       ; 1
     24c:       32 0f           add     r19, r18

      while( display_u>10 )     { display_symbols[5]++; display_u = display_u - 10; }

     24e:       8b 30           cpi     r24, 0x0B       ; 11
     250:       91 05           cpc     r25, r1
     252:       18 f0           brcs    .+6             ; 0x25a <display_U+0xbc>
     254:       0a 97           sbiw    r24, 0x0a       ; 10
     256:       23 2f           mov     r18, r19
     258:       f8 cf           rjmp    .-16            ; 0x24a <display_U+0xac>
     25a:       20 93 63 01     sts     0x0163, r18

     25e:       08 95           ret


После этой замены размер прошивки увеличился на 42 байта, и это еще не добавлена прединициализация элементов display_symbols нулем или 0x30 (впрочем, она не должна существенно изменить размер кода).

Что мы видим - на получение одного значения теперь надо не 6 опкодов вызова функции, а 14/13/12.
Функция размером 20 машинных операций/опкодов. Соответственно решение с циклом while займет больше места ( 3*6 + 20 < 3*13) в прошивке даже если в коде будет только три цикла.

Вызываемая функция - делает ту же математику вычитанием, соответственно не может быть "во МНОГО" раз медленнее.

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

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

Не учите людей говнокодерской х-не.

Значит буду попытаться избегать деления, хотя сейчас конечно мне это не актуально. Спасибо.

Re: Как передать int по USART?

Ср фев 08, 2023 16:29:11

pavel2000 писал(а):если оно делается всё тем же способом сложения-вычитания?
да, подпрограмма деления тоже делается способом сложения-вычитания, только ты, видимо, забыл, что там сложения-вычитания у тебя делаются 17 (семнадцать) раз.
а вычесть, например, 1000 нужно максимум 9 раз. а минимум - вообще ни разу.
что быстрее, всегда делать 17 кругов или сделать (максимум) 9 кругов, или вообще не сделать ни одного круга?

Re: Как передать int по USART?

Ср фев 08, 2023 21:23:27

> В каком месте тут "во МНОГО"

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

Но использование циклов для решения задачи всё равно остается говнокодом, в этой части мое мнение остается без изменений,
т.к строгой необходимости использования именно цикла вместо оператора деления в общем случае я не вижу.

Если в проекте не хватает производительности на оператор деления - то его использование циклов не спасет,
т.к. когда выпадет "9999" то число циклов отличаться будет уже не так МНОГО, как в варианте "1111".
А проект, который работает только при 1111 и валится при 9999 .... ну вы поняли мысль.

Re: Как передать int по USART?

Ср фев 08, 2023 22:22:26

пусть не МНОГО, но в несколько раз.
pavel2000 писал(а):строгой необходимости использования именно цикла вместо оператора деления в общем случае я не вижу.
а то, что оператор деления использует циклы, ты опять забыл? так посмотри свой представленный код с делением.
pavel2000 писал(а):использование циклов для решения задачи всё равно остается говнокодом
так что, использование оператора деления также будет говнокодом, так как оператор деления использует циклы. даже говнокодом в квадрате против вычитания и сложения, так как работает медленнее, чем вычитания и сложения.

Re: Как передать int по USART?

Ср фев 08, 2023 22:23:16

Язык программирования придуман не для того, чтобы процессору было легче, а чтобы легче было человеку. Любой, сколь угодно миниатюрный и/или сверхбыстрый код есть говно, если на его понимание человеку требуется больше усилий. Весь "гениальный" код - код одного программиста, и умирает вместе с ним, т.к. никому более не нужен. В отличие от.

Re: Как передать int по USART?

Ср фев 08, 2023 23:37:13

Но использование циклов для решения задачи всё равно остается говнокодом

А то, что в системе команд некоторых МК нет операции умножения-деления - как с этим быть? И ничего, что код написан на Си - от этого такая команда в МК волшебным образом не появится. Компилятор, зная конкретную модель МК , сам решает - использовать соответствующую команду или подпрограмму при отсутствии необходимой.
СпойлерНа бывшей моей работе как-то я выразил сомнение в оптимальности и вообще работоспособности увиденной программы. И их шеф заявил так: "Программа написана на языке Си, компилятор ошибок не выявил - НЕПРАВИЛЬНОЙ ОНА БЫТЬ НЕ МОЖЕТ! " :) О существовании понятия "логическая ошибка" бедняга понятия не имел. :shock:

Re: Как передать int по USART?

Чт фев 09, 2023 00:12:40

любой, сколь угодно миниатюрный и/или сверхбыстрый код есть говно, если на его понимание человеку требуется больше усилий. Весь "гениальный" код - код одного программиста, и умирает вместе с ним, т.к. никому более не нужен. В отличие от.

Это гораздо практичнее, нежели отсутствие коммерчески успешного устройства вообще. В попытке получить "правильный" код можно вообще ничего не получить.
Ну и само видение "правильного" кода - очень индивидуальное понятие. Это особенно заметно для чисто радиотехнических устройств, где написать "правильный" с точки зрения классического программиста код вообще невозможно - настолько экзотически используются аппаратные ресурсы для генерации режима реального времени. Можно канешна посоветовать взять более мощный чип МК, а равно добавить в схему FPGA, что возможно и с инженерной точки зрения будет оправдано, но тогда это "правильное" во всех отношениях устройство (включая его код) будет нужно только его создателю. Рынок его не примет. Дорого.
А с "не совсем правильным" кодом, который ВОЗМОЖНО не осилит некий гипотетический программист пришедший на смену автору, можно упростить ситуацию правильно написанными комментариями и сопроводительной документацией с описанием алгоритмов и генерируемых диаграмм работы.
Помнится, что в 80-х годах прошлого века найти в программах обслуживающих бортовую РЛС сам код было отдельной нетривиальной задачей. Комментариев было больше, чем кода. А читать код и понимать его было доступно только программистам с профильным образованием прикладной математики со специализацией в обработке радиолокационных сигналов.
Я вот сегодня примерно такой же код писал для сходного по генезису устройства (не подумайте ничего про БРЛС - сугубо мирное и гражданское)... :tea: :)))

ЗЫ. Павел2000 может считать это сообщение обещанным ему. :wink: :roll: Тут в соседней ветке коллега roman.com решает создать из мусора в собственном столе не меньше, чем PHY Ethernet. Вот с ним пообщайтесь на предмет "правильного кода". Он парень веселый. Рассмеется вам в лицо. Я так думаю. :)))
Ответить