如何在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
相关产品推荐
相关产品推荐

