mbed OS6开发中如何将数组内float值转换为可比较的chrono时间值
mbed OS6 MIDI播放项目的chrono时间比较实现方案
核心逻辑说明
C++ chrono的duration类型天生支持跨单位的安全隐式转换与比较,不需要手动计算时间偏移量,只要明确每个时间值对应的实际单位即可。遇到的本质问题是两个时间源的单位定义不统一,只要把两边的duration转成同语义的类型,就可以直接做逻辑判断。
注意:代码中
std::chrono::duration<double> timerus = motor1timer.elapsed_time()这行的变量名存在误导——因为模板参数为double的duration默认计数单位为1秒,转完的实际数值单位是秒,并非微秒,后续写逻辑时很容易因为单位认知偏差出bug。
可直接落地的实现方案
方案1:浮点秒单位对比(适配新手,代码改动最少)
这种方式完全匹配现有float秒数组的语义,不需要做复杂的整数精度转换:
- 把数组里存的float秒值,直接封装为
std::chrono::duration<float>类型:该类型的计数单位为1秒,和数组值的定义完全一致 - 把定时器返回的elapsed时间,也转为同类型的浮点秒duration
- 两个同类型的duration直接做大小比较,chrono会自动完成单位换算,不会出现类型不兼容的编译错误
对应参考代码:
// 已解析得到的MIDI音符启动时间数组,单位为秒 constexpr float note_start_secs[] = {0.5f, 1.2f, 2.7f, 3.9f}; // mbed OS6 的HighResTimer 本身基于chrono实现,和标准库接口兼容 HighResTimer motor1_timer; // 播放进度标记 size_t played_note_count = 0; // 定时器周期触发回调,比如1ms执行一次 void motor_timer_tick_handler() { // 获取当前已经运行的时间,转为浮点秒单位 std::chrono::duration<float> current_elapsed = motor1_timer.elapsed_time(); // 顺序检查待触发的音符 while (played_note_count < sizeof(note_start_secs)/sizeof(note_start_secs[0])) { // 将数组中的float秒值直接转为同类型duration std::chrono::duration<float> note_trigger_point(note_start_secs[played_note_count]); if (current_elapsed >= note_trigger_point) { // 满足时间条件,触发步进电机执行对应音符动作 trigger_step_motor(played_note_count); played_note_count++; } else { // 还未到达下一个音符的触发时间,退出检查循环 break; } } }
方案2:整数微秒单位对比(低精度场景下更稳定)
如果担心长时间运行下浮点累计误差导致的时间偏移,可以切换为整数微秒单位的对比逻辑:
- 将数组中的float秒值,通过
duration_cast转为整数类型的微秒duration - 定时器返回的elapsed_time本身就是微秒级分辨率的整数duration,不需要额外转换即可直接对比
参考转换代码片段:
// 将2.3秒的float值,转为整数微秒单位的duration std::chrono::microseconds trigger_us = std::chrono::duration_cast<std::chrono::microseconds>( std::chrono::duration<float>(2.3f) ); // 直接和elapsed_time返回的微秒duration对比 if (motor1_timer.elapsed_time() >= trigger_us) { // 触发播放 }
常见避坑点
- 不要手动对
elapsed_time()的返回值做乘除系数换算(比如乘1e6、除1e3这种),chrono内置的duration_cast会自动处理单位换算的取整规则,手动计算很容易出现单位反向匹配的低级错误 - 不要直接调用
duration.count()拿原始计数值和float秒数组对比:比如微秒级duration的count()返回值是微秒数,直接和秒级的float值对比会差1e6倍 - 触发逻辑用顺序遍历的方式即可,不需要每次都从头遍历整个音符数组,记录当前播放进度的索引可以大幅降低循环开销
内容的提问来源于stack exchange,提问作者CEEA
相关产品推荐
相关产品推荐

