در دنیای سیستمهای نهفته (Embedded Systems)، خواندن وضعیت یک کلید فشاری یکی از اولین و پایهایترین کارهایی است که یاد میگیریم. اما چالشی به نام "Bouncing" یا اثر لرزش کلید وجود دارد که اگر به درستی مدیریت نشود، میتواند عملکرد کل برنامه ما را مختل کند. در این مقاله، یک کتابخانه بهینه و بسیار کارآمد برای نویزگیری (Debounce) کلیدها در میکروکنترلرهای STM32 را معرفی میکنیم که نه تنها این مشکل را حل میکند، بلکه قابلیت تشخیص فشردن های کوتاه و طولانی را نیز به سادگی فراهم میکند.
پدیده Bouncing چیست و چرا باید آن را جدی بگیریم؟
کلیدهای فشاری قطعات مکانیکی هستند. وقتی شما یک کلید را فشار میدهید یا رها میکنید، تیغههای فلزی داخل آن برای چند میلیثانیه میلرزند و چندین بار به هم برخورد کرده و جدا میشوند. از دید میکروکنترلر که با سرعت بسیار بالایی پین ورودی را میخواند، این لرزشها به صورت دهها یا صدها بار فشردن و رها شدن کلید تفسیر میشود.
این موضوع باعث میشود که با یک بار فشردن دادن کلید، کدی که نوشتید دهها بار اجرا شود. برای مثال، اگر با هر بار فشردن کلید یک شمارنده را افزایش دهید، با یک بار فشردن ممکن است عدد شمارنده به جای ۱، به ۲۰ یا ۳۰ تغییر کند! اینجاست که Debouncing یا نویزگیری اهمیت پیدا میکند.
معرفی یک کتابخانه بهینه: خداحافظی با روشهای ناکارآمد
روشهای مختلفی برای نویزگیری وجود دارد. یکی از روشهای متداول، استفاده از یک آرایه برای ذخیره نمونههای متوالی از وضعیت کلید و بررسی یکسان بودن تمام آنهاست. این روش کار میکند، اما یک مشکل بزرگ دارد: با هر بار فراخوانی تابع، باید یک حلقه (loop) روی تمام اعضای آرایه اجرا شود. اگر پنجره زمانی نویزگیری شما بزرگ باشد (مثلاً ۱۰۰ میلیثانیه)، این کار بار پردازشی غیرضروری به CPU تحمیل میکند.
کتابخانهای که در اینجا معرفی میکنیم، از یک روش بسیار هوشمندانه و بهینه استفاده میکند.
ویژگی کلیدی این کتابخانه: استفاده از شمارنده (Integrator/Counter)
به جای ذخیره دهها نمونه در یک آرایه، ما فقط از یک شمارنده استفاده میکنیم. منطق کار به این صورت است:
اگر کلید فشرده تشخیص داده شود: شمارنده را یک واحد افزایش میدهیم (تا یک حد ماکسیمم مشخص).
اگر کلید رها تشخیص داده شود: شمارنده را یک واحد کاهش میدهیم (تا به صفر برسد).
یک کلید تنها زمانی "فشرده پایدار" در نظر گرفته میشود که شمارنده به حد ماکسیمم خود (DEBOUNCE_TICKS
) برسد و تنها زمانی "رها شده پایدار" است که شمارنده به صفر برسد. این روش نیازی به هیچ حلقهای ندارد و در هر فراخوانی، تنها یک مقایسه ساده انجام میدهد که فوقالعاده سریع و بهینه است.
ویژگیهای اصلی کتابخانه
۱. بهینگی و کارایی فوقالعاده (Efficiency)
همانطور که گفته شد، در این کتابخانه زمان مورد نیاز برای پردازش وضعیت کلید همیشه ثابت است و به اندازه پنجره زمانی نویزگیری شما بستگی ندارد. این ویژگی باعث میشود که کتابخانه حتی روی میکروکنترلرهای ضعیفتر یا در پروژههایی که به زمانبندی دقیق نیاز دارند، عملکردی عالی داشته باشد. علاوه بر این، مصرف حافظه آن نیز بسیار پایین است (فقط چند متغیر برای هر کلید).
۲. ساختار ماژولار با استفاده از Callback
این کتابخانه به صورت ماژولار طراحی شده است. تمام وضعیت یک کلید در یک ساختار (struct
) به نام Key_Handle_t
ذخیره میشود. این به شما اجازه میدهد به راحتی چندین کلید را به صورت مستقل مدیریت کنید.
مهمتر از آن، استفاده از توابع Callback است. شما دیگر نیازی ندارید که منطق برنامه خود را درون کتابخانه بنویسید. کافیست توابعی را تعریف کنید که در زمان وقوع رویداد (فشردن کوتاه یا فشردن طولانی) باید اجرا شوند و آدرس آنها را به تابع اصلی کتابخانه بدهید. این کار باعث جداسازی کامل منطق سطح پایین سختافزار از منطق سطح بالای برنامه میشود و کد شما را بسیار تمیزتر و قابل توسعهتر میکند.
۳. تشخیص فشارهای کوتاه و طولانی (Short & Long Press)
این کتابخانه به طور داخلی یک ماشین حالت (State Machine) دارد که به راحتی میتواند بین حالتهای "رها شده"، "فشرده شده" و "فشرده شده طولانی" جابجا شود. با استفاده از تایمر داخلی HAL_GetTick
، مدت زمان فشرده بودن کلید را اندازهگیری کرده و بر اساس زمان هایی که شما تعریف میکنید (SHORT_PRESS_THRESHOLD_MS
و LONG_PRESS_THRESHOLD_MS
)، رویداد مناسب را تشخیص میدهد.
چگونه از این کتابخانه استفاده کنیم؟
استفاده از این کتابخانه بسیار ساده است:
فایلهای
debounce_btn.h
وdebounce_btn.c
را به پروژه خود در STM32CubeIDE یا هر محیط توسعه دیگری اضافه کنید.در فایل
main.c
، هدر کتابخانه را اضافه کنید.یک متغیر از نوع
Key_Handle_t
برای کلید خود تعریف کنید.توابع Callback خود را برای فشردن کوتاه و طولانی بنویسید.
در بخش (Initialization)، تابع
Key_Init
را برای معرفی پین کلید فراخوانی کنید.در حلقه اصلی برنامه (
while(1)
) یا ترجیحاً در یک وقفه تایمر (مانند SysTick) که هر ۵ یا ۱۰ میلیثانیه اجرا میشود، تابعKey_Process
را فراخوانی کنید.
دانلود کتابخانه به همراه فایل آموزش استفاده از آن
امیدواریم از این آموزش استفاده برده باشید!
با سایر آموزش های اصفهان درایو همراه باشید!