×

Arduino und SPI - MCP3008


Gepostet Oktober 2017, Kategorie: I2C & SPI


Thumbnail: Arduino und SPI - MCP3008

Der MCP3008 ist ein 10-bit-ADC mit 8 Eingängen. Die Daten werden bei diesem IC über das SPI-Protokoll übertragen. Dieser IC wird in diesem Post über den Arduino Uno angesteuert.


Inhaltsverzeichnis


    Der MCP3008 ist ein 10-bit-ADC mit 8 Eingängen. Die Daten werden bei diesem IC über das SPI-Protokoll übertragen. Die Betriebsspannung für diesem Chip kann im Bereich von 2,7 bis 5,5 V liegen. Damit ist dieser IC 5 V-kompatibel und das Logiklevel des Arduinos (5 V) und auch des Calliope (3,3 V) kann verwendet werden.
    Datenblatt: https://cdn-shop.adafruit.com/datasheets/MCP3008.pdf

    Aufbau

    MCP3008 und Arduino - Aufbau|50MCP3008 und Arduino - Schaltplan|50

    Der MCP3008 wird mit der SPI-Schnittstelle des Arduinos verbunden. Hierfür sind die folgenden Pins am Arduino Uno vorgesehen:

    Pin SPI-Leitung Bedeutung Funktion
    13 SCK Slave Clock Taktsignal der SPI-Schnittstelle
    12 MISO Master In, Slave Out Datenleitung für Daten vom Slave an den Master
    11 MOSI Master Out, Slave In Datenleitung für Daten vom Master an den Slave

    Außerdem wird die CS- (Chip Select) / SS- (Slave Select) -Leitung mit einem beliebigen digitalen Pin des Arduinos verbunden - in diesem Beispiel Pin 10.

    Die Stromversorgung des MCP3008 findet über die Pins VDD und GND statt. Außerdem wird AGND (Analog Ground) mit Masse verbunden. Über VREF-Pin wird die Referenzspannung des AD-Wandlers festgelegt. Hier sollte für eine exakte Messung eine Referenzspannungsquelle verwendet werden. In diesem Fall werden jedoch die 5 V der Stromversorgung verwendet.

    Der Ausgang eines Potentiometers ist am Channel 0 des MCP3008 angeschlossen. Die eingestellt Spannung soll durch den MCP3008 gemessen werden.

    Programmierung

    SPI - Grundlagen

    Zuerst sollte die Frage beantwortet werden, wie eine SPI-Kommunikation grundlegend funktioniert. Die Grundlage eines SPI-Modul bildet jeweils eine Schieberegister im Master und im Slave. Wenn die SCK-Taktleitung taktet, so werden vom Master zum Slave Daten über die MOSI-Leitung gesendet und gleichzeitig werden Daten vom Slave zum Master über MOSI-Leitung übertragen.

    Grundaufbau von SPI
    (Quelle: https://learn.mikroe.com/ebooks/wp-content/uploads/sites/2/2016/01/8051-chapter-04-image-037.gif?x18014)

    Dieses Verfahren lässt sich auch in der Methode SPI.transfer() erkennen, die beim Arduino verwendet wird, um Daten über die SPI-Schnittstelle zu übertragen. (siehe https://www.arduino.cc/en/Reference/SPITransfer). Als Argument dieser Methode werden die Daten angegeben, die gesendet werden und nach der Übertragung werden die empfangenen Daten als Rückgabewert der Funktion erhalten.

    uint8_t received = SPI.tranfer(send);

    Damit mehrere Slaves an einen SPI-Bus angeschlossen werden können, besitzt jeder SPI-Slave einen CS-Pin (Chip Select). Die CS-Pins jedes Slaves wird mit einen anderen digitalen Ausgang des Mikrocontrollers verbunden. Indem der Mikrocontrollers einen CS-Pin auf Masse zieht, kann dieser festlegen mit welchem SPI-Slave kommuniziert werden soll.

    MCP3008-Kommunikation

    Im folgenden soll untersucht werden, welches Bytes an den MCP3008 übertragen bzw. empfangen werden müssen, um eine AD-Wandlung durchzuführen und das Ergebnis auszulesen. Hier hilft die Abbildung 6-1 aus dem Datenblatt des MCP3008.

    Abbildung 6-1 aus dem Datenblatt des MCP3008

    Im ersten Schritt wird, wie in der Abbildung zu sehen der CS-Pin auf LOW gesetzt.

    digitalWrite(CS, LOW);

    Anschließend wird das Byte 0x01 über den SPI-Bus übertragen.

    SPI.transfer(0x01);

    Das erste Bit des nächsten Bytes, welches übertragen wird, gibt an, ob es sich um eine Einzelmessung oder eine Differenzmessung handelt. Da eine Einzelmessung durchgeführt werden soll, wird dieses Bit auf 1 gesetzt. (siehe Tabelle 5-2 auf Seite 19)

    Außerdem wird in diesem Byte die Kanalnummer übertragen, auf dem gemessen werden soll. Wenn die Variable channel eine Zahl von 0 bis 7 enthält, so ergibt sich die folgende Befehlszeile.

    uint8_t msb = SPI.transfer(0x80 + (channel << 4));

    Das empfangen Byte wird in der Variable msb zwischengespeichert und die ersten beiden Bytes des Messergebnisses.

    Innerhalb der nächsten SPI-Übertragung wird das Messergebnis weiterübertragen. Es müssen keine Daten gesendet werden. Aus diesem Grund wird der Wert 0x00 übertragen, damit über SPI empfangen werden kann.

    uint8_t lsb = SPI.transfer(0x00);

    Nun muss das Messergebnis aus den Variablen msb und lsb zusammengesetzt werden. Da von msb nur die ersten beiden Bits verwendet werden, werden alle übrigen Bits durch msb & 0x03 zu null gesetzt.

    uint16_t result = ((msb & 0x03) << 8) + lsb;

    Am Ende der Übertragung wird der CS-Pin auf HIGH gesetzt, um den IC zu deaktivieren.

    Beispielprogramm

    Um die gemessenen Daten des AD-Wandlers über die serielle Schnittstellen auszugeben, kann das folgenden Programm verwendet werden. Der eben beschrieben Ablauf befindet sich in der Funktion mcp3008_read().

    #include <SPI.h>
    const uint8_t CS = 10;
     
    void setup() {
      Serial.begin(9600);
      SPI.begin();
      SPI.setClockDivider(SPI_CLOCK_DIV8);
     
      pinMode(CS, OUTPUT);
      digitalWrite(CS, HIGH);
    }
     
    void loop() {
      uint16_t reading = mcp3008_read(0);
      Serial.println(reading);
      delay(500);
    }
     
    uint16_t mcp3008_read(uint8_t channel) {
      digitalWrite(CS, LOW);
      SPI.transfer(0x01);
      uint8_t msb = SPI.transfer(0x80 + (channel << 4));
      uint8_t lsb = SPI.transfer(0x00);
      digitalWrite(CS, HIGH);
      return ((msb & 0x03) << 8) + lsb;
    }

    Mit SPI.begin() werden die Pins der SPI-Schnittstelle eingestellt. Die Methode SPI.setClockDivider(SPI_CLOCK_DIV8) stellt die Taktrate der SPI-Schnittstelle auf 2 MHz ein (). Dies ist nötig, da die Taktrate bei 5 V maximal 3.6 MHz betragen darf (siehe Datenblatt Seite 4).

    In der Arduino-Konsole sind die folgenden Werte zu sehen:
    Konsolenausgabe

    Aufnahme mit Logikanalysator

    Aufnahme mit Logikanalysator|100

    Die Kommunikation findet wie erwartet statt. Die Taktfrequenz beträgt 2 MHz. Der aktuelle Analogwert ist 0x36b = 875.