PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Analog Comparator funktioniert nicht



Sylvia Heib
24.09.2009, 07:47
Hallo,

ich bin gerade dabei, den Analog Comparator meines Atmega32 ein zu
stellen.
ich habe mit dem Befehl
ACSR =(1<<ACBG);
den AIN0 auf innere Referenz (2,56V) umgeschaltet.

Danach mit
DDRB =(0<<PB3);
den AIN1 als Eingang definiert.


Laut AVR Tutorial würde der AC immer parallel zum Controller mitlaufen,
man müßte ihn sogar explizit ausschalten wenn man ihn nicht benötigt, um
Strom zu sparen.
Damit er AC auch wirklich eingeschaltet ist, sag ich dem ACSR noch:
ACSR = (0<<ACD);

Die Allgemeinen Interrupts werden mit
sei();
eingeschaltet

Über einen Spannungsteiler gebe ich nun die Vergleichsspannung auf den
Eingang AIN1.
Nun kommt das Problem:

Egal wie hoch die Vergleichsspannung ist, der AC gibt mir immer auf ACO
ein High heraus, er sagt also, die innere Referenzspannung sei höher als
die Vergleichsspannung.
Selbst wenn die Vergleichsspannung bei +5V liegt, meint der ACO, die
Referenzspannung sei aber immer noch höher.
Habe ich irgendetwas vergessen?


Ich habe da so ein Gerücht gehört, der AC des Atmega32 würde in der DIL
Version nicht funktionieren? Hat da jemand schon so etwas gehört, oder
ähnliche Erfahrungen gemacht?

Grüße von
Sylvia

PicNick
24.09.2009, 08:02
Was auch immer, um wirksam zu sein, muss das heissen
DDRB &= ~(1<<PB3);

ACSR &= ~(1<<ACD);

schaut pervers aus, is aber eben C, um einzelne Bits auf 0 zu setzen

Sylvia Heib
24.09.2009, 08:31
Hallo Robert,
ich habe den Code abgeändert, es funktioniert trotzdem nicht.
Aber danke für deine Antwort
Sylvia

wkrug
24.09.2009, 09:30
Ich hab mal das Datenblatt angeschaut.

Folgende Register müssen mit Werten befüllt werden:
SFIOR
ACSR

Wenns über Interrupts Laufen soll müssen diese auch enabled sein - Rätselhaft.

MCUCR ist auch eine beliebte Fehlerquelle, hat aber soweit ich sehe kein Bit für den Comperator und die Interrupts hast Du mit #asm("sei"); ja auch freigegeben.

Das die JTAGEN Fuse ist auch ein beliebter Fehler, betrifft aber nur den Port C

Sylvia Heib
24.09.2009, 11:07
Ich habe nun mit

SFIOR &= ~(1<<ACME);

ACME auf 0 gesetzt, damit laut Datenblatt AIN1 mit dem negativen Eingang des AC verbunden wird, aber.........
est verändert sich immer noch nichts.
Das JTAGEN Fuse ist gesetzt,
bei MCUCR wüsste ich jetzt nicht, was ich setzen soll.
Grüße von
Sylvia

PicNick
24.09.2009, 11:57
Was ich jetzt nachgelesen habe, sollte sein


ACSR &= ~(1<<ACD) ' comp aktiv
ACSR |= (1<<ACBG) ' intern. referenz
SFIOR &= ~(1<<ACME) ' AIN1 immer als Ref neg. Input

DDRB &= ~(1<<PB3); ' PB3 als Input
PORTB &= ~(1<<PB3); ' sicherheitshalber Pullup abschalten.
' kann nicht schaden


ehrlich gesagt, mehr weiss ich im moment auch nicht

Sylvia Heib
24.09.2009, 12:26
Habe den Code genauso geflasht, geht aber immer noch nicht.
Vielen Dank trotzdem!
Gruß
Sylvia

PicNick
24.09.2009, 12:47
Ich will mir nicht deinen Zorn zuziehen, aber vielleicht hat's doch was mit deinem Programm.
Sei doch mal so gut und zeig dein Programm mal her.

Sylvia Heib
24.09.2009, 13:39
Der Code ist in ein größeres Programm eingebunden,
prinzipiell sieht er so aus:



/*
* Der ATMEGA 32 wird als Slave konfiguriert, und wartet auf die Anweisungen des Masters. *
* Bekommt er eine 11 geschickt, soll der seine Lämpchen blinken lassen, bei einer 00 soll das Lauflicht *
* gestartet werden. Unterschreitet die Spannung am AC 2,5V, soll aus dem Programm ausgestiegen werden
*/

