Auslesen eines MCP3008 mit Pigpio oder anderer Library in C

  • Liebes Forum,

    Ich und meine Teamkollegen sind Programmieranfänger und bauen für einen Wettbewerb gerade einen fahrenden Roboter, der unter anderem in der Lage sein muss Analogwerte auszuwerten. Dazu haben wir uns zwei MCP3008 besorgt. Das ist ein A/D-Wandler, mit dem man über den SPI-Bus kommunizieren kann und der acht Eingangskanäle für acht Analogwerte hat.

    Um den MCP3008 auszulesen haben wir zunächst diese Library verwendet.

    Diese funktioniert zwar und lässt sich sehr leicht bedienen, allerdings stellte sich heraus, dass das Auslesen des Wandlers viel zu lange dauert. Für die Abfrage eines einzelnen der acht Eingangskanäle am A/D-Wandler wird mehrfach eine Datei geöffnet und geschlossen, was letztlich ca. 25 Millisekunden pro Kanal dauert. Bei insgesamt 12 Analogwerten die wir verarbeiten müssen, ist das für uns nicht zu gebrauchen.

    Daher haben wir uns der Pigpio Library zugewendet. Auf deren Homepage gibt es ein Beispielprogramm (Code s. unten), dass wir auch schon ausprobiert haben. Das Auslesen geht hier sehr schnell.

    In dem Beispielprogramm geht es zwar darum, zwei Kanäle von zwei MCP3008 gleichzeitig abzufragen. Für unsere Zwecke würde es reichen die Kanäle zweier MCP3008 alle nacheinander abzufragen, aber wenn man immer zwei gleichzeitig bekommt, jeweils einen von jeweils einem der beiden Wandler ist das natürlich auch ok.

    Dazu müssten wir es allerdings mit dem Programm hinbekommen den abgefragten Kanal auch zu wechseln und daran scheitern wir momentan.

    Wir haben deher zwei Fragen:

    a) Kann uns jemand eine einfachere Möglichkeit aufzeigen zwei MCP3008 auszulesen?

    b) Oder kann uns jemand helfen das Beispielprogramm richtig zu verstehen, so dass wir die Kanäle wechseln können?

    Zu a)

    Wir wollten ungerne WiringPi verwenden, da wir aus verschiedenen Gründen dringend Pigpio brauchen, aber vielleicht kann man unter Umständen ja auch gefahrlos beide kombinieren? Das wäre dann wohl ein Thema für einen anderen Thread, bzw. eine lange Reihe von Feldversuchen.

    Zu b)

    Nach unserem bisherigen Verständnis müsste man den Wert von „buf“ in Zeile 147 so ändern, dass die Funktion rawWaveAddSPI die richtige Bitfolge für den MCP3008 kennt, entsprechend dem Kommentar in den Zeilen 127-134.

    Im Beispiel steht an dieser Stelle „0xC0“, also binär „11000000“. Die Bits für die Auswahl des Kanals wären dem Kommentar entsprechend der vierte, fünfte und sechste von rechts. Gewählt wäre hier also Kanal 0.

    Ändern wir den Wert von „buf“ beispielsweise in „F8“, also „1111100“, müsste man also Kanal 7 ausgewählt haben. Oder „C8“ für „11001000“ also Kanal 1.

    So klappt es aber leider nicht. Der Kanal der abgefragt wird bleibt bei beiden angeschlossenen Wandlern der Kanal 0.
    An Kanal 0 kann Spannung gemessen werden und an keinem der anderen. Wir haben auch nicht vergessen neu zu kompilieren. Wir hocken schon ziemlich lange daran.

    Unser Verdacht ist, das an mindestens einer anderen Stelle noch was geändert werden muss und dass das in den Kommentaren nicht gekennzeichnet ist, da der Zweck des Programms ja ein anderer ist. Nämlich zu demonstrieren wie man zwei der Wandler zum gleichen Zeitpunkt ausliest.

    Vielen Dank euch schonmal!


    Hier das Programm von dem ich spreche (hier auch nochmal ohne Zeilennummern):


    Hier die Funktion rawWaveAddSPI aus der Pigpio-library Version 61

    Einmal editiert, zuletzt von Wonnegrausen (18. April 2017 um 19:50)

  • Auslesen eines MCP3008 mit Pigpio oder anderer Library in C? Schau mal ob du hier fündig wirst!


  • bemühe doch bitte erst mal die Forensuche mit dem Stichwort "MCP3008" im Betreff ...
    Da wirst Du seitenweise Informationen finden ...

    Sorry, das war mir bekannt, aber ich hatte nichts gefunden, das sich auf C bezog und so aus sah, als könnte es helfen.


    Versucht es mal so:

    Code
    buf[0] = 0xC8; // Start bit, single ended, channel 1.
            
    rawWaveAddSPI(&rawSPI, offset, SPI_SS, buf, 5, BX, B0, B0) ;

    Fantastisch, besten Dank dafür! Ich kann jetzt alle 8 Werte auslesen. "spiTxBits" scheint irgendwie die Anzahl der gesendeten control-Bits zu sein die überhaupt auf "1" gesetzt werden können?

    Wenn es mir gelingt, werde ich dieses Programm in eine Funktion packen der man nur noch ein paar Parameter geben muss und die dann einen oder mehrere Werte zurück gibt, je nachdem ob man einen oder mehrere Wandler angeschlossen hat.

    Momentan kann ich das was hier im Beispiel die Main Funktion ist nur einmal richtig aufrufen, vor oder während dem zweiten Mal kommt dann "Sig handler: Unhandled signal 11, terminating" Dazu las ich woanders: "signal 11 is a segment violation, i.e. the program is accessing memory outside of that allocated to the program.".

    Evtl. wird beim zweiten Mal irgendetwas getan, das das Programm nur einmal tun darf?

    Ich lade herzlich dazu ein mir weiterhin zu helfen. Wenn hier am Ende die besagte Funktion steht, könnten ähnlich unbedarfte Leute das dann auch für ihre Projekte nutzen. :thumbs1:

    Ich habe bei #define alles so eingestellt, dass erstmal nur ein Wandler ausgelesen wird und der Messwert "val" ist jetzt Return-Wert der Main Funktion. Diese Main Funktion habe ich "test" genannt und versuche diese dann in einer neuen Main mehrfach aufzurufen (s. unten, Zeile 53)

    Funktionieren tut das wie gesagt genau einmal und das Terminal sieht dann so aus:

    Ansonsten ist vielleicht noch interessant, dass wenn ich in der neuen Main-Funktion das printf vor dem Aufrufen der "test"-Funktion nicht auskommentiere printf("Position 1\n"); , steht im Terminal außer "Position 1" überhaupt nichts mehr. Das Programm scheint sich schon zu schließen bevor es zu irgendeinem anderen printf kommt.
    Vielleicht versuche ich mich doch zum ersten mal in der Anwendung eine Debuggers bevor ich weitermache...

    Einmal editiert, zuletzt von Wonnegrausen (19. April 2017 um 14:11)

  • Hallo Wonnegrausen,

    wenn ein Programm nicht macht, was ich erwarte, dann gehe ich da folgendermaßen vor:

    Ich suche die erste Programmzeile, die ausgeführt wird. Die schreibe ich in eine Zeile (oder meinetwegen die Zeilennummer). Daneben schreibe ich in mehreren Spalten die aktuellen Werte der verwendeten Variablen.
    Dann nehme ich die nächste Zeile. Wenn eine andere Funktion aufgerufen wird, mache ich das mit dieser Funktion genauso ...

    Wenn Du das auch so machst, dann wird Du feststellen, dass Du genau das Verhalten, das Du gerade beobachtest, auch so programmiert hast.

    Als Hinweis: Die Zeile, die eine Mehrfachmessung zunichte macht, hat sich in die Funktion [font="Courier New"]test()[/font] "verirrt". Man kann auch sagen: Vermurkstes Design...

    Deswegen darf auch nur eine einzige Messung durchgeführt werden. Die Fehlermeldung ist absolut berechtigt.


    EDIT2: Diese Schritte habe ich im Kopf gemacht - den Fehler aber trotzdem lokalisiert...

    EDIT1: Übrigens: Der Code selber ist sehr wüst und zeugt nicht unbedingt davon, dass Ihr Euch über die Library-Funktionen im Klaren seid. Das ginge alles deutlich einfacher. Aber das ist ein ganz anderes Thema.


    Beste Grüße

    Andreas

    Ich bin wirklich nicht darauf aus, Microsoft zu zerstören. Das wird nur ein völlig unbeabsichtigter Nebeneffekt sein.
    Linus Torvalds - "Vater" von Linux

    Linux is like a wigwam, no windows, no gates, but with an apache inside dancing samba, very hungry eating a yacc, a gnu and a bison.

    Einmal editiert, zuletzt von Andreas (19. April 2017 um 15:22)

  • Servus,
    ich hab' mit der pipgio und SPI bisher noch nichts zu tun gehabt, aber ich frage mich, warum Du Funktionen wie rawWaveAddSPI() benutzt, die in der pigpio.h ( https://github.com/joan2937/pigpio/blob/master/pigpio.h ) explizit als "Not intended for general use" verwendest?

    Warum machst Du Dir das Leben so schwer und verwendest nicht einfach die "normalen" SPI-Funktionen der Library (spi_open(), spi_read(), ... -> click <- )? :s

    cu,
    -ds-

  • Vielleicht habe ich das Ganze ein bisschen missverständlich dargestellt.

    Das Programmbeispiel ist nicht von mir. Das habe ich von der offiziellen Pigpio-Seite. Ob es dennoch von jemanden geschrieben wurde, der sich nicht gut mit der Library auskennt, kann ich nicht beurteilen. Das beinahe-Original steht mehr oder weniger im ersten Post und da habe ich auch das Original verlinkt.

    Von mir ist lediglich folgender Versuch:

    Code
    int main(void)
    {
                   while(1)
                   {
                   /* printf("Position 1\n"); */
                   printf("Kanal 7: %i\n", test());
                   printf("Position 2\n");
                   }
    return 0;
    }

    Sowie ein paar Modifikationen an dem Programm selbst, die das Ganze funktionieren lassen sollen. Z.B. dass die ehemalige main-Funktion jetzt die Funktion „test“ ist und den Wert "value" zurückgibt, was ja auch einmal pro Programmaufruf funktioniert.

    Ich handele deshalb so, weil ich mich erst seit kurzem mit Programmierung auseinandersetze und mir bis jetzt nicht zugetraut habe, mit den vorhandenen SPI-Funktionen einen funktionierenden SPI-Bus herzustellen. Deshalb versuche ich mit etwas vorhandenem mir eine Funktion zusammenzubasteln die ich in meinem Programm verwenden kann.

    Ich sehe mich jedenfalls momentan nicht in der Lage den Fehler in meinem obigen Versuch zu finden. Ich würde mich gerne hinsetzen und anständig C Programmieren lernen, aber da es sich eigentlich um eine Regelungstechnische Aufgabe handelt (die die anderen Projektteams mit einem Arduino bestreiten), haben wir noch ein paar andere Bretter zu bohren und ich versuche daher mit recht wenig weit zu kommen und schlimmstenfalls um Hilfe zu betteln.

    Ich werde mich mal mit den SPI-Funktionen auseinandersetzen. Wenn Andreas mir dennoch die Lösung des obigen Rätsels ausnahmsweise verrät, wäre ich ihm sehr dankbar, dann hätte ich evtl. etwas als Notlösung.
    :danke_ATDE:


    EDIT:

    zu Funktion spi_open: Sehe ich das richtig, dass dazu der pigpio daemon laufen muss? Ich hatte bisher ohne gearbeitet.

    Einmal editiert, zuletzt von Wonnegrausen (19. April 2017 um 18:32)

  • Naja ... wenn dem so ist wie Du schreibst, dann ist es doch vollkommen kontraproduktiv einfach irgend einen Code zu verwenden, den Du selbst gar nicht verstehst. Notfalls musst Du halt ein anderes Beispiel suchen, das Du auch verstehst.
    Deshalb ja meine Frage ...
    Die Vorgehensweise ist in so einem Fall (Bausteine per SPI ansteuern) doch:
    Datenblatt nehmen, Schaltung entwerfen und aufbauen
    Kommunikations-Art feststellen ( in Deinem Fall SPI )
    einen SPI-Kanal öffnen
    Protokoll aus dem Datenblatt entnehmen
    Control-Byte ermitteln und senden
    Antwort des Slave lesen und lt. Protokoll auswerten

    btw: SPI erzeugst Du nicht, SPI ist das Serial Peripheral Interface und ist ein serieller Bus.

    //EDIT: ich denke nicht, dass da der pigpio daemon laufen muss. Wenn doch, dann merkst Du das schon ;)

    cu,
    -ds-

  • Juhu. Mit meinen jeweils 50% Verständnis von der Library, dem Datenblatt und einem anderen Beispielprogramm das eigentlich auch wieder was ganz anderes machen soll, hab ich es geschafft.

    Hier der Code mit ein paar Kommentaren, damit andere Wenigkönner einfach mal schnell ein bis zwei von diesen Wandlern anschließen und benutzen können.

    Nicht vergessen das SPI Interface vom Rasberry einzuschalten (sudo raspi-config)!
    Und der pigpiod muss übrigens auch rumlaufen (sudo pigpiod).

    (EDIT: Ergänzen könnte man auch noch, dass der Wandler an den jeweiligen GPIOs für Hardware SPI angeschlossen sein muss, und der auszulesende Wandler an am SPI-Kanal 0 angeschlossen, damit der Code unten funktioniert. Andernfalls (Kanal 1), s. Kommentar im Code)

    Einmal editiert, zuletzt von Wonnegrausen (20. April 2017 um 19:40)

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!