Arduino-voorbeeldsoftware voor SPI absolute encoders
2024-10-08
Deze tutorial met Arduino-voorbeeldsoftware geeft gebruikers een goed uitgangspunt voor het configureren en uitlezen van gegevens vanaf AMT22 absolute encoders van Same Sky met SPI-communicatie (Serial Peripheral Interface). De tutorial geeft aan welke hardware en software er nodig is en wat de belangrijkste instellingsvereisten zijn. Het bevat voorbeeldsoftwarepakketten en instructies voor zowel single-turn als multi-turn uitvoeropties. Hieronder staat een lijst van wat u nodig hebt om te beginnen:
- Arduino-printplaat
- AMT22-encoder
- AMT-06C-1-036-kabel of vergelijkbare kabel met juiste connector
- Arduino IDE
- Download de AMT22 single-turn voorbeeldsoftware
- Download de AMT22 multi-turn voorbeeldsoftware
Overzicht van de AMT22 absolute encoder
De AMT22 van Same Sky (voorheen CUI Devices) is een absolute encoder met een resolutie van 12 of 14 bits, wat betekent dat hij een nauwkeurig aantal unieke posities per omwenteling levert. Voor de 12-bits variant komt dit neer op 4096 verschillende posities, terwijl het 14-bits model 16.384 posities per omwenteling heeft. Ongeacht hoe vaak het apparaat wordt gedraaid, het rapporteert continu de absolute positie, waardoor gebruikers nauwkeurige feedback krijgen over de exacte hoek van het apparaat.
Deze encoder is verkrijgbaar in zowel single-turn als multi-turn modellen. De single-turn variant meet de positie binnen een enkele rotatie van 360 graden, terwijl de multi-turn versie niet alleen de positie binnen een rotatie bijhoudt, maar ook het totale aantal volledige rotaties. Bovendien hebben de single-turn varianten een programmeerbaar nulpunt, zodat gebruikers een aangepaste referentie kunnen definiëren voor de oorsprong van de encoder.
Aan de slag
Zorg allereerst dat het apparaat in de RUN-modus staat door de schakelaar aan de achterkant van de encoder in de juiste stand te zetten (zie afbeelding 1). Monteer nu de AMT22-encoder op een motor of assemblage met behulp van de AMT montage-instructies. De AMT22 ondersteunt 9 verschillende asmaten, variërend van 2 mm tot 8 mm.
Afbeelding 1: Zet de schakelaar op de achterkant van de AMT22-encoder in de RUN-modus. (Bron afbeelding: Same Sky)
De aansluitingen in afbeelding 2 en tabel 1 zijn specifiek voor de Arduino Uno-print, maar de meegeleverde softwarecode is als het goed is compatibel met de meeste Arduino-printplaten. Houd er echter rekening mee dat de penconfiguratie per Arduino-model kan verschillen. Voor precieze aansluitingsdetails op andere printplaten wordt aangeraden de bijbehorende Arduino-documentatie te raadplegen.
Afbeelding 2: Arduino Uno-bedradingsaansluitingen met de AMT22-encoder. (Bron afbeelding: Same Sky)
|
Tabel 1: Arduino Uno-bedradingsaansluitingen nader omschreven. (Bron afbeelding: Same Sky)
De AMT22-encoder begint de absolute positiegegevens onmiddellijk te verzenden wanneer de SPI-communicatie begint, waardoor een traditionele opdracht-responsstructuur overbodig wordt. Tijdens de eerste byte van de SPI-overdracht stuurt de host 0x00. De AMT22 geeft tegelijkertijd een respons met geldige positiegegevens.
Als de host een opdracht (zie tabel 2) moet geven, zoals een opdracht om de nulwaarde in te stellen, wordt dit in de tweede byte verzonden. Dit wordt een ‘extended command’ of uitgebreide opdracht genoemd. Raadpleeg de AMT22-datasheet voor gedetailleerde technische informatie.
|
Tabel 2: Gedefinieerde AMT22-opdrachten. (Bron afbeelding: Same Sky)
Softwaretutorial - includes en defines
Omdat de SPI-bus van de Arduino wordt gebruikt als interface met de AMT22-encoder, moet de SPI-bibliotheek in de software worden opgenomen. Om de positiegegevens vanaf de Arduino naar de computer te sturen, wordt de ingebouwde USB-seriële verbinding binnen de Arduino IDE gebruikt, geconfigureerd op een baudrate van 115200.
Daarnaast moeten de opdrachten die door de AMT22 worden gebruikt, worden gedefinieerd. Aangezien de encoder de inhoud van de eerste byte niet verwerkt, wordt een NOP (no-operation) toegewezen om het communicatieproces te vereenvoudigen (zie listing 1).
Kopiëren
/* 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: De SPI-interface instellen.
Initialisatie
Begin in de functie setup() (zie listing 2) met het initialiseren van alle vereiste SPI-pennen en het configureren van de seriële interfaces voor communicatie.
De seriële poort moet geïnitialiseerd worden om gegevensoverdracht naar de hostcomputer mogelijk te maken. Dit wordt gedaan door de gedefinieerde BAUDRATE door te geven aan de functie Serial.begin().
Voordat SPI wordt ingeschakeld, moet de CS-lijn (chip select) op de juiste status worden gezet om de encoder voor te bereiden op communicatie.
Selecteer een kloksnelheid voor de SPI-bus om met de AMT22 te communiceren. Voor prototyping is een kloksnelheid van 500 kHz geschikt, hoewel de AMT22 snelheden tot 2 MHz ondersteunt. Het bereiken van 500 kHz kan worden gedaan met de instelling SPI_CLOCK_DIV32. Met de 16MHz-klok van de Arduino Uno resulteert deze deling in een SPI kloksnelheid van 500 kHz. Raadpleeg de documentatie van Arduino voor meer informatie over SPI-klokconfiguratie.
Nadat alles is geconfigureerd, kan de SPI-bus worden geïnitialiseerd met SPI.begin(). Hierdoor worden de drie speciale SPI-pennen ingesteld: MISO, MOSI en SCLK, wat het systeem voorbereidt op communicatie met de encoder.
Kopiëren
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: De functie setup() die alle SPI-pennen initialiseert.
SPI-communicatie
SPI-communicatie met de AMT22 wordt gedaan via de SPI-bibliotheek van Arduino, terwijl de CS-regeling wordt beheerd door de software met behulp van digitale I/O-pennen. De functie digitalWrite() wordt gebruikt om de CS-lijn aan of uit te zetten (zie listing 3).
De AMT22 verwacht dat twee bytes van 0x00 worden verzonden en stuurt onmiddellijk na ontvangst van deze bytes gegevens terug. Vanwege deze snelle respons moeten bepaalde minimale timingvereisten worden gevolgd, die worden beschreven in de AMT22-datasheet.
Ongeacht of de encoder een 12-bits- of 14-bitsversie is, reageert hij altijd met twee bytes (16 bits) aan gegevens. De bovenste twee bits zijn controlebits, die worden gebruikt om de integriteit van de gegevens te verifiëren. Voor de 12-bitsversie zijn de onderste twee bits beide 0 en moet de geretourneerde waarde 2 bits naar rechts worden verschoven (of door 4 gedeeld worden).
Om positiegegevens te verkrijgen wordt de functie SPI.transfer() aangeroepen, waarbij de opdracht AMT22_NOP wordt verzonden. De CS-lijn blijft tijdens dit proces laag. De AMT22 verzendt de hoge byte eerst, dus de ontvangen byte wordt 8 bits naar links verschoven om hem in de bovenste helft van een variabele uint16_t uit te lijnen. Deze waarde wordt in één bewerking toegewezen aan de encoderPosition variabele. Na een korte vertraging om aan de timingvereisten te voldoen, wordt een tweede SPI.transfer() aangeroepen om nog een AMT22_NOP-opdracht te verzenden. Het resultaat wordt geOR’ed met de huidige waarde in encoderPosition, waardoor de twee ontvangen bytes worden gecombineerd in een enkele variabele uint16_t. Tot slot wordt de CS-lijn vrijgegeven, waarmee de communicatie is voltooid.
Kopiëren
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: De SPI-communicatie instellen.
Verificatie van de checksum
Na het voltooien van de SPI-overdracht is het essentieel om de ontvangen gegevens te valideren met een checksum (zie listing 4).
Om deze validatie uit te voeren, kan een functie worden gemaakt op basis van de vergelijking in het gegevensblad. De checksum zit in de bovenste twee bits van de ontvangen waarde en maakt gebruik van oneven pariteit over de even en oneven bits in de positierespons.
De functie voert de volgende stappen uit:
- Bereken de pariteit voor de oneven bits (bit 1, 3, 5, 7, 9, 11, 13).
- Bereken de pariteit voor de even bits (bit 0, 2, 4, 6, 8, 10, 12, 14).
- Vergelijk de berekende pariteiten met de waarden van de checksumbits.
De functie retourneert ‘true’ als de checksum geldig is, wat aangeeft dat de integriteit van de gegevens is bevestigd. Als de checksum ongeldig is, retourneert de functie ‘false’, wat duidt op een mogelijke fout in de ontvangen gegevens.
Kopiëren
/*
* 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: De checksum valideren.
Gegevensopmaak
Als de checksumvalidatie de integriteit van de gegevens bevestigt, is de volgende stap het bijwerken van de encoderPosition variabele door de bovenste twee bits te verwijderen (zie listing 5). Dit kan worden bereikt door een bitwise AND-operatie toe te passen met 0x3FFF (of 0b0011111111111111), die effectief alle 14 onderste bits van de positiegegevens behoudt.
Daarnaast is het nodig om rekening te houden met de resolutie van de encoder, ongeacht of die 12 bits of 14 bits is. Als de resolutie 12 bits is, moet de waarde van de encoderPosition 2 bits naar rechts worden verschoven om de lagere resolutie aan te passen. Dit zorgt ervoor dat de positiegegevens nauwkeurig worden weergegeven in de encoderPosition variabele, die de werkelijke positie van de encoder weergeeft op basis van de gespecificeerde resolutie.
Kopiëren
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: De encoderPosition bijwerken.
De nulpositie instellen (alleen single-turn)
Bepaalde varianten van de AMT22-encoder bieden een programmeerbare nulpositie. Om deze nulpositie in te stellen, moet een specifieke opdrachtreeks van twee bytes worden verzonden. Het proces bestaat uit het eerst verzenden van de opdracht AMT22_NOP, gevolgd door een korte wachttijd om aan de minimale timingvereisten van de AMT22 te voldoen. Na deze wachttijd wordt de opdracht AMT22_ZERO verzonden terwijl de CS-lijn wordt vrijgegeven. Zodra de encoder deze opdracht ontvangt, wordt een reset uitgevoerd (zie listing 6).
Om communicatie met de encoder tijdens deze resetperiode te vermijden, wordt een vertraging van 250 ms geïmplementeerd, zodat er geen opdrachten naar de encoder worden verzonden tijdens de inschakeltijd.
Hoewel de software de nulpositie van de encoder aan het begin van de operation kan instellen, is het in de meeste toepassingen gebruikelijk om de nulpositie slechts eenmaal in te stellen tijdens de initiële configuratie van het apparaat voor gebruik binnen het systeem. Deze praktijk helpt de integriteit van de positiefeedback van de encoder te behouden gedurende de operationele levensduur.
Kopiëren
/*
* 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: De nulpositie van een single-turn AMT22-encoder instellen.
Het aantal omwentelingen uitlezen (alleen multi-turn)
Bepaalde varianten van de AMT22-encoder ondersteunen een multi-turn counter, waardoor gebruikers zowel de positie als het aantal omwentelingen kunnen uitlezen in één enkele gegevensopvraagsequentie.
Als de ontvangen positiegegevens ongeldig zijn, moet het systeem de gebruiker op de hoogte stellen van de fout. Als de positie daarentegen geldig is, moet het programma de positie rapporteren in decimaal formaat (zie listing 7). Deze mogelijkheid verbetert de functionaliteit van de encoder door uitgebreide feedback te geven over zowel de absolute positie als het aantal volledige omwentelingen, waardoor nauwkeurigere bewaking en regeling mogelijk wordt in toepassingen die precieze rotatiegegevens vereisen.
Kopiëren
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: De encoderPosition en het aantal omwentelingen uitlezen in een multi-turn AMT22-encoder.
De softwarecode uitvoeren
Nu de softwarecode is voltooid, is het tijd om deze naar de Arduino te uploaden en communicatie met de AMT22-encoder tot stand te brengen.
Om de uitvoer te controleren, opent u de seriële monitor in de Arduino IDE en stelt u de gegevenssnelheid in op 115200 baud. Hierdoor kunnen gebruikers de werking van de encoder observeren en de gerapporteerde positiegegevens in real-time bekijken. Zodra de seriële monitor actief is, begint de encoder met het verzenden van de positiegegevens, wat de functionaliteit van de encoder binnen het systeem aantoont (afbeelding 3).
Afbeelding 3: De gerapporteerde positie van de encoder, ontvangen door de Arduino (Bron afbeelding: Same Sky)
Meerdere encoders
Een belangrijk voordeel van het gebruik van een SPI-apparaat is de mogelijkheid om met meerdere encoders op dezelfde bus te communiceren. Hiervoor moet voor elke encoder een extra digitale I/O-pen worden toegewezen, zodat chip select (CS) afzonderlijk kan worden geregeld.
In de voorbeeldsoftware (zie listing 8) wordt een array van CS-pennen gebruikt om een willekeurig aantal encoders te ondersteunen. Dit ontwerp maakt schaalbare communicatie mogelijk, zodat de gebruiker eenvoudig meer encoders kan toevoegen als dat nodig is. Door de functies zo aan te passen dat ze het pennummer dat overeenkomt met het gewenste apparaat accepteren, kan de softwarecode dynamisch regelen welke encoder actief is op de SPI-bus, zodat elk apparaat onafhankelijk benaderd en bediend kan worden.
Kopiëren
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: Een array instellen voor het uitlezen van meerdere encoders.
De volgende stap is het doorlopen van elke CS-pen in de matrix en het uitlezen van de positie van elke aangesloten encoder. Hierdoor kan het systeem elke encoder activeren door de CS-lijn te activeren, de SPI-overdracht uit te voeren en de positiegegevens op te halen. De softwarecode selecteert achtereenvolgens elke encoder, voert de SPI-communicatie uit en geeft de CS-lijn vrij, zodat alle aangesloten apparaten om hun positiegegevens worden gevraagd (zie listing 9).
Kopiëren
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: De encoderPosition variabele vanaf meerdere encoders uitlezen.
Na de gegevensoverdracht is er een minimale wachttijd vereist voordat de CS-lijn wordt vrijgegeven. Volgens de datasheet is deze minimale tijd 3 microseconden. Hoewel deze vertraging meestal vanzelfsprekend wordt waargenomen bij langzamere gegevenssnelheden, is het een goede gewoonte om deze expliciet in de softwarecode te implementeren om een goede werking en naleving van de timingspecificaties te garanderen. Dit garandeert een betrouwbare communicatie met de AMT22-encoder.
Conclusie
Gebruikers hebben zojuist geleerd hoe ze gegevens van AMT22 absolute encoders van Same Sky configureren en uitlezen. Dit artikel richtte zich op de AMT22 absolute encoders. Same Sky heeft ook een lijn AMT modulaire encoders waaronder een reeks incrementele, absolute en commutatieversies.
Disclaimer: The opinions, beliefs, and viewpoints expressed by the various authors and/or forum participants on this website do not necessarily reflect the opinions, beliefs, and viewpoints of DigiKey or official policies of DigiKey.

