Timer nei microcontrollori ST
Una fondamentale periferica nei microcontrollori ST, come in tutti gli altri, è il timer.
Sono presenti timers con risoluzione diversa a seconda di ogni modello di scheda. La Nucleo F401RE, per esempio, è dotata di sette timers: TIM1, TIM3, TIM4, TIM9 e TIM11 con risoluzione a 16 bit; i timers TIM2 e TIM5 con risoluzione a 32 bit. Per altri modelli, verificare sul sito ufficiale ST Microelectronics.
Le funzioni che possono essere svolte da un timer sono molteplici:
- semplice generatore di ritardo (analogo alla HAL_Delay(...)) non bloccante per il processore in toto;
- input capture, misurare la durata degli impulsi di segnale in ingresso, come segnali da encoder o altre sorgenti di impulsi;
- output compare, generare segnali di uscita in momenti specifici, sincronizzati con altri eventi;
- generare interrupt a intervalli regolari per eseguire routine di servizio dell'interrupt (ISR);
- IMPORTANTE: generazione di segnali PWM.
![]() |
Figura 1: sorgente del timer. |
I parametri fondamentali di un timer sono:
- Contatore: registro interno che conta gli impulsi, della dimensione pari a ARR ;
- Prescaler: divide la frequenza della sorgente di clock per una costante reale, definita di prescaler (PSC). Solitamente è un valore a 16 bit, quindi può raggiungere al massimo il valore 65535. La frequenza del TIMx vale dunque:
- Auto Reload Register (ARR): il valore di questo registro definisce il massimo di conteggi che il contatore del timer TIMx può effettuare prima di azzerarsi (figura 2). I conteggi avvengono a ogni fronte di salita del timer. Non appena il contatore raggiunge il valore ARR, viene resettato, generando un'interrupt;
Il valore ARR viene utile nel calcolo dell'istante di generazione di un evento, a partire dall'inizio del conteggio, utile a inviare un segnale di interruzione, ad esempio:Figura 2: contatore del timer TIMx.
- Capture/Compare Register (CCR): registro interno utilizzato per catturare il valore del contatore in risposta a un evento esterno (capture) oppure commutare lo stato di un uscita non appena il valore inserito nel suddetto registro viene raggiunto dal contatore (compare).
I valori di prescaler e ARR sono impostabili dal programmatore in fase MX, ossia nell'ambiente STM32CubeIDE in fase di costruzione del progetto, e non nella scrittura del firmware (figura 3).
Attenzione! Scelto il valore di prescaler, detto F, indicare nella casella PSC il valore scelto "F-1", come mostrato in figura 4 un esempio, con PSC = 84.
Allo stesso modo per il valore ARR.
![]() |
Figura 4: prescaler di 84. |
Impostazione del timer e scelta della funzione:
Prima di tutto è necessario creare un progetto e impostare il clock a dovere.
Dopo aver impostato la sorgente di CLK e impostato i valori di PSC e ARR, è ora necessario scegliere una funzione. I vari timers possono avere più di un canale di comunicazione.
Nella schermata Pinout & Configurations recarsi nella sezione Timers e scegliere un timer. Per semplicità, si sceglierà il timer TIM1.
![]() |
Figura 5: attivazione del timer. |
Dopo aver scelto la sorgente del clock, tipicamente Clock Source -> Internal Clock, scegliere un canale e impostare la funzione (figura 6) tra quelle presenti di maggiore rilevanza:
- Input Capture direct mode;
- Output Compare CH1;
- PWM Generation CH1 (figura 7).
![]() | ||
Figura 6: funzioni del timer TIM1 CH1.
|
Non è sempre necessario scegliere una funzione tra quelle proposte. La scelta della funzione nel canale può anche essere lasciata su Disable. Per generare, ad esempio, un delay con periodo personalizzato, non è necessario né una Capture, né una Compare e tantomeno la generazione del segnale PWM.
Nella sezione configuration, inoltre, deve essere anche abilitata l'interruzione richiesta, nella sezione NVIC Settings (figura 8) tra le quali, si indicano TIMx update interrupt... che genera l'interruzione non appena il contatore ha raggiunto il valore ARR, e TIMx capture compare interrupt che genera l'interruzione nel momento in cui il valore del registro CCR viene modificato da un input (modalità capture) oppure il valore del contatore è pari a quello del CCR (modalità compare).
![]() |
Figura 8: interruzioni abilitabili. |
Alcune primitive fondamentali
Vengono qui di seguito esposte alcune primitive necessarie e utili all'utilizzo dei timers:
- TIM_HandleTypeDef *htim : struttura dati predefinita del timer, contiene intrinsecamente tutti i valori settati (PSC, ARR, CCR, ...). I canali di ogni timer sono definiti nella forma TIM_CHANNEL_1, TIM_CHANNEL_2, tanti quanti sono i canali di un singolo timer;
- HAL_TIM_Base_Start(TIM_HandleTypeDef *htim): avvia il timer e il rispettivo conteggio in modalità normale. Ricordarsi sempre di passare la struttura dati htim per riferimento (&htim1 ad esempio);
- HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim): analoga alla precedente, ma abilita le interruzioni da timer;
- HAL_TIM_Base_Stop(TIM_HandleTypeDef *htim) oppure HAL_TIM_Base_Stop_IT(TIM_HandleTypeDef *htim): ferma il conteggio del timer;
- HAL_TIM_OC_Start(TIM_HandleTypeDef *htim, uint32_t Channel) oppure HAL_TIM_OC_Start_IT(TIM_HandleTypeDef *htim, uint32_t Channel): avvia il conteggio del timer in modalità output compare (OC) senza o con interruzione (IT). Deve essere specificato, tra gli argomenti, anche il canale del timer;
- HAL_TIM_OC_Stop(TIM_HandleTypeDef *htim, uint32_t Channel) oppure HAL_TIM_OC_Stop_IT(TIM_HandleTypeDef *htim, uint32_t Channel) ferma il conteggio del timer in modalità output compare;
- HAL_TIM_IC_Start(TIM_HandleTypeDef *htim, uint32_t Channel) oppure HAL_TIM_IC_Start_IT(TIM_HandleTypeDef *htim, uint32_t Channel): avvia il conteggio del timer in modalità capture. Ovviamente vi sono le corrispettive che fermano il conteggio: HAL_TIM_IC_Stop(TIM_HandleTypeDef *htim, uint32_t Channel) e HAL_TIM_IC_Stop_IT(TIM_HandleTypeDef *htim, uint32_t Channel);
- HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel) oppure HAL_TIM_PWM_Start_IT(TIM_HandleTypeDef *htim, uint32_t Channel): avvia il conteggio del timer in modalità PWM senza o con interruzione (IT). Deve essere specificato, tra gli argomenti, anche il canale del timer;
- HAL_TIM_PWM_Stop(TIM_HandleTypeDef *htim, uint32_t Channel) oppure HAL_TIM_PWM_Stop_IT(TIM_HandleTypeDef *htim, uint32_t Channel): ferma il conteggio del timer in modalità PWM senza o con interruzione (IT);
- HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim): gestore dell'interruzione a seguito del raggiungimento di fine conteggio (ARR). Questo è un metodo personale void, al cui interno il programmatore deciderà cosa accade nel momento in cui viene generata l'interrupt da timer. Altre tipologie di CallBack possono essere fatte dalla funzione Output Compare (HAL_TIM_OC_DelayElapsedCallback)in cui l'interruzione è generata al raggiungimento del valore richiesto dal CCR.
__HAL_TIM_SET_COUNTER(__HANDLE__,__VALUE__) e __HAL_TIM_GET_COUNTER(__HANDLE__) I due metodi hanno a che fare con il registro contatore associato al timer. Il primo imposta un valore __VALUE__ da associare al contatore del timer. Il secondo, invece, preleva soltanto il valore associato al contatore nell'istante in cui viene chiamato.
Allo stesso modo, per il registro ARR, esistono i metodi __HAL_TIM_GET_AUTORELOAD(__HANDLE__) e __HAL_TIM_SET_AUTORELOAD(__HANDLE__, __VALUE__). La prima legge il valore del registro ARR, la seconda imposta un valore scelto dal programmatore.
Commenti
Posta un commento