در قسمت هشتم از آموزش آردوینو به بررسی استفاده از اعداد ممیز شناور و آرایهها در آردوینو، پرداختیم. در این قسمت قصد داریم به بررسی نحوه استفاده از توابع رشتهای در آردوینو بپردازیم.
در قسمت قبلی بررسی کردیم که چگونه میتوان از آرایههای کاراکتری برای ذخیره متن استفاده کرد. این آرایههای کاراکتری معمولاً رشته (استرینگ) نامیده میشوند. آردوینو یک استرینگ آبجکت (آبجکت رشتهای) دارد که دارای قابلیتهای زیادی برای ذخیره و ویرایش متن است. توجه داشته باشید که “S” ابتدای واژه String با حرف بزرگ نوشته میشود.
نکته✅
کلمه String با حرف اول بزرگ (S) به قابلیتهای مربوط به متن آردوینو اشاره دارد که توسط کتابخانه استرینگ آردوینو ارائه میشود. اما کلمه string با حرف اول کوچک (s) به تابع رشتهای آردوینو اشاره ندارد؛ بلکه به گروه کاراکترها اشاره می کند.
دستور زیر روش استفاده از رشتههای آردوینو را نشان میدهد:
اسکچ زیر را روی برد آردوینوی خود بارگذاری کنید و سریال مانیتور را برای مشاهده باز کنید.
برنامه:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | کد/* Basic_Strings sketch */ String text1 = "This text"; String text2 = " has more characters"; String text3; // to be assigned within the sketch void setup() { Serial.begin(9600); while(!Serial); // Wait for serial port (Leonardo, 32-bit boards) Serial.print("text1 is "); Serial.print(text1.length()); Serial.println(" characters long."); Serial.print("text2 is "); Serial.print(text2.length()); Serial.println(" characters long."); text1.concat(text2); Serial.println("text1 now contains: "); Serial.println(text1); } void loop() { } |
نکته✅
در بردهای آردوینو Uno و اکثر بردهای 8 بیتی، وقتی شما سریال مانیتور را در نرم افزار Arduino IDE باز میکنید، برد ریست میشود، به این معنی که هر خروجی سریالی که در تابع setup تولید میشود، بعد از باز کردن سریال مانیتور مشاهده خواهد شد. با این حال، در بردهای Leonardo و بردهای مبتنی بر SAMD، باز کردن پورت سریال به صورت اتوماتیک برد را ریست نمیکند، به این معنی که شما نمیتوانید سریال مانیتور را به سرعت باز کنید تا خروجی را ذخیره کنید بلکه نیاز است بعد از باز کردن پورت برد را به شکل دستی ریست کنید.
این اسکچ سه متغیر از نوع String با نامهای text2 ،text1 و text3 ایجاد میکند. متغیرهای نوع String قابلیتهایی برای ویرایش متن دارند. عبارت text1.length() طول (تعداد کاراکترهای) رشته text1 را برمیگرداند.
در زبان برنامهنویسی آردوینو، شما میتوانید از تابع concat برای ترکیب محتوای دو رشته استفاده کنید. در این حالت، محتوای text2 به انتهای محتوای text1 اضافه میشود. (کلمه concat مخفف concatenate است.)
سریال مانیتور به شکل زیر نمایش داده میشود:
1 2 3 4 | text1 is 9 characters long. text2 is 20 characters long. text1 now contains: This text has more characters |
راه دیگر ترکیب رشتهها، استفاده از عملگر جمع رشته است. به این منظور، دو خط زیر را به انتهای کد تابع setup اضافه کنید:
1 2 | text3 = text1 + " and more"; Serial.println(text3); |
کد جدید باعث میشود که سریال مانیتور کد زیر به انتهای صفحهنمایش اضافه شود:
1 | This text has more characters and more |
شما میتوانید از توابع indexOf و lastIndexOf برای پیداکردن نمونهای از یک کاراکتر خاص در یک رشته استفاده کنید.
نکته✅
در زبان برنامهنویسی آردوینو، شما با اسکچهایی روبهرو خواهید شد که از آرایههای کاراکتری یا پوینترها بهعنوان دنبالهای از کاراکترها استفاده میکنند، بهجای نوع String. در ادامه این آموزش درباره نحوه استفاده از آرایههای کاراکتری بدون کمک String آردوینو و چگونگی ذخیره رشتههای ثابت در حافظه فلش بهجای حافظه اصلی (حافظه رم) آردوینو صحبت میشود.
اگر کد زیر را مشاهده کردید:
1 | char oldString[] = "this is a character array"; |
این کد از آرایههای کاراکتری مشابه زبان C استفاده میکند. اگر این اعلان (Declaration) به شکل زیر باشد:
1 | String newString = "this is a string object"; |
کد از رشتههای آردوینو استفاده میکند. برای تبدیل یک آرایه کاراکتری مشابه زبان C به یک آردوینو استرینگ، فقط باید محتویات آرایه را به استرینگ آبجکت اختصاص دهید:
1 2 | char oldString[] = "I want this character array in a String object"; String newString = oldString; |
برای استفاده از هر یک از توابع فهرست شده در جدول 1 باید آنها را بر روی یک استرینگ آبجکت فراخوانی کنید، مانند مثال زیر:
1 | int len = myString.length(); |
جدول زیر (جدول 1) مروری کوتاه بر توابع رشتهای آردوینو است:
تابع | وظیفه |
---|---|
charAt(n) | n اُمین کاراکتر استرینگ را برمی گرداند |
compareTo(S2) | استرینگ موجود را با استرینگ S2 مقایسه می کند |
concat(S2) | یک استرینگ جدید که ترکیبی از String موجود و استرینگ S2 است را برمی گرداند |
endsWith(S2) | اگر استرینگ به کاراکترهای S2 ختم شود، مقدار true را برمیگرداند |
equals(S2) | اگر استرینگ دقیقاً مطابق با S2 باشد، مقدار true را برمیگرداند (به حروف بزرگ و کوچک حساس است) |
equalsIgnoreCase(S2) | مانند قبلی (equals) است اما به حروف بزرگ و کوچک حساس نیست |
getBytes(buffer,len) | کاراکترهای len(gth) را در بایت بافر موجود، کپی می کند |
indexOf(S) | استرینگ (یا کاراکتر) داده شده را برمیگرداند ـ اگر ۱ پیدا نشود |
lastIndexOf(S) | مانند قبلی (indexOf) است اما از انتهای استرینگ شروع می شود |
length() | تعداد کاراکترهای استرینگ را برمیگرداند |
remove(index) | کاراکتر موجود در استرینگ موجود را حذف می کند |
remove(index, count) | تعداد مشخصی از کاراکترها را از استرینگ موجود شروع می کند |
replace(A,B) | همه نمونه های استرینگ (یا کاراکتر) A را با B جایگزین می کند |
reserve(count) | تعداد مشخص شده بایت ها را تخصیص می دهد تا استرینگ بعدی، عملکرد بهتری داشته باشد |
setCharAt(index,c) | کاراکتر c را در استرینگ موجود ذخیره می کند |
startsWith(S2) | اگر استرینگ با کاراکترهای S2 شروع شود، مقدار true برمی گرداند |
substring(index) | استرینگ را با کاراکترهای شروع شده از index تا انتهای استرینگ برمی گرداند |
substring(index,to) | مانند قبلی ( ) است، اما استرینگ فرعی در محل کاراکتر، قبل از position به پایان می رسد |
toCharArray(buffer,len) | حداکثر کاراکترهای رشته ای را در بافر موجود، کپی می کند |
toFloat() | مقدار ممیز شناور (floating-point) ارقام عددی استرینگ را برمیگرداند |
toInt() | مقدار صحیح ارقام عددی استرینگ را برمیگرداند |
toLowerCase() | رشتهای را با تمام کاراکترها به حروف کوچک تبدیل می کند |
toUpperCase() | رشتهای را با تمام کاراکترها به حروف بزرگ تبدیل می کند |
trim() | رشتهای را با حذف تمام فضای خالی اصلی و انتهایی برمیگرداند |
آرایهی کاراکتری زبان C بهتر است یا رشتهی آردوینو؟!
استفاده از استرینگ دیتا داخلی آردوینو نسبت به آرایهی کاراکتری زبان C آسانتر است، اما این دیتاها از طریق کدهای پیچیده در کتابخانه String ایجاد میشوند و ممکن است مشکلات بیشتری برای شما در پی داشته باشند.
دادهی String به دلیل استفاده از حافظهی داینامیک، بسیار انعطافپذیر است. در واقع، زمانی که یک رشته (String) ایجاد میکنید و یا آن را تغییر میدهید، آردوینو یک قسمت جدید از حافظه را از کتابخانهی C درخواست میدهد و زمانی که از یک رشته (String) استفاده کردید، آردوینو باید آن حافظه را خالی کند.
این کار معمولاً بهراحتی انجام میشود، اما بردهای آردوینو 8 بیتی حافظهی بسیار کمی دارند (آردوینو Uno: 2 کیلوبایت) به طوری که حتی نشت کوچک حافظه (small memory leak) هم تأثیر زیادی بر روی اسکچ شما دارد.
نشت حافظه (memory leak) زمانی اتفاق میافتد که از طریق یک باگ کتابخانه یا استفاده نادرست از آن، حافظه تخصیصیافته، خالی نشود. زمانی که این اتفاق میافتد، حافظهای که برای آردوینو در دسترس است بهندرت کم و کمتر میشود. (تا زمانی که آردوینو نیاز به ریست داشته باشد)
مساله دیگر مشکل مرتبط با فرگمنتیشن حافظه (memory fragmentation) است: هنگامی که بهصورت پیوسته حافظه خود را تخصیص میدهید و خالی میکنید، بعد از مدتی، آردوینو دارای بلوکهای کوچکتری از حافظهی آزاد شده (خالی) است که این موضوع ممکن است حتی اگر حافظهی رم کافی هم وجود داشته باشد، باز هم باعث مشکل در تخصیص رشته (String) شود. اگر در مورد فرگمنتیشن کنجکاو هستید مقاله فرگمنتیشن چیست؟ + روش های جلوگیری از فرگمنتیشن حافظه برای شما مفید است.
حتی اگر نشت حافظه هم وجود نداشته باشد، نوشتن کد برای بررسی اینکه درخواست یک رشته (String) به دلیل کمبود حافظه به مشکل خورده، کار پیچیدهای است. (توابع String شبیه به توابع پردازش در زبان برنامهنویسی هستند، اما برخلاف آنها، آردوینو دارای مکانیزم استثناهای زمان اجرا (runtime) نیست). پر شدن حافظهی heap، یک باگ است که پیداکردن این باگ، کمی دشوار است؛ زیرا ممکن است اسکچ شما بدون مشکل برای روزها و یا حتی هفتهها اجرا شود.
اگر شما از آرایههای کاراکتری (char array) استفاده کنید، کنترل کاملی بر روی مصرف حافظه خواهید داشت. به این صورت که در زمان کامپایل کردن، مقدار مشخصی از حافظه را تخصیص میدهید؛ بنابراین نشت حافظه نخواهید داشت. همچنین، اسکچ آردوینو شما همیشه دارای همان مقدار حافظهی قابلدسترس خواهد بود.
اگر بخواهید حافظهی بیشتری از آنچه در دسترس است، تخصیص دهید، پیداکردن علت مشکل، آسانتر است؛ زیرا ابزارهایی وجود دارند که به شما میگویند که چقدر حافظهی استاتیک تخصیص دادهاید.
استفاده از آرایههای کاراکتری زبان C، ممکن است شما را مشکل دیگری مواجه کند: در زبان C مکانیسمی وجود ندارد که از دسترسی به حافظه خارج از محدودهی آرایه جلوگیری کند؛ فرض کنید که یک آرایه با چهار کارکتر تعریف میکنید (myString[4]) آرایه شما از اندیس ۰ تا ۳ خواهد داشت، ولی کامپایلر جلوی دسترسی شما به اندیس ۵ یا ۶ یا ۷ را نخواهد گرفت، این مساله میتواند باعث مشکل آوررایت حافظه خواهد شد.
باتوجهبه استفاده از حافظهی استاتیک، امکان دارد کتابخانهی String آردوینو، همه حافظهی در دسترس شما را مصرف کند. بهطورکلی، آرایههای کاراکتری زبان C نیازمند دقت بالایی هستند و شما باید اطمینان حاصل کنید که از محدودههای آرایههای مورداستفاده، عبور نمیکنید؛ بنابراین اگر نیاز به قابلیت پردازش rich-text دارید و مکرراً رشتهها را ایجاد و تغییر میدهید، میتوانید از کتابخانهی String آردوینو استفاده کنید.
همچنین، اگر نیاز به ایجاد و تغییر آنها در یک لوپ تکراری دارید، بهتر است یک آرایهی کاراکتری بزرگ تخصیص دهید و کد خود را با دقت بنویسید تا از محدودههای آن آرایه عبور نکنید.
دلیل دیگری که ممکن است به خاطر آن از آرایههای کاراکتری (char array) به جای رشتههای آردوینو استفاده کنید، اسکچهای بزرگی است که به حافظهی فلش زیادی نیاز دارند.
برای تبدیل رشته به عدد اگر از StringToInt آردوینو استفاده کنید دوکیلوبایت بیشتر از وقتی که از آرایههای کاراکتری زبان C و تابع atoi برای تبدیل به عدد صحیح استفاده می کنید حافظه مصرف میشود. همچنین، نسخهیString آردوینو برای ذخیرهی اطلاعات تخصیص (allocation) و رشتهی واقعی (actual string)، به حافظهی رم بیش تری نیاز دارد.
اگر مشکوک به نشت حافظه در کتابخانهی String یا هر کتابخانهی دیگری که از حافظهی داینامیک استفاده میکند هستید، میتوانید در هر زمان که بخواهید مقدار حافظهی خالی را مانیتور کنید. هنگام شروع ساخت اسکچ خود، شما باید مقدار حافظهی رم (RAM) را بررسی کرده تا متوجه شوید که آیا در طول زمان، مقدار آن، کاهش مییابد یا خیر.
توجه🛑
اگر مشکوک به مشکلی در کتابخانهی String هستید، میتوانید در لیست باگهای اوپن سورس String جستوجو کنید.
برای مشاهده توزیع آردوینو اسکچهای نمونه String به قسمت File→Examples→Strings مراجعه نمایید.
برای مراجعه به صفحه رفرنس استرینگهای آردوینو (String reference page) روی لینک زیر کلیک کنید:
https://www.arduino.cc/reference/en/language/variables/data-types/stringobject/
برای دریافت آموزش کتابخانه String به لینک زیر مراجعه نمایید:
https://docs.arduino.cc/tutorials/
در قسمت بعدی آموزش آردوینو درباره روشهای استفاده از استرینگها توضیح خواهیم داد. در ادامه حتماً همراه سیسوگ باشید.