STM32F4定时器 - 计算周期和分频,以生成1毫秒延迟

8

我正在使用STM32F407VGT6CubeMX。所以我开始使用通用定时器,但是我卡在了预分频和周期值上。

基本上,我想每n毫秒(其中n=1,2,3..)生成一个定时器中断并执行一些任务。 有很多公式变体来计算周期和预分频的值。

一些公式版本如下:

TIMupdateFreq(HZ) = Clock/((PSC-1)*(Period-1))
Update Event = TIM clk/((PSC+1)*(ARR+1)*(RCR+1))
Prescaler = ((((ClockSpeed) / ((period) / (1 / frequency))) + 0.5) - 1)

那么问题来了,我的核心时钟运行在168 MHz,但我可以看到定时器连接到运行在84 MHz的APB1总线上。

我尝试了生成1毫秒延迟的代码(根据作者),并在使用预分频和周期值后生成了可以生成1毫秒延迟的代码(凭直觉 - 没有示波器)。

该代码使用预分频值为41999和周期为1999。

因此,
PSC - 41999
ARR - 1999
将其应用于第二个公式

更新事件 = TIM时钟/((PSC+1)*(ARR+1)*(RCR+1))

更新事件 = 84000000/(42000*2000) = 1(这是1毫秒的延迟吗?)

好的,现在我正在尝试理解如何选择 PSC = 41999Period = 1999??它是纯粹基于假设,就像无论我使用什么公式,我都必须假设一个变量?如果我想要1.5或2.3或4.9这样精确的时间,如何计算预分频和周期?

此外,当我使用 PSC=41999Period =999 时,更新事件值为2:

更新事件 = 84000000/(42000*1000) = 2

但我的延迟每秒都会加倍。即500毫秒。

当我使用 PSC=39999Period=4199 时,更新事件值为0.5:

更新事件 = 84000000/(40000*4200) = 0.5

我的延迟是2毫秒。

3个回答

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

重新排列它

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

如果方程右边的值已知,但左边有两个未知数。一种简单解决方法是将其中一个设为0,例如PSC设为0ARR设为右侧的值减1。

不幸的是,大多数定时器仅具有16位寄存器,因此当 TIMclk/Updatefrequency > 65535 时,此方法行不通。PSCARR必须都介于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 MHz输入频率除以一些值,得到结果为2 Hz。2 Hz 频率意味着每秒两次事件,因此事件的间隔确实为500毫秒。


谢谢您的解释。我现在明白了。 - Ehsan Habib

10

我想在这里提供一个更全面的答案。对于一个84MHz的时钟,有很多预分频和周期的组合可以使用。以下只是其中几个:

  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)

使用这个程序,每个人都能有信心地计算这些值。希望它能够证明有用。

6

没有所谓的“变化”。只有一个公式存在:

Period = (PSC+1)*(ARR+1) / TmerClockFreq 单位为秒 Period = 1000 * (PSC+1)*(ARR+1) / TmerClockFreq 单位为毫秒

因此,您需要找到最接近所需周期时间的ARR和PSC值。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接