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?
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) = 2
und (ARR+1) = 36000
,
was gibt PSC = 1
und 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!
@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.
Scott Seidman
bitsmack
Scott Seidman
Motor