-1

私はこの問題に対する答えをすべて探していましたが、何も見つけることができませんでした。私の ISR がトリガーされると、ISR は完全に正常に実行されるはずのすべての処理を実行し、終了してメイン ループに戻る前に、ISR が再度実行されます。2 回目の処理が完了すると、メイン ループに戻ります。これは、115V リレーを使用して割り込みを操作した場合にのみ発生します。

停電が発生したとき、または電源が復旧したときを検出しようとしています。ピン変更割り込みを使用して、リレーが閉じているか開いているかを検出しています。電源が切れると、リレーが開き、ISR がトリガーされます。このセットアップを通常の押しボタンまたはスイッチに接続すると、すべてが必要に応じて機能し、問題はありません。問題があるのは、リレーに接続されている場合のみです。

これが私が持っているコードです:(私はcliを必要としないことを知っています。私はすべてを試してきました)

ISR(PCINT2_vect){

    cli();

    sbi(PORTC,5);
    _delay_ms(6000);
    cbi(PORTC,5);
    for(delay_counter=0;delay_counter<2;delay_counter++)
    {
        _delay_ms(6000);
    }
    sbi(PORTC,5);
    _delay_ms(6000);
    if(bit_is_set(PIND,2))
    {
        lcd_clrscr();
        lcd_puts("Sending SMS");
        usart_print("at");
        USART_Transmit('\r');
        _delay_ms(6000);
        for(i=0;i<=1;i++)
            {
                usart_print("at*smsm2m=");
                USART_Transmit('"');
                for(j=0;j<11;j++)
                {
                    USART_Transmit(Alert_Numbers[i][j]);
                }
                usart_print(" Power has been lost");
                USART_Transmit('"');
                USART_Transmit('\r');
                _delay_ms(6000);
            }

            lcd_clrscr();
            lcd_puts("SMS Sent");
            _delay_ms(6000);
            lcd_clrscr();
            lcd_puts("Status:NO POWER");
            cbi(PORTC,5);
        }

        else if(bit_is_clear(PIND,2))
        {
            lcd_clrscr();
            lcd_puts("System Reset");
            _delay_ms(6000);
            _delay_ms(6000);
            usart_print("at");
            USART_Transmit('\r');
            _delay_ms(6000);
            for(i=0;i<=1;i++)
            {
                usart_print("at*smsm2m=");
                USART_Transmit('"');
                for(j=0;j<11;j++)
                {
                    USART_Transmit(Alert_Numbers[i][j]);
                }
                usart_print(" Pump regained power");
                USART_Transmit('"');
                USART_Transmit('\r');
                _delay_ms(6000);
            }

            lcd_clrscr();
            lcd_puts("POWER ON");
            _delay_ms(6000);
            lcd_clrscr();
            lcd_puts("Status: Good");

        }
        else
        {

        }


}

int main(void)
{    /*Initializations*/
    DDRC = 0x20; // PORTC,5 is now output
    sbi(PORTC,5);
    USART_Init(51);
    lcd_init(LCD_DISP_ON);
    lcd_clrscr();

    /*Set interrupts*/
    DDRD  = 0b11111011;   // set PD2 to input
    PORTD = 0b00000100;   // set PD2 to high
    PCICR |= (1 << PCIE0);
    PCMSK0 |= (1 << PCINT0);
    PCICR |= (1<<PCIE2);
    PCMSK2 |= (1<<PCINT18);
    sei();


    lcd_clrscr();
    lcd_puts("Status: Good");

    /*Main Program Loop: NOP*/
    while(1)
    {
            lcd_clrscr();
            lcd_puts("MAIN LOOP");
            for(delay_counter=0;delay_counter<3;delay_counter++)
            {
                    _delay_ms(6000);
            }
    }
}
4

3 に答える 3

1

私は自分で問題を抱えていたので、古いエントリですが回答することにしました:

割り込みが 2 回発生するのは、割り込みフラグがリセットされていないためです。これは一部の atmega タイプの問題です。次の簡単な 1 行で問題を解決できます。

これを ISR 割り込み関数の最後に投稿します。

PCIFR |= (1<<PCIF2);

これにより、PCINT2 割り込みの割り込みフラグ ビットに「1」が書き込まれます。他の割り込みを使用している場合は、他のフラグを 1 に設定する必要があります。割り込みフラグが反転していることに注意してください。したがって、1 は割り込みを無効にし、0 は割り込みをトリガーします。

データシートを見てください: http://www.atmel.com/images/doc2545.pdf ポイント13.2.5を参照してください:

ビット 2 - PCIF2: ピン変更割り込みフラグ 2 - PCINT23..16 ピンの論理変更が割り込み要求をトリガーすると、PCIF2 がセット (1) になります。SREG の I ビットと PCICR の PCIE2 ビットがセット (1) されている場合、MCU は対応する割り込みベクタにジャンプします。フラグは割り込みルーチン実行時にクリアされます。または、フラグに論理 1 を書き込むことによってフラグをクリアすることもできます。

これがあなたと、おそらく同じ問題を抱えている他の人の助けになることを願っています。データシートでレジスタの名前と割り込みフラグに対応するビットを検索し、1 に設定するだけです。

さよなら

于 2014-01-25T00:25:55.170 に答える
1

ピン変更割り込みを使用して、リレーが閉じているか開いているかを検出しています。

そうしないでください。真剣に。メカニカル スイッチを割り込みピンに接続して ISR をトリガーしようとしないでください。

そうすることを主張する場合は、少なくとも、スイッチの信号がµC の入力ピンに到達する前に、ハードウェアで適切にデバウンスされていることを確認してください。

その上、あらゆる種類の待機 ( _delay_ms(6000);) は、ISR で実行したいものではありません。

于 2013-08-27T13:29:11.310 に答える