7

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

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

一些版本的公式是:

TIMupdateFreq(HZ) = 时钟/((PSC-1)*(Period-1))
更新事件 = TIM clk/((PSC+1)*(ARR+1)*(RCR+1))
预分频器 = ((( (时钟速度) / ((周期) / (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(这是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 毫秒。

提前致谢

4

3 回答 3

15

TIMupdateFreq(HZ) = 时钟/((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(这是1ms延迟吗??)

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

这个PSC = 41999Period = 1999是怎么选的?

采取简单的公式,

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

将其重新排列为

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

那么您在右侧有一个已知值,但在左侧有两个未知数。简单的解决方案是设置其中一个,例如设置PSC0ARR右侧的值 - 1。

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

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

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

幸运的是,最后有很多零,您可以选择 eg10000作为预分频器 ( 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 毫秒。

于 2018-08-18T18:33:19.180 回答
7

我想我会在这里给出更全面的答案。对于 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)

使用这个程序,每个人都可以自信地计算这些值。我希望它被证明是有用的。

于 2018-11-29T21:53:08.683 回答
6

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

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

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

于 2018-08-18T09:13:09.993 回答