#include <avr/io.h>
#ifndef F_CPU
#define F_CPU 160000000UL
#endif
#include <util/delay.h>
#include <inttypes.h>
#include <avr/interrupt.h>
#include "outpin.h" // Lib um Pins ein und aus zu schalten
#include "i2csylvia.h" // Lib für die I2C übertragung
#include <avr/interrupt.h> // Externe Interrupts





outpin_t led2;
outpin_t led3;
outpin_t led4;
outpin_t led5;

uint16_t i;

uint8_t Spannung_weg; //Variable zur Betriebsspannungs anzeigen

int befehl;



void lauflicht(void)
{
....Code für ein Lauflicht
}


void blinklicht(int n, int ms)
{
.....Code für Blinklicht
}



// den Befehl ausführen
void takeorder()
{
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA); // Clear TWINT to start tranmission, send ACK to receive mor Bits
while (!(TWCR & (1<<TWINT))); // Wait for TWIN flag is set.This indicates that
// Data byte has been received, and ACK/NACK has been returned
befehl = i2cReadData();
switch(befehl)
{
case 11: blinklicht(2,200); // wird eine 11 geschikt : 2x langsam blinken
break;
case 00: lauflicht(); // bei einer 00 : 2 x lauflicht
break;
//default : blinklicht (4,100); // wird etwas anderes geschickt: schnelles Fehlerblinken
break;
}
}

int main (void)
{
DDRB &= ~(1<<PB3); // AIN1 als Eingang initialisieren
PORTB &=~(1<<PB3); // Sicherheitshalber Pullup abschalten


outpin_init(&led2,'A',7); // Initialisierung der LED`s 2-3 auf Port Ausgänge 3-7
outpin_init(&led3,'A',6);
outpin_init(&led4,'A',4);
outpin_init(&led5,'A',3);



sei(); // set enable interrupt --> global interrupts einschalten

i2cinit(16);
uart_init();




ACSR |= (1<<ACBG); // AC Auf Interne Referenzspannung (2,56V) umschalten
ACSR &= ~(1<<ACD); // AC explizit einschalten
SFIOR &= ~(1<<ACME); // AIN1 wird mit dem Invertierten Eingang des Comperators verbunden

TWAR = 0x40; // Die Slave Adresse wird auf "64" festgelegt
TWCR = (1<<TWEA)|(0<<TWSTA)|(0<<TWSTO); // Das Senden der Bestätigungsbits (ACK) zulassen,Start und Stop auf 0 setzen
TWCR =(1<<TWIE); // Interrupts zulassen
blinklicht(3,1000); // 3x langsam Blinken als optische bestätigung, das der Slave wartet

while(1) // In einer Endlosschleife auf die Befehle des Masters warten
{

Spannung_weg = ACO; // Comperator auslesen, sobald die Spannung am Testwiderstand 2,56V unterschreitet, ist ACO auf High (1)
if(Spannung_weg ==1) //Wenn die Betriebsspannung weg ist, aus dem Programm ausssteigen
{
blinklicht(1,1000);
break;
}


takeorder(); // Den gesendeten Befehl ausführen
}

}

PicNick
24.09.2009, 14:06
Au weia. Sollte heissen:


Spannung_weg = ACSR & (1<<ACO); // ACO aus ACSR rausfummeln
if(Spannung_weg != 0)
{
blinklicht(1,1000);


Zur Erläuterung:
ACO hat den festen Wert 5
Daher ist
Spannung_weg = 5

Und
if (Spannung_weg == 1)

geht nie auf

Sylvia Heib
24.09.2009, 17:41
Das verstehe ich nicht,
laut Datenblatt heist es doch, wenn Uist<Uref dann hat ACO = High, also 1
wenn Uist > Uref, dann ACO = Low also 0?
Wie kommst du auf 5?

Gruß
Sylvia

PicNick
24.09.2009, 18:56
ACO ist ja nur ein Bit im Register ACSR
die Bits dort ACSR haben die Nummern 7 - 0
dafür gibt es Namen, einer davon ist ACO, das ist Bit Nr 5
die Namen findest du in der Doku-PDF s 197

das dient dazu, dass man schreiben kann z.B


ACSR |= (1<<ACBG) und nicht
ACSR |= (1<<6)
beides ergibt
ACSR |= 0x40 (0100 0000)

danach ist genau dieses Bit im register gesetzt.

ACO


"ACO high" heisst, im ACSR steht xx1x xxxx
"ACO low " heisst, im ACSR steht xx0x xxxx

um es abzufragen, macht man also
Spannung_weg = ACSR & (1<<ACO);

das bedeutet
ACSR = xxNx xxxx (low oder hi)
(1<<ACO) = 0010 0000
logisch und & = 00N0 0000 --> ergebnis

in "spannung_weg" steht dann also entweder
0000 0000 ( Bit nr 5 "ACO" = 0)
oder 0010 0000 ( Bit nr 5 "ACO" = 1)

du kannst also auch nicht auf == 1) abfragen.



