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

如何在Arduino Mega2560上不使用库函数控制两路舵机与蜂鸣器

Arduino Mega2560双路舵机+蜂鸣器驱动问题修复

核心故障原因

  • 引脚输出配置错误:原代码两次对DDRB直接赋值,后一次配置覆盖前一次,最终仅PB6(引脚12)为输出模式,PB5(引脚11)被重置为输入模式,第一路舵机无控制信号输出
  • 定时器1通道配置被覆盖:第一次配置TCCR1A时开启了OC1A通道PWM输出,第二次配置TCCR1A时直接赋值清空了COM1A1位,导致第一路舵机PWM输出被关闭
  • 冗余重复配置:TCCR1B、ICR1属于定时器1全局配置,仅需设置一次即可,重复赋值无意义且存在误改风险

修正后代码

#define servo90 3000                                    //OCR1A value for the servo to reach 90 degrees
#define servo0 1000                                     //OCR1A value for the servo to reach 0 degrees
#define servoA90 3000                                    //OCR1B value for the servo to reach 90 degrees
#define servoA0 1000


volatile unsigned long sysTick = 0;                                 //共用系统计时变量
unsigned long oldSysTickServo = 0;
unsigned long oldSysTickServoA = 0;

//Buzzer I/O signal is connected to PIN 5
int tune1[] = {261, 277, 294, 311, 330, 349, 370, 392, 415, 440};
int dur1[] = {500, 500, 500, 500, 500, 500, 500, 500, 50};

int i, j, n = 10; //n is inialitsed to the number of notes in tune 1.
void setup() {
  //同时设置PB5(引脚11)、PB6(引脚12)为输出模式
  DDRB |= (1 << DDB5) | (1 << DDB6);

  //set up a 1ms system tick timer
  cli();                                                //disable global interrupts
  TCCR0A = 0;
  TCCR0B = (1 << CS01) | (1 << CS00);                   //start the timer with a prescale of 64
  TIMSK0 = (1 << OCIE0A);                               //setup the output compare interrupt with OCR0A
  OCR0A = 250;                                          //set up the OCR0A value for exactly 1ms
  sei();                                                //enable global interrupts


  //一次性配置定时器1为双路PWM输出模式
  TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11); //同时开启OC1A、OC1B通道PWM输出
  TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11);   //Set the prescale to 8, Fast PWM with TOP in ICR1
  TCCR1C = 0;
  ICR1 = 40000;                                         //20ms周期适配舵机控制
  OCR1A = servo90;
  OCR1B = servoA90;


  //蜂鸣器定时器配置
  DDRE = (1 << DDE3);
  TCCR3A = (1 << COM3A1) | (1 << WGM31);
  TCCR3B = (1 << WGM33) | (1 << WGM32) | (1 << CS32);
}

void loop() {
  for (i = 0; i < n; i++) {
    ICR3 = tune1[i];
    OCR3A = tune1[i] / 2;
    TCNT3 = 0;

    for (j = 0; j < dur1[i]; j++) {
      _delay_ms(1);
      //可将舵机状态判断移到此处提升响应实时性
    }

    ICR3 = 0; OCR3A = 0; TCNT3 = 0;

    //舵机1状态切换
    if (sysTickVal() >= oldSysTickServo + 500)
    {
      oldSysTickServo = sysTickVal();
      OCR1A = (OCR1A == servo0) ? servo90 : servo0;
    }
    //舵机2状态切换
    if (sysTickVal() >= oldSysTickServoA + 500)
    {
      oldSysTickServoA = sysTickVal();
      OCR1B = (OCR1B == servoA0) ? servoA90 : servoA0;
    }
  }
}
ISR(TIMER0_COMPA_vect)
{
  sysTick++;
}

/**************************************************************************************************************************************/
//Function Name: sysTickVal
//Description: return the systick value without race condition
unsigned long sysTickVal()
{
  unsigned long val;
  cli();
  val = sysTick;
  sei();
  return val;
}

内容的提问来源于stack exchange,提问作者shakir ahamed shuvo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 10:48:03