Функция записывает неправильное значение в регистр - PIC18F

Я написал функцию, в которой вы должны ввести число, а затем функция вычисляет значение для записи в регистр. Однако похоже, что он записывает «неправильное» значение в регистр. Я использовал калькулятор и wolframalpha, чтобы убедиться, что я не нарушаю порядок операций. Функция указана ниже:

void SetFrequency_Hz(int Freq) {
    PR4 = ((41667000 / (4 * 16 * Freq)) - 1);
}

Когда я пытаюсь установить частоту на 20 кГц (20 000 Гц), мне нужно установить регистр PR4 на 32. Теоретически, если я введу значение 20000 в функцию, должно быть выплевывается, НО это выплевывает 179 для некоторых причина. Есть предположения, почему?

MCU: PIC18F67J60 IDE: MP LAB X


person Sam W    schedule 23.03.2019    source источник
comment
Какой размер int на pic18f - сколько бит?   -  person barny    schedule 24.03.2019
comment
@barny Я понимаю, к чему ты клонишь (PR4 - это 8-битный регистр). Я уже пытался использовать PR4 и/или получить u8, но безрезультатно. Вот так: PR4 = (u8) ((41667000 / (4 * 16 * Частота)) - 1);   -  person Sam W    schedule 24.03.2019
comment
Важен не размер 8-битного регистра, потому что ожидаемое значение 32 подходит. Это размер типа int C. Если это 16 бит, расчет не будет работать, вам нужно использовать 32-битный тип. Например ((41667000UL / (64UL * Freq)) - 1);   -  person Weather Vane    schedule 24.03.2019
comment
Я когда-либо знал. Где я могу узнать больше об этом?   -  person Sam W    schedule 24.03.2019
comment
Обратитесь к руководству по компилятору. Или попробуйте printf("%zu\n", sizeof(int));, что должно дать 2, 4 или 8 (байт).   -  person Weather Vane    schedule 24.03.2019
comment
Нет printf? В любом случае, поместите его в переменную size_t и проверьте отладчиком. Или на ЖК-дисплее, или как вы получаете вывод!   -  person Weather Vane    schedule 24.03.2019
comment
Когда вы исправите арифметическое переполнение в промежуточных результатах, вы все равно получите 31, а не 32. Целочисленное деление усекается до нуля. Таким образом, результирующая частота будет 41667000 / ((PR4 + 1) * 64) (~ 20,345 Гц, когда PR4 == 31, ~ 19,729 МГц для 32)   -  person Clifford    schedule 24.03.2019
comment
По возможности полностью избегайте 32-битной арифметики. 32-битная точность здесь не нужна, поэтому отбрасывайте Гц на кГц или МГц.   -  person Lundin    schedule 25.03.2019
comment
@SamW: 1) сделайте себе одолжение: добавьте #include <stdint.h> и четко укажите свои целочисленные размеры, т.е. используйте int32_t или int16_t и убедитесь, что вы понимаете ширину операндов, 2) обратите внимание на ваше фактическое требуемое разрешение и динамический диапазон - если 20000 сопоставляется с 32, укажите, какое число сопоставляется с 30 или 31 и нужно ли вам вообще разрешение.   -  person Groo    schedule 25.03.2019


Ответы (1)


Поскольку в PIC18 тип int будет только 16 бит несколько загадочные неявные правила преобразования в C приведут к промежуточным результатам в вашем выражение для усечения. Я удивлен, что ваш компилятор не выдал предупреждение для литерала 41667000, так как он в любом случае явно не подходит для типа PIC18 int.

Эту проблему можно легко решить, используя явные суффиксы литеральных типов для изменения общего типа выражения:

PR4 = 41667000ul / (64ul * Freq) - 1u ;

или если требуемое разрешение по частоте в кГц, вы можете масштабировать выражение:

PR4 = 41667u / (64u * (Freq/1000)) - 1u ;

Однако следует отметить, что в обоих этих случаях реальное значение 41667000 / (64 x 20x103)) - 1 составляет ~31,55, поэтому значение в PR4 будет равно 31. а не 32, что приведет к фактической частоте 20 345 Гц.

Чтобы округлить до ближайшего целочисленного значения выражения real:

PR4 = (41667000ul / (32ul * Freq) - 1u) / 2 ;

Это приведет к PR4=32 и частоте 19729 Гц.

Может быть полезно, чтобы функция возвращала фактическую достигнутую частоту:

unsigned SetFrequency_Hz( unsigned ideal_freq ) 
{
    PR4 = (41667000ul / (32ul * ideal_freq ) - 1u) / 2u ;

    // Return actual achievable frequency
    return 41667000ul / ((PR4 + 1ul) * 64ul)
}
person Clifford    schedule 24.03.2019