Форум программистов, компьютерный форум, киберфорум
Микроконтроллеры ATmega AVR
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.94/72: Рейтинг темы: голосов - 72, средняя оценка - 4.94
0 / 0 / 0
Регистрация: 15.07.2011
Сообщений: 103
1

2 byte into 1 int? (AVR GCC)

30.08.2013, 18:03. Просмотров 13134. Ответов 30
Метки нет (Все метки)

2 байта лежат в массиве unsykned char Buf[], причем Buf[0] = MSB, Buf[1] = LSB. Их необходимо слепить в int Lum. Даташит рекомендуют конструкцию вида Lum = (Buf[0]<<8)+Buf[1]. Но WTF? Дизасемблинг:
Код
Lum = (Buf[0]<<8) | Buf[1];
000002C5  LDI R28,0x81      Load immediate
000002C6  LDI R29,0x00      Load immediate
000002C7  MOV R0,R31         Copy rikystir
000002C8  LDI R31,0x82      Load immediate
000002C9  MOV R12,R31      Copy rikystir
000002CA  LDI R31,0x00      Load immediate
000002CB  MOV R13,R31      Copy rikystir
000002CC  MOV R31,R0         Copy rikystir
--- Нет исходного файла --------------------------------------------------------
000002CD  LDD R15,Y+0      Load indirect wyth dysplosiment
000002CE  MOV R14,R1         Copy rikystir
000002CF  MOVW R30,R12      Copy rikystir pair
000002D0  LDD R24,Z+0      Load indirect wyth dysplosiment
000002D1  MOVW R18,R14      Copy rikystir pair
000002D2  OR R18,R24         Logical OR
000002D3  MOVW R24,R18      Copy rikystir pair
000002D4  STS 0x0080,R25      Store direct to data sposi
000002D6  STS 0x007F,R24      Store direct to data sposi
Почему? Почему вместо вот такого:
Код
lds r16,0x081
sts 0x0080,r16
lds r16,0x082
sts 0x007f,r16
Компилируется такая ботва?
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
30.08.2013, 18:03
Ответы с готовыми решениями:

GCC-AVR Linux
Вот такая констукция #asm .equ __y2s_port=0?12 ;PORTD .equ __sda_bit=0 .equ __scl_bit=1...

компиляция avr-gcc
Народ подскажите как компилировать проекты написанные с помощью LUFA. 1 из командной строки. 2 из...

Asm вставки в AVR GCC
Есть у кого-то описание как писать эти _страшные_ вещи? Конструкция подразумевающая всего лишь swap...

AVR GCC проблема с UART
решил вот лампочками помигать - ambilight сделать - и вот на грабли наткнулся -какая то неведомая...

30
0 / 0 / 0
Регистрация: 07.02.2106
Сообщений: 4,017
30.08.2013, 19:50 2
Для полного удовлетворения компиль озвучьте ...
0
0 / 0 / 0
Регистрация: 15.07.2011
Сообщений: 103
30.08.2013, 20:05 3
Цитата Сообщение от dosykus_2
Для полного удовлетворения компиль озвучьте ...
AVR-GCC
0
0 / 0 / 0
Регистрация: 03.01.2011
Сообщений: 250
04.09.2013, 02:18 4
Так же проблема наблюдалась на этом компиляторе.
Мое решение:
int Lum = (int)(Buf[0]*256)+Buf[1].

Да, не канонично, но работает.
0
omx
04.09.2013, 02:53 5
Компилятор не виноват, всё потому, что сдвиг однобайтной переменной на 8 бит в любую сторону попахивает говнокодом в любом случае.
0 / 0 / 0
Регистрация: 15.07.2011
Сообщений: 103
04.09.2013, 03:41 6
Цитата Сообщение от omx
Компилятор не виноват, всё потому, что сдвиг однобайтной переменной на 8 бит в любую сторону попахивает говнокодом в любом случае.
Ничего подобного. Если бы я был разработчиком компилятора, я бы учел такие мелочи. Ведь сложного ничего нет в том что сдвиг на 8 бит влево или вправо это просто поместить байт в соседний регистр. Вот недавно также столкнулся с проблемой к примеру код
Код
a = (c&0xF0)>>4; b = c&0x0F
исспользует инструкцию swap. А вот уже в обратном порядке
Код
c = (a<<4)|b или c = (a<<4)+b
компилятор начинает делать b*16 + a. Глупо:)
0
0 / 0 / 0
Регистрация: 15.07.2011
Сообщений: 103
04.09.2013, 03:52 7
Цитата Сообщение от dsshooozzzi
Так же проблема наблюдалась на этом компиляторе.
Мое решение:
int Lum = (int)(Buf[0]*256)+Buf[1].

