ATMega328P freilaufender ADC-Interrupt wird nicht ausgelöst

Ich spiele mit einem ATMega328P, der mit einem USBtiny 1.0 läuft, und habe Folgendes eingerichtet:

  • Potentiometer an ADC0.
  • PB0 liefert Strom für eine LED.

Mein Programm spiegelt dann ADC0 auf die PWM auf PB0, sodass die Position des Potentiometers direkt die Helligkeit der LED steuert.

Dies funktioniert, wenn es innerhalb der Endlosschleife am Ende von main() ausgeführt wird, aber wenn ich es zum ADC-Interrupt verschiebe, scheint nichts zu passieren (siehe Kommentar "Entferne mich").

Ich stütze mich teilweise auf ein Tutorial unter http://www.avr-tutorials.com/adc/utilizing-avr-adc-interrupt-feature , verwende aber den freilaufenden Modus.

#define __AVR_ATmega328P__
#define F_CPU 1000000UL
#include <avr/io.h>
#include <avr/interrupt.h>

#define SET(register, bit) register |= _BV(bit)
#define CLEAR(register, bit) register &= ~_BV(bit)

int main(void) {
    // Set up ADC0 as a 8-bit potentiometer input.
    // -------------------------------------------------------------------------

    // Switch from 10-bit to 8-bit mode.
    // Our output is 8-bit anyway.
    SET(ADMUX, ADLAR);

    // Use AVCC as the reference for the ADC.
    SET(ADMUX, REFS0);
    CLEAR(ADMUX, REFS1);

    // Specify that we are only interested in ADC0.
    CLEAR(ADMUX, MUX0);
    CLEAR(ADMUX, MUX1);
    CLEAR(ADMUX, MUX2);
    CLEAR(ADMUX, MUX3);

    // Set the clock divider to 128x.
    // TODO: Experiment with reducing the divider when logic is in.
    SET(ADCSRA, ADPS0);
    SET(ADCSRA, ADPS1);
    SET(ADCSRA, ADPS2);

    // Set to free-running mode; the ADC will run continuously.
    CLEAR(ADCSRB, ADTS0);
    CLEAR(ADCSRB, ADTS1);
    CLEAR(ADCSRB, ADTS2);

    // Enable auto-triggering of the ADC by the above.
    SET(ADCSRA, ADATE);

    // Fire the ADC interrupt when a sample is ready.
    SET(ADCSRA, ADIE);

    // Enable the ADC now it has been configured.
    SET(ADCSRA, ADEN);

    // Start the free-running timer.
    SET(ADCSRA, ADSC);

    // Set up LED output on PB1.
    // -------------------------------------------------------------------------

    // Set the pin up as an output.
    SET(DDRB, PB1);

    // We'll be comparing a timer (sawtooth) to a value (OCR1A);
    // the pin will be high or low depending upon whether the timer is greater
    // or lower than the value (OCR1A).
    SET(TCCR1A, COM1A1);

    // Switch to fast PWM.
    // This doubles the frequency, but means that phase shifts when OCR1A is
    // changed.  Doesn't matter for us.
    SET(TCCR1A, WGM10);
    SET(TCCR1B, WGM12);

    // Disable the timer divider; as fast as possible.
    SET(TCCR1B, CS10);

    // Enable interrupts now everything is configured.
    // -------------------------------------------------------------------------
    sei();

    while (1) {
        // Remove me to have the ADC interrupt set the LED brightness instead.
        OCR1A = ADCH;
    }
}

// This ADC interrupt handler is called every time a potentiometer sample is ready.
ISR(ADC_vect) {
    OCR1A = ADCH;
}

Ich habe auch mit dem INT0-Interrupt in einem anderen Programm experimentiert, aber das löst anscheinend auch nicht den Interrupt-Handler aus.

avr-gcc-Version:

Using built-in specs.
Target: avr
Configured with: ../gcc-4.3.3/configure --enable-win32-registry=WinAVR-20100110 --with-gmp=/usr/local --with-mpfr=/usr/local --prefix=/c/WinAVR --target=avr --enable-languages=c,c++,objc --with-dwarf2 --enable-doc --disable-shared --disable-libada --disable-libssp --disable-nls --with-pkgversion='WinAVR 20100110' --with-bugurl='URL:http://sourceforge.net/tracker/?atid=520074&group_id=68108&func=browse'
Thread model: single
gcc version 4.3.3 (WinAVR 20100110)

Ich vermisse wahrscheinlich etwas Setup, aber ich konnte nichts finden, was ich nicht getan habe. Kann jemand sehen, was ich falsch mache? Danke schön.

Ich bin mit der AVR-Syntax nicht vertraut, aber wollten Sie CLEAR(ADMUX, MUX0)das, wenn Sie daran interessiert sind? Sind Sie auch sicher, dass der Interrupt überhaupt nicht ausgelöst wird - nicht einmal? Wenn Sie einmal das Interrupt-Flag in der ISR löschen, kann es das erneute Auslösen stoppen?
Ja. ADMUX MUX0-3 wählt einen einzelnen Eingang aus bis zu 16 Quellen aus. Ich arbeite mit dem Datenblatt, aber die Tabelle ist auch unter robotplatform.com/knowledge/ADC/adc_tutorial_3.html verfügbar . Ich bin mir ziemlich sicher, dass das ADC / PWM-Setup richtig ist, da es funktioniert, wenn ich ADC-> PWM in der main () -Schleife spiegele. Wenn ich die LED im Interrupt-Handler auf volle Helligkeit stelle und keine weiteren Änderungen daran vornehme, bleibt sie dunkel, also denke ich, dass sie überhaupt nicht gefeuert wird. Danke für's Nachsehen.
Hast du einen Haltepunkt in der ISR gesetzt? Daran erkennst du, dass es nicht brennt?
Ich habe Atmel Studio installiert, um Breakpoint-Unterstützung und die Binärdateien zu erhalten, die Arbeit generieren. Es muss etwas mit dem avr-gcc oder den mit WinAVR gelieferten Bibliotheken zu tun haben. Danke für die Hilfe!
Überprüfen Sie, ob die richtige MCU auf der Befehlszeile an den Compiler übergeben wird (-mmcu=...).

Antworten (2)

Dies scheint ein Problem mit den avr-gcc/libraries gewesen zu sein, die in WinAVR enthalten sind, oder wie es konfiguriert wurde. Das Erstellen derselben Anwendung mit Atmel Studio funktioniert wie erwartet.

avr-gcc-Version:

Ich kann Ihnen bestätigen, dass Ihr Code unter meinem Winavr, einer alten Version von 2009, funktioniert.