SPI 절대 인코더를 위한 Arduino 샘플 코드

작성자: Damon Tarry, Design Applications Engineer, Same Sky

이 Arduino 샘플 코드 튜토리얼의 목적은 사용자에게 SPI(직렬 주변 장치 인터페이스) 통신을 통해 Same Sky AMT22 절대 인코더의 데이터를 구성하고 읽을 수 있는 확실한 시작점을 제공하는 것입니다. 이 튜토리얼은 단일 회전 및 다중 회전 출력 옵션에 필요한 하드웨어 및 소프트웨어, 주요 설정 요구 사항, 샘플 코드 패키지 및 지침을 제공합니다. 시작하는 데 필요한 품목 목록은 다음과 같습니다.

AMT22 절대 인코더 개요

Same Sky(이전 CUI Devices)의 AMT22는 12비트 또는 14비트 분해능으로 제공되는 절대 인코더로, 회전당 정확한 고유 위치 수를 제공합니다. 12비트 버전의 경우 이는 4,096개의 고유 위치로 변환되고, 14비트 모델은 회전당 16,384개 위치를 제공합니다. 장치의 회전 횟수에 관계없이 절대 위치가 보고되므로 장치의 정확한 각도에 대해 사용자에게 정확한 피드백을 제공할 수 있습니다.

이 인코더는 단일 회전 및 다중 회전 모델로 제공됩니다. 단일 회전 버전은 단일의 360도 회전 내에서 위치를 측정하고 다중 회전 버전은 회전 내에서의 위치 뿐만 아니라 전체 회전의 총 개수도 추적합니다. 또한 단일 회전 버전은 영점을 프로그래밍할 수 있으므로 사용자가 인코더의 원점에 대한 사용자 지정 참조를 정의할 수 있습니다.

시작하기

인코더의 후면에 위치한 스위치를 적절한 위치로 조정하여 장치가 RUN 모드에 있도록 합니다(그림 1). 이제 적절한 설치를 위해 AMT 실장 지침을 사용하여 AMT22 인코더를 모터 또는 조립에 실장합니다. AMT22는 2mm ~ 8mm 범위의 서로 다른 9개 샤프트 크기를 지원합니다.

RUN 모드로 전환된 Same Sky AMT22 인코더 구성도그림 1: AMT22 인코더의 후면에 있는 스위치를 RUN 모드로 돌립니다. (이미지 출처: Same Sky)

그림 2 및 표 1에 표시된 연결은 Arduino Uno 기판용이지만 제공된 코드는 대부분의 Arduino 기판과 호환됩니다. 그러나, 핀 구성은 Arduino 모델에 따라 다를 수 있습니다. 다른 기판에 대한 정확한 연결 세부 사항은 해당 Arduino 관련 문서를 참조하시기 바랍니다.

AMT22 인코더에 대한 Arduino Uno 배선 연결 구성도그림 2: AMT22 인코더에 대한 Arduino Uno 배선 연결. (이미지 출처: Same Sky)

기능 인코더 핀 번호 Arduino Uno 핀 AMT-DBC-1-036
+5V 1 5V 흰색/녹색
SCLK 2 13 파란색/흰색
MOSI 3 11 흰색/파란색
GND 4 GND 녹색/흰색
MISO 5 12 주황색/흰색
CS 6 2 흰색/주황색

표 1: 세부적으로 정의된 Arduino Uno 배선 연결. (이미지 출처: Same Sky)

AMT22 인코더는 SPI 통신 시작 시 절대 위치 데이터를 즉시 전송하는 것으로 시작하므로 기존의 명령-응답 구조를 필요로 하지 않습니다. SPI 전송의 첫 바이트 동안 호스트는 0x00을 보내고 AMT22는 유효한 위치 데이터로 동시에 응답합니다.

호스트가 명령을 실행해야 하는 경우(예: 영점 설정 명령)(표 2) 해당 명령은 전송의 두 번째 바이트에서 보내집니다. 이는 확장된 명령으로서 참조됩니다. 자세한 기술 정보는 AMT22 규격서를 참조하십시오.

명령 바이트 참고 사항
Get Position 0x00 0x00
Set Zero 0x00 0x70 단일 회전만 해당
Get Turns 0x00 0xA0 다중 회전만 해당

