## Arduino Ticker 模块 API 手册

### 1. 概述

Ticker 是一个用于定时调用函数的库，提供了简单易用的软件定时器功能。它支持周期性和单次触发两种模式，可以在指定的时间间隔后执行回调函数。Ticker 使用共享的软件定时器资源，支持创建多个 Ticker 实例。

### 2. API 介绍

Ticker 类位于 `arduino` 命名空间中。

#### 2.1 构造函数

```cpp
Ticker()
```

创建一个新的 Ticker 实例。

**参数**
无

#### 2.2 析构函数

```cpp
~Ticker()
```

销毁 Ticker 实例并自动停止定时器。

#### 2.3 `attach` 方法

```cpp
void attach(float seconds, callback_function_t callback)
```

以秒为单位设置周期性定时器。

**参数**

- `seconds`: 定时周期（秒），支持浮点数
- `callback`: 回调函数，类型为 `std::function<void(void)>`

**返回值**
无

#### 2.4 `attach_ms` 方法

```cpp
void attach_ms(uint64_t milliseconds, callback_function_t callback)
```

以毫秒为单位设置周期性定时器。

**参数**

- `milliseconds`: 定时周期（毫秒），最小值为1ms
- `callback`: 回调函数

**返回值**
无

#### 2.5 `attach` 方法（带参数版本）

```cpp
template<typename TArg> 
void attach(float seconds, void (*callback)(TArg), TArg arg)
```

设置带参数的周期性定时器。

**参数**

- `seconds`: 定时周期（秒）
- `callback`: 回调函数指针
- `arg`: 传递给回调函数的参数

**返回值**
无

**注意**
参数大小必须不超过 `sizeof(void*)`

#### 2.6 `attach_ms` 方法（带参数版本）

```cpp
template<typename TArg> 
void attach_ms(uint64_t milliseconds, void (*callback)(TArg), TArg arg)
```

以毫秒为单位设置带参数的周期性定时器。

**参数**

- `milliseconds`: 定时周期（毫秒）
- `callback`: 回调函数指针
- `arg`: 传递给回调函数的参数

**返回值**
无

#### 2.7 `once` 方法

```cpp
void once(float seconds, callback_function_t callback)
```

设置单次触发定时器（秒）。

**参数**

- `seconds`: 延迟时间（秒）
- `callback`: 回调函数

**返回值**
无

#### 2.8 `once_ms` 方法

```cpp
void once_ms(uint64_t milliseconds, callback_function_t callback)
```

设置单次触发定时器（毫秒）。

**参数**

- `milliseconds`: 延迟时间（毫秒）
- `callback`: 回调函数

**返回值**
无

#### 2.9 `once` 方法（带参数版本）

```cpp
template<typename TArg> 
void once(float seconds, void (*callback)(TArg), TArg arg)
```

设置带参数的单次触发定时器。

**参数**

- `seconds`: 延迟时间（秒）
- `callback`: 回调函数指针
- `arg`: 传递给回调函数的参数

**返回值**
无

#### 2.10 `once_ms` 方法（带参数版本）

```cpp
template<typename TArg> 
void once_ms(uint64_t milliseconds, void (*callback)(TArg), TArg arg)
```

以毫秒为单位设置带参数的单次触发定时器。

**参数**

- `milliseconds`: 延迟时间（毫秒）
- `callback`: 回调函数指针
- `arg`: 传递给回调函数的参数

**返回值**
无

#### 2.11 `detach` 方法

```cpp
void detach()
```

停止定时器并解除回调函数。

**参数**
无

**返回值**
无

#### 2.12 `active` 方法

```cpp
bool active() const
```

检查定时器是否处于活动状态。

**参数**
无

**返回值**

- `true`: 定时器正在运行
- `false`: 定时器已停止

### 3. 使用说明

1. **最小定时周期**：由于底层使用1ms的基础定时器，所有定时器都会对齐到1ms。

2. **多实例支持**：多个 Ticker 共享同一定时器。如果需要多个实例且精度要求较高，推荐优先使用硬件 Timer 。

3. **回调函数限制**：回调函数应该尽快执行完毕，避免长时间阻塞，例如打印太多log将影响定时器周期。

### 4. 示例程序

