Analog Comparator => Interrupt läst sich nicht einstellen

Gast #3415570
Hallo,
Ich versuche beim ATmega8 den Analog Comparator in mein Aktuelles 
Projekt einzubauen.
Dazu soll der Comparator Interrupt jedes Mal Auslösen, wenn die Spannung 
am AIN1 geringe wird als die Reverenz.
Dies lässt sich im Register ACSR mit ACIS1 = 1 und ACIS0 = 0 einstellen.
Jedoch löst der Interrupt bei jedem wechsle aus.
Hat einer von euch eine Idee weshalb er immer auslöst?
Hier der Code:
1
DDRB = 0xff;    
2
ACSR = (0<<ACD)|(1<<ACIE)|(1<<ACIS1)|(0<<ACIS0);
3
//ACD Comparator Aktivieren   ACIE Interrupt aktivieren 
4
  sei();
5
    while(1){
6
      //mache solange nix bis der Interrupt auslöst
7
    while (test == 0)
8
      {
9
    _delay_us(1);
10
    }  
11
            
12
      PORTB = 0xff;_delay_ms(1000);
13
      PORTB = 0x00;_delay_ms(100);
14
      test = 0;
15
    }
16
    }
17
  //Comperrator Interrupt
18
     ISR(ANA_COMP_vect){
19
//die Variable sorgt dafür dass das Programm  die while schleife verlässt //und die LEDs einmal Blinken
20
      test = 1;
21
        
22
      }
grüße
Gast #3415599
ist laut Datenblatt der ACD auf 1 ist der Comparator ausgeschaltet.
Deshalb ziehe ich das bit auf 0 um ihn zu aktivieren.

• Bit 7 – ACD: Analog Comparator Disable
When this bit is written logic one, the power to the Analog Comparator 
is switched off. This bit
can be set at any time to turn off the Analog Comparator. This will 
reduce power consumption in
Active and Idle mode. When changing the ACD bit, the Analog Comparator 
Interrupt must be
disabled by clearing the ACIE bit in ACSR. Otherwise an interrupt can 
occur when the bit is
changed.
Gast #3415630
Martin schrieb:

> Dies lässt sich im Register ACSR mit ACIS1 = 1 und ACIS0 = 0 einstellen.
> Jedoch löst der Interrupt bei jedem wechsle aus.
> Hat einer von euch eine Idee weshalb er immer auslöst?

Einzig denkbare Erklärung: Es gibt beim Pegelwechsel heftige 
Überschwinger des Eingangssignals. Das ist allerdings ein absolut 
übliches Problem, willkommen also in der Welt der realen Elektronik 
(also dort, wo reine Spice-Jockeys niemals hinkommen)...

Softwaremäßig kannst du dagegen (auf leichte Art) nur dann etwas machen, 
wenn du den AC als Input für den Timer1 benutzt. Dann kannst du nämlich 
den für dessen IPC-Funktionalität bereits hardwaremäßig eingebauten 
Tiefpass mitbenutzen. (Stichwort für die Suche im Datenblatt: "noise 
canceler"). Dein Handler ist dann nicht der AC-Int, sondern der ICP-Int 
des Timers. Das geht natürlich nur dann, wenn du ICP oder das 
ICP-Register noch nicht für andere Zwecke verwendest.

Benutzt du hingegen den AC-Interrupt direkt, dann mußt du dir so einen 
Tiefpass (oder einen besseren) in Software selber bauen. Das ist 
eigentlich kein wirklich großes Problem, denn man kann ein wichtige 
Eigenschaft von ISRs als Zeitkonstante dafür benutzen: Die verdammten 
Dinger verbrauchen nämlich selber eine ziemlich genau quantifizierbare 
Menge an Rechenzeit. Jedenfalls, wenn man die "richtige" (eigentlich: 
die einzig wirklich geeignete) Sprache zu ihrer Programmierung 
benutzt...

Tipp1: Echte Hochsprachen sind dafür völlig ungeeignet.
Tipp2: Blöde Makroassembler mit Hochsprachen-Attitüde wie z.B. C 
ebenfalls.
       Jedenfalls wenn man ein wirklich deterministisches Zeitverhalten
       erreichen möchte...
Gast #3415737
> Dazu soll der Comparator Interrupt jedes Mal Auslösen, wenn die Spannung
> am AIN1 geringe wird als die Referenz.

> ACSR = (0<<ACD)|(1<<ACIE)|(1<<ACIS1)|(0<<ACIS0);


Zwei Punkte verstehe ich nicht:

1. fehlt da nicht ein (1<<ACBG)  ?
2. muss das nicht (1<<ACIS1)|(1<<ACIS0)  heißen  ?
Gast #3416742
Vielen dank für die Antworten, jedoch glaube ich nicht das es nötig ist 
einen Tiefpass-Filter einzubauen, denn meine Schaltung Schwingt nicht 
und das Signal ist "Sauber", bis auf das rauschen meines Oszis :)
ACIS1 und 0 können folgendermaßen Programiert werden :
1 0 = ACIS
0 0 Comparator Interrupt on Output Toggle
1 0 Comparator Interrupt on Falling Output Edge
1 1 Comparator Interrupt on Rising Output Edge

