خانه > آموزش > کنترل LED توسط سوئیچ با LPC1768

کنترل LED توسط سوئیچ با LPC1768

در این مطلب می­ خواهیم با استفاده از یک سوئیچ یک LED  که به یکی از پایه های LPC1768 متصل شده است را کنترل نماییم.

اگر با رجیسترهای GPIO آشنایی ندارید بخوانید–> کار با ورودی خروجی همه منظوره(GPIO) در LPC1768

قبل از هر چیز باید با مفهوم مقاومت های بالاگذر(Pull-up) و پایین ­گذر(Pull-Down) آشنا شویم.

مقاومت های بالاگذر و پایین­ گذر

فرض کنید یک سوئیچ به پایه 8 پورت 1 وصل شده باشد. حال می­خواهیم با استفاده از برنامه متوجه شویم که کلید در وضعیت پایین(فشرده شده) قرار دارد یا در وضعیت بالا(رها شده). برای این کار باید از رجیستر FIOPIN پورت 1 استفاده کنیم. همان­طور که در مطلب کار با ورودی خروجی همه منظوره در LPC1768 دیدیم، رجیستر FIOPIN نشان دهنده آخرین وضعیت پایه های میکرو چه در وضعیت ورودی و چه در وضعیت خروجی است. با این تفاوت که در وضعیت خروجی نوشتن صفر و یک منطقی روی این رجیستر، وضعیت پایه را تغییر می ­دهد اما در وضعیت ورودی خواندن این رجیستر وضعیت فیزیکی پایه را به ما می­دهد.

حال فرض کنید که سوئیچ مورد نظر مانند شکل زیر به میکرو متصل شده باشد.

lpc1768-controlling-led-with-switch1

در این حالت مشخص است که اگر سوئیچ فشرده شده باشد بیت 8 از رجیستر FIOPIN پورت 1، صفرمنطقی خوانده می­ شود. اما اگر سوئیچ در وضعیت بالا باشد چه وضعیتی پیش می­ آید؟ در این حالت در اصطلاح پایه میکروکنترلر در وضعیت شناور(floating) قرار می­گیرد و خواندن بیت متناظر رجیستر  FIOPIN ممکن است منجر به نتایج نامشخصی گردد. در مدارات میکروکنترلری در هنگام اتصال سوئیچ خارجی باید از به وجود آمدن چنین حالت­ هایی جلوگیری کرد. برای جلوگیری از این حالت باید کاری کرد که وقتی کلید در وضعیت رهاشده قرار دارد پایه در وضعیت یک منطقی قرار گیرد. برای این کار از یک مقاومت بالاگذر مانند شکل زیر می­ توان استفاده نمود.

lpc1768-controlling-led-with-switch2

 همانطور که از شکل فوق مشخص است وقتی که سوئیچ در وضعیت رهاشده قرار دارد از طریق مقاومت بالاگذر پایه میکرو به VCC وصل می­شود و وقتی که سوئیچ در وضعیت فشرده شده قرار دارد پایه به زمین متصل شده و جریان کمی از مقاومت بالاگذر می­گذرد(به شرطی که مقاومت بالاگذر به اندازه کافی بزرگ انتخاب شده باشد).

این مدار را می­ توان به طریق دیگری هم طراحی کرد. به این صورت که سوئیچ را به VCC متصل کرده و پایه میکرو را با مقاومت پایین­ گذر به زمین وصل کرد. این مدار در شکل زیر نمایش داده شده است.

lpc1768-controlling-led-with-switch3

بنابراین به طور ساده می­ توان گفت که وظیفه مقاومت­ های بالاگذر و پایین ­گذر این است که وضعیت پایه را در حالتی که سوئیچ رها شده است از حالت شناور در بیاورند.

مقاومت های بالاگذر و پایین ­گذر داخلی میکروکنترلر LPC1768

یکی از ویژگی­های میکروکنترلرهای پیشرفته از جمله LPC1768 این است که در تمامی پایه­های GPIO امکان فعال کردن مقاومت­های بالاگذر و پایین­ گذر وجود دارد. بنابراین نیازی به قرار دادن مقاومت بیرونی وجود ندارد. فعال کردن این مقاومت­ ها با برنامه نویسی و مقداردهی به رجیسترهای (PINMODE0 تا PINMODE9) ممکن می­ باشد. کارکرد این رجیسترها که همگی مشابه هم می­ باشد در صفحات 121 تا 124 راهنمای کاربری میکروکنترلرLPC1768 اورده شده است. برای مثال کارکرد رجیستر PINMOSE0 در جدول زیر نشان داده شده است.

lpc1768-controlling-led-with-switch4

همانطور که از جدول فوق مشخص است این رجیستر برای کنترل وضعیت مقاومت بالاگذر و پایین­ گذر پایه­ های صفر تا 15 پورت صفر به کار می­ رود. کاربرد بقیه رجیسترهای PINMODE هم به صورت مشابه برای پایه­ های دیگر میکروکنترلر می­ باشد.