Hilft das als Tip, oder verwirrt das ?

Sylvia Heib
25.09.2009, 08:00
Hallo, du kannst gut erklären, das habe ich jetzt verstanden.
Nur ändern sich leider trotzdem nichts.
Mein ACO ist immer auf High.
Meine Vergleichsspannung ist im Normalfall auf 2,8V, da dachte ich mir, vielleicht ist der Unterschied zur inneren Referenzspannung 2,56V zu klein, und habe auf externe Referenzspannung umgeschaltet (einfach ACSR |=(1<<ACGB) auskommentiert).
Nun gebe ich eine Veränderliche Referenzspannung von 0-5V auf AIN0.
Aber egal, wie die Referenzspannung aussieht, sogar wenn sie 0V ist,
das ACO sagt:High, also sie sei größer als meine Vergleichsspannung 2,8V.
Warum nur?
Grüße von
Sylvia

PicNick
25.09.2009, 08:20
Du hast wohl nicht die Möglichkeit, einfach mal den Mega32 zu tauschen ? Es sollte nicht das Wölkchen des Zweifels über Dir kreisen, dass der µC vielleicht doch einen Schaden hat.
Dass der Comparator beim DIL grundsätzlich nicht funzt, habe ich noch nie gehört, kann es mit auch nicht vorstellen.

Wenn sich nicht inzwischen irgendein schlauer Kopf findet, der Dir wirklich helfen kann, werd ich wohl mein Zeug rauskramen und die Sache selbst versuchen. Ist ja zum Eierlegen. Bis dahin hab' ich wohl nur die Weisheit eines Pfarrers bei der Eheberatung *g*

Sylvia Heib
25.09.2009, 08:33
hab das Wölkchen vertrieben, und den µC ausgewechselt,
.....ändert nichts.
Gruß
Sylvia

wkrug
25.09.2009, 17:09
Lass mal dein Programm im Simulator vom AVR Studio 4 laufen und guck mal ob es dann da geht.
Oft sind es wirklich nur ein paar verwurstelte Bits, die das Problem machen.
Im Studio kannst Du die Reaktion deines Programms schritt für Schritt austesten.
Das hat mir bei der Fehlersuche schon oft geholfen.

Die Eingänge kannst Du durch manipulation der entsprechenden Portpins simulieren.

Der Simulator hat nur seine Schwächen, wenn die komunikation mit anderen Bausteinen getestet werden soll.

oberallgeier
26.09.2009, 09:41
Hi, Sylvia,


... den AIN0 auf innere Referenz (2,56V) umgeschaltet ... Über einen Spannungsteiler gebe ich nun die Vergleichsspannung auf den Eingang AIN1.
Nun kommt das Problem...Bitte nicht böse sein, wenn ich jetzt meinen Beitrag poste: hast Du GND Deiner Vergleichsspannungen und den GND Deines Controllers (also alle drei Niveaus !) miteinander verbunden? (Bei mir ist es so: offenkundige Fehler merke ich meist erst ganz zum Schluss - das ist leider auch hier im Forum schon dokumentiert :( ).

Sylvia Heib
01.10.2009, 08:16
ja,
alle GND''`s sind miteinander verbunden
Gruß
Sylvia

Sylvia Heib
01.10.2009, 10:35
Hab die LÖSUNG!!! O:)

ich schreibe:

Spannung_weg =((ACSR &(1<<ACO)) ?1 :0)

Das bedeutet:
Wenn der Wert in ACSR "true" ist (er wird hier 32, wenn das 5.Bit(ACO) auf High geht, dann soll Spannung_weg eine 1 sein.
Im anderen Fall ist Spannung_weg eine 0.
Nun kann ich schreiben:

if(Spannung_weg==1)
tue was....

Das funktioniert!
Danke für eure Hilfe
Grüße von
Sylvia

Ceos
01.10.2009, 10:59
es würde auch reichen, wenn du schreibst

if(!Spannung_weg)

das entspricht dem ausdruck

if(Spannung_weg == 0)

wenn du

i(SPannung_weg)

schreibst iss dass ungefähr so wie

if(Spannung_weg != 0)

nur zum verständnis

true und false versteht der gcc nur so, true ist alles was ungeleich 0 ist, false IST GLEICH 0