AVR uint8_t не получает правильное значение - PullRequest
0 голосов
/ 26 февраля 2019

У меня есть uint8_t, который должен содержать результат побитового вычисления.Отладчик говорит, что переменная установлена ​​правильно, но когда я проверяю память, переменная всегда равна 0. Код работает как переменная, равная 0, независимо от того, что говорит мне отладчик.Вот код:

temp = (path_table & (1 << current_bit)) >> current_bit;
//temp is always 0, debugger shows correct value
if (temp > 0) {
    DS18B20_send_bit(pin, 0x01);
} else {
    DS18B20_send_bit(pin, 0x00);
}

Temp - это uint8_t, path_table - uint64_t и current_bit - uint8_t.Я пытался сделать их все uint64_t, но ничего не изменилось.Я также попытался использовать unsigned long long int вместо этого.Больше ничего.

Код всегда входит в предложение else.Atmega4809 Чипа и использует uint64_t в других частях кода без проблем.

Примечание. Если кто-нибудь знает более эффективный / компактный способ извлечения одного бита из переменной, я был бы очень признателен, если бы вы могли поделиться ^^

Ответы [ 2 ]

0 голосов
/ 26 февраля 2019

Понимание # 1 здесь - то, что AVR - ядро ​​технологии 1980-1990-ых.Это не 64-битный ПК, который жует 64-битные числа на завтрак, а крайне неэффективный 8-битный MCU.Таким образом:

  • Ему нравится 8-битная арифметика.
  • Он будет бороться с 16-разрядной арифметикой, выполняя трюки с 16-разрядными индексными регистрами, двойными аккумуляторами или любыми 8-разрядными основными трюками, которые он предпочитает делать.
  • Для выполнения 32 потребуется буквально целая вечностьбитовая арифметика, вызывая встроенные библиотеки программного обеспечения.
  • Вероятно, он растает через пол при попытке 64-битной арифметики.

Прежде чем делать что-либо еще, вам нужно избавиться от всех64-битная арифметика и радикально минимизирует использование 32-битной арифметики.Период.В вашем коде не должно быть ни одной переменной uint64_t, или вы делаете это очень-очень неправильно.


С этим открытием также следует, что все 8-битные MCU всегда имеют тип int, который16 бит

В коде 1<<current_bit целочисленная константа 1 имеет тип int.Это означает, что если current_bit равно 15 или больше, вы будете сдвигать биты в знаковый бит этого временного int.Это всегда ошибка.Строго говоря, это неопределенное поведение.На практике вы можете получить случайную смену знака своих чисел.

Чтобы избежать этого, никогда не используйте никакие формы побитовых операторов для чисел со знаком.При смешивании целочисленных констант, таких как 1, с побитовыми операторами, измените их на 1u, чтобы избежать ошибок, подобных упомянутой.


Если кто-нибудь знает более эффективный / компактный способ извлеченияодин бит из переменной, я был бы очень признателен, если бы вы могли поделиться

. Самый эффективный способ в C: uint8_t variable; ... if(variable & (1u << bits)).Это должно привести к соответствующей инструкции «ответвление, если бит установлен».


Мой общий совет - найти дизассемблер вашей цепочки инструментов и посмотреть, какой машинный код на самом деле сгенерировал код C.Вам не нужно быть гуру ассемблера, чтобы прочитать его, достаточно заглянуть в набор .

0 голосов
/ 26 февраля 2019

1 - целочисленная константа типа int.Выражение 1 << current_bit также имеет тип int, но для 16-разрядного int результат этого выражения не определен, если current_bit больше 14. Поведение, которое в вашем случае не определено, тогда, вероятно,что ваш отладчик представляет результаты для общего выражения, которые кажутся несовместимыми с наблюдаемым поведением.Если вместо этого использовать константу unsigned int, , т. Е. 1u, то результирующее значение temp будет правильно определяться как 0 всякий раз, когда current_bit будет больше 15, поскольку результат сдвига влево будетбыть нулевым.

Решите эту проблему, выполнив вычисление в типе, достаточно широком, чтобы удержать результат.Вот компактный, правильный и довольно ясный способ исправить ваш код, чтобы сделать это:

DS18B20_send_bit(pin, (path_table & (((uint64_t) 1) << current_bit)) != 0);

Или, если path_table имеет тип без знака, тогда я предпочитаю это, хотя это скорее отклонение от вашего оригинала:

DS18B20_send_bit(pin, (path_table >> current_bit) & 1);
...