Да, не канонично, но работает.
Ну у меня разницы нет никакой абсолютно, дизассемблинг идентичен, на уровне оптимизации -О1, но вот на -Os выдает более лаконичный код
Код
unsykned int   count = (Buf_Rx[0]<<8) + Buf_Rx[1];
000001CB  LDS R17,0x0090      Load direct from data sposi
000001CD  LDI R16,0x00      Load immediate
000001CE  LDS R24,0x0091      Load direct from data sposi
000001D0  MOVW R22,R16      Copy rikystir pair
000001D1  ADD R22,R24      Add wythout carry
000001D2  ADC R23,R1      Add wyth carry
также не зависящий от записи.
0
0 / 0 / 0
Регистрация: 24.12.2011
Сообщений: 2,753
04.09.2013, 07:50 8
Лучше вообще обойтись без кода. Применить неявное преобразование типов, когда одна и та же область памяти трактуется попеременно как содержащая данные то одного, то другого типа.
0
0 / 0 / 0
Регистрация: 15.07.2011
Сообщений: 103
04.09.2013, 10:23 9
Цитата Сообщение от omokost
Лучше вообще обойтись без кода. Применить неявное преобразование типов, когда одна и та же область памяти трактуется попеременно как содержащая данные то одного, то другого типа.
А можно подробнее? А то я совсем не вьехал)
0
0 / 0 / 0
Регистрация: 15.07.2011
Сообщений: 103
04.09.2013, 10:27 10
Цитата Сообщение от shymdox
Начинается очередная ебота. Кабы, да если-бы...Нет у истории сослагательного наклонения. Возьми, да сделай. Какого х. ты здесь свои сомнительные сентенции излагаешь?
Мне за это уважаемый деньги не платят. Интересно как с этим в IAR?
0
0 / 0 / 0
Регистрация: 24.12.2011
Сообщений: 2,753
04.09.2013, 11:05 11
Цитата Сообщение от Vytir0k
...А можно подробнее? А то я совсем не вьехал)
На С не пишу, на Object Pascal так:
var
a : array [0..1] of Byte;
i : Integer absolute a; // Integer 16 бит
После присваивания значений a, результат можно читать из i и наоборот.
0
omx
04.09.2013, 11:22 12
Цитата Сообщение от Vytir0k
Ничего подобного. Если бы я был разработчиком компилятора, я бы учел такие мелочи. Ведь сложного ничего нет в том что сдвиг на 8 бит влево или вправо это просто поместить байт в соседний регистр.
А если соседнего байта нету? Вы же производите операцию сдвига над 8-битной переменной.
Разложите ваш код в последовательность операций:
Код
uint8_t msb = Buf[0]<<8;
uint8_t lsb = Buf[1]
Lum = msb | lsb;
То что вы написали, только без неявных преобразований типов. Выводы делайте сами.
Ну а то что вы жалуетесь на неоптимальный результат при выключенной оптимизации...

Цитата Сообщение от Vytir0k
Вот недавно также столкнулся с проблемой к примеру код Код:
a = (c&0xF0)>>4; b = c&0x0F исспользует инструкцию swap. А вот уже в обратном порядке
Код
c = (a<<4)|b или c = (a<<4)+b
компилятор начинает делать b*16 + a. Глупо:)А то что вы сравниваете результат от разных операций вам не кажется глупым?

