Guten Abend liebe Forumsmitglieder, ich bin noch ein Anfänger und meine Erfahrungen in Sachen Mikrocontrollerprogrammierung sind noch nicht so gut, von daher möchte ich gerne eine Frage in dieses Forum hineinstellen - genaugenommen sind es mehrere Fragen. Einiges habe ich schon anhand des Datenblatts verstanden, aber an anderen Stellen bin ich mir noch nicht so sicher. Ich habe einen AD-Wandler mit der Bezeichnung Max186. Dabei handelt es sich um einen 12bit-AD-Wandler, der acht Kanäle hat. Die Kommunikation findet über den SPI-Bus statt - und genau an der Stelle harpert es. Ich möchte den Max186 mit meinem Raspberry Pi verbinden. Der Raspberry Pi verfügt schon über einen SPI-Bus und über Python kann ich die SPI-Funktionen einbinden. Hier ist mal ein Link zum Datenblatt von dem ADC: http://datasheets.maximintegrated.com/en/ds/MAX186-MAX188.pdf Der SPI-Bus besitzt also 3 Verbindungsleitungen - MISO, MOSI, SCLK/CLK. Diese drei Leitungen verbinde ich mit dem Raspberry. Ein Problem ist - der ADC arbeitet mit 5 Volt, der Raspi mit 3,3 Volt. Die Pegel an den GPIO-Ports am Raspi betragen etwa 3 Volt. Die Mindestspannung an den Kontakten vom ADC muss 2,4 Volt betragen, damit der ADC an dem jeweiligen Kontakt auf HIGH schaltet. Also reicht das aus vom Raspi. Der ADC liefert einen Pegel von 4 Volt (Output Voltage High). Da baue ich mir dann einfach einen kleinen Spannungsteiler, damit die Spannung, die ich an den Pin des Raspis sende, max. 3 Volt beträgt und ich den Raspi nicht kaputt mache. Dann muss ich noch CS mit einem freien GPIO-Port des Raspis verbinden und da fangen meine Schwierigkeiten an. Im Datenblatt steht über dem Anschluss CS (Chipselect) ein Balkten. Dass heisst für mich, dass ich alles negiert zu betrachten habe. Ich habe es jetzt so verstanden - ist der Pegel von CS_quer = HIGH, dann befindet sich der ADC im Ruhezustand - also muss ich den Pin vom Raspi auf HIGH setzen, wenn der ADC aus sein soll. Möchte ich nun mit dem ADC kommunizieren, dann muss ich den GPIO-Port vom Raspi auf LOW setzen, damit der ADC "eingeschaltet" wird. Habe ich das so richtig kapiert? Und jetzt kommt mein nächstes Problem - die Sache mit dem Clock. Am SPI-Bus ist ja ein Anschluss mit der Bezeichnung Clock vorhanden (SCLK). Ich habe es jetzt so verstanden - immer, wenn ein Clock-Signal gesendet wird, dann wird ein Bit vom ADC gelesen und auch gesendet (auch auf dem Raspi). Wenn ich nun mit meinem ADC kommunizieren will, dann würde ich es folgendermassen machen: Init-Zustand: GPIO = HIGH (damit ADC ausgeschaltet ist). Kommunikationszustand: GPIO = LOW (ADC einschalten) Sende/Empfange über SPI, bis Vorgang abgeschlossen GPIO = HIGH (ADC ausschalten) Ich bin mir jetzt leider noch nicht sicher, ob ich es so richtig verstanden habe. Ich würde mich sehr freuen, wenn jemand von Euch mir etwas weiterhelfen könnte.
Das Raspberry Pi hat Harware-CS-Pins für SPI, das sind die CE0 und CE1 hier: http://elinux.org/images/2/2a/GPIOs.png Nimm einfach die, dann sollte der SPI-Controller dir diesen Problembereich schonmal abnehmen.
AD-Wandler mittels SPI auslesen schrieb: > Wenn ich nun mit meinem ADC kommunizieren will, dann würde ich es > folgendermassen machen: > > Init-Zustand: > GPIO = HIGH (damit ADC ausgeschaltet ist). > > Kommunikationszustand: > GPIO = LOW (ADC einschalten) > Sende/Empfange über SPI, bis Vorgang abgeschlossen > GPIO = HIGH (ADC ausschalten) Richtig, in etwa so läuft das im Allgemeinen, auch wenn du vergessen hast zu erwähnen, ob die auch den richtigen SPI-Mode eingestellt hast, es gibt nämlich derer vier. Allerdings beschreibt SPI auch bloß die gundsätzliche Funktionsweise der Kommunikation. Der Teufel steckt aber oft im Detail, nämlich in deiner Zeile > Sende/Empfange über SPI, bis Vorgang abgeschlossen hast du gleich zwei völlig nichtssagende Allgemeinplätze verwendet, nämlich "Vorgang" und "abgeschlossen". Das ist beides nicht von SPI abgedeckt, sondern fast bei jedem Scheiß-Chip ein wenig anders umgesetzt. Und die Beschreibung dieser wichtigen Details ist leider nur in wenigen Datenblättern wirklich eindeutig und völlig unmißverständlich. Manchmal hat man sogar fast den Eindruck, daß ausgerechnet bei diesem Kapitel der Schreiberling absichtlich vorher abgefüllt wurde... Wie auch immer. Was ich eigentlich sagen wollte: SPI kann schon für sich selber genug Probleme schaffen. Zusätzliche Probleme durch improvisierte oder gleich ganz abwesende Pegelwandler will man da echt nicht auch noch haben. Du solltest also deine Bastellösungen besser über Bord werfen, wenn du nicht tagelang darüber rätseln willst, ob nun deine Software noch unfertig ist oder ob es wegen der improvisierten Hardware nicht funktioniert. Solche Bastellösungen kann man mal ausprobieren, wenn man sich mit dem speziellen Target bereits auskennt und es in einer ordentlichen Hardwareanbindung stabil am Laufen hat. Wenn es nämlich dann ohne Pegelwandler nicht mehr funktioniert, weiß man wenigstens sofort, woran es liegt...
c-hater schrieb: > Du solltest also deine Bastellösungen besser über Bord werfen, ok, und was soll ich dann stattdessen machen?
Schade, für den MCP3008 gäbe es fertigen Code und ausführliche Anleitungen. https://learn.adafruit.com/reading-a-analog-in-and-controlling-audio-volume-with-the-raspberry-pi Viellecht findet sich da ein Hinweis auf das übersehene Detail.
AD-Wandler mittels SPI auslesen schrieb: > Dann muss ich noch CS mit einem freien GPIO-Port des Raspis verbinden > und da fangen meine Schwierigkeiten an. Im Datenblatt steht über dem > Anschluss CS (Chipselect) ein Balkten. Dass heisst für mich, dass ich > alles negiert zu betrachten habe. Ich habe es jetzt so verstanden - ist > der Pegel von CS_quer = HIGH, dann befindet sich der ADC im Ruhezustand > - also muss ich den Pin vom Raspi auf HIGH setzen, wenn der ADC aus sein > soll. Möchte ich nun mit dem ADC kommunizieren, dann muss ich den > GPIO-Port vom Raspi auf LOW setzen, damit der ADC "eingeschaltet" wird. > Habe ich das so richtig kapiert? Hast du. Der Raspberry ist der Master und der kann mit den Slaves sprechen. Damit die Slaves auch wissen wer genau gemeint ist bekommen sie das durch ChipSelect mitgeteilt. Und den Querstrich hast du richtig interpretiert ;) AD-Wandler mittels SPI auslesen schrieb: > Ich habe es jetzt so verstanden - immer, wenn ein Clock-Signal gesendet > wird, dann wird ein Bit vom ADC gelesen und auch gesendet (auch auf dem > Raspi). Auch das ist richtig. Doch vorsicht. Wichtig ist hier auch in welchem Clock-Mode du dich befindest. Bist du im external Mode dann gibst du an der SCKL-Leitung die Abtastrate vor mit der die Analogsignale gesampelt werden. Das ist ein wenig tricky. Schau dir auch mal die Timing-Diagramme an.
Michael Köhler schrieb: > Doch vorsicht. Wichtig ist hier auch in welchem Clock-Mode du dich > befindest. Bist du im external Mode dann gibst du an der SCKL-Leitung > die Abtastrate vor mit der die Analogsignale gesampelt werden. Das ist > ein wenig tricky. Schau dir auch mal die Timing-Diagramme an. Ich möchte gerne den internen Clock-Mode benutzen, aber das kann ich ja über das Datenbit einstellen, dass ich dann über den SPI-Bus versenden möchte. In der Tabelle 2 in dem Datasheet (Control-Byte-Format) kann ich ja einstellen, welchen Clock-Modus ich verwenden will, welcher der 8 Kanäle abgetastet werden soll, ob die Messung uni- oder bipolar und sigle-ended oder differentiell ist. Wenn ich es also erfolgreich angeschlossen habe und ich am Kanal 1 mit Internal-Clock, Single-Ended, unipolar messen möchte, dann bastele ich mir ein Byte: SendByte = 10001110 Also würde mein Programm im Pseudocode etwa so aussehen: # init GPIO(CE0) = HIGH SendByte = 10001110 # LeseWert: CE0 = LOW Sende SendByte CE0 = HIGH warte 1,5 Mikrosekunden (acquisition time) CE0 = LOW Lese LeseBytes CE0 = HIGH Ich muss ja einen Moment warten, bis die Messung am ADC fertig ist. Ich habe es jetzt so verstanden, dass ich nach dem Senden von SendByte CE0 erstmal wieder auf HIGH setzen muss (Figure 9 in dem Datasheet). Nach der Acquisition-Time von 1,5 Mikrosenkunden setze ich CS = LOW und bei der fallenden Flanke von SCLK wird das erste Bit empfangen. Kann ich eigentlich auch länger als die 1,5 Mikrosekunden warten? In dem Datenblatt habe ich gelesen, dass man ein ExternalClock nur benutzen soll, wenn es schnell genug geht. Wenn man länger als 10 Mikrosekunden wartet, dann entläd sich der Kondensator am Hold-Glied und die Messung wird verfälscht. Aber um den erzeugten Wert zu lesen, müsste ich doch theoretisch auch eine Sekunde warten können - oder geht der binäre Wert, der dann seriell über den SPI-Bus versendet wird, auch nach einiger Zeit "verloren", wenn er nicht schnell genug gelesen wird (also meine Wartezeit zu lange ist)?
Ich glaube, das ist oben untergegangen: Der SPI-Controller hat ein Hardware-CE, was automatisch immer so geschaltet wird, wie es sein soll (CE0/CE1 auf dem Pin-Header). Bei mir hat das immer funktioniert. Willst du es nicht erstmal damit versuchen?
Sven B. schrieb: > Willst du es nicht erstmal damit versuchen? Doch will ich - ich habe es erst durch Deinen Beitrag verstanden, dass die beiden CE0/1 auch zum SPI-Bus gehören, aber ich wollte es gerne vom Grundprinzip her verstanden haben. CE0/1 wird ja automatisch durch das SPI-dev-Modul von Python gesetzt, weil ich dort ja anwählen muss, welcher device benutzt wird.
Ja, genau. Gut, zu Lehrzwecken ist das sinnvoll das so zu machen :-)
Ich hab jetzt noch ein Problem mit der maximalen Strombelastbarkeit des D_out-PINS an dem ADC. Ich muss mir ja einen Spannungsteiler bauen und der Gesamtwiderstand des Spannungsteilers muss so gewählt werden, dass der Strom nicht zu groß (und ggf. auch nicht zu klein) sein darf. Ich finde dazu keine Angabe in dem Datenblatt. Ich habe in der Tabelle bei "Electrical Characteristics" im Datasheet geschaut (Seiten 3-5) und lediglich auf Seite 4 unter "DIGITAL OUTPUTS DOUT, SSTRB) gefunden, dass Output Voltage Low = max. 0,4 Volt ist Output Voltage High = min 4 Volt Leeakage Current = +- 10 uA Output Capacity = 15pF. Ist das die Angabe Leakage Current, die ich zur Bestimmung des Gesamtwiderstands verwenden muss?
In Abs. Maximum Ratings steht "Digital Output Sink Current 25mA". 1 bis 2mA pro Pin ist auf jeden Fall ok würde ich sagen.
:
Bearbeitet durch User
Ist mit "Sink Current" der Gesamtstrom gemeint, mit dem der ADC belastet werden darf? Dort steht auch bei Absolute Maximum Ratings: Vdd to AGND -0,3V to 6 V. Warum ist dort von -0,3 Volt die Rede? Heisst das "nur", dass der ADC bis -0,3 Volt nicht kaputt geht? Könnte ich den ADC auch mit 3,3 Volt betreiben? So würde ich das jetzt verstehen. Aber das geht ja nicht, da die Vergleichsspannung vom ADC 4,096 Volt betragen muss. Dat der ADC dazu einen internen Spannungsregler, der dann aus den 5 Volt exakte 4,096 Volt macht?
Die Absolute Maximum Ratings geben an, bei welchen Werten der IC knapp
noch nicht kaputt wird. Das heißt aber nicht dass er im gesamten Bereich
auch zuverlässig funktioniert. An diesen sollte man sich im Normalfall
auch nicht orientieren.
In den ELECTRICAL CHARACTERISTICS steht was von
>Positive Supply Voltage VDD 5 ±5% V
:
Bearbeitet durch User
AD-Wandler mittels SPI auslesen schrieb: > Ist mit "Sink Current" der Gesamtstrom gemeint, mit dem der ADC belastet > werden darf? Ich weiß leider nicht, ob sich das auf einzelne Outputs oder auf die Summe bezieht. 25mA pro Output klingt eigentlich zu viel. Aber bestimmt weiß das jemand anders hier.
Ok, ich belaste den D_Out vom ADC mit 1mA. Ich hab jetzt ein kleines Problem. Ich habe jetzt versucht, mit dem Oszi den SPI-Bus zu checken. Wenn ich MISO und MOSI brücke und mit dem Oszi messe, dann sehe ich ein Binärsignal im Oszi und empfange am SPI-Bus etwas. Wenn ich jetzt nur alleine den MOSI-Anschluss checke, dann sehe ich am Oszi garnichts. Ich habe auch schon versucht, den MISO-Anschluss auf Masse und einmal auf Vcc zu legen - da misst das Oszi auch nichts. CS und SCLK funktionieren beide einwandfrei. Ich habe auch es dierekt am ADC ausprobiert, MOSI an D_In am ADC und MISO mit D_out verbunden. Dort genauso - ist das verbunden, dann messe ich keine Pegel im Oszi. Woran könnte das liegen?
Wenn der CS falsch ist sendet der ADC nicht, sondern hat tristate and Dataout. Ich implementiere eine SPI Schnittstelle jeweils per software genau nach datenblatt. Manche Datenblaetter haben diesbezueglich keine Redundanz, dh man muss jeden Satz genau lesen und verstanden haben, nicht einfach Annahmen treffen.
Meine Erfahrung mit SPI ist dass man beim Empfänger (also beim Slave bei MOSI und CS und beim Master bei MISO) einen kleinen Kondensator (100pF) nach GND braucht, weil sonst wegen kleiner Störungen oft komisches Zeug passiert. Kannst du ja mal versuchen. Grüße, Sven
Vielen Dank fuer die Vielzahl Eurer Tipps. Irgendwie hats auf einmal funktioniert. Ich hoffe, dass es jetzt aber nur nicht auf dem Steckbrett so ist, sondern auch noch, wenn ich später den Kram auf eine Platine schweiße.
AD-Wandler mittels SPI auslesen schrieb: > Irgendwie hats auf einmal funktioniert. Passt auch zu meiner Aussage mit dem Kondensator.
AD-Wandler mittels SPI auslesen schrieb: > wenn ich später > den Kram auf eine Platine schweiße. Ich empfehle löten, beim Schweißen wirst du die Bauteile wahrscheinlich töten.
Ich habe nun ein Softwareproblem beim Auslesen des AD-Wandlers. Ich empfange etwas und kann auch was senden. Ich habe ein kleines Python-Programm für den Raspberry geschrieben, dass den AD-Wandler auslesen soll:
1 | Import spidev |
2 | Import time |
3 | |
4 | spi = spidev.SpiDev() |
5 | spi.open(0,0) |
6 | |
7 | sendbit = [] |
8 | sendbit.append(0b10000010) # bipolarer Modus |
9 | acquisition_time = 12./1000000 |
10 | |
11 | spi.writebytes(sendbit) |
12 | time.sleep(acquisition_time) |
13 | result=spi.readbytes(2) |
Bei der Variable result hab ich so meine Probleme. Es sind dort zwei Werte enthalten, einmal für das bit0 und dann für das bit1. Das AD-Wandlerergebnis ist 12bit breit. Ich messe bipolar, also von -2 bis +2 Volt. Eines der 12 Bits muss also für das Vorzeichen stehen, ob plus oder minus. Ich gehe davon aus, wenn das MSB=True ist (most significant bit), dann ist das Ergebnis positiv, also Spannung größer Null. Ich habe es im Datenblatt aber noch nicht gefunden. Jetzt geht es noch darum, die Bits zusammenzufassen, um ein Gesamtergebnis zu bekommen. Dazu habe ich mir gedacht, dass ich Bit0 einfach um vier stellen nach links shifte, Bit1 vier Stellen nach rechts. Regebnis = (result[0]<<4)&(result[1]>>4) Aber irgendwie kommt da nichts gescheites bei heraus und ich weis nicht, wo der Fehler liegen könnte.
Huch? Komische Umrechnung. Ich würde sowas machen wie (bits[1] << 8) + bits[0] oder so. Modulo Vorzeichen.
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.