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
die 'einfachste' Lösung wäre:
1 | //...
|
2 | uint32_t wert; |
3 | //lesen ...
|
4 | wert = ((uint32_t)SPDR << 11); |
5 | //lesen...
|
6 | wert |= ((uint32_t)SPDR << 3); |
7 | // lesen ...
|
8 | wert |= (SPDR>>5); |
9 | //...
|
Aber bei deiner Lösung fehlen wahrscheinlich nur die casts (merke: man kein ein Byte nicht 11 Mal schieben ;) ) hth. Jörg
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
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.