Skip to content

Commit 20b5562

Browse files
committed
add: 添加定时器的API
1 parent e75737c commit 20b5562

1 file changed

Lines changed: 261 additions & 0 deletions

File tree

docs/library/timer.md

Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
---
2+
title: 硬件定时器
3+
icon: fa-solid fa-clock
4+
---
5+
6+
`HardwareTimer`库旨在提供对部分AirMCU硬件定时器功能的访问(如果需要其他功能,可以通过HAL/LL访问它们)。
7+
8+
使用该库假设您对 AirMCU 硬件定时器架构有一些基本了解。首先提醒一下,所有定时器并不等同,也不支持相同的功能。请参阅您的 MCU 的参考手册。
9+
10+
一些例子:
11+
1. `TIM6``TIM7` 没有输出的引脚,这就是为什么在可用时,它们被用于实现 `Tone``Servo`
12+
2. 有些定时器有多达 4 个输出通道,其中有 4 个互补通道,而其他定时器则没有互补通道,或者只有 1 或 2 个通道...
13+
14+
每个定时器可以提供多个通道,但是重要的是要理解同一定时器的所有通道共享相同的计数器,因此具有相同的周期/频率。
15+
16+
::: warning
17+
出于通用性目的,`HardwareTimer` 库使用所有定时器,如 16 位定时器(即使有些定时器的位数更多)。
18+
:::
19+
20+
## API接口
21+
22+
```cpp
23+
void pause(void); // Pause counter and all output channels
24+
void pauseChannel(uint32_t channel); // Timer is still running but channel (output and interrupt) is disabled
25+
void resume(void); // Resume counter and all output channels
26+
void resumeChannel(uint32_t channel); // Resume only one channel
27+
28+
void setPrescaleFactor(uint32_t prescaler); // set prescaler register (which is factor value - 1)
29+
uint32_t getPrescaleFactor();
30+
31+
void setOverflow(uint32_t val, TimerFormat_t format = TICK_FORMAT); // set AutoReload register depending on format provided
32+
uint32_t getOverflow(TimerFormat_t format = TICK_FORMAT); // return overflow depending on format provided
33+
34+
void setPWM(uint32_t channel, PinName pin, uint32_t frequency, uint32_t dutycycle, callback_function_t PeriodCallback = nullptr, callback_function_t CompareCallback = nullptr); // Set all in one command freq in HZ, Duty in percentage. Including both interrup.
35+
void setPWM(uint32_t channel, uint32_t pin, uint32_t frequency, uint32_t dutycycle, callback_function_t PeriodCallback = nullptr, callback_function_t CompareCallback = nullptr);
36+
37+
void setCount(uint32_t val, TimerFormat_t format = TICK_FORMAT); // set timer counter to value 'val' depending on format provided
38+
uint32_t getCount(TimerFormat_t format = TICK_FORMAT); // return current counter value of timer depending on format provided
39+
40+
void setMode(uint32_t channel, TimerModes_t mode, PinName pin = NC); // Configure timer channel with specified mode on specified pin if available
41+
void setMode(uint32_t channel, TimerModes_t mode, uint32_t pin);
42+
43+
TimerModes_t getMode(uint32_t channel); // Retrieve configured mode
44+
45+
void setPreloadEnable(bool value); // Configure overflow preload enable setting
46+
47+
uint32_t getCaptureCompare(uint32_t channel, TimerCompareFormat_t format = TICK_COMPARE_FORMAT); // return Capture/Compare register value of specified channel depending on format provided
48+
void setCaptureCompare(uint32_t channel, uint32_t compare, TimerCompareFormat_t format = TICK_COMPARE_FORMAT); // set Compare register value of specified channel depending on format provided
49+
50+
void setInterruptPriority(uint32_t preemptPriority, uint32_t subPriority); // set interrupt priority
51+
52+
//Add interrupt to period update
53+
void attachInterrupt(callback_function_t callback); // Attach interrupt callback which will be called upon update event (timer rollover)
54+
void detachInterrupt(); // remove interrupt callback which was attached to update event
55+
bool hasInterrupt(); //returns true if a timer rollover interrupt has already been set
56+
//Add interrupt to capture/compare channel
57+
void attachInterrupt(uint32_t channel, callback_function_t callback); // Attach interrupt callback which will be called upon compare match event of specified channel
58+
void detachInterrupt(uint32_t channel); // remove interrupt callback which was attached to compare match event of specified channel
59+
bool hasInterrupt(uint32_t channel); //returns true if an interrupt has already been set on the channel compare match
60+
void timerHandleDeinit(); // Timer deinitialization
61+
62+
// Refresh() is usefull while timer is running after some registers update
63+
void refresh(void); // Generate update event to force all registers (Autoreload, prescaler, compare) to be taken into account
64+
65+
uint32_t getTimerClkFreq(); // return timer clock frequency in Hz.
66+
67+
static void captureCompareCallback(TIM_HandleTypeDef *htim); // Generic Caputre and Compare callback which will call user callback
68+
static void updateCallback(TIM_HandleTypeDef *htim); // Generic Update (rollover) callback which will call user callback
69+
70+
// The following function(s) are available for more advanced timer options
71+
TIM_HandleTypeDef *getHandle(); // return the handle address for HAL related configuration
72+
int getChannel(uint32_t channel);
73+
int getLLChannel(uint32_t channel);
74+
int getIT(uint32_t channel);
75+
int getAssociatedChannel(uint32_t channel);
76+
#if defined(TIM_CCER_CC1NE)
77+
bool isComplementaryChannel[TIMER_CHANNELS];
78+
#endif
79+
```
80+
81+
## 使用方式
82+
83+
1. `HardwareTimer` 是一个 C++ 类,要做的第一件事是以 `TIM` 实例作为参数实例化一个对象。
84+
85+
::: note
86+
有些实例由 Servo、Tone 和 SoftSerial 使用(请参阅 TIMER_SERVO、TIMER_TONE 和 TIMER_SERIAL),但仅在使用时使用。只要确保与您自己的使用没有冲突即可。
87+
:::
88+
89+
```cpp
90+
HardwareTimer *MyTim = new HardwareTimer(TIM3); // TIM3 is MCU hardware peripheral instance, its definition is provided in CMSIS
91+
```
92+
93+
2. 然后就可以配置通道的模式。
94+
95+
::: note
96+
无需配置引脚模式(输出/输入/AlternateFunction),它将由 HardwareTimer 库自动完成。
97+
:::
98+
99+
::: note
100+
通道范围[1..4],但并非所有定时器都支持4个通道。
101+
:::
102+
103+
```cpp
104+
MyTim->setMode(channel, TIMER_OUTPUT_COMPARE_PWM1, pin);
105+
```
106+
107+
支持模式有:
108+
109+
```cpp
110+
typedef enum {
111+
TIMER_DISABLED, // == TIM_OCMODE_TIMING no output, useful for only-interrupt
112+
// Output Compare
113+
TIMER_OUTPUT_COMPARE, // == Obsolete, use TIMER_DISABLED instead. Kept for compatibility reason
114+
TIMER_OUTPUT_COMPARE_ACTIVE, // == TIM_OCMODE_ACTIVE pin is set high when counter == channel compare
115+
TIMER_OUTPUT_COMPARE_INACTIVE, // == TIM_OCMODE_INACTIVE pin is set low when counter == channel compare
116+
TIMER_OUTPUT_COMPARE_TOGGLE, // == TIM_OCMODE_TOGGLE pin toggles when counter == channel compare
117+
TIMER_OUTPUT_COMPARE_PWM1, // == TIM_OCMODE_PWM1 pin high when counter < channel compare, low otherwise
118+
TIMER_OUTPUT_COMPARE_PWM2, // == TIM_OCMODE_PWM2 pin low when counter < channel compare, high otherwise
119+
TIMER_OUTPUT_COMPARE_FORCED_ACTIVE, // == TIM_OCMODE_FORCED_ACTIVE pin always high
120+
TIMER_OUTPUT_COMPARE_FORCED_INACTIVE, // == TIM_OCMODE_FORCED_INACTIVE pin always low
121+
122+
//Input capture
123+
TIMER_INPUT_CAPTURE_RISING, // == TIM_INPUTCHANNELPOLARITY_RISING
124+
TIMER_INPUT_CAPTURE_FALLING, // == TIM_INPUTCHANNELPOLARITY_FALLING
125+
TIMER_INPUT_CAPTURE_BOTHEDGE, // == TIM_INPUTCHANNELPOLARITY_BOTHEDGE
126+
127+
// Used 2 channels for a single pin. One channel in TIM_INPUTCHANNELPOLARITY_RISING another channel in TIM_INPUTCHANNELPOLARITY_FALLING.
128+
// Channels must be used by pair: CH1 with CH2, or CH3 with CH4
129+
// This mode is very useful for Frequency and Dutycycle measurement
130+
TIMER_INPUT_FREQ_DUTY_MEASUREMENT,
131+
132+
TIMER_NOT_USED = 0xFFFF // This must be the last item of this enum
133+
} TimerModes_t;
134+
```
135+
136+
3. 然后就可以配置`PrescalerFactor`。定时器时钟将除以该因子(如果定时器时钟为 10Khz,预分频器因子为 2,则定时器将以 5kHz 计数)。
137+
138+
:::note
139+
将方法 `setOverflow``format == MICROSEC_FORMAT``format == HERTZ_FORMAT` 一起使用时,预分频器的配置是自动的。
140+
:::
141+
142+
::: note
143+
预分频器用于定时器计数器,因此对所有通道都是通用的。
144+
:::
145+
146+
::: note
147+
预分频器因子范围:[1..0x10000](硬件寄存器范围为[0..0xFFFF])。
148+
:::
149+
150+
```cpp
151+
MyTim->setPrescaleFactor(8);
152+
```
153+
154+
4. 然后就可以配置溢出(也称为翻转或更新)。
155+
156+
对于输出,它对应于周期或频率。
157+
158+
对于输入捕获,建议使用最大值:0x10000,以避免在捕获发生之前发生翻转。
159+
160+
::: note
161+
162+
将方法 setOverflow 与 format == MICROSEC_FORMAT 或 format == HERTZ_FORMAT 一起使用时,预分频器的配置是自动的。
163+
164+
溢出是所有通道共有的。
165+
166+
溢出范围:[1..0x10000](硬件寄存器的范围为[0..0xFFFF])。
167+
168+
:::
169+
170+
```cpp
171+
MyTim->setOverflow(10000); // Default format is TICK_FORMAT. Rollover will occurs when timer counter counts 10000 ticks (it reach it count from 0 to 9999)
172+
MyTim->setOverflow(10000, TICK_FORMAT);
173+
MyTim->setOverflow(10000, MICROSEC_FORMAT); // 10000 microseconds
174+
MyTim->setOverflow(10000, HERTZ_FORMAT); // 10 kHz
175+
```
176+
177+
5. 然后可以配置 CaptureCompare(通道特定的 CaptureCompare 寄存器)。
178+
179+
::: note
180+
CaptureCompare 仅适用于一个通道。
181+
182+
CaptureCompare 范围:[0.. 0xFFFF]
183+
:::
184+
185+
```cpp
186+
MyTim->setCaptureCompare(channel, 50); // Default format is TICK_FORMAT. 50 ticks
187+
MyTim->setCaptureCompare(channel, 50, TICK_FORMAT)
188+
MyTim->setCaptureCompare(channel, 50, MICROSEC_COMPARE_FORMAT); // 50 microseconds between counter resetand compare
189+
MyTim->setCaptureCompare(channel, 50, HERTZ_COMPARE_FORMAT); // 50 Hertz -> 1/50 seconds between counterreset and compare
190+
MyTim->setCaptureCompare(channel, 50, RESOLUTION_8B_COMPARE_FORMAT); // used for Dutycycle: [0.. 255]
191+
MyTim->setCaptureCompare(channel, 50, RESOLUTION_12B_COMPARE_FORMAT); // used for Dutycycle: [0.. 4095]
192+
```
193+
194+
可以在更新中断(翻转)和/或捕获/比较中断上附加用户回调。如果未指定通道,则用户回调将附加到更新事件。请注意,更新中断标志 (UIF) 在更新事件发生并生成中断时设置,并在执行用户回调之前由 HAL 驱动程序自动清除。用户回调无需显式清除 UIF。
195+
196+
```cpp
197+
MyTim->attachInterrupt(Update_IT_callback); // Userdefined call back. See 'Examples' chapter to see how to use callback with or without parameter
198+
MyTim->attachInterrupt(channel, Compare_IT_callback); // Userdefined call back. See 'Examples' chapter to see how to use callback with or without parameter
199+
```
200+
201+
6. 现在可以启动定时器了
202+
203+
::: note
204+
同一定时器的所有通道同时启动(因为每个定时器只有 1 个计数器)。
205+
:::
206+
207+
```cpp
208+
MyTim->resume();
209+
```
210+
211+
计时器可以暂停然后恢复
212+
213+
```cpp
214+
MyTim->pause();
215+
// ...
216+
MyTim->resume();
217+
```
218+
219+
以下是完整 PWM 配置的示例:
220+
221+
```cpp
222+
MyTim->setMode(channel, TIMER_OUTPUT_COMPARE_PWM1, pin);
223+
// MyTim->setPrescaleFactor(8); // Due to setOverflow with MICROSEC_FORMAT, prescaler will be computedautomatically based on timer input clock
224+
MyTim->setOverflow(100000, MICROSEC_FORMAT); // 10000 microseconds = 10 milliseconds
225+
MyTim->setCaptureCompare(channel, 50, PERCENT_COMPARE_FORMAT); // 50%
226+
MyTim->attachInterrupt(Update_IT_callback);
227+
MyTim->attachInterrupt(channel, Compare_IT_callback);
228+
MyTim->resume();
229+
```
230+
231+
为了简化基本 PWM 配置,提供了专用的一体化 API。溢出/频率以赫兹为单位,占空比以百分比为单位。
232+
233+
```cpp
234+
MyTim->setPWM(channel, pin, 5, 10, NULL, NULL); // No callback required, we can simplify the function call
235+
MyTim->setPWM(channel, pin, 5, 10); // 5 Hertz, 10% dutycycle
236+
```
237+
238+
一些额外的 API 允许检索配置:
239+
240+
```cpp
241+
getPrescaleFactor();
242+
getOverflow();
243+
getCaptureCompare(); // In InputCapture mode, this method doesn't retrieve configuration but retrieve thecaptured counter value
244+
getCount();
245+
```
246+
247+
另外,要使用中断回调:
248+
249+
```cpp
250+
detachInterrupt()
251+
```
252+
253+
::: note
254+
一旦计时器启动并启用回调,您可以通过 `detachInterrupt` 和 `attachInterrupt` 自由禁用和启用回调,次数不限。但是,如果第一个 resume (= 计时器启动)在调用 `attachInterrupt` 之前完成,则 `HardwareTimer` 将无法稍后附加中断(出于性能原因,计时器将启动禁用中断)
255+
:::
256+
257+
如果在定时器运行时分离和附加中断,您还可以通过该方法知道是否已经附加了回调(无需在外部跟踪它)
258+
259+
```cpp
260+
hasInterrupt()
261+
```

0 commit comments

Comments
 (0)