Mein Problem ist, dass der Interrupt auslöst, auch wenn ihm durch
ACIS1 und ACIS0 gesagt wurde das er nur auslösen soll wenn Z.b. die 
Flanke Fällt.
Momentan löst er bei jedem Wechsel aus.
Sorry wenn ich mich schlecht ausgedrückt habe :)
Gast #3416955
> Dazu soll der Comparator Interrupt jedes Mal Auslösen, wenn die Spannung
> am AIN1 geringer wird als die Referenz.
> ACSR = (0<<ACD)|(1<<ACIE)|(1<<ACIS1)|(0<<ACIS0);

Sie triggern derzeit auf die fallende Flanke des Ausganges des 
Komparators, also auf die steigende Flanke von AIN1.
Und was haben Sie an AIN0 angeschlossen?
Gast #3420189
Hallo,
heute Abend werde ich den Code mal mit dem ATmega64 ausprobieren um so 
Fehler ausschließen zu können.
<hat einer von euch evl. noch einen Code, wo der AC verwendet wird? :)
grüße
Gast #3420241
Vorschlag: Minimalaufbau zum Lernen:
Controller, 4 LEDs + Rs zur Kontrollanzeige, RC-Glied mit Taster an AIN1
Wie schon mal erwähnt die interne Referenz benutzen. Eine Variable in 
der ISR hochzählen und in der Hauptschleife auf den LEDs ausgeben.
Gast #3423347
Hallo,
ich habe den Code so umgeschrieben, dass ich sehen kann wie oft der 
Interrupt auslöst und kam zu einem erstaunlichen Ergebnis, der löst in 
der Zeit in der die LED einmal kurz blinkt insgesamt 4X mal aus 
(2mal=22X 3mal= 26X 3mal= 39X ...),
Darauf hin habe ich den Code so geändert das der Prozessor im Interrupt 
die Interrupts deaktiviert.
Sie werden auch erst dann wieder aktiviert, wenn die Anzeige wie oft der 
Interrupt ausgelöst hat fertig ist.
Leider löst der Interrupt immer noch viel zu oft aus (1mal = 2X 2mal = 
15X 3mal= 21X 4mal= 24X)
#3423502
martin schrieb:
> Darauf hin habe ich den Code so geändert das der Prozessor im Interrupt
> die Interrupts deaktiviert.

Das ist wohl keine Lösung, da auch bei abgeschaltetem I-Flag die 
Ereignisse zum Auslösen der Interrupts gescannt werden und auch die 
Interrupt-Pending-Flags gesetzt werden. Es wird lediglich der Aufruf der 
ISR unterdrückt, bis das I-Flag wieder gesetzt ist.

Falls Deine Interrupts durch Prellen des Signals auftreten, könntest Du 
das (zumindest teilweise) unterdrücken, indem Du am Ende der ISR das 
Pending-Flag (ACI in ACSR) löscht, also einen während der Abarbeitung 
der ISR aufgetretenen weiteren Interrupt entwertest. Dazu müsstest Du 
das Bit ACI im Register ACSR per Programm auf 1 setzen. Um das I-Flag 
musst Du Dich während der ISR nicht kümmern, das wird per Hardware beim 
Aufruf der ISR gelöscht und durch RETI (Rücksprung aus der ISR) wieder 
gesetzt.

