Code d'exemple Arduino pour codeurs absolus SPI

Par Damon Tarry, Design Applications Engineer, Same Sky

Ce tutoriel d'exemple de code Arduino vise à donner aux utilisateurs un point de départ solide pour la configuration et la lecture des données des codeurs absolus AMT22 de Same Sky avec communication SPI (Serial Peripheral Interface). Le tutoriel présente le matériel et les logiciels nécessaires, les exigences de configuration clés, ainsi que des exemples de paquets de code et des instructions pour les options de sortie monotour et multitour. Vous trouverez ci-dessous une liste des éléments requis pour démarrer :

Présentation du codeur absolu AMT22

L'AMT22 de Same Sky (anciennement CUI Devices) est un codeur absolu disponible en résolution 12 bits ou 14 bits, ce qui signifie qu'il fournit un nombre précis de positions uniques par tour. Pour la variante 12 bits, cela se traduit par 4096 positions distinctes, tandis que le modèle 14 bits présente 16 384 positions par tour. Quel que soit le nombre de rotations du dispositif, il indique en permanence sa position absolue, offrant aux utilisateurs un retour précis sur l'angle exact du dispositif.

Ce codeur est disponible en modèles monotour et multitour. La variante à un seul tour mesure la position sur une seule rotation de 360 degrés, tandis que la version à plusieurs tours enregistre non seulement la position sur une rotation mais également le nombre total de rotations complètes. De plus, les variantes monotour disposent d'un point zéro programmable, permettant aux utilisateurs de définir une référence personnalisée pour l'origine du codeur.

Démarrage

Assurez-vous que le dispositif est en mode RUN en réglant le commutateur situé à l'arrière du codeur sur la position appropriée (Figure 1). Montez maintenant le codeur AMT22 sur un moteur ou un assemblage à l'aide des instructions de montage AMT pour garantir une installation correcte. L'AMT22 prend en charge 9 tailles d'arbre différentes s'étendant de 2 mm à 8 mm.

Schéma du codeur AMT22 de Same Sky commuté en mode RUNFigure 1 : Placez le commutateur situé à l'arrière du codeur AMT22 en mode RUN. (Source de l'image : Same Sky)

Les connexions indiquées dans la Figure 2 et le Tableau 1 sont spécifiquement destinées à la carte Arduino Uno, mais le code fourni devrait être compatible avec la plupart des cartes Arduino. Cependant, gardez à l'esprit que la configuration des broches peut différer d'un modèle Arduino à l'autre. Pour des détails de connexion précis sur d'autres cartes, il est recommandé de se référer à la documentation Arduino correspondante.

