i2c mit c++ Ansteuern

Heute ist Stammtischzeit:
Jeden Donnerstag 20:30 Uhr hier im Chat.
Wer Lust hat, kann sich gerne beteiligen. ;)
  • Hallo zusammen,
    ich möchte mich kurz vorstellen:
    1971 geboren,
    1987 Kommunikationselektroniker gelernt,
    abgebrochenes Studium Nachrichtentechnik =(
    seit dem Betriebselektriker, Schwerpunkt Fehlersuche mit S7 bei einem Automobilzulieferer,
    seit 2 Wochen Besitzer einer Raspberry Pi 3.

    Ich weiß schon das mein Betriebssystem linux ist,
    das "sudo" die Rechte von "root" ersetzt,
    und das "nano" ein Texteditor ist.

    ... und das war gar nicht so einfach raus zu finden! :bravo2:

    Mein Ziel ist es das die Raspi ein paar Steuerungsaufgaben in meinem Haus automatisiert. Das ganze soll unter c++ geschehen. Ich hab da zwar keine Ahnung von, aber auf der ein oder anderen Seite im Internet wird die Sprache empfohlen.
    Einzelne gpios kann ich auch schon ein- und ausschalten.

    Ich hab alle möglichen Sachen installiert um auf den i2c-Bus zuzugreifen.
    Über einen Level-Shifter habe ich zwei PCF8574 (IO-Expander) sowie einen PCF8591 angeschlossen.

    Bei dem Befehl:

    Code
    pi@raspberrypi:~ $ sudo i2cdetect -y 1


    kommt tatsächlich als Antwort:
    0 1 2 3 4 5 6 7 8 9 a b c d e f
    00: -- -- -- -- -- -- -- -- -- -- -- -- --
    10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    30: -- -- -- -- -- -- -- -- 38 39 -- -- -- -- -- --
    40: -- -- -- -- -- -- -- -- 48 -- -- -- -- -- -- --
    50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    70: -- -- -- -- -- -- -- --


    da bin ich schon ein bisschen stolz auf mich! :D

    Jetzt hab ich im Netz das Programm pcf8591.cpp gefunden:


    Wenn ich jetzt:

    Code
    pi@raspberrypi:~ $ sudo g++ pcf8591.cpp -o pcf8591


    eingebe, dann kommt

    Code
    /tmp/cc5ZLyXt.o: In function `readInput(int, int)':
    pcf8591.cpp:(.text+0x1c): undefined reference to `wiringPiI2CReadReg8'
    pcf8591.cpp:(.text+0x28): undefined reference to `wiringPiI2CReadReg8'
    /tmp/cc5ZLyXt.o: In function `main':
    pcf8591.cpp:(.text+0x48): undefined reference to `wiringPiSetupGpio'
    pcf8591.cpp:(.text+0x50): undefined reference to `wiringPiI2CSetup'
    pcf8591.cpp:(.text+0x154): undefined reference to `wiringPiI2CWriteReg8'
    pcf8591.cpp:(.text+0x1dc): undefined reference to `delay'
    collect2: error: ld returned 1 exit status
    pi@raspberrypi:~ $


    als Antwort.
    Muss ich da noch irgend was installieren? Ist das Programm nicht richtig (für mich)? Die Adresse 48 stimmt......

    Danke für Eure Hilfe,

    Gruss,

    Achim Meyer

    Einmal editiert, zuletzt von hunter_spike (17. November 2016 um 11:42)

  • Servus Achim,


    ...
    pcf8591.cpp: (.text+0x1c): undefined reference to `wiringPiI2CReadReg8'
    ...
    collect2: error: ld returned 1 exit status
    pi@raspberrypi:~ $


    da fehlt Dir noch die wiringPi-Library, die Du dazubinden musst.
    Mal abgesehen davon, dass Du kein sudo für den Aufruf des Compilers brauchst, sollte der Aufruf

    Code
    $ g++ pcf8591.cpp -o pcf8591 -lwiringPi


    zum Erfolge führen.

    Zwei Dinge noch: Code bitte in Code-tags posten:
    [ code]
    da
    steht
    mein Code
    [ /code]
    sonst wird das schnell undurchschaubar. Das Leerzeichen nach der öffnenden eckigen Klammer aber beim realen Einsatz weglassen.

    Ausserdem empfehle ich dir die pigpio-Bibliothek zu verwenden. Ich habe die Erfahrung gemacht, dass die um einiges stabiler und scheinbar auch sauberer implementiert ist.
    Diese Bibliothek wird bereits mit dem Standard-Jessie mitinstalliert. Die Doku dazu findest Du z.B. -> hier <- ...

    cheers,
    -ds-

  • Abhaengig davon, *was* du so steuern willst, solltest du deine Entscheidung fuer C++ ueberdenken. Und das sage ich als jemand, der die Sprache beruflich jeden Tag nutzt. C und C++ sind relativ schwer zu verstehen, und bringen dafuer hohe Ausfuehrungsgeschwindigkeit. Die ist aber gerade im Bereich Heimautomation oft voellig unnoetig. Eine nette GUI, komfortable Konfigurationsmoeglichkeiten und Definition von Ereignissen wenn ein Sensor anspringt sind viel wichtige. Du musst ja nicht im uS-Takt deine Heizung regeln. Morgens um 6:00 einschalten (oder was auch immer) kannst du genauso gut zB mit Python. Und das ist viel freundlicher fuer Anfaenger.

    Ich glaube auch nicht, dass dein Code das tut, was du tun willst (wenn er denn kompiliert).

    (A[0]+A[1]+A[2]+A[3])/4

    zB berechnet einfach den Durchschnitt deines A-Arrays. Das ist wohl kaum was du willst, sonst kannst du gleich stattdessen "0x41" hinschreiben statt diesem komplizierten Ausdruck.

  • Hallo deets,
    Du hast bestimmt Recht. Der beschriebene Fall geht einfacher zu lösen. Ich hab mir vor ein paar Wochen ein dickes c++-Buch gekauft und die ersten 100 Seiten trocken runtergelesen. So grob hab ich verstanden, was da steht.
    Neben der Raspi reizt es mich aber auch PIC-Prozessoren zu programmieren. Außerdem sind die Industrieroboter meines Arbeitgebers auf c++-Basis programmiert.
    Wäre sicherlich nicht von Nachteil wenn ich da ein Ass im Ärmel hätte.

    Zum oben geschriebenen Programm:
    Habe das ja nur aus dem Netz runter geladen damit meine Chips irgend was machen. Über den Sinn hab ich mir noch keine Gedanken gemacht.


    Gruss,

    Achim

    Einmal editiert, zuletzt von hunter_spike (17. November 2016 um 12:13)

  • Hallo Dreamshader und deets,
    ich habe diese Woche Nachtschicht und die Raspi auf der Firma liegen. Wenn alle Maschinen laufen hab ich Zeit für die Raspi :)

    dreamshader, dein Tip

    Code
    $ g++ pcf8591.cpp -o pcf8591 -lwiringPi


    hat funktioniert.

    Aber warum ich das machen muss hab ich nicht verstanden:

    Ich rufe das Programm g++ auf.
    Das soll pcf8591.cpp übersetzen
    Sollte schon eins da sein dann überschreiben.
    Das Neue Programm soll pcf8591 heißen.

    Die wiringPi habe ich doch schon mit include in meiner Headerdatei eingebunden......

    deets, das Programm macht scheinbar das, was es soll:
    4 Analogsignale einlesen,
    Der Reihe nach auf dem Bildschirm ausgeben,
    den Durchschittswert auf den analogen Ausgang ausgeben.
    Bin ich aber auch erst drauf gekommen als ich sah, das da ein "Write" vor der Berechnung steht...

    Danke erstmal für Eure Hilfe.

    Gruss,

    Achim


    Folgendes hat sich schon erledigt. Erst die Suche benutzen....dann fragen. :(
    Hätte mit dem kill-Befehl abbrechen können. Stecker ziehen geht aber auch. ';-)
    Das Prog benötigt auf jeden Fall noch eine Routine zum beenden.

    Automatisch zusammengefügt:

    Und da habe ich gleich das nächste Problem:
    Ich hatte eben das Prog ausgeführt und die Funktion mit Taschenlampe und Multimeter getestet. Alles gut.
    Beim verlassen der Werkstatt hab ich alle Fenster an der Raspi geschlossen.
    Wie ich gerade wieder rein komme und spaßeshalber mit der Taschenlampe auf den LDR leuchte, da bewegt sich das Multimeter.
    Wo ist denn jetzt das laufende Programm???
    Wie muss ich das Termial beenden, damit das Programm auch geschlossen wird???

    Gruss,

    Achim

    Einmal editiert, zuletzt von hunter_spike (18. November 2016 um 03:59)

  • Mit dem include hast du nur die Deklarationen der Library bekannt gemacht - was du benutzen kannst. Die *Definitionen*, also der eigentliche Code (in schon komplilierter Form) kommt erst durch das linken dazu. Dann gibt's noch Unterschiede zwischen statischem und dynamischen linken, der loader-path muss deine Library finden etc.... aber wenn's erstmal laeuft, ist ja gut.

    Ein Programm das laeuft bricht man unter Unix uebrigens mic Control-C ab. Nur zu dem Zweck eine Eingabeverarbeitung einzufuehren waere etwas zu viel des guten.

  • Ich nochmal,
    das lauffähige, oben genannte Prog fängt wie folgt an:

    wofür steht denn das "fd" und das "reg" hinter den Befehlen. Ich war eigentlich davon ausgegangen das da Werte an die einzelnen Befehle übergeben werden oder zurückgegeben werden. Habe probiert die Werte mit cout auszugeben. Aber das klappt alle irgendwie nicht. =(

  • Steht doch sowohl in der Dokumentation zu wiringPI als auch in deinem eigenen Quellcode, der die aufruft. Ich meine "wiringPiI2CReadReg8" das dann einen Parameter "reg" bekommt - was soll das denn sein?

    http://wiringpi.com/reference/i2c-library/

    """
    int wiringPiI2CReadReg8 (int fd, int reg) ;
    int wiringPiI2CReadReg16 (int fd, int reg) ;
    These read an 8 or 16-bit value from the device register indicated.
    """

  • Ich glaub ich hab da gerade was verstanden:
    Zeile 6 ff:

    Code
    int readInput(int fd, int reg)
    {
        wiringPiI2CReadReg8(fd, reg);
        return wiringPiI2CReadReg8(fd, reg);
    }

    Den Befehl "readInput" baue ich mir da gerade selber (Unterprogramm). Er bekommt zwei Werte, die in dem Unterprogramm "fd" und "reg" heißen.

    In Zeile 16:

    Code
    int dacModule = wiringPiI2CSetup(0x48);


    gebe ich dem Befehl wiringPiI2CSetup die Adresse von meinem Chip mit. Den Rückgabewert schreibe ich in dacModule.

    Weiter unten bei:

    Code
    for (i=0;i<4;i++) A[i] = readInput(dacModule, A_Reg[i]);

    bestimme ich, das "readInput" die Werte "dacModule" und "A_Reg(0-4)" erhält, die aber in "readInput"selber "fd" und "reg" heißen.
    "A_Reg" ist das Register, in dem der Analogwert steht. "dacModule" ist der Analogwert.

    Ist das annähernd so richtig???

  • Erm, nein. dacModule ist ein "Handle" bzw. File-Deskriptor (darum fd genannt), das dein geöffnetes Devices mit der Adresse 0x48 identifiziert. Wenn du mit diesem Device interagieren willst (also Daten lesen oder schreiben), musst du das mit angeben, denn du könntest ja dutzende Module angebunden haben - die wollen unterschieden werden.

    Und A_Reg[i] enthaelt offensichtlich eines von 4 Registern, die dann von einem Device gelesen werden sollen. Der Analogwert ist dann der *RETURNWERT* von readInput, und wird in A[i] gespeichert.

  • Nirgens im Netz ist ein einfaches Programm zu finden um einen PCF8574 anzusteuern. Aber ich habe es tatsächlich geschafft mir eins selber zu schreiben:


    Frage 1: Mein Englisch ist nicht das beste, aber ich meine verstanden zu haben das wiringPi die Eingänge beim PCF8574 "umdreht", da die ja normal immer "1" sind macht wiringPi die auf immer "0" und umgekehrt. Hab ich da was falsch gemacht oder was falsch verstanden? (Weil bei"255" sind alle Relais aus und bei "0" sind alle an.

    Frage 2: was müsste ich tun, wenn ich jetzt ein zweites Modul gleichzeitig benutzen möchte. Andere Hardwareadresse ist klar. Aber wie sag ich dem dacModule welche ich gerade meine?
    Im Zweifel müsste es doch über:

    int wiringPiI2CWriteReg8 (int fd, int reg, int data) ;


    gehen, da ich da über "reg" die Adresse mitgebe. Gehts auch anders?

  • Habe ich dir doch schon gesagt - der Parameter fd. Alleine aus einem Auschlussprinzip sollte dir doch die Frage kommen, warum der da ist. Und wenn man sieht, dass er aus dem setup-call kommt in das die Adresse gegeben wird, dann schaut einem das Biest doch direkt in die Augen.

    Zur Invertierung kann ich nichts sagen.
    Automatisch zusammengefügt:
    Nachtrag: du hast den file-descriptor jetzt dacModule genannt. Das ist eben der Parameter, der das konkrete Device steuert. Du musst also verschiedene solcher Variablen vorhalten & je nach gewünschtem I2C-Device benutzen.


  • ......


    Nachtrag: du hast den file-descriptor jetzt dacModule genannt. Das ist eben der Parameter, der das konkrete Device steuert. Du musst also verschiedene solcher Variablen vorhalten & je nach gewünschtem I2C-Device benutzen.

    Ah jetzt ja: Der Groschen viel Pfennigweise:

    Code
    int dacModule = wiringPiI2CSetup(0x38)
    int NameDesZweitenModuls = wiringPiI2CSetup(0x40)

    Danke schön!!!
    :bravo2:

Jetzt mitmachen!

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