ارتباط سریال: گفتوگو با رایانه
با نرخ باود، print و read، برد را وادار کن مقدارش را گزارش کند و فرمان تکحرفی تو را بگیرد.
در پایان این درس میتوانید
- توضیح دهی نرخ باود چیست و چرا دو طرف باید عدد یکسانی داشته باشند.
- بدانی هر بایت با بیت استارت و استاپ ده بیت روی سیم میگیرد و زمان ارسال یک خط را حساب کنی.
- با Serial.begin و Serial.print و Serial.println مقدار متغیرها را روی رایانه ببینی.
- با Serial.available و Serial.read فرمان کاربر را بگیری و بدانی چرا شرط available لازم است.
- بدانی پایههای D0 و D1 مال سختافزار سریالاند و هنگام استفاده از سریال باید خالی بمانند.
تا اینجا برد فقط با نور و صدا با تو حرف زده است. ولی همین که برنامه از چند خط بیشتر شود، لازم میشود بدانی داخل متغیرها چه عددی نشسته است. ارتباط سریال دقیقاً همین پنجره است؛ یک مسیر متنی دوطرفه میان میکروکنترلر و رایانه که هم گزارش میدهد و هم فرمان میگیرد. همان سیم USB که برنامه را داخل تراشه ریخت، پس از پایان بارگذاری به این گفتوگو اختصاص پیدا میکند.
UART و نرخ باود
سختافزاری که این گفتوگو را میچرخاند UART نام دارد. «سریال» یعنی بیتها بهجای آنکه هشتتایی و موازی روی هشت سیم بروند، پشت سر هم از یک سیم میگذرند؛ یک سیم برای فرستادن و یک سیم برای دریافت. سیم ساعت مشترکی هم در کار نیست، پس دو طرف باید از پیش توافق کنند که هر بیت چقدر طول میکشد. نام این توافق نرخ باود است: تعداد بیت در ثانیه. با نرخ ۹۶۰۰، هر بیت یک تقسیم بر ۹۶۰۰ ثانیه، یعنی حدود ۱۰۴ میکروثانیه، روی سیم میماند.
هر بایت هم تنها سفر نمیکند. اول یک بیت استارت میرود تا گیرنده بفهمد قطار داده راه افتاده است، بعد هشت بیت خودِ داده، و آخر یک بیت استاپ که خط را به حالت آرام برمیگرداند. پس هزینهٔ واقعی هر کاراکتر هشت بیت نیست، ده بیت است؛ یعنی یکپنجم ظرفیت خط خرج علامتگذاری میشود. اگر نرخ باود دو طرف یکی نباشد گیرنده در لحظههای نادرست نمونهبرداری میکند و روی صفحه بهجای متن، کاراکتر درهم و بیمعنی میبینی.
یک نمونهٔ عددی
میخواهی بدانی چاپکردن چقدر گران تمام میشود. یک خط بیست کاراکتری با نرخ ۹۶۰۰ باود چقدر طول میکشد؟ هر کاراکتر یک بایت است و هر بایت با استارت و استاپ ده بیت، پس روی هم بیست ضربدر ده یعنی ۲۰۰ بیت روی سیم میرود. زمان لازم برابر است با ۲۰۰ تقسیم بر ۹۶۰۰ ثانیه که میشود ۰٫۰۲۰۸ ثانیه، یعنی حدود ۲۰٫۸ میلیثانیه. پس در هر ثانیه دستبالا ۴۸ خط از این دست جا میشود. اگر همین خط را داخل حلقهای بدون تأخیر بگذاری، برنامه در هر دور بیست میلیثانیه پشت خط سریال منتظر میماند؛ به همین دلیل در پروژههای حساس به زمان یا نرخ باود را بالا میبرند یا کمتر چاپ میکنند.
پایههای D0 و D1 مال سریالاند
روی برد Uno سختافزار سریال به پایههایD0برای دریافت وD1برای ارسال چسبیده است و همین دو پایه از راه یک تراشهٔ واسط به سوکت USB میروند. تا وقتی از سریال استفاده میکنی این دو پایه را خالی بگذار: هر قطعهای که رویشان ببندی هم سیگنال سریال را خراب میکند و هم ممکن است بارگذاری برنامه را از کار بیندازد. برای همین در کیت این درس الایدی روی پایهٔ ۸ بسته شده است، نه روی ۰ یا ۱.
چاپکردن
Serial.begin(9600) را در setup() مینویسی؛ این خط نرخ باود را تعیین و سختافزار سریال را روشن میکند و همان عدد باید در پنجرهٔ سریال هم انتخاب شود. Serial.print() متن یا عدد را میفرستد و همانجا میماند، و Serial.println() همان کار را میکند ولی دو کاراکتر پایان خط هم میچسباند تا نوشتهٔ بعدی سر خط تازه بیفتد. برای عدد اعشاری، آرگومان دوم تعداد رقم پس از ممیز است: Serial.println(v, 2) دو رقم چاپ میکند.
شنیدن
راه برگشت هم به همین سادگی است. Serial.available() میگوید چند بایت رسیده و هنوز خوانده نشده است؛ سختافزار بایتهای ورودی را در یک بافر ۶۴ بایتی نگه میدارد تا وقتی برنامه فرصت کند سراغشان برود. Serial.read() یک بایت را برمیدارد و از بافر بیرون میکشد. اگر بافر خالی باشد و باز هم بخوانی، عدد منفی یک تحویل میگیری نه یک کاراکتر واقعی؛ پس همیشه اول شرط available() را بگذار. یک نکتهٔ عملی هم هست: بیشتر پنجرههای سریال ته هر خط کاراکتر پایان خط میفرستند، پس برنامهات باید کاراکترهای ناشناخته را بیصدا رد کند.
در بازهٔ نیمثانیهای که برنامه پشت delay() ایستاده، سختافزار سریال بیکار نیست و بایتهای رسیده را در بافر انبار میکند. برای همین فرمان تو گم نمیشود، فقط با کمی تأخیر دیده میشود. ولی اگر بیش از ۶۴ بایت پیش از خواندن برسد، قدیمیترینها از دست میروند.
ابزار اصلی عیبیابی
میکروکنترلر نقطهٔ توقف و اشکالزدای گامبهگام ندارد، پس چاپ مقدار عملاً تنها چشم توست. وقتی مداری کار نمیکند، پیش از آنکه قطعه را عوض کنی عدد را چاپ کن: اگر analogRead() همیشه صفر برمیگرداند مشکل در سیم زمین است نه در برنامه، و اگر عدد پرشهای تصادفی دارد احتمالاً اتصال لق است. در کیت این درس هر دو سوی گفتوگو را با هم میبینی: مقدار پتانسیومتر مرتب چاپ میشود و تو با فرستادن یک حرف، الایدی را روشن یا خاموش میکنی.
رابطههای کلیدی
مأموریت روی میز کار
کیت را اجرا کن و پنجرهٔ سریال را روی ۹۶۰۰ بگذار؛ مقدار پتانسیومتر مرتب چاپ میشود و با فرستادن یک حرف میتوانی الایدی را روشن یا خاموش کنی.
- کد را اجرا کن و پنجرهٔ سریال را روی ۹۶۰۰ بگذار؛ پیچ پتانسیومتر را بچرخان و ببین عدد چاپشده بین ۰ و ۱۰۲۳ حرکت میکند.
- حرف n و بعد حرف f را بفرست و تأیید کن که الایدی روشن و خاموش میشود؛ بعد با علامت پرسش وضعیت فعلی را بپرس.
- عدد داخل Serial.begin را به ۱۹۲۰۰ تغییر بده ولی پنجرهٔ سریال را روی ۹۶۰۰ نگه دار و کاراکترهای درهم را ببین؛ بعد هر دو را یکی کن.
- زمان delay را از ۵۰۰ به ۵۰ کاهش بده و ببین چاپها چقدر تندتر میشوند و خواندن روی صفحه چقدر سختتر.
- آرگومان دوم Serial.println را از ۲ به ۴ ببر و ببین ولت با چند رقم اعشار بیشتر چاپ میشود.
مدار و کد این درس از پیش چیده شدهاند. آزادانه تغییرشان بدهید — پروژههای خودتان دستنخورده میمانند. تمامصفحه با همین کیت
آزمون این درس
۵ پرسش چهارگزینهای. پس از ثبت، پاسخ درست و توضیح هر پرسش را میبینید. میتوانید هر چند بار که خواستید تلاش کنید؛ بهترین نمره در کارنامه ثبت میشود.