Hallo
ich bemühe mich schon seid Stunden diesen AD Wandler zum laufen zu
bringen doch bisher leider erfolglos. (Linear Technology)
Datenblatt unter:
http://www.linear.com/pc/downloadDocument.do?navId=H0,C1,C1155,C1001,C1152,P2287,D3179
Anschluss:
PIN 1,2 auf 5 Volt
PIN 3,5,7-10,14-16 auf 0 V (GND)
PIN 12 auf MISO, Atmega
PIN 13 auf SCK, Atmega
PIN 11 auf PC1, Atmega
Hier ist mein Programm, vielleicht könnt ihr mir helfen, vielen Dank.
(Erklärung unten)
// SPI, Atmega als Master
// MOSI, SS und SCK Ausgang, alle anderen als Eingänge
DDRB |= (1 << DDB3) | (1 << DDB5); // SPI Ausgänge aktivieren
DDRB |= (1 << DDB2); // Slave Select Ausgang
DDRC |= (1 << DDC1); // CS_nicht, ADC LTC2436
PORTC |= (1 << PC1); // CS_nicht ein
// Enable SPI, Master, Vorteiler 32
SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1);
SPSR = (1 << SPI2X);
uint32_t SPI_lesen() { // LTC2436
SPCR &= ~(1 << CPOL); // Polarität der Taktleitung, damit SCK von
Atmega
//SPCR |= (1 << CPHA);
PORTB |= (1 << PB2); // SPI aktivieren
PORTC &= ~(1 << PC1); // CS_nicht aus, ADC starten
unsigned char Daten1, Daten2, Daten3;
SPDR = 0;
while(!(SPSR & (1 << SPIF))) {
; // warten bis Daten übertragen
}
Daten3 = SPDR;
SPDR = 0;
while(!(SPSR & (1 << SPIF))) {
; // warten bis Daten übertragen
}
Daten2 = SPDR;
SPDR = 0;
while(!(SPSR & (1 << SPIF))) {
; // warten bis Daten übertragen
}
Daten1 = SPDR;
PORTC |= (1 << PC1); // CS_nicht ein, ADC aus
PORTB &= ~(1 << PB2); // SPI ausschalten
uint32_t wert = (Daten3 << 11);
wert |= (Daten2 << 3);
wert |= (Daten1 >> 5);
//SPCR &= ~(1 << CPHA);
//SPCR |= (1 << CPOL); // Polarität der Taktleitung
return wert;
}
Diese ADC hat nämlich ein 19 Bit Output-format ich hoffe das ich mich
beim hin und her schieben der Bits nich geirrt habe.
Weiters wird automatisch einmal Channel0 und beim nächsten ansprechen
Channel1 ausgelesen, d.h. man muss immer 2 mal auslesen pro Zyklus.
Folgendes verhalten hat mein Programm:
Ich mache eine Abtastung über den Timer interrupt alle Sekunden.
nun lege oich einen Spannungswert am Eingang des ADC an.
Komischerweise sprigt der Wert jetzt alle Sekunden hin und her, einmal
stimmt er, einmal ist er falsch (abwechselnd immer die beiden Werte).
Überprüfen kann ich den Wert auf einem LCD bzw. einen DAC.
Die letzten 16 Bit der Variable wert sollte dann der Integerwert sein.
Vielen Dank im voraus
Werner
Danke für den Hinweis, war hat aber leider das Ergebnis nicht verändert.
(Lustigerweise gibt der Compiler eine Warnung aus wenn ich in einer
anderen Routine um 17 Bit verschiebe)
Irgendwas mach ich falsch. Muss wohl nochmal das Datenblatt studieren.
Von den Bits her müsste es aber stimmen.
Werd wohl nochmal ein neues Bauteil probieren.
Werner
kannst du mal ein kompilierbares beispiel posten/anhängen?
Nicht dass am Ende das:
> Komischerweise sprigt der Wert jetzt alle Sekunden hin und her, einmal> stimmt er, einmal ist er falsch (abwechselnd immer die beiden Werte).
und das:
> wird automatisch einmal Channel0 und beim nächsten ansprechen> Channel1 ausgelesen,
zusammenhängen ;)
'ne genauere Fehlerbeschreibung wäre auch schön ;)
hth. Jörg
Mit dem neuen Bauteil geht's gleich besser!
Jetzt machen beide Channels grundsätzlich das richtige.
Allerdings steht im Datenblatt dass automatisch beim ersten Aufruf des
ADCs, Kanal 0 ausgelesen wird, beim 2 Aufruf Kanal 1, dann 0, dann 1,
immer abwechselnd (Ping Pong mäßig).
Das tut es bei mir noch nicht. Ich lese in meiner Hauptroutine 2x den
ADC aus, dann schreib ich ihn aufs Display. Blöderweise wird in Zeile 1
einmal der Wert von Kanal 0, einmal von Kanal 1 angezeigt.
Eigentlich sollte jeder in einer eigenen Zeile dargestellt sein(siehe
PRG).
Das heißt für mich er liest pro Zyklus nur einmal und nicht die zweimal
wie es im Prg steht, entweder sind längere Pausen notwendig oder ...?
Über Potis lege ich Spannungen an den ADC zum testen.
Erklärung zum Programm:
Diese Routine wird alle Sekunden aufgerufen (meine Abtastung):
ISR(TIMER1_COMPA_vect).
Von dort aus werden alle Routinen die benötigt werden aufgerufen.
mfg
Werner
Muss was korrigieren, genau genommen schreibt er lauter einsen in Bit
15-0.
zeigt nämlich 65535 an, am Display in Zeile 2 an.
Das heißt er liest bei jedem Routinen aufruf (Abtastroutine) einmal den
ADC aus. Darum toggelt der Wert in der ersten Zeile zw. Kanal 0 und 1
herum.
Werner
Laut Datenblatt (Diagramm, s. 8) wechselt der ADC den Kanal erst NACH
dem auslesen. Und die nächste Wandlung dauert rund 150ms (t_conv, S. 5).
Stell doch die Timer-ISR auf die halbe Zeit und lass abwechselnd einen
Kanal in die passende Zeile ausgeben.
(da deine ISR aber schon ziemlich lang ist, würde ich auf Job-Flag (oder
sleep-Mode) umstellen: der Timerinterrupt setzt eine Variable/ein Bit,
die main() fragt diese Variable ab und verarbeitet die Werte, sobald die
Sekunde rum ist)
hth. Jörg
Danke
das hab ich mir auch schon gedacht mit Zeit halbieren.
Das richtige Programm kommt erst das ist nur ein kleiner Teil davon.
Es kommen noch ein paar Rechnungen hinzu, geht sich aber alles aus, hab
ich schon getestet mit dem internen ADC.
Wird nämlich eine Temperaturgeregelte Stromregelung wo ein
Temp.abhängiger Widerstand in einer Brückenschaltung ausgewertet wird,
... .
Ich habs in der ISR gemacht damit mir kein anderer Interrupt die
Routinen unterbricht (man kann zwar die Interrupts abstellen, aber naja,
auch nicht sauber):-).
Auf alle Fälle nochmal vielen Dank für deine Hilfe
Werner
Eine eigene Frage?
Dieser Thread ist über 19 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.