AVR GCC — проблема с типизацией

#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» 🙂