...
Gast #3423728
Bei Assembler hätte ich nun gefragt, ob vielleicht der Stackpointer 
nicht inititalisiert wurde, aber da man ja angeblich in C "einfach 
losrennen" kann, ohne sich um solchen Thünkram zu kümmern, muss es wohl 
an etwas anderem liegen.
Gast #3424164
Verwendest du einen Taster? Falls ja, kann es sein, dass er prellt. 
Entweder - wie schon von anderen erwähnt - eine RC-Kombination mit 
größerem Tau als die Prellzeit vorschalten oder das Signal sauberer 
erzeugen. Im einfachsten Fall mit einem Frequenzgenerator 1 Hz, 
Rechteck. Oder einen Pin des µCs togglen. Der erzeugt kein Prellen.
Gast #3424257
ich verwende ein Netzteil um die Spannung zu erzeugen.
Des weiterem habe ich heute den Tiefpass gebaut(Kondensator 100up 
Widerstand 4k7) ob die Werte passen kann ich leider nicht beurteilen, 
aber dadurch ist die Anzahl der Ausgelösten Interrupts nicht 
zurückgegangen.
Gast #3425675
Also für mich nochmal zu Verständnis:
Sobalt einmal ein Interrupt ausgelöst ist werden in der Zeit(in der der 
Interrupt arbeitet) keine weiten Interrupts ausgeführt, auch wen das 
Signal Schwingt und der AC dadurch nochmal auslösen müsste?
Wieso ist den dann die Variable, die bei jedem Interrupt +1 gezählt wird 
so hoch ?
Und warum wirkt sich das dann auf das auslöse verhalten aus?
Gast #3425687
Hi

>Also für mich nochmal zu Verständnis:
>Sobalt einmal ein Interrupt ausgelöst ist werden in der Zeit(in der der
>Interrupt arbeitet) keine weiten Interrupts ausgeführt, auch wen das
>Signal Schwingt und der AC dadurch nochmal auslösen müsste?

Wenn während der Abarbeitung der Interruptroutine (mindestens) ein neues 
Ereignis eintritt, wird das gespeichert und der Interrupt wird nach der 
Interruptroutine erneut ausgelöst.

MfG Spess
Gast #3428697
OH vielen dank Spess :)
Ich habe jetzt am ende des ISR´s ACi mit einer 1 Beschrieben, und 
zusätzlich ein Delay von 10us eingebaut um so nachträgliches Rauschen zu 
verhindern.

Macht es den eigentlich Sinn den Comperrator so zu Programmieren, dass 
er bei steigender/fallender Flanke auslöst? (da ja jedes Signal Rauscht 
in meinem Beispiel mit ein mikro--Farad im ns Bereich)?
Grüße
Martin
#3428803
Martin schrieb:
> zusätzlich ein Delay von 10us eingebaut

Wenn Dir der AC-Interrupt zu schnell ist, dann lass den AC-Interrupt 
doch ganz weg und polle im Timer-Interrupt den AC-Ausgang (ACO in ACSR). 
Dort ist auch eine Entprellung möglich, die man mit einer 
Flankenerkennung kombinieren kann. Das verschlingt lange nicht so viel 
Rechenzeit wie ein 10ms-Delay und ist durch Variation des 
Timer-Intervalls recht gut an das Rauschen Deines Signals anpassbar.

...
Gast #3428824
> und das Signal ist "Sauber", bis auf das rauschen meines Oszis :)

> Des weiterem habe ich heute den Tiefpass gebaut

Und nun gibt es plötzlich ein Problem mit dem Rauschen.
Jetzt fällt mir nur noch Otto Reutter ein:
"Da fragt man sich ganz fassungslos
wie kommt das bloß, wie kommt das bloß?"
Gast #3434579
Vielen Danke für die vielen Ideen, die Schlussendlich zur Lösung meines 
Probleme frühten :D
Ich habe das Problem via dem ACO Bits gelöst.
ich Poste den Code für nachfolgende Leute die ähnliche Probleme haben :D

