Проблема с объединением байтов на микроконтроллере ATmega328P

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

Проблема возникает как при использовании встроенного компилятора, так и при включенном LTO.

uint16_t hi_val;

void InstrumentRunner::setValue(uint8_t key, uint8_t highByte, uint8_t lowByte){
    if(key == GET_ENCODER_HI){
        //set enc val
        hi_val = (highByte << 8) | lowByte;
    }
    if(key == GET_ENCODER_LO){
        //set enc val
        uint16_t lo_val = (highByte << 8) | lowByte;
        uint32_t encode = (hi_val << 16) | lo_val ;
        debug.println(hi_val);
        debug.println(lo_val);
        debug.println(encode);
        encoder.setCount(encode);
    }
}

выход в консоли при отправке числа например 399886, проблема имеется при превышении значения 2^16, поскольку старшая часть не добавляется :

6
6670
6670

Контроллер-то какой?

в заголовке ATmega328

Вы сдвигаете 16-битное hi_val на 16 битов. Результат - всегда 0.

Сначала сделайте его 32-битным, а потом уже сдвигайте.

Кстати, тоже самое про сдвиг highByte на 8. Сначала сделайте его 16-битным, а потом сдвигайте.

просто микроконтроллер установленный в тестовый образец платы, если интересует
image
спасибо помогло! но что то странно в других местах кода работает при 16 битной переменной

6
6670  
399886

Недоработка. Видимо контроллер китайский.

Не работает. Если, что работает, значит там по каким-то причинам, оно само привелось к 32-битам, это конкретно смотреть надо, что там за код.

Может это зависит от настроек. Я помню из прежних обсуждений, что по умолчанию при вычислениях производится привидение к int. Проверил у себя в Atmel\Studio\7.0, сдвиг байта происходит нормально, пока не выходит за пределы int

1 лайк

Ой, это очень непросто. Оно-то да, всё приводится к int, но … тут были обсуждения совершенно неочевидных ошибок из-за таких сдвигов. Сейчас я уже убегаю, но, завтра, если интересно, поищу.

В любом случае, это реально непросто и там масса нюансов. Лучше привести ручками и всегда контролировать ситуацию.

“в других местах” - это где? На 32-разрядной архитектуре?

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

Так и я о том, что на разных архитектурах int разный.