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

ATtiny2313A 1kHz PWM控制6V直流电机故障排查与寄存器配置求助

问题分析与解决方案

核心问题梳理

  1. 定时器寄存器配置错误
    • Timer0的WGM模式位分配错误:WGM02属于TCCR0B,但代码中错误写入TCCR0A,且TCCR0B重复设置WGM01/WGM00,直接导致PWM模式失效。
    • Timer1的WGM模式位错误:WGM12属于TCCR1B,代码中误写入TCCR1A;且未设置时钟分频位CS1x,Timer1完全未运行,导致PD5(OC1A)、PB4(OC1B)无输出。
  2. 定时器通道与引脚映射不匹配
    ATtiny2313A的PWM引脚对应关系为:
    • PB2 = OC0A(Timer0通道A)
    • PB3 = OC0B(Timer0通道B)
    • PD5 = OC1A(Timer1通道A)
    • PB4 = OC1B(Timer1通道B)
      原代码未正确关联控制逻辑与对应通道,导致输出引脚状态异常。
  3. Timer1资源冲突
    原代码同时用Timer1测量RC输入PWM和生成输出PWM,导致Timer1无法正常工作。
  4. PWM频率配置错误
    原配置未针对1kHz目标频率设置正确的分频系数与TOP值,无法输出指定频率的PWM信号。

修正后的代码实现

#define F_CPU 16000000L
#include <avr/io.h>
#include <util/delay.h>
#include <stdint.h>

// 引脚与定时器通道映射
#define LEFT_PWM_A PB2  // OC0A
#define LEFT_PWM_B PB3  // OC0B
#define RIGHT_PWM_A PB4 // OC1B
#define RIGHT_PWM_B PD5 // OC1A
#define RC_INPUT PD2

volatile uint16_t rc_pulse_width = 0;

// 用Timer0中断捕获RC输入PWM,避免与Timer1冲突
ISR(TIMER0_COMPA_vect) {
    static uint8_t edge_flag = 0;
    if (!edge_flag) {
        if (PIND & (1 << RC_INPUT)) {
            TCNT0 = 0;
            edge_flag = 1;
        }
    } else {
        if (!(PIND & (1 << RC_INPUT))) {
            rc_pulse_width = TCNT0 * 16; // 分频16,每个计数对应1us
            edge_flag = 0;
        }
    }
}

void init_timer0() {
    // Timer0:CTC模式,分频16,用于RC输入捕获
    TCCR0A = (1 << WGM01);
    TCCR0B = (1 << CS02);
    OCR0A = 255; // 溢出周期约4ms,覆盖RC PWM的1-2ms范围
    TIMSK |= (1 << OCIE0A);
    sei(); // 全局中断使能
}

void init_pwm_timers() {
    // Timer0:Fast PWM模式,输出左电机PWM
    TCCR0A = (1 << COM0A1) | (1 << COM0B1) | (1 << WGM01) | (1 << WGM00);
    TCCR0B = (1 << CS01); // 分频8,频率7812.5Hz

    // Timer1:Fast PWM模式,生成精确1kHz PWM
    ICR1 = 1999; // 16MHz/(8*(1999+1))=1000Hz
    TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11);
    TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11); // 分频8,WGM模式14
}

void init_io() {
    // 设置PWM引脚为输出
    DDRB |= (1 << DDB2) | (1 << DDB3) | (1 << DDB4);
    DDRD |= (1 << DDD5);
    // 初始输出低电平
    PORTB &= ~((1 << LEFT_PWM_A) | (1 << LEFT_PWM_B) | (1 << RIGHT_PWM_A));
    PORTD &= ~(1 << RIGHT_PWM_B);
    // RC输入引脚设为下拉输入
    DDRD &= ~(1 << RC_INPUT);
    PORTD |= (1 << RC_INPUT);
}

int main(void) {
    init_io();
    init_timer0();
    init_pwm_timers();

    uint8_t left_pwm = 0;
    uint16_t right_pwm = 0;

    while (1) {
        // 归一化RC输入值(1000-2000us对应0-255/65535)
        if (rc_pulse_width >= 1000 && rc_pulse_width <= 2000) {
            left_pwm = (rc_pulse_width - 1000) * 255 / 1000;
            right_pwm = (rc_pulse_width - 1000) * 65535 / 1000;
        } else {
            left_pwm = 0;
            right_pwm = 0;
        }

        // 电机控制逻辑
        if (rc_pulse_width >= 1500) {
            // 右转:右电机输出PWM,左电机停
            OCR0A = 0;
            OCR0B = 0;
            OCR1A = right_pwm;
            OCR1B = right_pwm;
        } else if (rc_pulse_width <= 1300) {
            // 左转:左电机输出PWM,右电机停
            OCR1A = 0;
            OCR1B = 0;
            OCR0A = left_pwm;
            OCR0B = left_pwm;
        } else {
            // 停止:所有PWM输出0
            OCR0A = 0;
            OCR0B = 0;
            OCR1A = 0;
            OCR1B = 0;
        }

        _delay_ms(50);
    }
    return 0;
}

关键配置说明

  1. Timer1 1kHz PWM设置
    采用Fast PWM模式(WGM13/WGM12/WGM11=1),以ICR1=1999为TOP值,配合分频系数8,输出精确1kHz PWM;COM1A1/COM1B1=1配置为非反相输出,匹配时清零引脚、溢出时置位。
  2. Timer0 输入捕获设置
    改用Timer0通过中断检测RC输入PWM的电平变化,释放Timer1专用于PWM输出,避免资源冲突。
  3. 引脚映射修正
    严格对应ATtiny2313A的定时器通道与物理引脚,确保PWM信号从指定引脚输出。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 10:35:55