קוד לדוגמה של Arduino עבור אנקודרים אבסולוטיים SPI
2024-10-08
מדריך קוד דוגמה זה של Arduino נועד לתת למשתמשים נקודת התחלה מוצקה להגדרת תצורה וקריאת נתונים מהאנקודרים האבסולוטיים AMT22 של Same Sky עם תקשורת ממשק היקפי טורי (SPI). מדריך הלמידה יספק את החומרה והתוכנה הדרושים, דרישות הגדרה עיקריות, חבילות קוד לדוגמה והוראות עבור אפשרויות יציאה סיבוב-יחיד ורב-סיבובים כאחד. להלן רשימה של מה שנדרש כדי להתחיל:
- לוח Arduino
- אנקודר AMT22
- כבל AMT-06C-1-036 , או כבל דומה עם מחבר מתאים
- Arduino IDE
- הורדת קוד דוגמה AMT22 סיבוב-יחיד
- הורדת קוד דוגמה AMT22 רב-סיבובים
סקירה כללית של אנקודר אבסולוטי AMT22
ה-AMT22 של Same Sky (לשעבר CUI Devices) הוא אנקודר אבסולוטי המוצע ברזולוציה של Bit-12 או Bit-14, כלומר מספק מספר מדויק של מיקומים ייחודיים בכל סיבוב. עבור גרסת Bit-12, זה מתורגם ל-4,096 מיקומים שונים, בעוד שדגם Bit-14 כולל 16,384 מיקומים בכל סיבוב. ללא קשר למספר הפעמים שההתקן מסתובב, הוא מדווח באופן רציף על מיקומו האבסולוטי, ומעניק למשתמשים משוב מדויק על הזווית המדויקת של ההתקן.
אנקודר זה זמין בדגמים של סיבוב-יחיד ורב-סיבובים כאחד. גרסת סיבוב-יחיד מודדת את המיקום בתוך סיבוב-יחיד של 360 מעלות, בעוד שגרסת רב-סיבובים עוקבת לא רק אחר המיקום אלא גם אחר סה"כ מספר הסיבובים שהושלמו. בנוסף, גרסות סיבוב-יחיד כוללות נקודת אפס הניתנת-לתכנות, המאפשרת למשתמשים להגדיר ייחוס מותאם-במיוחד למקור האנקודר.
צעדים ראשונים
ודאו שההתקן הוא באופן RUN על ידי כוונון המתג הממוקם בגב האנקודר למצב המתאים (איור 1). כעת הרכיבו את אנקודר AMT22 למנוע או למכלל באמצעות הוראות הרכבת AMT כדי להבטיח התקנה נכונה. ה-AMT22 תומך ב-9 גודלי ציר שונים הנעים בין 2 מ"מ ל-8 מ"מ.
איור 1: העבירו את המתג בגב אנקודר AMT22 לאופן RUN. (מקור התמונה: Same Sky)
החיבורים המתוארים באיור 2 ובטבלה 1 מיועדים במיוחד עבור לוח Arduino Uno, אך הקוד המסופק אמור להיות תואם לרוב לוחות Arduino. עם זאת, זכרו שתצורות הפינים עשויות להיות שונות בין דגמי Arduino השונים. לפרטי חיבור מדויקים על לוחות אחרים, מומלץ לעיין בתיעוד המתאים של Arduino.
איור 2: חיבורי חיווט Arduino Uno עם אנקודר AMT22. (מקור התמונה: Same Sky)
|
טבלה 1: הגדרה מורחבת של חיבורי חיווט Arduino Uno. (מקור התמונה: Same Sky)
אנקודר AMT22 מתחיל לשדר את נתוני המיקום האבסולוטי שלו מיד עם תחילת תקשורת SPI, ומבטל את הצורך במבנה פקודה-תגובה מסורתי. במהלך ה-Byte הראשון של העברת ה-SPI, המארח שולח 0x00, וה-AMT22 מגיב בו-זמנית עם נתוני מיקום תקפים.
אם המארח צריך להוציא פקודה (טבלה 2), כגון פקודת הגדרת אפס, היא תישלח ב-Byte השני של השידור. זו נקראת פקודה מורחבת. לפרטים טכניים מפורטים, עיינו בגיליון הנתונים של AMT22.
|
טבלה 2: הגדרת פקודות AMT22. (מקור התמונה: Same Sky)
מדריך למידה קוד - כולל ומגדיר
מכיוון שאפיק SPI של Arduino משמש לממשק עם אנקודר AMT22, ספריית SPI צריכה להיכלל בקוד. כדי לשלוח את נתוני המיקום מה-Arduino למחשב, משתמשים בחיבור USB-טורי המובנה בתוך ה-Arduino IDE, המוגדר בקצב Baud של 115,200.
בנוסף, יש להגדיר את הפקודות המשמשות את ה-AMT22. מאחר והאנקודר לא מעבד את תוכן ה-Byte הראשון, פקודת 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) מוגדר למצב המתאים כדי להכין את האנקודר עבור תקשורת.
בחרו קצב שעון עבור אפיק SPI כדי לתקשר עם ה-AMT22. למטרות בניית אב-טיפוס מתאים קצב שעון של kHz 500, למרות שה-AMT22 תומך בקצבים של עד MHz 2. השגת kHz 500 יכולה להיעשות באמצעות הגדרת SPI_CLOCK_DIV32. בהתחשב בשעון MHz 16 של Arduino Uno, חלוקה זו מביאה לקצב שעון SPI של kHz 500. לפרטים נוספים על תצורת שעון SPI, עיינו בתיעוד של Arduino.
לאחר הגדרת הכל, ניתן לאתחל את אפיק SPI באמצעות ()SPI.begin, אשר יגדיר את שלושת פיני ה-SPI הייעודיים: MISO, MOSI ו-SCLK, המכינים את המערכת עבור תקשורת עם האנקודר.
העתק
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: הפונקציה ()setup מאתחלת את כל פיני ה-SPI.
תקשורת SPI
תקשורת SPI עם AMT22 מטופלת דרך ספריית ה-SPI של Arduino, בעוד שבקרת בחיראת השבב (CS) מנוהלת באמצעות הקוד באמצעות פיני I/O דיגיטליים. פונקציית ()digitalWrite משמשת לאשר או לבטל אישור של קו CS (רשימה 3).
ה-AMT22 מצפה ששני Bytes של 0x00 יישלחו, והוא מחזיר נתונים מיד לאחר קולטת Bytes אלה. עקב תגובה מהירה זו, יש לעמוד בדרישות תזמון מינימליות מסוימות, המפורטות בגיליון הנתונים של ה-AMT22.
לא משנה אם האנקודר הוא גרסת Bit-12 או Bit-14, הוא תמיד מגיב עם שני Bytes (Bit-16) של נתונים. שני הביטים העליונים הם ביטי בדיקה המשמשים לוודא את שלמות הנתונים. עבור גרסת Bit-12, שני הביטים התחתונים הן שניהם 0, ויש להסיט את הערך המוחזר ימינה ב-2 ביטים (או לחלק ב-4) עבור שימוש נכון.
כדי לקבל נתוני מיקום, קוראים לפונקציה ()SPI.transfer, השולחת את פקודת AMT22_NOP. קו CS נשאר נמוך במהלך תהליך זה. ה-AMT22 שולח תחילה את ה-הגבוה Byte, כך שה-Byte הנקלט מוסט שמאלה ב-Bit 8 כדי ליישר אותו בחצי העליון של משתנה uint16_t. ערך זה מוקצה למשתנה encoderPosition בפעולה אחת. לאחר שיהוי קצר כדי לעמוד בדרישות התזמון, מתבצעת קריאה שנייה של ()SPI.transfer לשליחת פקודת AMT22_NOP נוספת. התוצאה עוברת פעולת OR עם הערך הנוכחי ב-encoderPosition, המשלבת למעשה את שני ה-Bytes שנקלטו לתוך משתנה 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.
וידוא בדיקת Checksum
לאחר השלמת העברת ה-SPI, חיוני לאמת את הנתונים שהתקבלו באמצעות בדיקת Checksum (רשימה 4).
כדי לממש אימות זה, ניתן ליצור פונקציה המבוססת על המשוואה שסופקה בגיליון הנתונים. בדיקת Checksum כלולה בשני הביטים העליונים של הערך הנקלט, והוא משתמש בזוגיות אי-זוגית על פני הביטים הזוגיים והאי-זוגיים בתגובת המיקום.
הפונקציה תבצע את השלבים הבאים:
- חישוב הזוגיות עבור הביטים האי-זוגיים (ביטים 1, 3, 5, 7, 9, 11, 13)
- חישוב הזוגיות עבור הביטים הזוגיים (ביטים 0, 2, 4, 6, 8, 10, 12, 14)
- השוואת הזוגיות המחושבת מול הערכים המצוינים על ידי הביטים של ה-Checksum
הפונקציה תחזיר True אם סכום הבדיקה תקף, מה שמצביע על אישור שלמות הנתונים. אם בדיקת Checksum אינה תקפה, הפונקציה תחזיר 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: אימות בדיקת Checksum.
פורמט הנתונים
אם אימות ה-Checksum מאשר את שלמות הנתונים, השלב הבא הוא עדכון משתנה encoderPosition על ידי הסרת שני הביטים העליונים (רשימה 5). ניתן להשיג זאת על ידי הפעלת פעולת AND בשיטת ביטים עם 0x3FFF (או 0b0011111111111111), אשר למעשה שומר על כל 14 הביטים התחתונים של נתוני המיקום.
בנוסף, יש צורך להביא בחשבון את הרזולוציה של האנקודר - בין אם היא Bit-12 או Bit-14. אם הרזולוציה היא Bit-12, יש להסיט ימינה את 2 הביטים של ערך encoderPosition כדי להתאים עבור הרזולוציה הנמוכה יותר. זה מבטיח שנתוני המיקום מיוצגים במדויק במשתנה 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 מציעים מאפיין מיקום אפס ניתן-לתכנות. כדי להגדיר את מיקום אפס זה, יש לשלוח רצף פקודות ספציפי של שני-Byte. התהליך כולל שליחת פקודת AMT22_NOP תחילה, ולאחר מכן המתנה קצרה כדי לעמוד בדרישות התזמון המינימליות שהוגדרו על ידי ה-AMT22. לאחר המתנה זו, הפקודה AMT22_ZERO נשלחת תוך הבטחה שקו בחירת שבב (CS) משוחרר. ברגע שהאנקודר יקלוט פקודה זו, הוא יבצע פעולת איפוס (רשימה 6).
כדי להימנע מתקשורת עם האנקודר במהלך איפוס זה, ממומש שיהוי של ms 250 המבטיח שלא יישלחו פקודות לאנקודר במהלך ההפעלה שלו.
בעוד שהקוד יכול להגדיר את מיקום האפס של האנקודר בתחילת הפעולה, נפוץ יותר ביישומים טיפוסיים להגדיר את מיקום האפס פעם אחת בלבד במהלך הגדרת תצורה הראשונית של ההתקן עבור שימוש המערכת. פרקטיקה זו עוזרת לשמור על שלמות משוב המיקום של האנקודר לאורך חיי הפעולה שלו..
העתק
/*
* 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: קריאת encoderPosition ומונה הסיבובים באנקודר AMT22 רב-סיבובים.
הרצת הקוד
כשהקוד נוצר בהצלחה, הגיע הזמן להעלות אותו ל-Arduino ולהקים תקשורת עם אנקודר AMT22.
כדי לנטר את היציאה, פתחו את הצג הטורי ב-Arduino IDE וודאו שקצב הנתונים מוגדר ל-Baud 115,200. זה יאפשר למשתמשים לבחון את פעולת האנקודר ולצפות בנתוני המיקום המדווחים בזמן-אמת. לאחר שהצג הטורי פעיל, האנקודר צריך להתחיל לשדר את מידע המיקום שלו ולהדגים את הפונקציונליות שלו בתוך המערכת (איור 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.
סיכום
כעת למשתמשים אמורה להיות הבנה בסיסית של הגדרת התצורה וקריאת הנתונים מהאנקודרים האבסולוטיים AMT22 של Same Sky. מאמר זה התמקד באנקודרים האבסולוטיים AMT22. ל-Same Sky יש גם קו של אנקודרים מודולריים AMT המציעים מגוון של גרסות אינקרמנטליות, אבסולוטיות וקומוטציה.
מיאון אחריות: דעות, אמונות ונקודות מבט המובעות על ידי מחברים שונים ו/או משתתפי פורום באתר אינטרנט זה לא בהכרח משקפות את הדעות, האמונות ונקודות המבט של חברת DigiKey או את המדיניות הרשמית של חברת DigiKey.

