Таймеры STM32F4 - расчет периода и предварительного масштабирования, а также создание задержки в 1 мс

Я использую STM32F407VGT6 с CubeMX.
Итак, я начал с таймеров общего назначения, и я застрял со значениями предварительного масштабирования и периода.

В основном я хочу генерировать прерывание таймера каждые n (где n = 1,2,3 ..) мс и выполнять некоторые задачи.
В формуле есть много вариантов для расчета значения периода и предварительного масштабирования

Некоторые версии формулы:

TIMupdateFreq (HZ) = Clock / ((PSC-1) * (Period-1))
Обновление события = TIM clk / ((PSC + 1) * (ARR + 1) * (RCR + 1)) < br /> Предделитель = ((((ClockSpeed) / ((период) / (1 / частота))) + 0,5) - 1)

Итак, переходя к вопросу, мои основные часы работают на 168 MHz, но я вижу, что таймер подключен к APB1 Bus, который работает на 84 MHz.

Я пробовал код, который генерирует задержку 1 мс (по словам автора), и после использования этих значений для предварительного масштабирования и периода я сгенерировал код, который также генерирует задержку 1 мс (по интуиции - без области действия).

В коде используется значение предварительной шкалы 41999 и период 1999 года.

Итак,
PSC - 41999
ARR - 1999
Применяя это ко второй формуле

Update Event = TIM clk/((PSC+1)*(ARR+1)*(RCR+1))

Update Event = 84000000/(42000*2000) = 1 (Это задержка в 1 мс ??)

Хорошо, теперь я пытаюсь понять, как выбраны эти PSC = 41999 и Period = 1999 ?? Основано ли это исключительно на предположении, поскольку в любой формуле, которую я использую, я должен предполагать одну переменную? Как рассчитать предварительную шкалу и период, если я хочу сказать 1,5, 2,3 или 4,9 что-то вроде этого точного времени ??

ИЗМЕНИТЬ

Более того, когда я использовал PSC=41999 and Period =999, значение события обновления равно 2.

Update Event = 84000000/(42000*1000) = 2

Но у меня задержка в два раза в секунду. т.е. 500 мс

и когда я использую PSC=39999 and Period =4199, значение события обновления равно 0,5.

Update Event = 84000000/(40000*4200) = 0.5

и моя задержка 2 мс.

заранее спасибо


person Ehsan Habib    schedule 18.08.2018    source источник


Ответы (3)


TIMupdateFreq (HZ) = Clock / ((PSC-1) * (Period-1))

Это явно неверно. Счетчики идут от 0 до значения регистра (включительно), всегда на один цикл больше, чем значение регистра, а не на один меньше.

Событие обновления = TIM clk / ((PSC + 1) * (ARR + 1) * (RCR + 1))

Этот лучше, но таймеры общего назначения не имеют регистров RCR. Вы можете принять RCR=0 и опустить *(RCR+1) в формуле.

Предделитель = ((((ClockSpeed) / ((период) / (1 / частота))) + 0,5) - 1)

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

Update Event = 84000000/(42000*2000) = 1 (Это задержка в 1 мс ??)

Нет, это задержка в одну секунду (1 с) или частоту 1 Гц.

как эти PSC = 41999 и Period = 1999 выбираются?

Возьмите простую формулу,

Updatefrequency = TIM clk/((PSC+1)*(ARR+1))

переставить это на

(PSC+1)*(ARR+1) = TIMclk/Updatefrequency

тогда у вас есть известное значение справа, но два неизвестных слева. Тривиальным решением было бы установить один из них, например От PSC до 0, а ARR до значения справа - 1.

К сожалению, большинство таймеров имеют только 16-битные регистры, поэтому это не сработает, когда TIMclk/Updatefrequency > 65535. И PSC, и ARR должны находиться в диапазоне от 0 до 65535. Вам нужно будет найти факторизацию, удовлетворяющую этим ограничениям.

Давайте посмотрим на пример, вам нужна задержка в 2,3 секунды. Обратите внимание, что 2,3 с - это период, а не частота, поэтому вам нужно будет подставить обратное значение в формулу.

(PSC+1) * (ARR+1) = 84000000 / (1 / 2.3) = 84000000 * 2.3 = 193200000

К счастью, в конце много нулей, вы можете просто выбрать, например, 10000 в качестве предварительного делителя (PSC=9999), а ARR становится 19320-1 = 19319. Если желаемое соотношение не является хорошим круглым числом, вам следует прибегнуть к целочисленной факторизации или написать небольшая программа для поиска всех возможных делителей (for(i=0;i<65536;i++) ...).

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

Update Event = 84000000/(42000*1000) = 2

Но у меня задержка в два раза в секунду. т.е. 500 мс

Обратите внимание на размеры. Вы используете частоты в формуле, вы делите входную частоту 84 МГц на некоторые значения и в результате получаете 2 Гц. Частота 2 Гц означает два события каждую секунду, поэтому между событиями действительно 500 мсек.

person followed Monica to Codidact    schedule 18.08.2018
comment
Спасибо за это объяснение. Я понял. - person Ehsan Habib; 18.08.2018

Нет никаких «вариаций». Существует только одна формула:

Period = (PSC+1)*(ARR+1) / TmerClockFreq в секундах Period = 1000 * (PSC+1)*(ARR+1) / TmerClockFreq в миллисекундах