표 2: 정의된 AMT22 명령. (이미지 출처: Same Sky)

코드 튜토리얼 - 포함 내용 및 정의

Arduino의 SPI 버스는 AMT22 인코더와의 연결에 사용되므로 코드에 SPI 라이브러리가 포함되어 있어야 합니다. Arduino에서 컴퓨터로 위치 데이터를 보내려면 Arduino IDE 내의 내장된 USB-직렬 연결을 활용하여 115200의 보드 속도로 구성되어야 합니다.

또한 AMT22에서 사용되는 명령도 정의되어야 합니다. 인코더는 첫 번째 바이트의 내용을 처리하지 않으므로 통신 프로세스를 간소화하기 위해 NOP(작업 없음)가 할당됩니다(목록 1).

복사
/* 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

목록 1: SPI 인터페이스 설정.

초기화

setup() 함수(목록 2)에서는 먼저, 필요한 모든 SPI 핀을 초기화하고 통신을 위한 직렬 인터페이스를 구성합니다.

직렬 포트는 호스트 컴퓨터로의 데이터 전송을 허용하도록 초기화되어야 합니다. 이러한 작업은 정의된 BAUDRATE를 Serial.begin() 함수로 전달하여 수행됩니다.

SPI를 활성화하기 전에, 인코더가 통신을 준비할 수 있도록 칩 선택(CS) 회선을 적절한 상태로 설정하십시오.

AMT22와 통신할 수 있도록 SPI 버스에 대한 클록 속도를 선택합니다. 프로토타이핑이 목적인 경우 500kHz의 클록 속도가 적절하지만 AMT22는 최대 2MHz의 속도를 지원합니다. SPI_CLOCK_DIV32 설정을 사용하면 500kHz를 달성할 수 있습니다. Arduino Uno의 16MHz 클록을 고려할 경우 이는 500kHz SPI 클록 속도를 제공할 수 있습니다. SPI 클록 구성에 대한 자세한 내용은 Arduino 관련 문서를 참조하십시오.

모든 구성을 마치면 SPI.begin()을 사용하여 SPI 버스를 초기화할 수 있으며 이는 3개의 전용 SPI 핀인 MISO, MOSI, SCLK를 설정하여 시스템이 인코더와 통신할 수 있도록 준비합니다.

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

목록 2: 모든 SPI 핀을 초기화하는 setup() 함수.

SPI 통신

AMT22와의 SPI 통신은 Arduino의 SPI 라이브러리를 통해 처리되고 칩 선택(CS) 제어는 디지털 I/O 핀을 사용하는 코드를 통해 관리됩니다. digitalWrite() 함수는 CS 회선을 어설션 또는 어설션 해제하는 데 사용됩니다(목록 3).

AMT22에는 2개 바이트의 0x00이 전송되어야 하며 이 바이트를 받은 직후 데이터가 반환됩니다. 이렇게 빠른 응답으로 인해 특정한 최소 타이밍 요구 사항을 준수해야 하며, 해당 내용은 AMT22 규격서에 설명되어 있습니다.

인코더가 12비트 버전인지 또는 14비트 버전인지에 관계없이 AMT22는 항상 2바이트(16비트)의 데이터로 응답합니다. 상위 2개 비트는 체크 비트로서 데이터 무결성을 확인하는 데 사용됩니다. 12비트 버전의 경우 하위 2개 비트가 모두 0이며 반환되는 값은 적절한 사용을 위해 오른쪽으로 2개 비트만큼 이동해야 합니다(또는 4로 나뉨).

위치 데이터를 획득하기 위해 SPI.transfer() 함수가 호출되어 AMT22_NOP 명령이 전송됩니다. CS 회선은 이 프로세스 동안 low로 유지됩니다. AMT22는 high 바이트를 먼저 전송하므로, 수신된 바이트는 8개 비트만큼 왼쪽으로 이동하여 uint16_t 변수의 위쪽 절반에 정렬됩니다. 이 값은 한 번의 작업으로 encoderPosition 변수에 할당됩니다. 타이밍 요구 사항을 충족하기 위해 잠시 지연된 후, 두 번째 SPI.transfer() 호출을 통해 또 다른 AMT22_NOP 명령이 전송됩니다. 해당 결과는 encoderPosition의 현재 값과 OR 연산되어 수신된 2개 바이트가 단일 uint16_t 변수로 효과적으로 결합됩니다. 마지막으로 CS 회선이 해제되어 통신이 완료됩니다.

복사
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);

목록 3: SPI 통신 설정.

체크섬 확인

SPI 전송을 완료한 후에는 체크섬을 사용하여 수신 데이터의 유효성을 검사해야 합니다(목록 4).

이 유효성 검사를 구현하려면 규격서에 제공된 수식을 기반으로 하여 함수를 생성해야 합니다. 체크섬은 수신된 값의 상위 2개 비트에 포함되며 위치 응답의 홀수 및 짝수 비트에서 홀수 패리티를 활용합니다.

함수는 다음 단계를 수행합니다.

  1. 홀수 비트에 대해 패리티를 계산합니다(비트 1, 3, 5, 7, 9, 11, 13).
  2. 짝수 비트에 대해 패리티를 계산합니다(비트 0, 2, 4, 6, 8, 10, 12, 14).
  3. 체크섬 비트에 의해 표시된 값과 계산된 패리티를 비교합니다.

체크섬이 유효한 경우 함수는 true를 반환하며 이는 데이터 무결성이 확인되었음을 나타냅니다. 체크섬이 유효하지 않은 경우 함수는 false를 반환하여, 수신된 데이터에 잠재적 오류가 있음을 알립니다.

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

목사 4: 체크섬의 유효성 검사.

데이터 형식 지정

체크섬 유효성 검사를 통해 데이터의 무결성이 확인되면 다음 단계는 상위 두 개 비트를 제거하여 encoderPosition 변수를 업데이트하는 것입니다(목록 5). 이는 0x3FFF(또는 0b0011111111111111)로 비트별 AND 연산을 적용하여 위치 데이터의 하위 14개 비트를 모두 효과적으로 유지함으로써 달성할 수 있습니다.

또한 인코더의 분해능 즉, 12비트 또는 14비트도 고려해야 합니다. 분해능이 12비트인 경우 더 낮은 분해능에 맞게 조정하려면 encoderPosition 값을 오른쪽으로 2개 비트만큼 이동합니다. 그러면 지정된 분해능에 따라 인코더의 실제 위치를 반영하여 위치 데이터를 encoderPosition 변수에서 정확하게 표시할 수 있습니다.

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

목록5: encoderPosition 업데이트.

영점 위치 설정(단일 회전만 해당)

AMT22 인코더의 특정 변형은 프로그래밍 가능한 영점 위치 기능을 제공합니다. 이 영점 위치를 설정하려면 특정 2바이트 명령 시퀀스를 전송해야 합니다. 이 프로세스에는 먼저 AMT22_NOP 명령을 보내고 AMT22에서 지정된 최소 타이밍 요구 사항을 충족하도록 짧게 기다리는 과정이 포함됩니다. 이러한 대기 이후, 칩 선택(CS) 회선이 해제되었는지 확인하면서 AMT22_ZERO 명령이 전송됩니다. 인코더가 이 명령을 수신하면 재설정 작업을 수행합니다(목록 6).

재설정 주기 동안 인코더와의 통신을 회피하기 위해 250ms의 지연이 구현되어, 작동 시간 동안 인코더에 명령이 전송되지 않도록 합니다.

작동을 시작할 때 코드가 인코더의 영점 위치를 설정할 수도 있지만, 일반적인 애플리케이션에서는 시스템 내에서 사용하기 위해 장치를 처음 구성하는 동안 영점 위치를 한 번만 설정하는 것이 더 일반적입니다. 이는 작동 수명에 걸쳐 인코더의 위치 피드백 의 무결성을 유지하는 데 도움이 됩니다.

복사
/*
 * 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
}

목록 6: 단일 회전 AMT22 인코더의 영점 위치 설정.

회전전 수 읽기(다중 회전만 해당)

AMT22 인코더의 특정 버전은 다중 회전 카운터를 지원하므로 사용자는 단일 데이터 검색 시퀀스에서 위치와 회전 수를 모두 읽을 수 있습니다.

수신된 위치 데이터가 유효하지 않은 경우 시스템은 사용자에게 오류를 알려야 합니다. 반대로, 위치가 유효한 경우 프로그램은 십진수 형식으로 위치를 보고해야 합니다(그림 7). 이 기능은 절대 위치와 전체 회전 수에 대한 포괄적인 피드백을 제공하여 인코더의 기능을 향상시켜 정밀한 회전 데이터가 필요한 애플리케이션에서 보다 정확한 모니터링 및 제어를 용이하게 합니다.

복사
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);

목록 7: 다중 회전 AMT22 인코더의 encoderPosition 및 회전 수 읽기.

코드 실행

코드를 성공적으로 생성했다면 이제 Arduino 로 업로드하고 AMT22 인코더와 통신을 설정해야 합니다.

출력을 모니터링하려면 Arduino IDE에서 직렬 모니터를 열고 데이터 전송률이 115200보드로 설정되었는지 확인하십시오. 이를 통해 사용자는 인코더의 작동을 관찰하고 보고된 위치 데이터를 실시간으로 볼 수 있습니다. 직렬 모니터가 활성화되면 인코더는 위치 정보 전송을 시작하여 해당 시스템 내에서 기능을 시연해야 합니다(그림 3).

인코더에서 보고된 위치 이미지그림 3: Arduino에서 수신한, 인코더의 보고된 위치(이미지 출처: Same Sky)

다수의 인코더

SPI 장치 사용의 중요한 장점 중 하나는 동일한 버스에서 여러 인코더와 통신할 수 있다는 점입니다. 이렇게 하려면, 각 인코더에 추가 디지털 I/O 핀을 할당하여 개별 칩 선택(CS) 제어가 가능하도록 해야 합니다.

예제 코드(목록 8)에서는 CS 핀 배열을 사용하여 임의 개수의 인코더를 지원합니다. 이러한 설계 덕분에 통신 확장이 가능하며 사용자가 필요에 따라 더 많은 인코더를 손쉽게 추가할 수 있습니다. 원하는 장치에 해당하는 핀 번호를 수용하도록 함수를 수정하여 SPI 버스에서 어떤 인코더가 활성화되어 있는지 동적으로 제어함으로써 각 장치가 독립적으로 액세스하고 작동할 수 있도록 보장할 수 있습니다.

복사
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

목록 8: 다수의 인코더를 읽기 위한 어레이 설정.

다음 단계는 어레이의 각 CS 핀을 반복하여 연결된 각 인코더에서 위치를 읽는 것입니다. 이를 통해 시스템은 칩 선택 회선을 어설션하고 SPI 전송을 수행하며 위치 데이터를 검색하여 각 인코더를 활성화할 수 있습니다. 이 코드는 각 인코더를 순차적으로 선택하고 SPI 통신을 실행하고 CS 회선을 해제하여 연결된 모든 장치에 해당 위치 정보를 쿼리합니다(목록 9).

복사
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);
}

목록 9: 여러 인코더의 encoderPosition 변수 읽기.

데이터 전송 후, 칩 선택 회선이 해제되기 전에 최소한의 대기 시간이 필요합니다. 규격서에 따르면 이 최소 시간은 3마이크로초입니다. 이 지연은 일반적으로 느린 데이터 속도에서 자연스럽게 관찰되지만, 적절한 작동과 타이밍 사양 준수를 위해 코드에 명시적으로 구현하는 것이 좋습니다. 이를 통해 AMT22 인코더와의 신뢰할 수 있는 통신을 보장할 수 있습니다.

결론

이제 사용자는 Same Sky의 AMT22 절대 인코더에서 데이터를 구성하고 읽는 방법을 기본적으로 이해할 수 있어야 합니다. 이 기사에서는 AMT22 절대 인코더를 중점적으로 소개했습니다. Same Sky는 또한 다양한 증분, 절대 및 정류 버전을 제공하는 AMT 모듈식 인코더 제품군도 제공합니다.

면책 조항: 이 웹 사이트에서 여러 작성자 및/또는 포럼 참가자가 명시한 의견, 생각 및 견해는 DigiKey의 의견, 생각 및 견해 또는 DigiKey의 공식 정책과 관련이 없습니다.

작성자 정보

Damon Tarry, Design Applications Engineer, Same Sky