Arduino-Beispielcode für SPI-Absolutwertgeber
2024-10-08
Diese Arduino-Beispielcode-Anleitung soll einen soliden Ausgangspunkt für die Konfiguration und das Auslesen von Daten aus den Absolutwertgebern AMT22 von Same Sky mit SPI-Kommunikation (Serial Peripheral Interface) bieten. Die Anleitung gibt Auskunft darüber, welche Hard- und Software benötigt wird, welche Voraussetzungen für die Einrichtung erfüllt sein müssen und enthält Beispielcode-Pakete und Anweisungen für eingängige und mehrgängige Drehgeber. Im Folgenden finden Sie eine Liste der für die ersten Schritte erforderlichen Informationen:
- Arduino-Board
- AMT22-Encoder
- Kabel AMT-06C-1-036 oder ähnliches Kabel mit entsprechendem Steckverbinder
- Arduino-IDE
- Download Beispielcode für eingängigen AMT22
- Download Beispielcode für mehrgängigen AMT22
Übersicht zum Absolutwertgeber AMT22
Der AMT22 von Same Sky (ehemals CUI Devices) ist ein Absolutwertgeber, der entweder mit einer Auflösung von 12 oder 14 Bit angeboten wird und somit eine präzise Anzahl eindeutiger Positionen pro Umdrehung liefert. Bei der 12-Bit-Variante sind das 4096 verschiedene Positionen, während das 14-Bit-Modell 16.384 Positionen pro Umdrehung aufweist. Unabhängig davon, wie oft die Komponente gedreht wird, meldet sie kontinuierlich ihre absolute Position und gibt dem Benutzer eine genaue Rückkopplung über den exakten Winkel der Komponente.
Dieser Encoder ist sowohl als eingängiges als auch als mehrgängiges Modell erhältlich. Die eingängige Variante misst die Position innerhalb einer einzigen 360-Grad-Drehung, während die mehrgängige Version nicht nur die Position innerhalb einer Rotation, sondern auch die Gesamtzahl der vollständigen Drehungen erfasst. Zusätzlich verfügen die eingängigen Varianten über einen programmierbaren Nullpunkt, der es dem Benutzer ermöglicht, eine Referenz für den Ursprung des Encoders zu definieren.
Einführung
Stellen Sie sicher, dass sich die Komponente im RUN-Modus befindet, indem Sie den Schalter auf der Rückseite des Encoders in die entsprechende Position bringen (Abbildung 1). Befestigen Sie nun den AMT22-Encoder an einem Motor oder einer Baugruppe unter Verwendung der AMT-Montageanweisungen, um eine ordnungsgemäße Installation zu gewährleisten. Der AMT22 unterstützt 9 verschiedene Wellengrößen im Bereich von 2 mm bis 8 mm.
Abbildung 1: Schalten Sie den Schalter auf der Rückseite des AMT22-Encoders in den Modus RUN. (Bildquelle: Same Sky)
Die in Abbildung 2 und Tabelle 1 skizzierten Verbindungen sind speziell für das Arduino-Uno-Board gedacht, aber der mitgelieferte Code sollte mit den meisten Arduino-Boards kompatibel sein. Beachten Sie jedoch, dass die Pinkonfigurationen bei verschiedenen Arduino-Modellen unterschiedlich sein können. Für genaue Anschlussdetails zu anderen Boards wird empfohlen, die entsprechende Arduino-Dokumentation zu konsultieren.
Abbildung 2: Arduino-Uno-Verdrahtung mit dem AMT22-Encoder (Bildquelle: Same Sky)
|
Tabelle 1: Weitere Details zur Arduino-Uno-Verdrahtung. (Bildquelle: Same Sky)
Der AMT22-Encoder beginnt sofort mit der Übertragung seiner absoluten Positionsdaten, sobald die SPI-Kommunikation beginnt, wodurch eine traditionelle Befehl-Antwort-Struktur überflüssig wird. Während des ersten Bytes der SPI-Übertragung sendet der Host 0x00, und der AMT22 antwortet sofort mit gültigen Positionsdaten.
Wenn der Host einen Befehl ausgeben muss (Tabelle 2), z. B. einen Nullsetzbefehl, wird dieser im zweiten Byte der Übertragung gesendet. Man spricht hier von einem erweiterten Befehl. Detaillierte technische Daten finden Sie im Datenblatt des AMT22.
|
Tabelle 2: Definierte AMT22-Befehle. (Bildquelle: Same Sky)
Kodierungsanleitung - Include- und Define-Anweisungen
Da der SPI-Bus des Arduino für die Schnittstelle mit dem AMT22-Encoder verwendet wird, muss die SPI-Bibliothek in den Code aufgenommen werden. Um die Positionsdaten vom Arduino an den Computer zu senden, wird die eingebaute serielle USB-Verbindung innerhalb der Arduino-IDE verwendet, die mit einer Baudrate von 115200 konfiguriert ist.
Darüber hinaus müssen die vom AMT22 verwendeten Befehle definiert werden. Da der Encoder den Inhalt des ersten Bytes nicht verarbeitet, wird zur Vereinfachung des Kommunikationsprozesses ein NOP (no-operation) zugewiesen (Listing 1).
Kopieren
/* Include the SPI library for the arduino boards */
#include <SPI.h>
/* Serial rates for UART */
#define BAUDRATE 115200
/* SPI commands */
#define AMT22_NOP 0x00
#define AMT22_ZERO 0x70
#define AMT22_TURNS 0xA0
Listing 1: Einrichten der SPI-Schnittstelle.
Initialisierung
In der Funktion setup() (Listing 2) initialisieren Sie zunächst alle erforderlichen SPI-Pins und konfigurieren die seriellen Schnittstellen für die Kommunikation.
Die serielle Schnittstelle sollte initialisiert werden, um die Datenübertragung zum Host Computer zu ermöglichen. Dies geschieht durch die Übergabe der definierten BAUDRATE an die Funktion Serial.begin().
Stellen Sie vor der Freigabe von SPI sicher, dass die Chip-Select-Leitung (CS) auf den entsprechenden Status gesetzt ist, um den Encoder für die Kommunikation vorzubereiten.
Wählen Sie eine Taktrate für den SPI-Bus zur Kommunikation mit dem AMT22. Für Prototyping-Zwecke ist eine Taktrate von 500 kHz geeignet, obwohl der AMT22 Raten bis zu 2 MHz unterstützt. 500 kHz können mit der Einstellung SPI_CLOCK_DIV32 erreicht werden. Angesichts des 16-MHz-Takts des Arduino Uno ergibt diese Einstufung eine SPI-Taktrate von 500 kHz. Weitere Einzelheiten zur Konfiguration des SPI-Takts finden Sie in der Arduino-Dokumentation.
Nachdem alles konfiguriert ist, kann der SPI-Bus mit SPI.begin() initialisiert werden, wodurch die drei dedizierten SPI-Pins eingerichtet werden: MISO, MOSI und SCLK, wodurch das System für die Kommunikation mit dem Encoder vorbereitet wird.
Kopieren
void setup()
{
uint8_t cs_pin = 2;
//Set the modes for the SPI CS
pinMode(cs_pin, OUTPUT);
//Get the CS line high which is the default inactive state
digitalWrite(cs_pin, HIGH);
//Initialize the UART serial connection for debugging
Serial.begin(BAUDRATE);
//set the clockrate. Uno clock rate is 16Mhz, divider of 32 gives 500 kHz.
//500 kHz is a good speed for our test environment
//SPI.setClockDivider(SPI_CLOCK_DIV2); // 8 MHz
//SPI.setClockDivider(SPI_CLOCK_DIV4); // 4 MHz
//SPI.setClockDivider(SPI_CLOCK_DIV8); // 2 MHz
//SPI.setClockDivider(SPI_CLOCK_DIV16); // 1 MHz
SPI.setClockDivider(SPI_CLOCK_DIV32); // 500 kHz
//SPI.setClockDivider(SPI_CLOCK_DIV64); // 250 kHz
//SPI.setClockDivider(SPI_CLOCK_DIV128); // 125 kHz
//start SPI bus
SPI.begin();
}
Listing 2: Die Funktion setup(), die alle SPI-Pins initialisiert.
SPI-Kommunikation
Die SPI-Kommunikation mit dem AMT22 wird mit der SPI-Bibliothek des Arduino gehandhabt, während die Chip-Select-Steuerung (CS) über den Code mit digitalen I/O-Pins verwaltet wird. Die Funktion digitalWrite() dient zur Aktivierung oder Deaktivierung der CS-Leitung (Listing 3).
Der AMT22 erwartet, dass zwei Bytes mit 0x00 gesendet werden, und sendet die Daten sofort nach dem Empfang dieser Bytes zurück. Aufgrund dieser schnellen Reaktion müssen bestimmte Mindestanforderungen an das Timing eingehalten werden, die im Datenblatt des AMT22 aufgeführt sind.
Unabhängig davon, ob es sich bei dem Encoder um eine 12-Bit- oder 14-Bit-Version handelt, antwortet er immer mit zwei Bytes (16 Bit) an Daten. Die oberen beiden Bits sind Prüfbits, die zur Überprüfung der Datenintegrität dienen. Bei der 12-Bit-Version sind die unteren beiden Bits 0, und der zurückgegebene Wert muss um 2 Bits nach rechts verschoben (oder durch 4 geteilt) werden, damit er richtig verwendet werden kann.
Um Positionsdaten zu erhalten, wird die Funktion SPI.transfer() aufgerufen, die den Befehl AMT22_NOP sendet. Die CS-Leitung bleibt während dieses Prozesses auf LOW-Pegel. Der AMT22 sendet das High-Byte zuerst, so dass das empfangene Byte um 8 Bits nach links verschoben wird, um es in der oberen Hälfte einer uint16_t-Variablen auszurichten. Dieser Wert wird der Variable encoderPosition in einem Vorgang zugewiesen. Nach einer kurzen Verzögerung, um die Timing-Anforderungen zu erfüllen, wird ein zweiter SPI.transfer()-Aufruf durchgeführt, um einen weiteren AMT22_NOP-Befehl zu senden. Das Ergebnis wird mit dem aktuellen Wert in encoderPosition ODER-verknüpft, wodurch die beiden empfangenen Bytes zu einer einzigen uint16_t-Variablen kombiniert werden. Zum Schluss wird die CS-Leitung freigegeben, womit die Kommunikation abgeschlossen ist.
Kopieren
uint8_t cs_pin = 2;
//set the CS signal to low
digitalWrite(cs_pin, LOW);
delayMicroseconds(3);
//read the two bytes for position from the encoder, starting with the high byte
uint16_t encoderPosition = SPI.transfer(AMT22_NOP) << 8; //shift up 8 bits because this is the high byte
delayMicroseconds(3);
encoderPosition |= SPI.transfer(AMT22_NOP); //we do not need a specific command to get the encoder position, just no-op
//set the CS signal to high
digitalWrite(cs_pin, HIGH);
Listing 3: Einrichten der SPI-Kommunikation.
Verifizieren der Prüfsumme
Nach Abschluss der SPI-Übertragung müssen die empfangenen Daten unbedingt mit einer Prüfsumme validiert werden (Listing 4).
Zur Durchführung dieser Validierung kann eine Funktion auf der Grundlage der im Datenblatt angegebenen Gleichung erstellt werden. Die Prüfsumme ist in den oberen zwei Bits des empfangenen Wertes enthalten, und es wird eine ungerade Parität über die ungeraden und geraden Bits in der Positionsantwort verwendet.
Die Funktion führt die folgenden Schritte aus:
- Berechnung der Parität für die ungeraden Bits (Bits 1, 3, 5, 7, 9, 11, 13)
- Berechnung der Parität für die geraden Bits (Bits 0, 2, 4, 6, 8, 10, 12, 14)
- Vergleich der berechneten Paritäten mit den durch die Prüfsummenbits angegebenen Werten
Die Funktion gibt TRUE zurück, wenn die Prüfsumme gültig ist, was bedeutet, dass die Integrität der Daten bestätigt ist. Wenn die Prüfsumme ungültig ist, gibt die Funktion den Wert FALSE zurück und signalisiert damit einen möglichen Fehler in den empfangenen Daten.
Kopieren
/*
* Using the equation on the datasheet we can calculate the checksums and then make sure they match what the encoder sent.
*/
bool verifyChecksumSPI(uint16_t message)
{
//checksum is invert of XOR of bits, so start with 0b11, so things end up inverted
uint16_t checksum = 0x3;
for(int i = 0; i < 14; i += 2)
{
checksum ^= (message >> i) & 0x3;
}
return checksum == (message >> 14);
}
Listing 4: Validierung der Prüfsumme.
Formatierung der Daten
Wenn die Validierung der Prüfsumme die Integrität der Daten bestätigt, wird im nächsten Schritt die Variable encoderPosition aktualisiert, indem die beiden oberen Bits entfernt werden (Listing 5). Dies kann durch eine bitweise UND-Verknüpfung mit 0x3FFF (oder 0b0011111111111111) vorgenommen werden, bei der alle 14 unteren Bits der Positionsdaten erhalten bleiben.
Außerdem muss die Auflösung des Encoders berücksichtigt werden - ob sie nun 12 oder 14 Bit beträgt. Bei einer Auflösung von 12 Bit muss der Wert für die EncoderPosition um 2 Bits nach rechts verschoben werden, um die geringere Auflösung auszugleichen. Dadurch wird sichergestellt, dass die Positionsdaten in der Variable encoderPosition genau dargestellt werden und die tatsächliche Position des Encoders auf der Grundlage seiner spezifizierten Auflösung reflektieren.
Kopieren
if (verifyChecksumSPI(encoderPosition)) //position was good
{
encoderPosition &= 0x3FFF; //discard upper two checksum bits
if (RESOLUTION == 12) encoderPosition = encoderPosition >> 2; //on a 12-bit encoder, the lower two bits will always be zero
Serial.print(encoderPosition, DEC); //print the position in decimal format
Serial.write('\n');
}
else //position is bad
{
Serial.print("Encoder position error.\n");
}
Listing 5: Aktualisieren von encoderPosition.
Position auf Null setzen (nur für eingängigen Betrieb)
Bestimmte Varianten des AMT22-Encoders bieten eine programmierbare Option für die Nullposition. Um diese Nullposition zu setzen, muss eine bestimmte Zwei-Byte-Befehlssequenz gesendet werden. Bei diesem Prozess wird zuerst der Befehl AMT22_NOP gesendet, gefolgt von einer kurzen Wartezeit, um die vom AMT22 festgelegten Mindestanforderungen an das Timing zu erfüllen. Nach dieser Wartezeit wird der Befehl AMT22_ZERO gesendet, wobei sichergestellt wird, dass die Chip-Select-Leitung (CS) freigegeben ist. Sobald der Encoder diesen Befehl erhält, führt er einen Reset-Vorgang durch (Listing 6).
Um eine Kommunikation mit dem Encoder während dieser Reset-Periode zu vermeiden, wird eine Zeit von 250 ms implementiert, die sicherstellt, dass während der Einschaltverzögerung keine Befehle an den Encoder gesendet werden.
Während es möglich ist, dass der Code die Nullposition des Encoders zu Beginn des Betriebs einstellt, ist es bei typischen Anwendungen üblicher, die Nullposition nur einmal während der anfänglichen Konfiguration der Komponente für die Verwendung innerhalb des Systems einzustellen. Diese Praxis trägt dazu bei, die Integrität der Rückkopplung des Encoders während seiner gesamten Betriebsdauer zu erhalten.
Kopieren
/*
* The AMT22 bus allows for extended commands. The first byte is 0x00 like a normal position transfer,
* but the second byte is the command.
* This function takes the pin number of the desired device as an input
*/
void setZeroSPI(uint8_t cs_pin)
{
//set CS to low
digitalWrite(cs_pin, LOW);
delayMicroseconds(3);
//send the first byte of the command
SPI.transfer(AMT22_NOP);
delayMicroseconds(3);
//send the second byte of the command
SPI.transfer(AMT22_ZERO);
delayMicroseconds(3);
//set CS to high
digitalWrite(cs_pin, HIGH);
delay(250); //250 millisecond delay to allow the encoder to reset
}
Listing 6: Einstellung der Nullposition eines eingängigen AMT22-Encoders.
Zähler für Anzahl der Umdrehungen lesen (nur für mehrgängigen Betrieb)
Bestimmte Varianten des AMT22-Encoders unterstützen einen mehrgängigen Zähler, der es dem Benutzer ermöglicht, sowohl die Position als auch die Anzahl der Umdrehungen in einer einzigen Datenabrufsequenz zu lesen.
Wenn die empfangenen Positionsdaten ungültig sind, sollte das System den Benutzer über den Fehler informieren. Ist die Position hingegen gültig, sollte das Programm die Position im dezimalen Format melden (Listing 7). Diese Funktion erweitert die Funktionalität des Encoders, indem sie eine umfassende Rückkopplung sowohl über die absolute Position als auch über die Anzahl der vollständigen Umdrehungen liefert und so eine genauere Überwachung und Steuerung in Anwendungen ermöglicht, die präzise Rotationsdaten erfordern.
Kopieren
uint8_t cs_pin = 2;
//set the CS signal to low
digitalWrite(cs_pin, LOW);
delayMicroseconds(3);
//read the two bytes for position from the encoder, starting with the high byte
uint16_t encoderPosition = SPI.transfer(AMT22_NOP) << 8; //shift up 8 bits because this is the high byte
delayMicroseconds(3);
encoderPosition |= SPI.transfer(AMT22_TURNS); //we send the turns command (0xA0) here, to tell the encoder to send us the turns count after the position
//wait 40us before reading the turns counter
delayMicroseconds(40);
//read the two bytes for turns from the encoder, starting with the high byte
uint16_t encoderTurns = SPI.transfer(AMT22_NOP) << 8; //shift up 8 bits because this is the high byte
delayMicroseconds(3);
encoderTurns |= SPI.transfer(AMT22_NOP);
delayMicroseconds(3);
//set the CS signal to high
digitalWrite(cs_pin, HIGH);
Listing 7: Lesen der encoderPosition und des Zählers der Umdrehungen in einem mehrgängigen AMT22-Encoder.
Ausführen des Codes
Nachdem der Code erfolgreich erstellt wurde, ist es an der Zeit, ihn auf den Arduino hochzuladen und die Kommunikation mit dem AMT22-Encoder herzustellen.
Um den Ausgabe zu überwachen, öffnen Sie den seriellen Monitor in der Arduino-IDE und stellen Sie sicher, dass die Datenrate auf 115200 Baud eingestellt ist. Dies ermöglicht es, den Betrieb des Encoders zu beobachten und die gemeldeten Positionsdaten in Echtzeit zu sehen. Sobald der serielle Monitor aktiv ist, sollte der Encoder mit der Übertragung seiner Positionsinformationen beginnen und damit seine Funktion innerhalb des Systems demonstrieren (Abbildung 3).
Abbildung 3: Die vom Encoder gemeldete Position, empfangen vom Arduino (Bildquelle: Same Sky)
Mehrere Encoder
Ein wesentlicher Vorteil der Verwendung einer SPI-Komponente ist die Möglichkeit, mit mehreren Encodern über denselben Bus zu kommunizieren. Um dies zu ermöglichen, muss jedem Encoder ein zusätzlicher digitaler I/O-Pin zugewiesen werden, der eine individuelle Chip-Select(CS)-Steuerung ermöglicht.
In dem Beispielcode (Listing 8) wird ein Array von CS-Pins verwendet, um eine beliebige Anzahl von Encodern zu unterstützen. Dieses Design ermöglicht eine skalierbare Kommunikation und erlaubt es, bei Bedarf weitere Encoder hinzuzufügen. Durch Modifizierung der Funktionen zur Übernahme der Pin-Nummer, die der gewünschten Komponente entspricht, kann der Code dynamisch steuern, welcher Encoder auf dem SPI-Bus aktiv ist, wodurch sichergestellt wird, dass auf jede Komponente zugegriffen werden kann und diese unabhängig betrieben werden kann.
Kopieren
uint8_t cs_pins[] = {2}; //only one encoder connected, using pin 2 on arduino for CS
//uint8_t cs_pins[] = {2, 3}; //two encoders connected, using pins 2 & 3 on arduino for CS
Listing 8: Einrichten eines Arrays zum Lesen mehrerer Encoder.
Der nächste Schritt besteht darin, jeden CS-Pin im Array zu durchlaufen und die Position von jedem vernetzten Encoder zu lesen. Dadurch kann das System jeden Encoder aktivieren, indem es seine Chip-Select-Leitung aktiviert, die SPI-Übertragung durchführt und die Positionsdaten abruft. Der Code wählt nacheinander jeden Encoder aus, führt die SPI-Kommunikation aus und gibt die CS-Leitung frei, wodurch sichergestellt wird, dass alle vernetzten Komponenten nach ihren Positionsinformationen abgefragt werden (Listing 9).
Kopieren
void loop()
{
for(int encoder = 0; encoder < sizeof(cs_pins); ++encoder)
{
uint8_t cs_pin = cs_pins[encoder];
//set the CS signal to low
digitalWrite(cs_pin, LOW);
delayMicroseconds(3);
//read the two bytes for position from the encoder, starting with the high byte
uint16_t encoderPosition = SPI.transfer(AMT22_NOP) << 8; //shift up 8 bits because this is the high byte
delayMicroseconds(3);
encoderPosition |= SPI.transfer(AMT22_NOP); //we do not need a specific command to get the encoder position, just no-op
//set the CS signal to high
digitalWrite(cs_pin, HIGH);
if (verifyChecksumSPI(encoderPosition)) //position was good, print to serial stream
{
encoderPosition &= 0x3FFF; //discard upper two checksum bits
if (RESOLUTION == 12) encoderPosition = encoderPosition >> 2; //on a 12-bit encoder, the lower two bits will always be zero
Serial.print("Encoder #");
Serial.print(encoder, DEC);
Serial.print(" position: ");
Serial.print(encoderPosition, DEC); //print the position in decimal format
Serial.write('\n');
}
else //position is bad, let the user know how many times we tried
{
Serial.print("Encoder #");
Serial.print(encoder, DEC);
Serial.print(" position error.\n");
}
}
//For the purpose of this demo we don't need the position returned that quickly so let's wait a half second between reads
//delay() is in milliseconds
delay(500);
}
Listing 9: Lesen der Variable encoderPosition von mehreren Encodern.
Nach der Datenübertragung ist eine Mindestwartezeit erforderlich, bevor die Chip-Select-Leitung freigegeben wird. Dem Datenblatt zufolge beträgt diese Mindestzeit 3 Mikrosekunden. Während diese Verzögerung bei langsameren Datenraten in der Regel auf natürliche Weise auftritt, empfiehlt es sich, sie explizit in den Code zu implementieren, um einen ordnungsgemäßen Betrieb und die Einhaltung der Timing-Spezifikationen zu gewährleisten. Dies gewährleistet eine zuverlässige Kommunikation mit dem AMT22-Encoder.
Fazit
Sie sollten nun ein grundlegendes Verständnis für die Konfiguration und das Auslesen von Daten aus den Absolutwertgebern AMT22 von Same Sky haben. Dieser Artikel konzentriert sich auf die Absolutwertgeber AMT22. Same Sky hat auch eine Reihe von modularen AMT-Encodern, die eine Reihe von inkrementellen, absoluten und Kommutierungsversionen anbieten.
Haftungsausschluss: Die Meinungen, Überzeugungen und Standpunkte der verschiedenen Autoren und/oder Forumsteilnehmer dieser Website spiegeln nicht notwendigerweise die Meinungen, Überzeugungen und Standpunkte der DigiKey oder offiziellen Politik der DigiKey wider.