Schéma de câblage de l'Arduino Uno avec le codeur AMT22Figure 2 : Connexions de câblage de l'Arduino Uno avec le codeur AMT22. (Source de l'image : Same Sky)

Fonction Numéro de broche du codeur Broche Arduino Uno AMT-DBC-1-036
+5 V 1 5 V Blanc/vert
SCLK 2 13 Bleu/blanc
MOSI 3 11 Blanc/bleu
GND 4 GND Vert/blanc
MISO 5 12 Orange/blanc
CS 6 2 Blanc/orange

Tableau 1 : Connexions de câblage Arduino Uno définies plus en détail. (Source de l'image : Same Sky)

Le codeur AMT22 commence à transmettre ses données de position absolue immédiatement dès que la communication SPI débute, éliminant ainsi le besoin d'une structure de commande-réponse traditionnelle. Pendant le premier octet du transfert SPI, l'hôte envoie 0x00 et l'AMT22 répond simultanément avec des données de position valides.

Si l'hôte doit émettre une commande (Tableau 2), telle qu'une commande de mise à zéro, elle sera envoyée dans le deuxième octet de la transmission. On parle de commande étendue. Pour des spécifications techniques détaillées, reportez-vous à la fiche technique AMT22.

Commande Octet Notes
Get Position 0x00 0x00
Set Zero 0x00 0x70 Monotour uniquement
Get Turns 0x00 0xA0 Multitour uniquement

Tableau 2 : Commandes AMT22 définies. (Source de l'image : Same Sky)

Tutoriel sur le code – Instructions Include et Define

Étant donné que le bus SPI de l'Arduino est utilisé pour interfacer avec le codeur AMT22, la bibliothèque SPI doit être incluse dans le code. Pour envoyer les données de position de l'Arduino à l'ordinateur, la connexion USB-série intégrée dans l'IDE Arduino est utilisée, configurée à un débit en bauds de 115200.

De plus, les commandes utilisées par l'AMT22 doivent être définies. Étant donné que le codeur ne traite pas le contenu du premier octet, une instruction NOP (no-operation) est attribuée pour simplifier le processus de communication (Liste 1).

Copier
/* 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

Liste 1 : Configuration de l'interface SPI.

Initialisation

Dans la fonction setup() (Liste 2), commencez par initialiser toutes les broches SPI requises et configurez les interfaces série pour la communication.

Le port série doit être initialisé pour permettre la transmission des données à l'ordinateur hôte. Cela se fait en passant le BAUDRATE défini dans la fonction Serial.begin().

Avant d'activer SPI, assurez-vous que la ligne chip select (CS) est définie sur l'état approprié afin de préparer le codeur à la communication.

Sélectionnez une fréquence d'horloge pour que le bus SPI communique avec l'AMT22. À des fins de prototypage, une fréquence d'horloge de 500 kHz convient, bien que l'AMT22 prenne en charge des fréquences jusqu'à 2 MHz. Il est possible d'atteindre 500 kHz avec le paramètre SPI_CLOCK_DIV32. Compte tenu de l'horloge 16 MHz de l'Arduino Uno, cette division donne une fréquence d'horloge SPI de 500 kHz. Pour plus de détails sur la configuration de l'horloge SPI, consultez la documentation Arduino.

Une fois la configuration terminée, le bus SPI peut être initialisé à l'aide de SPI.begin(), qui configure les trois broches SPI dédiées : MISO, MOSI et SCLK, préparant le système à la communication avec le codeur.

Copier
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();
}

Liste 2 : Fonction setup() qui initialise toutes les broches SPI.

Communication SPI

La communication SPI avec l'AMT22 est gérée via la bibliothèque SPI de l'Arduino, tandis que le contrôle chip select (CS) est géré via le code avec des broches E/S numériques. La fonction digitalWrite() est utilisée pour l'assertion ou la déassertion de la ligne CS (Liste 3).

L'AMT22 attend l'envoi de deux octets de 0x00 et renvoie les données immédiatement après avoir reçu ces octets. En raison de cette réponse rapide, certaines exigences de temporisation minimum doivent être respectées ; elles sont décrites dans la fiche technique AMT22.

Que le codeur soit une version 12 bits ou 14 bits, il répond toujours avec deux octets (16 bits) de données. Les deux bits supérieurs sont des bits de contrôle, utilisés pour vérifier l'intégrité des données. Pour la version 12 bits, les deux bits inférieurs sont tous les deux 0 et la valeur renvoyée doit être décalée de 2 bits vers la droite (ou divisée par 4) pour une utilisation correcte.

Pour obtenir les données de position, la fonction SPI.transfer() est appelée, envoyant la commande AMT22_NOP. La ligne CS reste à l'état LOW pendant ce processus. L'AMT22 envoie d'abord l'octet haut, de sorte que l'octet reçu est décalé de 8 bits vers la gauche pour l'aligner dans la moitié supérieure d'une variable uint16_t. Cette valeur est attribuée à la variable encoderPosition en une seule opération. Après un bref délai pour répondre aux exigences de temporisation, un deuxième appel SPI.transfer() est effectué pour envoyer une autre commande AMT22_NOP. Le résultat est associé à l'aide d'une fonction OU avec la valeur actuelle dans encoderPosition, combinant ainsi efficacement les deux octets reçus en une seule variable uint16_t. Enfin, la ligne CS est envoyée, terminant la communication.

Copier
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);

Liste 3 : Configuration de la communication SPI.

Vérification de la somme de contrôle

Une fois le transfert SPI terminé, il est essentiel de valider les données reçues à l'aide d'une somme de contrôle (Liste 4).

Pour implémenter cette validation, une fonction peut être créée à partir de l'équation fournie dans la fiche technique. La somme de contrôle est contenue dans les deux bits supérieurs de la valeur reçue et utilise une parité impaire dans les bits impairs et pairs dans la réponse de position.

La fonction exécute les étapes suivantes :

  1. Calcul de la parité pour les bits impairs (bits 1, 3, 5, 7, 9, 11, 13)
  2. Calcul de la parité pour les bits pairs (bits 0, 2, 4, 6, 8, 10, 12, 14)
  3. Comparaison des parités calculées avec les valeurs indiquées par les bits de somme de contrôle

La fonction renvoie TRUE si la somme de contrôle est valide, indiquant que l'intégrité des données est confirmée. Si la somme de contrôle n'est pas valide, la fonction renvoie la valeur FALSE, signalant ainsi une éventuelle erreur dans les données reçues.

Copier
/*
 * 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);
}

Liste 4 : Validation de la somme de contrôle.

Formatage des données

Si la validation de la somme de contrôle confirme l'intégrité des données, l'étape suivante consiste à mettre à jour la variable encoderPosition en supprimant les deux bits supérieurs (Liste 5). Cela peut être réalisé en appliquant une opération AND bit à bit avec 0x3FFF (ou 0b0011111111111111), qui conserve efficacement les 14 bits inférieurs des données de position.

De plus, il est nécessaire de prendre en compte la résolution du codeur, qu'elle soit de 12 ou 14 bits. Si la résolution est de 12 bits, la valeur encoderPosition doit être décalée de 2 bits vers la droite pour s'adapter à la résolution inférieure. Cela garantit que les données de position sont représentées avec précision dans la variable encoderPosition, reflétant la position réelle du codeur en fonction de sa résolution spécifiée.

Copier
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");
}

Liste 5 : Mise à jour d'encoderPosition.

Réglage de la position zéro (monotour uniquement)

Certaines variantes du codeur AMT22 offrent une fonction de position zéro programmable. Pour définir cette position zéro, une séquence de commandes spécifique de deux octets doit être envoyée. Le processus implique d'abord l'envoi de la commande AMT22_NOP, suivi d'une brève attente pour répondre aux exigences de temporisation minimum spécifiées par l'AMT22. Après ce temps d'attente, la commande AMT22_ZERO est envoyée tout en garantissant que la ligne chip select (CS) est libérée. Dès que le codeur reçoit cette commande, il effectue une opération de réinitialisation (Liste 6).

Pour éviter toute communication avec le codeur pendant cette période de réinitialisation, un délai de 250 ms est mis en place, garantissant qu'aucune commande n'est envoyée au codeur pendant le délai de mise sous tension.

Bien qu'il soit possible pour le code de définir la position zéro du codeur au début du fonctionnement, il est plus courant dans les applications classiques de définir la position zéro une seule fois lors de la configuration initiale du dispositif pour une utilisation dans le système. Cette pratique contribue à maintenir l'intégrité du retour de position du codeur tout au long de sa durée de vie opérationnelle.

Copier
/*
 * 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
}

Liste 6 : Réglage de la position zéro d'un codeur AMT22 monotour.

Lecture du compteur de tours (multitour uniquement)

Certaines variantes du codeur AMT22 prennent en charge un compteur multitour, permettant aux utilisateurs de lire à la fois la position et le nombre de tours dans une seule séquence de récupération de données.

Si les données de position reçues ne sont pas valides, le système doit informer l'utilisateur de l'erreur. En revanche, si la position est valide, le programme doit signaler la position au format décimal (Liste 7). Cette capacité améliore les fonctionnalités du codeur en fournissant un retour complet sur la position absolue et le nombre de tours complets, facilitant une surveillance et un contrôle plus précis dans les applications exigeant des données de rotation précises.

Copier
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);

Liste 7 : Lecture d'encoderPosition et du compteur de tours dans un codeur multitour AMT22.

Exécution du code

Une fois le code correctement créé, il faut le télécharger sur l'Arduino et établir la communication avec le codeur AMT22.

Pour surveiller la sortie, ouvrez le moniteur série dans l'IDE Arduino et assurez-vous que le débit de données est défini sur 115 200 bauds. Cela permet aux utilisateurs d'observer le fonctionnement du codeur et de visualiser les données de position communiquées en temps réel. Une fois le moniteur série actif, le codeur doit commencer à transmettre ses informations de position, démontrant ainsi son fonctionnement dans le système (Figure 3).

Image de la position communiquée par le codeurFigure 3 : La position communiquée par le codeur, reçue par l'Arduino. (Source de l'image : Same Sky)

Multiples codeurs

L'un des avantages majeurs de l'utilisation d'un dispositif SPI est la capacité à communiquer avec plusieurs codeurs sur le même bus. Pour ce faire, une broche E/S numérique supplémentaire doit être allouée à chaque codeur, permettant un contrôle de chip select (CS) individuel.

Dans l'exemple de code (Liste 8), une matrice de broches CS est utilisée pour prendre en charge un nombre arbitraire de codeurs. Cette conception permet une communication évolutive, permettant à l'utilisateur d'ajouter facilement plus de codeurs selon les besoins. En modifiant les fonctions pour accepter le numéro de broche correspondant au dispositif souhaité, le code peut contrôler dynamiquement quel codeur est actif sur le bus SPI, garantissant que chaque dispositif est accessible et peut fonctionner indépendamment.

Copier
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

Liste 8 : Configuration d'une matrice pour la lecture de plusieurs codeurs.

L'étape suivante consiste à parcourir chaque broche CS de la matrice et à lire la position de chaque codeur connecté. Cela permet au système d'activer chaque codeur par l'assertion de sa ligne chip select, l'exécution du transfert SPI et la récupération des données de position. Le code sélectionne séquentiellement chaque codeur, exécute la communication SPI et libère la ligne CS, garantissant que tous les dispositifs connectés sont interrogés pour connaître leurs informations de position (Liste 9).

Copier
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);
}

Liste 9 : Lecture de la variable encoderPosition de plusieurs codeurs.

Après le transfert de données, un temps d'attente minimum est requis avant de libérer la ligne chip select. Selon la fiche technique, ce temps minimum est de 3 microsecondes. Bien que ce délai soit généralement observé naturellement à des débits de données plus lents, il est recommandé de l'implémenter explicitement dans le code pour garantir un fonctionnement correct et le respect des spécifications de temporisation. Cela garantit une communication fiable avec le codeur AMT22.

Conclusion

Vous devriez maintenant avoir une compréhension de base de la configuration et de la lecture des données des codeurs absolus AMT22 de Same Sky. Cet article porte sur les codeurs absolus AMT22. Same Sky propose également une ligne de codeurs modulaires AMT offrant une sélection de versions incrémentales, absolues et de commutation.

Avertissement : les opinions, convictions et points de vue exprimés par les divers auteurs et/ou participants au forum sur ce site Web ne reflètent pas nécessairement ceux de DigiKey ni les politiques officielles de la société.

À propos de l'auteur

Damon Tarry, Design Applications Engineer, Same Sky