使用select实现异步定时器

本文介绍了一种使用select API实现的异步定时器,该定时器可以在不影响其他线程的情况下运行周期性任务。通过C++代码示例,展示了如何创建一个线程来执行指定的任务,并设置超时时间。

需求:

实现异步定时器,不干扰其它线程

实现:

使用select作为超时API,但一定程度增加系统payload

代码:

select_timer.hpp

#ifndef SRC_SELECT_TIMER_HPP_
#define SRC_SELECT_TIMER_HPP_
#include <sys/time.h>
#include <iostream>
#include <functional>
#include <thread>
using namespace std;
class select_timer {
public:
	select_timer(function<void()>task, int seconds) {
		thd_ = thread([this, &task, seconds] {
			while (true) {
				task();
				do_select_timeout(seconds);
			}
		});
	}
	~select_timer() {
		thd_.detach();
	}
private:
	void do_select_timeout(unsigned int seconds) {
		struct timeval tv = {0};
		tv.tv_sec = seconds;
		int err = 0;
		do {
			err = select(0, nullptr, nullptr, nullptr, &tv);
		}while (err < 0 && EINTR == errno);
	}
private:
	thread thd_;
};




#endif /* SRC_SELECT_TIMER_HPP_ */

main.cpp

#include "select_timer.hpp"
#include <iostream>
#include <chrono>
void fun() {
    cout << "I am fun()." << endl;
}
void fun1() {
	while (true) {
		cout << "I am fun1." << endl;
		this_thread::sleep_for(chrono::seconds(1));
	}
}
int main() {
	auto f = fun;
	select_timer(f, 1);
	thread th(fun1);
	if (th.joinable()) {
		th.join();
	}

	return 0;
}




make.sh

g++ -std=c++17 -g -o Test main.cpp  select_timer.hpp -pthread

 

<think>嗯,用户这次问的是GD32F103定时器异步级联的具体实现,看来是个嵌入式开发的实战需求。翻看之前的引用材料,虽然提到了GD32F303的BMS应用,但用户明确指出参考价值有限,重点应该放在他追问的异步级联上。 用户用词很专业,"原理、实现方法、应用场景"三个关键词抓得很准,说明至少是相关领域的开发者。可能正在调试定时器同步问题,或者需要扩展定时范围。考虑到GD32F103是GD32的入门系列,用户或许是中小企业的硬件工程师。 关于异步级联的实现难点,需要特别注意时钟隔离的部分。手册里提到TIMER1作为主定时器时,其触发输出信号(TRGO)要连接到从定时器的ITIx引脚,这个硬件连线很容易被忽略。上次有个用户就卡在寄存器配置都正确但级联失败,最后发现是跳线帽没接。 应用场景方面,除了常规的PWM扩展,其实在无刷电机控制里特别实用。比如用72MHz主频时,单个定时器只能产生约200kHz的16位PWM,但通过级联TIMER1和TIMER2后,就能用32位计数器实现0.1Hz精度的超低速PWM控制,这对某些需要缓慢启停的工业场景很关键。 突然想到个易错点:从定时器的时钟源必须配置为外部时钟模式,而很多人会忘记把SMCFG寄存器的SMC字段设置为0x07。这个细节得在步骤里重点标注,最好用加粗提醒。 </think>以下是关于GD32F103定时器异步级联的详细说明,结合原理、实现方法和应用场景: --- ### **一、异步级联原理** **核心机制**:主定时器通过触发信号(TRGO)控制从定时器的计数启停,解决时钟域差异问题。 - **时钟隔离**:主/从定时器使用不同时钟源(如主定时器用内部时钟,从定时器用外部时钟) - **信号同步**:主定时器溢出/更新事件产生触发信号,通过内部硬件链路同步到从定时器的触发输入(ITRx) - **计数控制**:从定时器工作在从模式(Slave Mode),触发信号重置其计数器或启动计数[^1] > 📌 **关键点**:异步级联突破时钟源限制,实现跨时钟域精确时序控制。 --- ### **二、实现步骤(以TIM1主控 + TIM2从动为例)** #### **1. 初始化配置** ```c // 主定时器 TIM1 配置 timer_parameter_struct timer_initpara; timer_struct_para_init(&timer_initpara); timer_initpara.prescaler = 7199; // 72MHz/(7199+1)=10kHz timer_initpara.alignedmode = TIMER_COUNTER_EDGE; timer_initpara.counterdirection = TIMER_COUNTER_UP; timer_initpara.period = 9999; // 10kHz下1秒周期 timer_initpara.clockdivision = TIMER_CKDIV_DIV1; timer_init(TIMER1, &timer_initpara); // 配置主模式:更新事件触发TRGO timer_master_output_trigger_source_select(TIMER1, TIMER_TRI_OUT_SRC_UPDATE); ``` #### **2. 从定时器配置** ```c // 从定时器 TIM2 配置 timer_initpara.prescaler = 0; // 无分频 timer_initpara.period = 0xFFFF; // 最大计数范围 timer_init(TIMER2, &timer_initpara); // 设置从模式:触发信号复位计数器 timer_slave_mode_select(TIMER2, TIMER_SLAVE_MODE_RESET); timer_input_trigger_source_select(TIMER2, TIMER_SMCFG_TRGSEL_ITI0); // 连接TIM1的TRGO ``` #### **3. 启动级联** ```c timer_enable(TIMER2); // 先启动从定时器(等待触发) timer_enable(TIMER1); // 主定时器启动后发送触发信号 ``` --- ### **三、应用场景** 1. **超长周期定时** - 场景:需1小时以上的精确定时(如环境监测) - 方案:TIM1(1秒周期)级联TIM2(16位计数器)→ 扩展至 $$ T_{total} = 1s \times 65536 = 18.2 \text{小时} $$ 2. **多时钟域同步** - 场景:主控板(内部时钟)与外部传感器(外部晶振)时序协同 - 方案:TIM1用内部72MHz时钟,TIM2用传感器提供的外部时钟,实现跨时钟域事件同步[^1] 3. **高精度脉冲捕获** - 场景:电机转速测量(低速时脉冲间隔长) - 方案:主定时器定时采样,从定时器捕获外部脉冲,避免低速时计数器溢出 --- ### **四、注意事项** 1. **触发延迟**:信号同步需2-3个时钟周期,超精密场景需补偿 2. **级联深度**:GD32F103最多支持2级级联(TIM1→TIM2→TIM3) 3. **模式兼容**:仅高级/通用定时器支持主从模式(如TIM1、TIM2/TIM3) > ⚠️ **调试技巧**:用示波器监测主定时器的TRGO引脚(如PB13/TIM1_TRGO)与从定时器输入引脚,确认信号同步性。 --- ### **相关问题** 1. GD32F103定时器级联时如何计算最大定时周期? 2. 异步级联与同步级联(同时钟源)有何性能差异? 3. 如何通过中断管理级联定时器的超时事件? 4. 在PWM输出模式下能否使用异步级联? [^1]: 参考GD32F103用户手册:定时器从模式控制寄存器(TIMERx_SMCFG)配置说明
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值