ACSR = (0<<ACD);

      while(1)
      {
        PORTB = (0<<PB2)|(1<<PB3);
      _delay_ms(100);
        while(ACSR &(1<<ACO))
        {
            PORTB = (1<<PB2)|(0<<PB3);
            _delay_ms(100);
        }

        while(ACSR &(0<<ACO))
        {
          PORTB = (0<<PB2)|(1<<PB3);
          _delay_ms(100);
        }

      }


Danke euch nochmal :D
Gast #3434717
Martin schrieb:
> Vielen Danke für die vielen Ideen, die Schlussendlich zur Lösung
> meines
> Probleme frühten :D
> Ich habe das Problem via dem ACO Bits gelöst.

Nein, hast du nicht. Du hast es durch einen Tiefpaßfilter gelöst (wie 
von mir vor gefühlten 100 Postings bereits empfohlen). Das ist nämlich, 
was deine dümmlichen Delays im Kern darstellen.

Daß dein Lösung funktioniert, weist übrigens noch auf eine Sache sehr 
deutlich hin: Du kannst nicht mit einem Oszi umgehen. Du warst nicht in 
der Lage, damit die für die Fehlfunktion verantwortlichen 
Signalbestandteile sichtbar zu machen. Nichtmal nach einem 
ausdrücklichen Hinweis, wonach du suchen mußt...

Du hast wohl noch sehr viel zu lernen. Dann würdest du wohl auch 
herausbekommen, daß Zeitkonstanten im Bereich von 100ms bei diesem 
Problem sehr deutlich darauf hinweisen, daß es eine Einflußnahme 
externer Schaltungsbestandteile gibt und diese wahrscheinlich über die 
Stromversorgung einwirken. Wohl die Referenz des AC unzureichend 
entkoppelt...

Ja, man kann solche krassen Schaltungsfehler auch durch Software 
kompensieren. "Schön" geht aber anders...
Gast #3435308
Die _Delay(100ms) sind nur dazu da, dass man am ende auch noch sehen 
kann, das die LEDs leuchten, und das man soweit möglich auf sie 
verzichten sollte weiß ich bereits :)
Dieser Aufbau soll legendlich ein Versuchsaufbau zeigen in dem der 
Prozessor sich nur um den AC kümmert.
#3435330
Martin schrieb:
> Dieser Aufbau soll legendlich ein Versuchsaufbau zeigen in dem der
> Prozessor sich nur um den AC kümmert.

Dumm ist nur, dass der "Prozessor" sich aufgrund der blockierenden 
Programmstruktur nur um den AC kümmern kann. Nun kommt es aber in der 
Praxis selten (eigentlich nie) vor, dass der Controller sich nur um 
ein Feature kümmern muss. Der Normalfall ist doch, dass so ein 
Controller auch noch weitere Aufgaben zu erledigen hat. Deshalb schreibt 
man die einzelnen Jobs so, dass sie möglichst wenig Rechenzeit binden 
und dem Controller die Möglichkeit geben, sich zwischendurch andere Jobs 
zu kümmern.

Meine letzte AC-Nutzung hatte ich bei der Auswertung eines 
RC-Empfängers. Dieser hatte kein Summensignal. Ich fasste daher Kanal 1, 
3 und 5 mit Dioden und PullDown-R zusammen (wired OR) und wollte diese 
mit dem ICP des Tiny2313 auswerten. Nur leider waren die Pegel durch den 
Spannungsabfall der Dioden zu niedrig für einen normalen Portpin. Also 
nutzte ich den AC als Eingang, die interne Bandgap-Spannung als Referenz 
und ließ den ICP-Interrupt vom AC auslösen. Geht wunderbar, decodiert 
hochpräzise alle 5 Kanäle und belastet dabei kaum die CPU. Somit kann 
sich der Tiny2313 voll um die anderen Aufgaben kümmern.

...
Gast #3435536
Martin schrieb:
> ist laut Datenblatt der ACD auf 1 ist der Comparator ausgeschaltet.
> Deshalb ziehe ich das bit auf 0 um ihn zu aktivieren.

Ja, aber genau das selbe passiert auch ohne das (0<<ACD). Denn 0<<ACD 
ist 0, und wenn man etwas mit 0 verODERt, ändert sich der Wert dadurch 
nicht.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 12 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.