```cpp
#include "Arduino.h"

using namespace arduino;

#define LED_PIN 52

// 测试状态
enum TestPhase {
    TEST_BASIC,
    TEST_MULTI,
    TEST_DONE
};

TestPhase currentPhase = TEST_BASIC;
uint32_t phaseStartTime = 0;

// 计数器
volatile uint32_t timer0_count = 0;
volatile uint32_t timer1_count = 0;
volatile uint32_t timer2_count = 0;
volatile uint32_t timer3_count = 0;
volatile bool led_state = false;

// Ticker对象
Ticker ticker0;
Ticker ticker1;
Ticker ticker2;
Ticker ticker3;
Ticker oneShotTicker;

// 基础测试回调
void basicCallback() {
    timer0_count++;
    led_state = !led_state;
    digitalWrite(LED_PIN, led_state);
}

// 多定时器测试回调
void timer0Callback() {
    timer0_count++;
}

void timer1Callback() {
    timer1_count++;
}

void timer2Callback() {
    timer2_count++;
}

void timer3Callback() {
    timer3_count++;
    led_state = !led_state;
    digitalWrite(LED_PIN, led_state);
}

void setup() {
    Serial.begin(115200);
    delay(1000);

    Serial.println("\n=== K230 Ticker Test (Quick Version) ===");
    Serial.println("Tests: Basic functionality & Multi-ticker");
    Serial.println("Total test time: ~15 seconds\n");

    pinMode(LED_PIN, OUTPUT);
    digitalWrite(LED_PIN, LOW);

    runBasicTest();
}

void loop() {
    uint32_t elapsed = millis() - phaseStartTime;

    switch(currentPhase) {
    case TEST_BASIC:
        if (elapsed >= 5000) {  // 5秒基础测试
            Serial.print("Basic test complete. Triggers: ");
            Serial.println(timer0_count);
            currentPhase = TEST_MULTI;
            runMultiTickerTest();
        }
        break;

    case TEST_MULTI:
        if (elapsed >= 10000) {  // 10秒多定时器测试
            showResults();
            currentPhase = TEST_DONE;
        } else if (elapsed % 2000 == 0) {  // 每2秒显示一次进度
            Serial.print(".");
        }
        break;

    case TEST_DONE:
        // 测试完成，空循环
        break;
    }

    delay(100);
}

void runBasicTest() {
    Serial.println("1. Basic Ticker Test");
    Serial.println("   - Periodic mode: 200ms");
    Serial.println("   - One-shot test: 2s delay");

    // 测试周期模式
    ticker0.attach_ms(200, basicCallback);  // 200ms周期

    Serial.println("   LED blinking at 5Hz...");
    delay(3000);  // 运行3秒

    // 停止周期定时器
    ticker0.detach();
    timer0_count = 0;

    // 测试单次模式
    Serial.println("Testing one-shot ticker...");
    oneShotTicker.once(2.0, []() {  // 2秒延迟
                       Serial.println("   One-shot triggered!");
                       timer0_count++;
                       });

    phaseStartTime = millis();
}

void runMultiTickerTest() {
    Serial.println("\n2. Multi-Ticker Test");
    Serial.println("   Ticker0: 100ms  (10Hz)");
    Serial.println("   Ticker1: 250ms  (4Hz)");
    Serial.println("   Ticker2: 500ms  (2Hz)");
    Serial.println("   Ticker3: 1000ms (1Hz)");
    Serial.print("   Running");

    // 重置所有计数器
    timer0_count = 0;
    timer1_count = 0;
    timer2_count = 0;
    timer3_count = 0;

    // 停止所有ticker
    ticker0.detach();
    ticker1.detach();
    ticker2.detach();
    ticker3.detach();
    oneShotTicker.detach();

    // 配置所有ticker
    ticker0.attach_ms(100, timer0Callback);   // 100ms
    ticker1.attach_ms(250, timer1Callback);   // 250ms
    ticker2.attach_ms(500, timer2Callback);   // 500ms
    ticker3.attach(1.0, timer3Callback);      // 1000ms

    // 记录开始时间
    phaseStartTime = millis();
}

void showResults() {
    Serial.println("\n\n=== Test Results ===");

    // 停止所有ticker
    ticker0.detach();
    ticker1.detach();
    ticker2.detach();
    ticker3.detach();

    // 显示结果
    Serial.println("Expected vs Actual triggers (10s test):");

    Serial.print("Ticker0 (100ms): ");
    Serial.print("Expected ~100, Actual ");
    Serial.print(timer0_count);
    Serial.println(abs((int)timer0_count - 100) <= 2 ? " ✓" : " ✗");

    Serial.print("Ticker1 (250ms): ");
    Serial.print("Expected ~40,  Actual ");
    Serial.print(timer1_count);
    Serial.println(abs((int)timer1_count - 40) <= 2 ? " ✓" : " ✗");

    Serial.print("Ticker2 (500ms): ");
    Serial.print("Expected ~20,  Actual ");
    Serial.print(timer2_count);
    Serial.println(abs((int)timer2_count - 20) <= 2 ? " ✓" : " ✗");

    Serial.print("Ticker3 (1000ms): ");
    Serial.print("Expected ~10,  Actual ");
    Serial.print(timer3_count);
    Serial.println(abs((int)timer3_count - 10) <= 1 ? " ✓" : " ✗");

    // 计算精度
    float accuracy0 = (timer0_count / 100.0) * 100;
    float accuracy1 = (timer1_count / 40.0) * 100;
    float accuracy2 = (timer2_count / 20.0) * 100;
    float accuracy3 = (timer3_count / 10.0) * 100;

    Serial.println("\nTicker Accuracy:");
    Serial.print("Ticker0: "); Serial.print(accuracy0, 1); Serial.println("%");
    Serial.print("Ticker1: "); Serial.print(accuracy1, 1); Serial.println("%");
    Serial.print("Ticker2: "); Serial.print(accuracy2, 1); Serial.println("%");
    Serial.print("Ticker3: "); Serial.print(accuracy3, 1); Serial.println("%");

    float avgAccuracy = (accuracy0 + accuracy1 + accuracy2 + accuracy3) / 4;
    Serial.print("\nAverage accuracy: ");
    Serial.print(avgAccuracy, 1);
    Serial.println("%");

    Serial.println("\n=== All tests completed! ===");

    // 关闭LED
    digitalWrite(LED_PIN, LOW);
}
```