Поэтому вам нужно найти ARR и PSC, которые предоставят вам время, максимально приближенное к требуемому периоду.

person 0___________    schedule 18.08.2018

Я подумал, что дам здесь более исчерпывающий ответ. Для тактовой частоты 84 МГц существует множество комбинаций предварительного делителя частоты и периода, которые будут работать. Здесь только несколько:

  PSC    ARR            F         ERROR EXACT
   1  41999  1000.000000  0.0000000000   YES
   2  27999  1000.000000  0.0000000000   YES
   3  20999  1000.000000  0.0000000000   YES
   4  16799  1000.000000  0.0000000000   YES
   5  13999  1000.000000  0.0000000000   YES
   6  11999  1000.000000  0.0000000000   YES
   7  10499  1000.000000  0.0000000000   YES
   9   8399  1000.000000  0.0000000000   YES
  11   6999  1000.000000  0.0000000000   YES
  13   5999  1000.000000  0.0000000000   YES
  14   5599  1000.000000  0.0000000000   YES
  15   5249  1000.000000  0.0000000000   YES
  19   4199  1000.000000  0.0000000000   YES

Как мне это придумать? Даже коммерческие инструменты, такие как MikroElektronica, предлагают только одну точную (или неточную) комбинацию. Как их всех найти? Я просто написал программу на Python, чтобы вычислить их все. Он классифицирует каждую как точную или отмечает относительную ошибку неточных. Изменяя допуск в верхней части программы, вы можете «сузить» или «ослабить» вычисления по мере необходимости.

Вот программа целиком:

import numpy as np
import pandas as pd

TARGET_F = 1000  # In Hz so 50.0 is 0.020 seconds period and 0.25 is 4 seconds period
CLOCK_MCU = 84000000
TOLERANCE = 0.0001

# -----------------------------------------------------


def abs_error(num1, num2):
    return abs((num1 - num2) / num1)


def hertz(clock, prescaler, period):
    f = clock / (prescaler * period)
    return f


def perfect_divisors():
    exacts = []
    for psc in range(1, 65536):
        arr = CLOCK_MCU / (TARGET_F * psc)
        if CLOCK_MCU % psc == 0:
            if arr <= 65536:
                exacts.append(psc)
    return exacts


def add_exact_period(prescaler):
    entries = []
    arr = CLOCK_MCU / (TARGET_F * prescaler)
    if arr == int(arr):
        entry = [prescaler, arr, TARGET_F, 0.0]
        entries.append(entry)
    return entries


def possible_prescaler_value():
    possibles = []
    for psc in range(1, 65536):
        if psc in exact_prescalers:
            continue
        h1 = hertz(CLOCK_MCU, psc, 1)
        h2 = hertz(CLOCK_MCU, psc, 65536)
        if h1 >= TARGET_F >= h2:
            possibles.append(psc)
    return possibles


def close_divisor(psc, tolerance):
    arr = CLOCK_MCU / (TARGET_F * psc)
    error = abs_error(int(arr), arr)
    if error < tolerance and arr < 65536.0:
        h = hertz(CLOCK_MCU, psc, int(arr))
        return psc, int(arr), h, error
    else:
        return None


#  ------------------------------------------------------------------------

# Make a dataframe to hold results as we compute them
df = pd.DataFrame(columns=['PSC', 'ARR', 'F', 'ERROR'], dtype=np.double)

# Get exact prescalars first.
exact_prescalers = perfect_divisors()
exact_values = []
for index in range(len(exact_prescalers)):
    rows = add_exact_period(exact_prescalers[index])
    for rowindex in range(len(rows)):
        df = df.append(pd.DataFrame(np.array(rows[rowindex]).reshape(1, 4), columns=df.columns))

# Get possible prescalers.
poss_prescalers = possible_prescaler_value()
close_prescalers = []
for index in range(len(poss_prescalers)):
    value = close_divisor(poss_prescalers[index], TOLERANCE)
    if value is not None:
        close_prescalers.append((value[0], value[1], value[2], value[3]))
df = df.append(pd.DataFrame(np.array(close_prescalers).reshape(len(close_prescalers), 4), columns=df.columns))

#  Adjust PSC and ARR values by -1 to reflect the way you'd code them.
df['PSC'] = df['PSC'] - 1
df['ARR'] = df['ARR'] - 1

#  Sort first by errors (zeroes and lowest errors at top of list, and
#  then by prescaler value (ascending).
df = df.sort_values(['ERROR', 'PSC'])

# Make and populate column indicating if combination is exact.
df['EXACT'] = pd.Series("?", index=df.index)
df['EXACT'] = np.where(df['ERROR'] == 0.0, "YES", "NO")

#  Format for output.
df['PSC'] = df['PSC'].map('{:.0f}'.format)
df['ARR'] = df['ARR'].map('{:.0f}'.format)
df['F'] = df['F'].map('{:.6f}'.format)
df['ERROR'] = df['ERROR'].map('{:.10f}'.format)

output = df.to_string()
print(output)
print()
print('these are the ', df.shape[0], ' total combination meeting your tolerance requirement')
exit(0)

Используя эту программу, каждый сможет с уверенностью вычислить эти значения. Я надеюсь, что это окажется полезным.

person TomServo    schedule 29.11.2018