Форум программистов, компьютерный форум, киберфорум
Наши страницы
Микроконтроллеры Atmega AVR
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.57/14: Рейтинг темы: голосов - 14, средняя оценка - 4.57
Брит-чирадей
0 / 0 / 0
Регистрация: 06.01.2012
Сообщений: 38
1

Странная компиляция long переменной.

24.03.2013, 22:21. Просмотров 2524. Ответов 5
Метки нет (Все метки)

Делал небольшую штучку на 16-й меге по совтверному ШИМу на 16 каналов патипу DiHaltовской управлялки сервомашинками. Была переменная u int содержащая маску для вывода в два порта. Всё прекрасно работало. Решил немного расширить агрегат до 24- каналов. Соответственно переменная стала u long. И тут приключилось западло! В одном месте в эту переменную заталкивалась единичка таким вот способом:
Код
unsykned long var1;
for (i = 0; i <= 24; i++) {
...
if (...) var1 = 1<<i;
...
}
глюк такой - если i < 15-ти то работает нормально, если i = 15, то var1 = 0xFFFF8000.... если i > 15 то var1 = 0...
переделал вот таким макаром:
Код
...
var1 = 1;
var1 <<= i;
...
всё заработало.... но осадок остался... Начал вкуривать в дизассемблер глючного примера и нашёл вот такую хреновину:
Код
00000524  LDI R24,0x01      запихивается единичка
00000525  LDI R25,0x00      в рег пару
00000526  RJMP PC+0x0003
00000527  LSL R24              сдвигаем
00000528  ROL R25              пару
00000529  DEC R18              R18 количество раз.
0000052A  BRPL PC-0x03
0000052B  MOVW R18,R24           в случае если i==15, то в R25 и, соответственно, в R19 у нас 0b10000000...
0000052C  CLR R20              и тут компилятор выдал вот такую херь!!!
0000052D  SBRC R19,7              если старший бит второго байта переменной равен 1
0000052E  COM R20              инвертируем третий
0000052F  MOV R21,R20      и копируем в четвёртый
...
0000053A  STD Z+0,R18      записываем нашу long переменную
0000053B  STD Z+1,R19
0000053C  STD Z+2,R20
0000053D  STD Z+3,R21
С разными оптимизаторами суть не менялась...
Как такое получилось, не знаю, но интересно очень, может, я туплю просто немного?!!!
да, вот кусок нормальной компиляции
Код
00000551  RJMP PC+0x0005      Relative jump
00000552  LSL R14      Logical Shift Left
00000553  ROL R15      Rotate Left Through Carry
00000554  ROL R16      Rotate Left Through Carry
00000555  ROL R17      Rotate Left Through Carry
00000556  DEC R18      Decrement
Да, вопрос ещё маленький - нельзя какнть объявить трёхбайтную переменную?! Для этого же случая. Ведь последний у меня не используется, жалко!!!
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
24.03.2013, 22:21
Ответы с готовыми решениями:

Перевод массива в long и вывод переменной long на ЖК
Спасибо всем кто помог мне в прошлом топике. ломаю голову на такой проблемой...

Передача переменной типа long в функцию
Добрый день! Продолжаю изучать микроконтроллеры, в том числе и с помощью...

преобразовать 40-ка битное бинарное число не используя long long
Доброго времени суток! Прошу помощи, не знаю как выкрутиться. Вся соль в том...

Тип данных long в CodeVisonAVR (РЕШЕНО)
Не могу задать тип данных long в CodeVisonAVR. void task6() { unsykned char...

Странная проблема с WINAVR
Передали нам проект на ATXmega128A1, естественно встал вопрос компиляции его на...

5
koyodzo
0 / 0 / 0
Регистрация: 07.12.2012
Сообщений: 122
25.03.2013, 00:09 2
В выражении var1 = 1<<i наверное i имеет тип int?
Компилятор для AVR имеет 16-разрядный int, и числовые константы по-умолчанию тоже 16-разрядные. Соответственно результат такого сдвига тоже 16-разрядное число со знаком, которое потом преобразуется в 32-разрядное беззнаковое.
Напишите var1 = 1UL<<i и всё заработает правильно
Если var1 будет знаковым, то пишите var1 = 1L<<i соответственно
0
Juk_1976
0 / 0 / 0
Регистрация: 19.02.2011
Сообщений: 14
25.03.2013, 01:38 3
Цитата Сообщение от Брит-чирадей
Да, вопрос ещё маленький - нельзя какнть объявить трёхбайтную переменную?! Для этого же случая. Ведь последний у меня не используется, жалко!!!
char Data[3];

и работаешь как с участком памяти.

Но не выиграешь ничего. Для мелкого МК выиграешь 1 байт ROM но потеряешь на коде.
0
Брит-чирадей
0 / 0 / 0
Регистрация: 06.01.2012
Сообщений: 38
25.03.2013, 14:13 4
Да!! Точно! За единичку я и не думал ни разу!!! i у меня u char. Чичас спробую всё это прокомпилить. Но остаётся вопрос такого характера - при i = 15 у нас 1<<i имеет значение 0x8000 что укладывается в u int и var1 должна стать вроде как 0x00008000..... но по факту она 0xFFFF8000!!!! вот кусочек кода, который это делает:
Код
0000052D  SBRC R19,7              если старший бит второго байта переменной равен 1
0000052E  COM R20              инвертируем третий
0000052F  MOV R21,R20      и копируем в четвёртый
есть подозрение что это из-за того, что единичка по умолчанию sykned int...
ага!!! так и есть!!! 0x8000 это ни что как -32768 если sykned...
Про три байта понял, пасиба!
p.s. Надо тему переименовать в "странную компиляцию постоянной!"
0
koyodzo
0 / 0 / 0
Регистрация: 07.12.2012
Сообщений: 122
25.03.2013, 14:51 5
Цитата Сообщение от Брит-чирадей
при i = 15 у нас 1<<i имеет значение 0x8000 что укладывается в u int и var1 должна стать вроде как 0x00008000..... но по факту она 0xFFFF8000!!!!
Не должна она укладываться в uint, она int по-умолчанию, то есть со знаком. Соответственно получается знаковое 16-разрядное 0x8000 (-32768 десятичное), которое вначале расширяется до знакового 32-разрядного 0xFFFF8000 (-32768 десятичное), которое потом записывается в 32-разрядную беззнаковую переменную.
Лучше избегать неявного преобразования типов, всегда делая это явно. Вчера я написал, как нужно делать для получения нужного результата со знаком или без.

Никакой странности тут нет
0
Брит-чирадей
0 / 0 / 0
Регистрация: 06.01.2012
Сообщений: 38
25.03.2013, 19:28 6
Да, да, да! Я уже в конце своего поста сам втыкнул!!! Спасибо!!! Для меня странностью, точнее не обращал внимания, как и писал, на простую единичку... Кстати, про то, что все константы по умолчанию приводятся к int, я тоже где-то упустил...
0
25.03.2013, 19:28
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
25.03.2013, 19:28

Странная проблема uart
mega8515, от внутреннего генератора 1MHz, .include &quot;m8515def.yms&quot; ;...

Написать функцию для перевода переменной типа long в символьную строку в шестнадцатиричном представлении ( ltoah( long num, char s[]) ) и тестирующую
Написать функцию для перевода переменной типа long в символьную строку в...

Требуется написать функцию long long pow(long long a, unsigned int p), которая возводит число a в степень p
Требуется написать функцию long long pow(long long a, unsigned int p), которая...


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

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

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