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

ATmega328PB中双AVR中断向量(PCINT0_vect与PCINT1_vect)仅能触发一个的问题咨询

ATmega328PB中双AVR中断向量(PCINT0_vect与PCINT1_vect)仅能触发一个的问题咨询

嘿,我看了你的代码和问题描述,马上就发现了几个关键问题,咱们一步步来梳理:

核心问题:PCICR寄存器被覆盖导致仅一组中断启用

你在SonarSensor_init0()和SonarSensor_init1()里都是直接给PCICR赋值:

// 在init0里
PCICR = (1<<PCIE0);
// 在init1里
PCICR = (1<<PCIE1);

这样的赋值方式会覆盖寄存器的原有值。比如先调用SonarSensor_init0(),此时PCICR的PCIE0位被置1,PCIE1位是0;接着调用SonarSensor_init1(),直接把PCICR设置成只有PCIE1位为1,之前的PCIE0位就被清零了!这就是为什么只有后调用的初始化函数对应的中断能工作。

正确的做法应该是用位或操作来保留原有位,只置位需要的位:

// 在init0里
PCICR |= (1<<PCIE0);
// 在init1里
PCICR |= (1<<PCIE1);

这样两个中断组的使能位都会被置1,不会互相覆盖。

其他需要修正的问题

  • 全局中断的错误操作:你的main()循环里反复调用sei(),而且每个ISR最后都调用cli()关闭全局中断。一旦某个ISR执行完调用cli(),后续所有中断都无法触发,这也会导致另一个中断没法工作。你只需要在main()开头调用一次sei()就够了,ISR里不要随便调用cli(),除非你有明确的理由要临时关闭中断(显然这里不需要)。

  • 定时器预分频的注释错误:你在SonarSensor_init1()里写的注释是“Timer without prescaler”,但实际设置的是TCCR1B |= (1<<CS12);——CS12置位、CS11和CS10为0的话,定时器1是256分频,不是无预分频。如果需要无预分频,应该设置TCCR1B |= (1<<CS10);(CS10置位,其他CS位清零)。这个错误会影响你的距离计算精度,得注意。

  • 定时器输入捕获的设置遗漏:在SonarSensor_init1()里你设置了ICES1(上升沿捕获),但这个是定时器1的输入捕获功能,不过你现在用的是PCINT中断来检测电平变化,其实这个设置和当前的PCINT中断逻辑无关,要么你改成用输入捕获中断来做(可能更准确),要么就可以去掉这个设置,避免混淆。

修改后的关键代码示例

修正后的初始化函数片段

void SonarSensor_init1(void)
{
    // ... 其他代码保持不变
    // 改用位或操作启用PCIE1
    PCICR |= (1<<PCIE1);
    // ... 其他代码保持不变
}

void SonarSensor_init0(void)
{
    // ... 其他代码保持不变
    // 改用位或操作启用PCIE0
    PCICR |= (1<<PCIE0);
    // ... 其他代码保持不变
}

修正后的main函数

int main(void)
{
    SonarSensor_init0();
    SonarSensor_init1();
    sei(); // 只需要在这里启用一次全局中断
    while(1)
    {
        PORTC |= (1 << PINC4);
        _delay_us(10);
        PORTC &= ~(1<<PINC4);
        
        PORTB |= (1 << PINB0);
        _delay_us(10);
        PORTB &= ~(1<<PINB0);
        
        // 可以在这里添加距离处理逻辑,比如打印distance1和distance2
    }
}

修正后的ISR函数(移除cli())

ISR(PCINT1_vect) {
    if ( (PINC & (1 << PINC5)) == (1 << PINC5))                            
    {
        TCNT1 = 0;
        PORTB |= (1 << PINB5);                                             
    }
    else
    {
        distance2 = TCNT1/3;                    
        PORTB &= ~(1 << PINB5);                 
        // 移除cli(); 不要关闭全局中断
    }
}

ISR(PCINT0_vect) {
    if ( (PINB & (1 << PINB1)) == (1 << PINB1))                            
    {
        TCNT0 = 0;
        PORTB |= (1 << PINB5);                                              
    }
    else
    {
        distance1 = TCNT0;                  
        PORTB &= ~(1 << PINB5);             
        // 移除cli(); 不要关闭全局中断
    }
}

按照这些修改,两个PCINT中断应该都能正常触发了,你可以试试看。

备注:内容来源于stack exchange,提问作者Tungstein

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.21 13:24:30