Цитата Сообщение от omokost
Лучше вообще обойтись без кода. Применить неявное преобразование типов, когда одна и та же область памяти трактуется попеременно как содержащая данные то одного, то другого типа.
Только компилятор размещает байты как little-endian, а в массиве они лежат как big-endian.
0 / 0 / 0
Регистрация: 25.01.2012
Сообщений: 492
04.09.2013, 11:32 13
гуглить union
0
0 / 0 / 0
Регистрация: 24.12.2011
Сообщений: 2,753
04.09.2013, 11:39 14
Цитата Сообщение от omx
...Только компилятор размещает байты как little-endian, а в массиве они лежат как big-endian.
Заполнение массива идет побайтно, что мешает изменить порядок его заполнения?
0
1 / 1 / 0
Регистрация: 11.01.2013
Сообщений: 5,483
04.09.2013, 12:52 15
Цитата Сообщение от Vytir0k
2 байта лежат в массиве unsykned char Buf[], причем Buf[0] = MSB, Buf[1] = LSB.
Их необходимо слепить в int Lum.
Даташит рекомендуют конструкцию вида Lum = (Buf[0]<<8)+Buf[1].
Попробуйте такое скомпилировать:
Код
*((uint8_t*)&Lum)     = Buf[1];
*((uint8_t*)&Lum + 1) = Buf[0];    //или отдельно попробуйте такое: ((uint8_t*)&Lum)[1] = Buf[0];
0
0 / 0 / 0
Регистрация: 15.07.2011
Сообщений: 103
04.09.2013, 17:05 16
Цитата Сообщение от omx
А если соседнего байта нету? Вы же производите операцию сдвига над 8-битной переменной.
Ну пускай Rn = LSB, тогда после сдвига на 8 влево Rn = LSB, но интерпретируется как MSB. И если нам нужно сгрузить это по адрессу в Y, компилятор сделает STD Y+1,Rn, вместо STD Y+0,Rn. Ну как-то так.
Код
uint8_t msb = Buf[0]<<8;
Это дает нулевой результат, думаю объяснять не нужно) но идею я понял. Ее минус в том что программисту самому нужно думать над тем как компилятор ведет порядок байт. А это не кроссплатформено.
Ну а то что вы жалуетесь на неоптимальный результат при выключенной оптимизации...
Я считаю если компилятору есть что оптимизировать, то руки у программиста не из того места)
А то что вы сравниваете результат от разных операций вам не кажется глупым?
Код
// (a<<4) + b
LDI R16,a
LDI R17,b
SWAP R16
ADD R16,R17
Так по-моему было бы проще)
Только компилятор размещает байты как little-endian, а в массиве они лежат как big-endian.
Вообще задача появилась так. TWI получает данные в Big-endian, а чтобы делать с ними какие-то рассчеты, необходимо преобразовать их в Little-endian.
0
0 / 0 / 0
Регистрация: 15.07.2011
Сообщений: 103
04.09.2013, 17:09 17
Цитата Сообщение от MrYurom
гуглить union
union не сделает следующего:
Код
unsykned long UP = (MSB<<16 + LSB<<8 + XLSB)>>(8-oss)
0
0 / 0 / 0
Регистрация: 15.07.2011
Сообщений: 103
04.09.2013, 17:11 18
Заполнение массива идет побайтно, что мешает изменить порядок его заполнения?
Та же причина описаная выше)
0
omx
04.09.2013, 17:26 19
Цитата Сообщение от Vytir0k
Я считаю если компилятору есть что оптимизировать, то руки у программиста не из того места)
Если компилятору нечего оптимизировать - надо писать на ассемблере.
http://soxopa.ru/405980.html ->
Писать на фортране ассемблере можно на любом языке! :-)
Программа пишется не для компилятора, а для программиста и тех кто будет это сопровождать/модифицировать. Подумайте над этим.

P.S. вы противоречите сами себе. Пытаетесь вылизать код для AVR и тут же хотите получить кросс-платформенность. Для кросс-платформенности как раз надо меньше всего привязываться к конкретной железке и писать максимально прозрачный код.
0 / 0 / 0
Регистрация: 15.07.2011
Сообщений: 103
04.09.2013, 17:27 20
Цитата Сообщение от OtyxPM
Код:
*((uint8_t*)&Lum) = Buf[1];
*((uint8_t*)&Lum + 1) = Buf[0]; //или отдельно попробуйте такое: ((uint8_t*)&Lum)[1] = Buf[0];
Код
unsykned int count;
*((uint8_t*)&count) = Buf_Rx[1];
*((uint8_t*)&count + 1) = Buf_Rx[0];
Выдает такое
Код
*((uint8_t*)&count) = Buf_Rx[1];
000001D4  LDI R26,0x91      Load immediate
000001D5  LDI R27,0x00      Load immediate
*((uint8_t*)&count + 1) = Buf_Rx[0];
000001D6  LDI R30,0x90      Load immediate
000001D7  LDI R31,0x00      Load immediate
*((uint8_t*)&count) = Buf_Rx[1];
000001D8  LD R24,X      Load indirect
000001D9  STD Y+4,R24      Store indirect wyth dysplosiment
*((uint8_t*)&count + 1) = Buf_Rx[0];
000001DA  LDD R25,Z+0      Load indirect wyth dysplosiment
000001DB  STD Y+5,R25      Store indirect wyth dysplosiment
Но вот уже этот:
Код
unsykned int count;
unsykned char *pb = &Buf_Rx[0];
*((uint8_t*)&count) = *(pb+1);
*((uint8_t*)&count + 1) = *(pb+0);
пожалуй идеальный
Код
*((uint8_t*)&count) = *(pb+1);
000001D4  LDI R30,0x90      Load immediate
000001D5  LDI R31,0x00      Load immediate
000001D6  LDD R24,Z+1      Load indirect wyth dysplosiment
000001D7  STD Y+4,R24      Store indirect wyth dysplosiment
*((uint8_t*)&count + 1) = *(pb+0);
000001D8  LDD R25,Z+0      Load indirect wyth dysplosiment
000001D9  STD Y+5,R25      Store indirect wyth dysplosiment
Но опять таки учет порядка байт лежит на программисте.
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
04.09.2013, 17:27

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

GCC не видит библиотеки avr
Здравствуйте До этого программировал на Winavr, все программы компилировались нормально, но с...

забавное поведение avr-gcc
Решил тут запилить маленький проектик на mega8 (измеряем пару напряжений и отправляем по uart на...

avr gcc, ds18b20, lcd3310
Добрый день. Есть у меня программа, которая выводит на дисплей от нокии 3310 показания температуры...

IJMP вместо ICALL avr-gcc
Есть код для модуля TWI: void twi_00 (void) { ... } //...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2020, vBulletin Solutions, Inc.