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:
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.
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...
> 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 ?
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 :)
> 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?
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
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.
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)
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.
...
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.
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.
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.
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?
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
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
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.
...
> 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ß?"
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
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...
Martin schrieb:> Ich habe das Problem via dem ACO Bits gelöst.
Hast Du nicht. Delays im 100ms-Bereich lösen kein Problem, sie sind das
Problem.
Ich empfahl Dir Pollen im Timer-Interrupt, evtl. kombiniert mit der
Entprellung (das ist ein Link auf einen Wiki-Artikel!!!) nach Peter
Dannegger, die auch die Flankenerkennung enthält.
...
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.
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.
...
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.