Перейти к содержанию
    

Битовые сдвиги

 
#include <iom8.h>

void main(void)
{
    unsigned long int a, n;

    n = 16;
    a = 1 << n;
    PORTB = a;
}

По идее в переменной "а" должен быть установлен 16 бит, а на деле там 0. Какие есть идеи?

 

Компилятор:

IAR C/C++ Compiler for AVR

4.12A/W32 [Evaluation] (4.12.1.3)

 

Для просмотра значений переменных использую родной симулятор.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

 
    n = 16;
    a = 1 << n;

По идее в переменной "а" должен быть установлен 16 бит, а на деле там 0. Какие есть идеи?

1 имеет тип int. Для avr int имеет 16 бит. Соответственно любой int сдвинутый на 16 будет нулем, что и имеем. Решение: привести 1 к типу unsigned long (или к unsigned long long) или сразу указать что она такого типа:

     a = (unsigned long long)1 << n;
или
     a = 1ULL << n;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Спасибо.

 

Но в сязи с этим возникает другой вопрос. Делаем тип переменной "а" unsigned long long. Как теперь сдвинуть на, например, 40 бит? Тут проблемы возникают даже при сдвиге на 7 бит.

 

Если провести присваивание вида

a = 1ULL;

то получим в "а" значение 0x0100000000000000;

Получается какя-то путаница в байтах числа.

 

При

a = 0xAFFULL;

а == 0xFF00000000000000

 

a = 0xABCDEFABCDEFABCD;

a == 0xCD00000000000000

Изменено пользователем CSB

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Спасибо.

 

Но в сязи с этим возникает другой вопрос. Делаем тип переменной "а" unsigned long long. Как теперь сдвинуть на, например, 40 бит? Тут проблемы возникают даже при сдвиге на 7 бит.

Где проблемы возникают?

  unsigned long long a;
  a = 1ULL << 40;

     21              a = 1ULL << 40;
   \   00000002   E000               LDI     R16, 0
   \   00000004   E051               LDI     R21, 1
   \   00000006   ....               LDI     R30, LOW(a)
   \   00000008   ....               LDI     R31, (a) >> 8
   \   0000000A   8300               ST      Z, R16
   \   0000000C   8301               STD     Z+1, R16
   \   0000000E   8302               STD     Z+2, R16
   \   00000010   8303               STD     Z+3, R16
   \   00000012   8304               STD     Z+4, R16
   \   00000014   8355               STD     Z+5, R21
   \   00000016   8306               STD     Z+6, R16
   \   00000018   8307               STD     Z+7, R16

IAR AVR v4.10B

 

 

Если провести присваивание вида

a = 1ULL;

то получим в "а" значение 0x0100000000000000;

Получается какя-то путаница в байтах числа.

 

При

a = 0xAFFULL;

а == 0xFF00000000000000

 

a = 0xABCDEFABCDEFABCD;

a == 0xCD00000000000000

Похоже вы не в ту сторону считаете, это у вас от кейла для x51 привычка к BigEndian. У AVR младший байт располагается по младшему адресу.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В ассемблере у меня получается две команды: очистка регистров и все!

 

Оптимизация: переключатель в положении "скорость", в списке выбрано None (Best debug support).

 

Кроме того получается разный результат при

a = 1ULL << 7;

и

n = 7;

a = 1ULL << n;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

try this

a = (long)1 << n;

Обычно это делается так

a = 1L << n;        // Константа со знаком

или так

a = 1UL << n;      // Константа без знака

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В ассемблере у меня получается две команды: очистка регистров и все!

Оптимизация: переключатель в положении "скорость", в списке выбрано None (Best debug support).

Кроме того получается разный результат при

a = 1ULL << 7;

и

n = 7;

a = 1ULL << n;

Что-то не так. Приведи весь код. Вот что получается у меня:

volatile int a;
void main (void) {
    int n = 7;
    a = 1ULL << 7;
    a = 1ULL << n;
}
     19          void main (void) {
   \                     main:
   \   00000000   939A               ST      -Y, R25
   \   00000002   938A               ST      -Y, R24
     20              int n = 7;
     21              a = 1ULL << 7;
   \   00000004   E800               LDI     R16, 128
   \   00000006   E010               LDI     R17, 0
   \   00000008   ....               LDI     R30, LOW(a)
   \   0000000A   ....               LDI     R31, (a) >> 8
   \   0000000C   8300               ST      Z, R16
   \   0000000E   8311               STD     Z+1, R17
     22              a = 1ULL << n;
   \   00000010   8300               ST      Z, R16
   \   00000012   8311               STD     Z+1, R17

Результат одинаковый.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Господа, каюсь :)

Я забыл про одну весьма немаловажную вещь: volatile!

Забыл с самого начала и что-бы компилятор не выкидывал код я делал PORTB = a; проверив перед этим: а вдруг "умный" компилятор посчитает старшую часть числа не нужной и не будет ее вычислять; для 16-битовых чисел все работало.

 

2 Сергей Борщ:

Большое спасибо!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...