STM32F4 定时器 - 计算周期和预分频,并产生 1 ms 延迟

STM32F4 Timers - Calculation of Period and Prescale, and Generating 1 ms Delay

我正在使用 STM32F407VGT6CubeMX
所以我从通用定时器开始,我被预分频和周期值困住了。

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

一些版本的公式是:

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,但我可以看到定时器连接到 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(这是1ms延迟吗??)

好的,现在我想了解如何选择 PSC = 41999Period = 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 毫秒。

提前致谢

没有"variations"。只有一个公式存在:

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

因此您需要找到 ARR 和 PSC,这将使您的时间尽可能接近所需的时间

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

这显然是错误的。计数器从0到寄存器值(含),总是比寄存器值多一个周期,不能少一个。

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

这个更好,但是通用定时器没有 RCR 寄存器。您可以假定 RCR=0,并从公式中省略 *(RCR+1)

Prescaler = ((((ClockSpeed) / ((period) / (1 / frequency))) + 0.5) - 1)

当没有可能的整数解时,这会尝试对结果进行舍入。稍后详细介绍。

Update Event = 84000000/(42000*2000) = 1 (Is this 1ms Delay??)

不,这是一秒 (1s) 延迟,或 1 Hz 频率。

how this PSC = 41999 and Period = 1999 are selected?

采用简单的公式,

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

重新排列为

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

然后你在右手边有一个已知值,但在左手边有两个未知数。简单的解决方案是设置其中之一,例如PSC0ARR 到右侧值 - 1.

不幸的是,大多数定时器只有 16 位寄存器,所以这在 TIMclk/Updatefrequency > 65535 时不起作用。 PSCARR 都必须介于 0 和 65535 之间。 您必须找到满足这些约束的因式分解。

让我们看一个例子,你想要延迟 2.3 秒。请注意,2.3s 是周期,而不是频率,因此您需要将其倒数代入公式。

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

幸运的是最后有很多零,你可以选择例如10000 作为预分频器 (PSC=9999),ARR 变为 19320-1 = 19319。如果所需的比率不是一个很好的整数,那么您应该求助于 integer factorization,或者编写一个小程序来查找所有可能的除数 (for(i=0;i<65536;i++) ...)。

也有可能根本没有精确的整数解,那你还是可以遍历所有可能的预分频器值,看看哪个给出的误差最小。

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

But my delay is twice in every sec. i.e 500ms

注意尺寸。您在公式中使用 frequencies,将 84 MHz 输入频率除以一些值,得到 2 Hz 结果。 2 Hz 频率意味着每秒发生两个事件,因此事件确实相隔 500 毫秒。

我想我应该在这里给出一个更全面的答案。对于 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 程序来计算它们。它将每个分类为精确的,或记录不精确的相对误差。通过更改程序顶部的公差,您可以根据需要 "tighten" 或 "loosen" 进行计算。

完整的程序如下:

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)

使用这个程序,每个人都可以自信地计算出这些值。希望有用。