עקב בקשת הקהל (וכאילו שחסרים לי פרויקטים אחרים להשלים), החלטתי לפתוח בפרויקט ארדואינו נוסף: Readuino, קורא הספרים האלקטרוני. המטרה היא לא ליצור מתחרה ל-Kindle של אמאזון אלא פשוט להדגים, באמצעות יישום בעל משמעות, טכניקות ועבודה עם כרטיסי SD.
בהתחשב במורכבות "מאחורי הקלעים" של העבודה עם מערכת קבצים, השילוב בין ארדואינו לקורא הכרטיסים הוא פשוט להפליא; אבל הפשטות הזו היא יחסית, ויש כמה דברים שצריך להבין ולהפנים לפני שאפשר להתחרע על נפח הזיכרון העצום שהכרטיסים הללו מעניקים. בפוסט זה נכסה, מאד בקצרה, את חומר הרקע החיוני, וניצור יישום ארדואינו ראשוני שמציג רשימה של הקבצים שנמצאים בתיקיה הראשית בכרטיס SD. מוכנים?
כרטיסי ה-SD (ראשי תיבות של Secure Digital), קצת בדומה ל-EEPROM של הארדואינו, הם רכיבי זכרון בלתי נדיף (Non-volatile), שאינו זקוק לאספקת חשמל שוטפת כדי לשמור על המידע. כמו ה-EEPROM, הכתיבה אליהם איטית בהרבה מהקריאה, ואורך החיים הרשמי מבחינת מספר כתיבות מוגבל לסביבות 100,000.
בניגוד ל-EEPROM, הכרטיס מכיל בתוכו גם שבב תקשורת, שמתווך בין המגעים המתכתיים לבין שטח האחסון בפועל. בעיקרון, אנחנו יכולים לכתוב קוד שיתקשר ישירות עם השבב הזה דרך המגעים, וכך לכתוב ולקרוא נתונים גולמיים. לשם כך צריך "רק" ללמוד את המפרטים הטכניים, שגרסה מקוצרת וחינמית שלהם אפשר למצוא כאן. עם זאת, בהנחה שאתם רוצים להספיק עוד דבר או שניים בחיים, האופציה השניה והשפויה היא להשתמש בספריית SD שמגיעה עם הארדואינו. שימו לב שמדובר בספריה כבדה למדי – עוד לפני שהקוד שלכם עושה משהו, עצם הגישה לכרטיס ולקבצים תעלה לכם כ-13 קילובייט.
מודול קורא הכרטיסים
מתאמים לכרטיסי SD, כמו זה שבתמונה למעלה, אפשר להשיג תמורת דולרים בודדים – וזהו מחיר הגיוני, כי אין בהם שום דבר מיוחד. רק קליפת מתכת ותפס להחזקה יציבה של הכרטיס, חיבורים בין המגעים של הכרטיס לפינים, ועוד כמה נגדים ורכיבים זולים אחרים. מודולים כאלה לא תורמים, בעצם, שום דבר מהותי מבחינת התקשורת בין הארדואינו לכרטיס ה-SD – הם מיועדים לנוחות בלבד. את התפקיד הזה הם דווקא ממלאים מצוין ורצוי מאד להצטייד במודול כזה או אחר לעבודה עם כרטיסים.
אל תתנו לשני טורי החיבורים להבהיל אתכם – למעשה, כל זוג מחובר בינו לבין עצמו, והבחירה באיזה צד להשתמש היא רק עניין של נוחות. יותר מזה, לא חייבים לחבר את כל הפינים – חלקם אופציונליים. מתוך שמונת הפינים הכפולים, אנו חייבים רק שישה:
- פין GND, כלומר Ground – ה"מינוס" של המעגל
- פין 3.3V או פין 5V – ה"פלוס" של המעגל. כרטיסי SD עובדים עם מתח של 3.3V, אך אם מסיבה כלשהי נוח לכם להשתמש דווקא ב-5V, המודול מסוגל לקלוט מתח כזה דרך הפין המתאים ולהמיר אותו.
- ארבעה פינים לתקן SPI
החומרים: ארדואינו, מטריצה, כרטיס ומודול לכרטיסתקן SPI
כבר נתקלנו בתקן SPI (ראשי תיבות של Serial Peripheral Interface – ממשק טורי לציוד היקפי) בפוסט על רכיב הזכרון 23K256. זהו תקן נפוץ מאד לתקשורת בסיסית עם רכיבים, והוא לא מפרט אילו פקודות יעברו בו ומה הן עושות – זה תלוי ברכיב הספציפי – אלא רק איך מעבירים את הפקודות ואת המידע הגולמי מצד לצד.
התקן מחייב ארבעה חיבורים בין ה-Master, הרכיב המנהל (במקרה שלנו – המיקרו-בקר שבארדואינו) לבין ה-Slave, הרכיב המנוהל (מודול ה-SD):
1. חיבור CS (ראשי תיבות של Chip Select), לפעמים נקרא גם SS (כלומר Slave Select). התקן מיועד לתקשורת עם רכיב יחיד בכל פעם, ולכן – אם יש יותר מרכיב מנוהל אחד – זהו החיבור שמאפשר לקבוע עם איזה רכיב מנוהל "מדברים". כמובן, הרכיבים עצמם אינם יודעים כמה אחרים יש במערכת, ולכן צריך להשתמש בפין זה גם אם יש רק רכיב מנוהל אחד. בגדול, כאשר מעבירים ערך HIGH דרך CS, הרכיב נהיה פעיל – וכשמעבירים LOW הוא מושבת.
2. חיבור SCK, או SCLK או CLK – חיבור "שעון" (Clock), שמתזמן העברה של ביט בודד. למשל, כשאנו שולחים שני ביטים ברצף ושניהם 0, איך הרכיב יודע מתי אחד נגמר והשני מתחיל? השעון מסמן כל ביט חדש באמצעות עליה מערך LOW לערך HIGH.
3. חיבור MOSI, או SIMO – כלומר Master Out / Slave In, נקרא לפעמים גם DI (ר"ת של Data In) זהו חיבור להעברת ביטים "מלמעלה למטה", מהרכיב המנהל לרכיב המנוהל.
4. חיבור MISO, או SOMI או DO (ר"ת של Data Out) – חיבור להעברת ביטים "מלמטה למעלה", מהרכיב המנוהל לרכיב המנהל.
הספריה SD של ארדואינו משתמשת בספריה SPI, שמטפלת בעצמה בפרטים הקטנים של תקשורת כזו. אז למה כל הפרטים האלה צריכים לעניין אתכם? קודם כל לידע כללי, ודבר שני – כדי שתדעו איך לחבר את החוטים נכון, כי הספריות המובנות מכריחות אתכם להשתמש בפינים ספציפיים בארדואינו!
הנה מיפוי הפינים עבור ספריית SPI (ו-SD) ללוחות ארדואינו "רגילים". המספרים שבסוגריים הם עבור לוחות Mega:
CS => 10 (53) MOSI => 11 (51) MISO => 12 (50) SCK => 13 (52)
את ה-CS של הרכיב המנוהל לא חייבים לחבר דווקא לפין 10 (53) בארדואינו – הספריה SPI מתירה לכם להגדיר לצורך העניין פין אחר – אבל בכל זאת, פין מס' 10 (53) חייב להיות מוגדר כ-OUTPUT אחרת יהיו בלגנים. בהתאם לכל זאת, הנה המערכת הבסיסית בה אשתמש לצורך הפרויקט:
מערכת הקבצים
ספריית SD לא מעניקה גישה ישירה לכתובות הזכרון שבכרטיס: היא עובדת ברמה גבוהה הרבה יותר, עם קבצים ותיקיות. גם קבצים ותיקיות הם, בסופו של דבר, ביטים על כרטיס ה-SD; הארגון שלהם מתבצע דרך אזור בזכרון שנקרא "טבלת מיקומי קבצים" (FAT – File Allocation Table), מעין מסד נתונים שבו מוגדר אילו ביטים שייכים לאיזה קובץ, מה היררכיית התיקיות, מה השם, תאריך היצירה וההרשאות של כל קובץ/תיקיה וכו' וכו'. כל זה נושא לספר או שניים: לענייננו, מה שחשוב כעת הוא שהכרטיס יהיה מפורמט ל-FAT שהספריה SD יודעת לעבוד איתה. נכון להיום, מדובר בשתי גרסאות: FAT16 ו-FAT32. כשאתם מפרמטים את הכרטיס לקראת העבודה עם ארדואינו, וודאו ש-FAT שמוגדרת היא אחת מאלה, ולא, נניח, NTFS המודרנית יותר של Windows.
התוכנה
אחרי כל ההקדמה הארוכה הזו, אנחנו מגיעים סוף כל סוף לתוכנה. הדבר הראשון שצריך להוסיף לקוד, למעלה, הוא השורה שתיתן לנו גישה לספריית ה-SD:
#include <SD.h>
כעת, אנחנו רוצים להתחבר לכרטיס – אבל חייבים לזכור שהכרטיס יכול להיות לא זמין, למשל אם שכחנו להכניס אותו למודול או לא הכנסנו עד הסוף. אז כדי למנוע תקלות מעצבנות כאלה, נבדוק את הערך שמחזירה פונקציית החיבור SD.begin ונגיב בהתאם, לדוגמה:
void setup() { Serial.begin(9600); if (!SD.begin()) Serial.println("SD reader error"); else /* Continue normally */; }
הפקודה השימושית הבאה היא זו שמאפשרת לנו לפתוח קובץ או תיקיה ולעשות איתם משהו. אגב, התיקיות בספריית SD מוגדרות באמצעות התו / (קו נטוי שעולה משמאל לימין), כמו בכתובות אינטרנט, ולא כמו בתיקיות של Windows. כזכור, אנחנו רוצים לראות אילו קבצים נמצאים בתיקיה הראשית (Root), ולכן קודם כל נפתח אותה:
File rootDir; rootDir = SD.open("/");
סוג המשתנה File הוא למעשה אובייקט שמוגדרת בספריית SD, ומיועד לטיפול בקבצים וגם – למרות השם – בתיקיות.
הגישה לקבצים בתיקיה מתבצעת בצורה סדרתית, כלומר אנחנו יכולים לקבל אותם רק אחד אחרי השני, באמצעות הפונקציה File.openNextFile. היא מיועדת, כמובן, לשימוש בתיקיות בלבד, ומחזירה לנו את הקבצים שבתיקיה בזה אחר זה. כשאין יותר קבצים, היא תחזיר ערך null. הנה הלולאה שסורקת את הקבצים ושולחת ל-Serial Monitor של הארדואינו את שמותיהם:
File currentFile; currentFile = rootDir.openNextFile(); while (currentFile) { Serial.println(currentFile.name()); currentFile = rootDir.openNextFile(); }
מה עושים אם רוצים לעבור שוב על רשימת הקבצים מההתחלה? מאפסים את הרשימה בעזרת הפונקציה:
rootDir.rewindDirectory();
ומה קורה אם התיקיה מכילה תיקיות-משנה? ואיך נכנסים לקובץ עצמו כדי לכתוב ולקרוא דברים? על כל זאת ועוד, בפוסט הבא בפרויקט Readuino…
מה שם רכיב המתאם כרטיס זכרון?
לא מכיר שם ספציפי. יש המון כאלה ב-ebay וב-aliexpress, חפש לפי מילות המפתח SD Card Arduino .
תודה רבה!!
בלי קשר אני רוצה להודות על כל המאמרים והסרטונים שלך.
נשמע מעניין מאד..
האם אפשר לקרוא מתוך רכיב ה microsd שקיים על ה Ethernet shield?
תודה
פרגית
בהחלט – נא לקרוא בעיון את חלק ה-Description כאן: http://arduino.cc/en/Main/ArduinoEthernetShield
מאמר נחמד, ונשמע כמו פרויקט מעניין 🙂
מחכה לפוסט הבא.