هر دو بیت برای کنترل یک پایه به کار می­ رود. در حالت  00 که به طور پیش­فرض فعال می ­باشد مقاومت بالاگذر داخلی فعال می­ باشد. حالت 01 مربوط به حالت تکرارشونده می­باشد. در حالت تکرارشونده هر وقت پایه در حالت 1 منطقی قرار گیرد همزمان مقاومت بالاگذر فعال می­ گردد و هر وقت پایه صفر منطقی گردد مقاومت پایین­ گذر فعال می­ گردد. این حالت موجب می­­ گردد که هر وقت پایه از خارج به هیچ سطح منطقی متصل نشده است(شناور) آخرین وضعیت قبلی پایه حفظ گردد. در حالت 10 نه مقاومت بالاگذر و نه پایین­ گذر فعال نمی ­باشند. و در حالت 11 مقاومت پایین­ گذر داخلی فعال می ­باشد.

نکته: باید توجه نمود که در صورتی که از مقاومت بالاگذر یا پایین­ گذر داخلی استفاده کردیم دیگر نباید از خارج به پایه میکروکنترلر مقاومت متصل کنیم.

چک کردن یک بیت از رجیستر با دستورات شرطی

اگر با دستکاری بیتی رجیسترها آشنایی ندارید بخوانید–> اتصال LED به LPC1768

وقتی که می­ خواهیم وضعیت سوئیچ را چک کنیم باید با استفاده از دستورات شرطی بیت متناظر با آن پایه را در رجیستر FIOPIN چک کنیم. همانطور که در مطلب  کار با ورودی خروجی همه منظوره در LPC1768 دیدیم دسترسی بیتی به رجیسترها نداریم اما با استفاده از عملگرهای منطقی می­توان وضعیت بیت خاص را چک کنیم. برای این کار رجیستر مورد نظر را به تعداد مورد نظر شیفت به راست داده و مقدار بدست آمده را با عدد 1، AND بیتی می­کنیم. برای بهتر متوجه شدن این نکته فرض کنید که یک سوئیچ به پایه 8 از پورت 1 وصل شده است و مقاومت بالاگذر داخلی این پایه هم فعال شده است. حال با توجه به شکل زیر مشخص است که نتیجه(  (FIOPIN>>8) & 0x01 ) اگر کلید فشرده شده باشد برابر صفر و اگر کلید رها شده باشد برابر 1 است. با این روش با یک دستور شرطی ساده می­توان بین این دو حالت تمایز ایجاد کرد. مثال(1) می­ تواند کاربرد این روش را بهتر نمایش دهد.

lpc1768-controlling-led-with-switch5

مثال1: برنامه ­ای بنویسید که وضعیت یک سوئیچ متصل به پایه 8 از پورت 1 را به طور مداوم چک نماید و در صورتیکه سوئیچ فشرده شده بود LED متصل به پایه 29 از پورت 1 را روشن و در غیر این صورت آن را خاموش نماید. برای پایه 8  از مقاومت بالا­گذر داخلی استفاده نمایید.

حل:

مثال 2: برنامه مثال قبلی را طوری ویرایش نمایید که با هر بار فشردن سوئیچ وضعیت LED معکوس گردد(اگر خاموش است روشن و اگر روشن است خاموش گردد).

حل: برای حل این مثال از عملگر XOR (^)  در زبان C استفاده می­ کنیم. حتما توجه دارید که هر سطح منطقی بعد از XOR شدن با صفر منطقی بدون تغییر می­ماند و XOR شدن با 1 منطقی سبب معکوس شدن آن سطح منطقی می ­گردد. بنابرین کافیست فقط بیت 29 ام از رجیستر FIOPIN پورت 1 را با یک منطقی و بقیه بیت ها را با صفر XOR نماییم. برنامه مورد نظر به صورت زیر می ­باشد.

