Verständnis der Einrichtung eines Timers auf einem STM32F10x

Ich versuche zu verstehen, wie man den Timer auf einem STM32F10x richtig einrichtet.

Das Board läuft mit einem externen Quarz von 16 MHz, und ich verwende die PLL:

/* PLLCLK = 16MHz / 2 * 9 = 72 MHz */
RCC_PLLConfig(RCC_PLLSource_HSE_Div2, RCC_PLLMul_9);

Das Board läuft also mit 72 MHz. Ich konfiguriere den Timer wie folgt:

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
TIM_TimeBaseInitTypeDef timerInitstructure;
timerInitstructure.TIM_Prescaler =72000-1;
timerInitstructure.TIM_CounterMode = TIM_CounterMode_Up;
timerInitstructure.TIM_Period=1;
timerInitstructure.TIM_ClockDivision = TIM_CKD_DIV1;
timerInitstructure.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM3,&timerInitstructure);
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM3,ENABLE);

Um sicherzustellen, dass ich die richtige Frequenz einstelle, schalte ich einen Pin mit dem Interrupt um, aber wenn ich mit dem Oszilloskop messe, bekomme ich 2,784 kHz. Kann mir jemand sagen, warum ich diese Frequenz bekomme?

Antworten (2)

Ich schrieb eine längere Antwort, bevor ich die einfache Lösung erkannte. Ich füge die vollständige Antwort hinzu, falls sie hilfreich ist.


Die schnelle Antwort: Die an die Funktion TIM_TimeBaseInit() übergebenen Werte sind nur 16-Bit, also ist 69999 ein ungültiger Wert. Sie müssen die Periode und den Prescaler so wählen, dass beide unter 65536 liegen.

Es gibt jedoch ein zweites Problem, also lies bitte weiter :)


Die ausführliche Antwort:

Es sieht so aus, als ob Sie einen Takt von 1 kHz (1 ms) anstreben?

Hier ist die Grundgleichung, wobei PSC der Prescaler und ARR die Periode ist ("Auto Reload Register"):

(PSC+1)(ARR+1) = (EventTime)(ClkFreq)

Für 1 ms:

(PSC+1)(ARR+1) = (1ms)(72MHz) = 72000

Jetzt können Sie einen beliebigen Satz von Werten auswählen, um dies wahr zu machen, solange sie jeweils 16 Bit nicht überschreiten. Ich entschied mich:

(PSC+1) = 2und (ARR+1) = 36000,

was gibt PSC = 1und ARR = 35999.

Stellen Sie dann die Uhr so ​​ein, wie Sie es getan haben.

In Ihrem Fall wählen Sie ARR=1 und PSC=71999. Umdrehen der Gleichungen:

EventTime = (PSC+1)(ARR+1)/ClkFreq

EventTime = (1+1)(71999+1)/72MHz = 2ms, was nicht das ist, wonach Sie suchen.

Natürlich ist das auch nicht wirklich das, was Sie bekommen, wegen des bereits erwähnten Problems mit der Größe des Prescalers.


Übrigens, wie @ScottSeidman betont, ist der Timer oft richtig eingestellt, die Uhr selbst jedoch nicht. Die Uhrbäume sind überraschend kompliziert! Eine Möglichkeit, die Uhren zu überprüfen, besteht darin, die RCC_MCOConfig()Funktion zu verwenden (oder das RCC_CFGR-Register zu sehen). Sie können verwendet werden, um die internen Takte direkt auf den MCO-Pin auszugeben.

Viel Glück!

2 ms würden einen 500-Hz-Timer erzeugen, und das OP nähert sich 5 kHz (einer 2,7-kHz-Rechteckwelle). Liegt das an der ungültigen Nummer, die an die Struktur übergeben wurde?
@ScottSeidman Ja, ich habe diesen Teil geschrieben, bevor ich das 16-Bit-Größenproblem erkannte. Ich habe meine Antwort nur zur Verdeutlichung etwas bearbeitet. Danke :)
Der Vollständigkeit halber zum Rest der STM32-ARM-Cortex-Familie möchte ich hinzufügen, dass das Problem oft genau das Gegenteil ist – der Timer ist richtig eingestellt und die Systemuhr ist falsch! Dies ist weniger wahrscheinlich für die F1, wo die Uhr ziemlich einfach ist, aber ein echtes Problem für die F4 und dergleichen, wo ziemlich geheimnisvolle Excel-basierte Uhr-Setup-Routinen verwendet werden, um Startdateien bereitzustellen. Tatsächlich überprüfe ich oft meine Uhreinstellung, indem ich ein wenig mit einem Timer umschalte!
Nun, ich weiß nicht, ob ich für diese großartige Antwort dankbar genug sein könnte. vielen Dank

@Bitsmack hat eine großartige Antwort gegeben, aber es gibt einen weiteren Parameter, der nicht erwähnt wurde: TIM_ClockDivision. Es ist einfach der Hardware-Taktdivisor, der zwischen der Busuhr und dem Zähler sitzt und diskrete Werte von 1, 2 oder 4 hat, wenn der Speicher dient. Im Beispiel des OP ist es 1 (TIM_CKD_DIV1). Wenn Sie also ClkFreq aus irgendeinem Grund in einen Bereich bringen müssen, in dem Sie 16-Bit-Werte für PSC und/oder ARR verwenden können, ist dieser Parameter nützlich. In diesem Fall nicht so sehr, aber wenn Sie es mit Kernen mit höheren Taktfrequenzen zu tun haben, dann vielleicht doch. Auch wenn Sie eine längere Timer-Dauer (Periode) benötigen. Die Formel von @bitsmack könnte also folgendermaßen geschrieben werden:

(PSC+1)(ARR+1) = (EventTime)[(ClkFreq)/ClkDiv]

Eine intuitive Art, sich einfache Timer vorzustellen, ist, dass die Timer-Ereignisfrequenz (Anmerkung: nicht die Ereigniszeit) einfach der Eingangstakt geteilt durch jeden dieser Parameter ist:

EventFreq = ClkFreq/ClkDiv/(PSC+1)/(ARR+1), and
EventTime = 1/EventFreq

was uns zu Bitsmacks Formel bringt. Sie können Ihre Anforderung entweder als Ereigniszeitintervallanforderung (ich möchte einen Timer mit einer Periode von 1 ms) oder als Ereignisfrequenzanforderung (ich möchte eine Interruptrate von 1 kHz) formulieren, die beide von den obigen Formeln bedient werden.