ATtiny2313A 1kHz PWM控制6V直流电机故障排查与寄存器配置求助
问题分析与解决方案
核心问题梳理
- 定时器寄存器配置错误
- Timer0的WGM模式位分配错误:WGM02属于
TCCR0B,但代码中错误写入TCCR0A,且TCCR0B重复设置WGM01/WGM00,直接导致PWM模式失效。 - Timer1的WGM模式位错误:WGM12属于
TCCR1B,代码中误写入TCCR1A;且未设置时钟分频位CS1x,Timer1完全未运行,导致PD5(OC1A)、PB4(OC1B)无输出。
- Timer0的WGM模式位分配错误:WGM02属于
- 定时器通道与引脚映射不匹配
ATtiny2313A的PWM引脚对应关系为:- PB2 = OC0A(Timer0通道A)
- PB3 = OC0B(Timer0通道B)
- PD5 = OC1A(Timer1通道A)
- PB4 = OC1B(Timer1通道B)
原代码未正确关联控制逻辑与对应通道,导致输出引脚状态异常。
- Timer1资源冲突
原代码同时用Timer1测量RC输入PWM和生成输出PWM,导致Timer1无法正常工作。 - 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; }
关键配置说明
- Timer1 1kHz PWM设置
采用Fast PWM模式(WGM13/WGM12/WGM11=1),以ICR1=1999为TOP值,配合分频系数8,输出精确1kHz PWM;COM1A1/COM1B1=1配置为非反相输出,匹配时清零引脚、溢出时置位。 - Timer0 输入捕获设置
改用Timer0通过中断检测RC输入PWM的电平变化,释放Timer1专用于PWM输出,避免资源冲突。 - 引脚映射修正
严格对应ATtiny2313A的定时器通道与物理引脚,确保PWM信号从指定引脚输出。
内容的提问来源于stack exchange,提问作者Julius
相关产品推荐
相关产品推荐

