#c #casting #bit-manipulation #avr
#c #Кастинг #манипулирование битами #avr
Вопрос:
Я использую микроконтроллер AVR для записи на микросхему программируемого делителя частоты через шину I2C. Через определенные промежутки времени я пытаюсь вызвать следующую функцию для обновления частоты выходного сигнала микросхемы:
void 1077WriteDiv(int16_t data)
{
uint8_t upperByte = (uint8_t)((uint16_t)data>>2);
i2c_start(DS1077_BASE_ADDRESS);
i2c_write(DIVIDE_REGISTER);
i2c_write(upperByte);
i2c_write(0x0);
i2c_stop();
}
Я пытаюсь получить верхние 8 бит десятибитового значения в переменной «данные» и записать его. Вторая команда «write» записывает младшие 8 бит регистра «divide» на микросхеме, в данном случае 0.
В качестве тестового примера я увеличиваю переменную «data» (которая по определенным причинам должна быть подписана) с нуля, сдвигая ее влево на 2 бита и вызывая эту функцию каждый раз. Я удаляю мусор. Однако, когда я делаю это:
void 1077WriteDiv(int16_t data)
{
//uint8_t upperByte = (uint8_t)((uint16_t)data>>2);
static uint8_t thing = 0;
i2c_start(DS1077_BASE_ADDRESS);
i2c_write(DIVIDE_REGISTER);
i2c_write(thing );
i2c_write(0x0);
i2c_stop();
}
Все работает так, как ожидалось. Очевидно, что есть какая-то проблема в том, как я переношу и типизирую исходную переменную «data», но я перепробовал все виды перестановок с теми же результатами. Было бы очень признательно, если бы кто-нибудь мог указать, где я могу ошибаться.
Комментарии:
1. Не могли бы вы показать нам код, который выполняет увеличение и сдвиг влево? Возможно, этот код плохой.
2. Пожалуйста, покажите нам код вызова…
3. gcc на самом деле не позволяет вам использовать
1077WriteDiv
в качестве идентификатора, не так ли? Можете ли вы показать нам свой реальный код?4. Вы уверены, что имеете в виду
>>2
, а неCHAR_BIT
или8
?5. @ephemient он говорит, что верхние 8 бит 10-битного значения…
Ответ №1:
Попробуйте
uint8_t upperByte = (uint8_t) ((data amp; 0x3FC) >> 2);
Вы не можете полагаться на приведение к меньшему int для удаления битов старшего порядка, от которых вы пытаетесь избавиться.
Ответ №2:
i2c_write(thing );
Это означало бы, что ваш разделитель увеличивает каждый вызов. Если вы увеличиваете «данные» и сдвигаете их вправо на два, то ваш делитель увеличивается каждые четыре вызова. Ваши два раздела кода не эквивалентны.
С каким интервалом вы вызываете эту функцию? Что такое «удаление мусора»? Откуда вы знаете, что значение, переданное в функцию, является правильным? Откуда вы знаете, что значение, отправленное на DS1077, неверно?
Проверьте все свои предположения.
Приведение и сдвиг выглядят для меня нормально. По крайней мере, я думаю, что они будут работать в любом компиляторе C, который я когда-либо использовал. С точки зрения стандарта C вы можете обратиться к этому проекту (ISO / IEC 9899: преобразования TC2 6.3):
В противном случае, если новый тип не имеет знака, значение преобразуется путем многократного добавления или вычитания на единицу больше максимального значения, которое может быть представлено в новом типе, пока значение не окажется в диапазоне нового типа
Это единственный, к которому у меня есть доступ прямо сейчас. Возможно, кто-то еще может ответить на стандартный вопрос. Возможно, компилятор не соответствует стандарту…
Комментарии:
1. К сожалению, более вероятно, что это какая-то неясная аппаратная проблема. Я потратил несколько часов, внимательно изучая дизассемблер и просматривая код на симуляторе, и в симуляции все работает отлично. Мне действительно трудно найти причину, по которой программное обеспечение не будет работать должным образом.
2. @Bitrex пересмотрите вопрос с вашими подробными выводами, и, возможно, кто-нибудь сможет вам помочь… К сожалению, большинство проблем неясны до тех пор, пока не появится сообщение «duh» 🙂