برنامه فوق ممکن است بر روی کاغذ درست به نظر آید اما به خاطر  برخی مسائل عملی در عمل ممکن است درست کار نکند. یکی اینکه وقتی CPU میکروکنترلر دستورات ابتدایی را اجرا کرده و به داخل حلقه اصلی برنامه(( while(1) می­رسد تا زمانی که تغذیه میکروکنترلر متصل است دائما در حال چک کردن دستور شرطی(if) می­باشد. بعد از هر بار چک کردن دستور شرطی چون هیچ دستور دیگری وجود ندارد به آخر حلقه اصلی رسیده و مجددا دستور شرطی را چک می­ کند. یعنی CPU در کسری از میکروثانیه(بسته به فرکانس کاری میکرو) دستور شرطی را چک می­کند. حال اگر در یک لحظه خاص کاربر سوئیچ را فشار دهد تا زمان رها کردن آن که قطعا یک زمانی طول می­ کشد(این زمان برای اشخاص مختلف متفاوت است ولی معمولا ممکن است چندصدمیلی ­ثانیه طول بکشد). در این مدت پایه میکروکنترلر در وضعیت صفر منطقی بوده و دستور شرطی درست می­ باشد. بنابراین با یک بار فشردن سوئیچ چندین بار دستورات داخل if اجرا می­ شوند. یعنی وضعیت LED بارها معکوس می­ شود.

مسئله دیگر یک مشکل متداول در هنگام اتصال سوئیچ به میکروکنترلر به نام پرش سوئیچ یا Switch bounce می­ باشد که در ادامه به آن می­ پردازیم.

پرش سوئیچ (Switch Bounce)

در مثال قبل یک سویچ را به میکروکنترلر متصل کردیم و مقاومت بالاگذر داخلی میکروکنترلر را در پایه مورد نظر فعال نمودیم. در این حالت وقتی سوئیچ در حالت رهاشده باشد سطح منطقی پایه در حالت 1 منطقی می­باشد. انتظار داریم با هر بار فشردن سوئیچ سطح منطقی آن از 1 به صفر تغییر کند و شاهد یک لبه پایین­ رونده در پایه P1.8 باشیم. و دوباره با رهاکردن آن یک لبه بالارونده در P1.8 مشاهده نماییم. اما در عمل وقتی سوئیچ را می­ فشاریم دو کنتاکت داخلی سوئیچ که از فلز تشکیل شده ­اند به طور مکانیکی به هم برخورد می­ کنند. این موجب می­شود که در ابعاد میکروسکپی این کنتاکت­ها چندین بار از هم جدا شده و مجددا با هم برخورد نمایند. یعنی در عمل چندین بار وضعیت پایه P1.8 میکروکنترلر بین 1 و صفر منطقی تغییر کند. این وضعیت در هنگام رهاکردن سوئیچ هم مجددا تکرار می­گردد. این مفهوم در شکل زیر نمایش داده شده است.

lpc1768-controlling-led-with-switch6

برای حل این دو مشکل راه ­های مختلفی ممکن است به ذهن برسد. مقالات مختلفی تحت عنوان پرش­گیری سوئیچ (Switch Debouncing) نوشته شده­ اند که روش ­های مختلف سخت­ افزاری و نرم ­افزاری را بررسی کرده­ اند که ما اکنون در پی بحث در مورد آن نیستیم. اما در اینجا به چند روش ساده برای حل این دو مشکل می­ پردازیم.

ساده ­ترین روشی که وجود دارد این است که در داخل دستور شرطی یک تاخیر زمانی ایجاد بکنیم. این تاخیر باید به اندازه ­ای باشد که مطمئن باشیم که دفعه بعدی که دستور شرطی توسط CPU چک می­شود کاربر دست سوئیچ را رها کرده است. یعنی دستور شرطی مثلا به صورت تغییر کند:

اما باز هم مشکلی که وجود دارد این است که عدد 200 میلی ثانیه را به صورت حدودی قرار دادیم. ممکن است کاربری بیشتر از این میزان تاخیر داشته باشد. اگر این عدد را بیش از حد بزرگ انتخاب کنیم باعث می شود تاخیر بیش از اندازه در حلقه اصلی ایجاد شود و کاربری که بخواهد چند بار پشت سر هم سوئیچ را فشار دهد هر بار باید به میزان این تاخیر صبر کند و مجدد سوئیچ را فشار دهد.
روش بهتر این است که میزان تاخیر بسته به کاربر متفاوت باشد. یعنی به میزانی در داخل دستور شرطی تاخیر ایجاد کنیم که کاربر سوئیچ را پایین نگه می دارد. این کار را می توان با استفاده از یک حلقه while تاخیری ایجاد کرد:

توجه داشته باشید که بلافاصله بعد از دستور while سمی­کالن(;) آمده است یعنی این حلقه شرطی هیچ دستوری ندارد و فقط برای ایجاد تاخیر در برنامه است.

اما با این کار مشکل پرش سوئیچ حل نمی ­­شود چرا که این برنامه پرش­ های سوئیچ را که در زمان خیلی کوتاهی اتفاق می ­افتند با فشردن مجدد سوئیچ اشتباه می­ گیرد. برای حل این مشکل می­ توان به دستور شرطی یک تاخیر کوتاه( این بار در حد چند میلی­ ثانیه) اضافه کرد تا از منطقه اولیه پرش سوئیچ عبور کنیم. برنامه کامل به این صورت می ­باشد:

 

۲ دیدگاه

  1. با سلام و عرض ادب
    بسیار روان و خوب توضیح داده بودید. فقط اشکالی در ترجمه مقاومت های pull-up و pull-down دیدم که به اشتباه بالاگذر و پایین گذر ترجمه شده که شبیه بحث فیلترهای فرکانسی هست. ترجمه صحیح مقاومت بالا کش یا پایین کششنده است.

    • با سلام و ادب.
      ممنون. بله من هم ترجمه های مختلفی از این دو اصطلاح دیدم ولی شاید ترجمه ای که شما فرمودید درست تر باشد. ممنون از تذکرتون.

پاسخ دهید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *