J'utilise STM32F407VGT6
Avec CubeMX
.
Je commençais donc avec des minuteries à usage général et je suis coincé avec des valeurs de pré-échelle et de période.
Fondamentalement, je veux générer une interruption de minuterie toutes les n
(où n = 1,2,3 ..) ms et effectuer certaines tâches.
Il y a beaucoup de variations dans la formule pour calculer la valeur de la période et de la pré-échelle
Certaines versions de formule sont:
TIMupdateFreq (HZ) = Horloge/((PSC-1) * (Période-1))
Événement de mise à jour = TIM clk/((PSC + 1) * (ARR + 1) * (RCR + 1))
Prescaler = ((((ClockSpeed)/((période)/(1/fréquence))) + 0,5) - 1)
Pour en venir à la question, mon horloge principale fonctionne à 168 MHz
Mais je peux voir que le minuteur est connecté à APB1 Bus
Qui fonctionne à 84 MHz
.
J'ai essayé un code qui génère un retard de 1 ms (dit par l'auteur) et après avoir utilisé ces valeurs pour la pré-échelle et la période, j'ai généré un code qui génère également un retard de 1 ms (par intuition - pas de portée).
Le code utilise une valeur de mise à l'échelle de 41999 et une période de 1999.
Alors,
PSC - 41999
ARR - 1999
Application de ceci à la deuxième formule
Update Event = TIM clk/((PSC+1)*(ARR+1)*(RCR+1))
Update Event = 84000000/(42000*2000) = 1
(ce délai est-il de 1 ms ??)
OK alors maintenant j'essaie de comprendre comment ces PSC = 41999
Et Period = 1999
Sont sélectionnés ?? Est-ce purement basé sur l'hypothèse que dans la formule que j'utilise, je dois assumer une variable. ?? Comment calculer la pré-échelle et la période si je veux dire 1,5 ou 2,3 ou 4,9 quelque chose comme ce timing précis. ??
MODIFIER
De plus, lorsque j'ai utilisé PSC=41999 and Period =999
La valeur de l'événement de mise à jour est 2.
Update Event = 84000000/(42000*1000) = 2
Mais mon retard est deux fois par seconde. soit 500 ms
et quand j'utilise PSC=39999 and Period =4199
La valeur de l'événement de mise à jour est 0,5.
Update Event = 84000000/(40000*4200) = 0.5
et mon retard de 2 ms.
Merci d'avance
TIMupdateFreq (HZ) = Horloge/((PSC-1) * (Période-1))
C'est évidemment faux. Les compteurs passent de 0 à la valeur de registre (inclus), il y a toujours un cycle de plus que la valeur de registre, pas un de moins.
Événement de mise à jour = TIM clk/((PSC + 1) * (ARR + 1) * (RCR + 1))
Celui-ci est meilleur, mais les temporisateurs à usage général n'ont pas de registres RCR
. Vous pouvez supposer RCR=0
Et omettre *(RCR+1)
de la formule.
Prescaler = ((((ClockSpeed)/((période)/(1/fréquence))) + 0,5) - 1)
Cela tente d'arrondir le résultat, lorsqu'aucune solution entière n'est possible. Plus d'informations plus tard.
Update Event = 84000000/(42000*2000) = 1
(ce délai est-il de 1 ms ??)
Non, il s'agit d'un retard d'une seconde (1 s) ou d'une fréquence de 1 Hz.
comment ces
PSC = 41999
etPeriod = 1999
sont sélectionnés?
Prenez la formule simple,
Updatefrequency = TIM clk/((PSC+1)*(ARR+1))
réorganiser
(PSC+1)*(ARR+1) = TIMclk/Updatefrequency
alors vous avez une valeur connue sur le côté droit, mais deux inconnues sur le côté gauche. La solution triviale serait de définir l'un d'eux, par exemple PSC
à 0
et ARR
à la valeur de droite - 1.
Malheureusement, la plupart des temporisateurs n'ont que des registres 16 bits, donc cela ne fonctionnera pas lorsque TIMclk/Updatefrequency > 65535
. PSC
et ARR
doivent se situer entre 0 et 65 535. Il faudrait trouver une factorisation qui réponde à ces contraintes.
Voyons un exemple, vous voudriez un délai de 2,3 secondes. Notez que 2,3 s est la période, pas la fréquence, vous devez donc mettre son inverse dans la formule.
(PSC+1) * (ARR+1) = 84000000 / (1 / 2.3) = 84000000 * 2.3 = 193200000
Heureusement, il y a beaucoup de zéros à la fin, vous pouvez simplement choisir par exemple 10000
En tant que prédécaleur (PSC=9999
), Et ARR
devient 19320-1 = 19319
. Si le rapport souhaité n'est pas un nombre rond de Nice, vous devez alors recourir à factorisation entière , ou écrire un petit programme pour rechercher tous les diviseurs possibles (for(i=0;i<65536;i++) ...
).
Il peut également arriver qu'il n'y ait pas de solutions entières précises du tout, alors vous pouvez toujours parcourir toutes les valeurs de prédimensionnement possibles et voir celle qui donne la plus petite erreur.
Update Event = 84000000/(42000*1000) = 2
Mais mon retard est deux fois par seconde. soit 500 ms
Notez les dimensions. Vous utilisez fréquences dans la formule, vous divisez la fréquence d'entrée de 84 MHz avec quelques valeurs, et obtenez 2 Hz en conséquence. La fréquence de 2 Hz signifie deux événements par seconde, donc les événements sont en effet séparés de 500 ms.
Il n'y a pas de "variations". Une seule formule existe:
Period = (PSC+1)*(ARR+1) / TmerClockFreq
en secondes Period = 1000 * (PSC+1)*(ARR+1) / TmerClockFreq
en millisecondes
Vous devez donc trouver l'ARR & PSC qui vous donnera le temps le plus proche possible de la période requise
Je pensais que je jetterais une réponse plus complète ici. Pour une horloge à 84 MHz, il y a beaucoup combinaisons de pré-échelle et de période qui fonctionneront. Voici quelques exemples:
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
Comment puis-je trouver cela? Même les outils commerciaux comme celui de MikroElektronica ne proposent qu'une seule combinaison exacte (ou inexacte). Comment les trouver tous? J'ai simplement écrit un programme python pour les calculer tous. Il classe chacun comme exact, ou note l'erreur relative de ceux qui sont inexacts. En changeant la tolérance en haut du programme, vous pouvez "resserrer" ou "desserrer" les calculs si nécessaire.
Voici le programme dans son intégralité:
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)
En utilisant ce programme, tout le monde pourra calculer ces valeurs en toute confiance. J'espère que cela se révèle utile.