You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Arduino读取4500RPM以上高速旋转编码器数据(手动跑步机场景)

原提问

设备清单

  • Arduino ATmega2560
  • 旋转编码器
  • 弧形手动跑步机

项目背景

计划用Arduino采集手动跑步机的距离、速度数据,实现方案为将旋转编码器与滑板轮联动,跑步机跑带运动时带动轮组同比例旋转。
经测试,轮组每旋转1圈,计数变量累计约2000个脉冲;轮组直径6cm,周长18.8495559215cm,换算得每行进1厘米对应约106个脉冲(2000 pulses/18.8495559215 cm ≈ 106 pulses/cm)。

测试代码

(参考开源方案修改,因跑步机仅单向运行,将原代码中两处counter--改为counter++,解决了中低速计数递减问题,但高速运行仍异常)

volatile long temp, counter = 0; //该变量随编码器旋转增减
    
void setup() {
  Serial.begin (9600);
  pinMode(2, INPUT_PULLUP); // 2号引脚设为内部上拉输入
  pinMode(3, INPUT_PULLUP); // 3号引脚设为内部上拉输入
  // 配置中断:编码器A相上升沿触发ai0中断,2号引脚对应外部中断0
  attachInterrupt(0, ai0, RISING);
  // 配置中断:编码器B相上升沿触发ai1中断,3号引脚对应外部中断1
  attachInterrupt(1, ai1, RISING);
}
   
void loop() {
  // 计数器每累计1厘米对应脉冲数时打印数值
  if( counter != temp && counter % 106 == 0 ){
    Serial.println (counter);
    temp = counter;
  }
}
   
void ai0() {
  // 2号引脚电平从低变高时触发该中断
  if(digitalRead(3)==LOW) {
    counter++;
  }else{
    counter++;
  }
}
   
void ai1() {
  // 3号引脚电平从低变高时触发该中断
  if(digitalRead(2)==LOW) {
    counter++;
  }else{
    counter++;
  }
}

当前问题

速度计算逻辑已验证可行,可通过millis()函数搭配时间变量实现,暂未写入代码。
当前代码在跑步机速度低于5km/h时运行正常,超过5km/h后会出现串口监视器周期性卡顿、数据不准的问题;需求是支持最高50km/h的速度检测,对应轮组转速超过4500RPM(75RPS),按2000P/R计算每秒需处理150000个脉冲。
待解答疑问:

  1. 当前编码器接在2、3号引脚,是否需要调整?
  2. 编码器有一根橙色Z线,现有方案仅用到A、B线,接入Z线是否能解决高速读取问题?
  3. 编码器目前使用Arduino的5V供电,参数显示最高支持26V供电,使用外部高压供电是否能提升性能?是否需要搭配继电器使用?
  4. 编码器支持多档分辨率可选,包括100、200、2000、5000P/R等,当前默认是2000P/R,调整到更高分辨率是否有助于解决问题?如何调整?

需求总结

需实现手动跑步机最高50km/h时速下的速度、距离数据采集,优先基于现有硬件给出解决高速读取卡顿、数据不准的方案;若现有旋转编码器方案不可行,也可接受其他测速测距方案建议,可额外采购必要硬件。

方案实拍图


解答

疑问解答

  1. 2、3号引脚为ATmega2560的标准外部中断引脚,硬件连接本身无需调整,当前性能瓶颈来自软件逻辑和脉冲处理压力,和引脚无关。
  2. Z线为编码器零位信号,每旋转一圈输出一个脉冲,仅用于累计误差校准,无法提升高速读取性能,额外接入还会增加中断处理开销,反而加剧卡顿问题。
  3. 编码器供电电压仅和输出电平兼容性有关,和脉冲响应性能无关,5V供电完全满足使用需求,外部高压供电无任何增益,也不需要搭配继电器。
  4. 更高分辨率会增加单位时间的脉冲数量,进一步加大CPU处理压力,反而会加剧问题。需往低调整分辨率,推荐降到100P/R,调整方式参考编码器说明书,一般通过本体上的拨码开关或配置引脚接高低电平切换。

现有硬件优化方案

按以下步骤修改即可满足50km/h检测需求:

  1. 降低编码器分辨率到100P/R:调整后每秒仅需处理7500个脉冲,CPU负载降至原来的5%,完全无处理压力。换算后每厘米对应约5.3个脉冲,测距精度可满足跑步机使用需求。
  2. 简化中断逻辑:因设备仅单向运行,无需接B相,仅保留A相连接2号引脚,中断服务函数删除所有冗余判断,直接累加计数器,大幅降低中断执行耗时。
  3. 优化串口配置:将波特率从9600调整到115200,修改打印逻辑为固定间隔(如每100ms)打印一次数据,避免频繁触发串口打印占用CPU资源。
  4. 增加变量读取保护:读取计数器变量时临时关闭中断,避免读取过程中变量被中断修改导致数据错误。

优化后代码示例

volatile unsigned long counter = 0;
unsigned long lastPrint = 0;
unsigned long lastCounter = 0;
const float pulsePerCm = 100.0 / 18.8496; // 100P/R下每厘米对应脉冲数

void setup() {
  Serial.begin(115200);
  pinMode(2, INPUT_PULLUP);
  attachInterrupt(0, countPulse, RISING);
}

void loop() {
  unsigned long now = millis();
  // 每100ms打印一次距离和速度
  if (now - lastPrint >= 100) {
    noInterrupts();
    unsigned long currentCount = counter;
    interrupts();
    
    float distance = currentCount / pulsePerCm / 100.0; // 单位:米
    float deltaCount = currentCount - lastCounter;
    float speed = (deltaCount / pulsePerCm / 100.0) * 36; // 单位:km/h,0.1s走的距离*360=km/h
    
    Serial.print("距离: ");
    Serial.print(distance);
    Serial.print("m, 速度: ");
    Serial.print(speed);
    Serial.println("km/h");
    
    lastCounter = currentCount;
    lastPrint = now;
  }
}

void countPulse() {
  counter++;
}

备选升级方案

若需要保留2000P/R的高分辨率,可额外采购PCF8583脉冲计数模块,该模块为专用硬件计数器,最高支持10MHz脉冲计数,通过I2C和Arduino通信,Arduino无需处理中断,仅需定时读取计数数值即可,可完全满足150k脉冲每秒的处理需求。
若不想使用编码器方案,可改用霍尔传感器+跑带贴磁铁的方案,每圈输出一个脉冲,结构简单稳定,完全满足跑步机测速测距需求。


内容的提问来源于stack exchange,提问作者Josh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 16:57:03