পাঠ ১৫ · ৫৭-এর মধ্যে · মডিউল ৪
Home / Courses / Microprocessors, Embedded Systems & IoT / ডিবাউন্সিং

ডিজিটাল ইনপুট ডিবাউন্সিং

Digital input debouncing
৮ মিনিট পড়া মধ্যম · Intermediate Python সিমুলেশনসহ সম্পূর্ণ বাংলায়

এই পাঠে যা শিখবেন

  • মেকানিক্যাল সুইচ বাউন্স কেন ঘটে, এবং এটি সফটওয়্যারে কী সমস্যা তৈরি করে
  • কাউন্ট-বেসড ডিবাউন্স অ্যালগরিদম কীভাবে কাজ করে
  • একটি সত্যিকারের সিমুলেশন — একটি নির্মিত বাউন্সি সিগন্যালে raw ট্রানজিশন গণনা বনাম ডিবাউন্স করার পরের ট্রানজিশন গণনা
  • সফটওয়্যার ডিবাউন্সিং বনাম হার্ডওয়্যার (RC ফিল্টার) ডিবাউন্সিং-এর মধ্যে সংক্ষিপ্ত পার্থক্য

১ · সুইচ বাউন্স সমস্যা

L14-এ দেখানো হয়েছে কীভাবে একটি বাটন GPIO পিনকে পুল-আপ ডিফল্ট থেকে বিপরীত অবস্থায় টেনে নেয়। কিন্তু বাস্তব জগতে একটি মেকানিক্যাল বাটনের ভেতরের দুটি ধাতব কন্টাক্ট একে অপরকে স্পর্শ করার সময় নিখুঁতভাবে, তাৎক্ষণিকভাবে "ছুঁয়ে" যায় না — সূক্ষ্ম যান্ত্রিক স্প্রিং-ব্যাক ও কম্পনের কারণে কন্টাক্টগুলো কয়েক মিলিসেকেন্ড ধরে বারবার সংযুক্ত-বিচ্ছিন্ন হতে থাকে, তারপর স্থির হয়। একটি মাইক্রোকন্ট্রোলার এত দ্রুত স্যাম্পল নিতে পারে (মাইক্রোসেকেন্ড রেজোলিউশনে) যে এই পুরো "কাঁপুনি" — যাকে বাউন্সContact bounceএকটি মেকানিক্যাল সুইচের ধাতব কন্টাক্ট বন্ধ/খোলার সময় কয়েক মিলিসেকেন্ড ধরে বারবার সংযুক্ত-বিচ্ছিন্ন হওয়ার যান্ত্রিক ঘটনা। বলা হয় — একাধিক পৃথক HIGH/LOW ট্রানজিশন হিসেবে দেখতে পায়, যদিও ব্যবহারকারী বাস্তবে মাত্র একবারই বাটন চেপেছেন।

কোনো ফিল্টার ছাড়া সরাসরি ইন্টারাপ্ট বা পোলিং-বেসড কোড লিখলে — "প্রতিটি ট্রানজিশনে একটি কাউন্টার বাড়াও" — একটি একক বাস্তব বাটন প্রেস ভুলবশত ৫-১৫টি (বা তারও বেশি) প্রেস হিসেবে গণনা হতে পারে। এটি একটি সুপরিচিত, বাস্তব এমবেডেড বাগ ক্লাস।

মেকানিক্যাল বাটন চাপা হলো (১ বার) কন্টাক্ট বাউন্স একাধিক raw ট্রানজিশন ডিবাউন্স ফিল্টার N-বার একই রিডিং লাগবে একটি পরিষ্কার ট্রানজিশন
ডিবাউন্স ফিল্টার একটি বাটন প্রেসের বাউন্সি raw সিগন্যালকে একটি একক, নির্ভরযোগ্য ট্রানজিশনে রূপান্তর করে।

২ · কাউন্ট-বেসড ডিবাউন্স অ্যালগরিদম

সবচেয়ে সহজ ও সাধারণ সফটওয়্যার ডিবাউন্স কৌশল হলো — একটি নতুন রিডিং তখনই "স্থিতিশীল" (accepted) হিসেবে মেনে নেওয়া হবে যখন সেই একই রিডিং পরপর অন্তত N বার (উদাহরণ — ৪ বার) এসেছে। যদি মাঝপথে রিডিং আবার বদলে যায়, তাহলে গণনা নতুন করে শুরু হয়। এভাবে দ্রুত এলোমেলো বাউন্স (যা কখনোই পরপর N বার একই মান দেয় না) ফিল্টার হয়ে বাদ পড়ে যায়, কিন্তু বাস্তব স্থায়ী পরিবর্তন (যা বাউন্স স্থির হওয়ার পর দীর্ঘক্ষণ একই মান দিতে থাকে) ধরা পড়ে।

Python
# একটি বাস্তব বাটন-প্রেস-তারপর-রিলিজের বাউন্সি raw স্যাম্পল সিকোয়েন্স -- হাতে তৈরি,
# যেন প্রতিটি এন্ট্রি একটি দ্রুত টাইম-স্যাম্পলে পিনের অবস্থা বোঝায়
raw_signal = [
    0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,   # প্রেস: বাউন্স করে শেষে HIGH-এ স্থির
    1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0,   # রিলিজ: বাউন্স করে শেষে LOW-এ স্থির
]

def count_raw_transitions(signal):
    return sum(1 for i in range(1, len(signal)) if signal[i] != signal[i - 1])

def debounce(signal, n_required=4):
    # পরপর n_required বার একই মান না আসা পর্যন্ত স্টেট বদলাবে না
    stable_state = signal[0]
    candidate = signal[0]
    run_length = 0
    output = []
    debounced_transitions = 0
    for sample in signal:
        if sample == candidate:
            run_length += 1
        else:
            candidate = sample
            run_length = 1
        if run_length >= n_required and candidate != stable_state:
            stable_state = candidate
            debounced_transitions += 1
        output.append(stable_state)
    return output, debounced_transitions


raw_transitions = count_raw_transitions(raw_signal)
debounced_output, debounced_transitions = debounce(raw_signal, n_required=4)

print(f"Raw সিগন্যাল ({len(raw_signal)} স্যাম্পল): {raw_signal}")
print(f"Raw ট্রানজিশন সংখ্যা: {raw_transitions}")
print()
print(f"ডিবাউন্স করা আউটপুট: {debounced_output}")
print(f"ডিবাউন্স করা ট্রানজিশন সংখ্যা: {debounced_transitions}")

    
raw সিগন্যালে মোট ১৪টি ট্রানজিশন আছে (বাউন্সের কারণে), কিন্তু ডিবাউন্স করার পর মাত্র ২টি ট্রানজিশন থেকে যায় — একটি প্রেসের জন্য (LOW→HIGH), একটি রিলিজের জন্য (HIGH→LOW)। এটাই বাস্তবে যা ঘটেছিল তার সঠিক প্রতিনিধিত্ব — ব্যবহারকারী একবার বাটন চেপে ছেড়ে দিয়েছেন, আর ডিবাউন্স অ্যালগরিদম ঠিক সেই দুটি প্রকৃত ঘটনাই শনাক্ত করেছে, মাঝের বাউন্স-জনিত ভুয়া ট্রানজিশনগুলো বাদ দিয়ে।

সফটওয়্যার ডিবাউন্সিং (উপরের মতো, কোনো অতিরিক্ত হার্ডওয়্যার লাগে না, শুধু কোড) ছাড়াও একটি হার্ডওয়্যার RC ফিল্টার (একটি ছোট রেজিস্টর-ক্যাপাসিটর নেটওয়ার্ক বাটনের সাথে যুক্ত করে সিগন্যালটাকে বৈদ্যুতিকভাবেই "স্মুথ" করে দেওয়া) ব্যবহার করেও ডিবাউন্স করা যায় — এতে সফটওয়্যারে কিছু করতে হয় না, কিন্তু অতিরিক্ত ফিজিক্যাল কম্পোনেন্ট লাগে। বেশিরভাগ আধুনিক এমবেডেড ডিজাইনে খরচ বাঁচাতে সফটওয়্যার ডিবাউন্সিংই বেশি ব্যবহৃত হয়।

মূল কথা · Key takeaway

মেকানিক্যাল সুইচ বাউন্স একটি বাস্তব ফিজিক্যাল ঘটনা যা একটি একক বাটন প্রেসকে একাধিক ভুয়া ট্রানজিশন হিসেবে দেখায়। একটি কাউন্ট-বেসড ডিবাউন্স ফিল্টার (পরপর N-বার একই রিডিং নিশ্চিত হওয়া পর্যন্ত স্টেট বদলাবে না) এই ভুয়া ট্রানজিশনগুলো বাদ দিয়ে শুধু প্রকৃত স্টেট-পরিবর্তনগুলো ধরে রাখে — এটি প্রায় প্রতিটি বাস্তব এমবেডেড প্রজেক্টে বাটন/সুইচ ইনপুট হ্যান্ডল করার একটি অপরিহার্য অংশ।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।

প্র ০১ উপরের কোড সেলে n_required-এর মান ১ করে দিলে debounce() ফাংশনটি কার্যকরভাবে কী করবে?

n_required=1 মানে প্রতিটি নতুন মান-ই "পরপর ১ বার" শর্ত সাথে সাথেই পূরণ করে ফেলবে — অর্থাৎ ফিল্টারিং কার্যত বন্ধ হয়ে যাবে এবং প্রতিটি raw ট্রানজিশনই সরাসরি গ্রহণ হয়ে যাবে। এই ক্ষেত্রে debounced_transitions ঠিক raw_transitions-এর সমান (১৪) হয়ে যাবে — অর্থাৎ কোনো বাউন্স ফিল্টার হবে না।

প্র ০২ n_required-এর মান অনেক বড় (যেমন ৫০) করে দিলে কী সমস্যা হতে পারে, বিশেষ করে দ্রুত পরপর দুটি বাটন প্রেস করলে?

n_required খুব বড় হলে ডিবাউন্স ফিল্টার একটি প্রকৃত, দ্রুত স্টেট-পরিবর্তনকেও "যথেষ্ট স্থিতিশীল নয়" ধরে বাতিল করে দিতে পারে — অর্থাৎ একটি বৈধ, দ্রুত ডাবল-ক্লিক বা দ্রুত বাটন প্রেস মিস হয়ে যেতে পারে। তাই n_required-কে যথেষ্ট বড় রাখতে হয় (বাউন্স ফিল্টার করার জন্য) কিন্তু যথেষ্ট ছোটও রাখতে হয় (বৈধ দ্রুত ইনপুট মিস না করার জন্য) — এটি একটি বাস্তব ইঞ্জিনিয়ারিং ট্রেড-অফ।

প্র ০৩ ডিবাউন্সিং কি শুধু বাটনের জন্যই দরকার, নাকি অন্য কোনো ধরনের ডিজিটাল ইনপুটেও দরকার হতে পারে?

যেকোনো মেকানিক্যাল কন্টাক্ট-ভিত্তিক সেন্সরে (রিলে, টগল সুইচ, মেকানিক্যাল লিমিট সুইচ, রোটারি এনকোডারের কিছু ধরন) একই বাউন্স সমস্যা হতে পারে — কারণ মূল কারণটা যান্ত্রিক (ধাতব কন্টাক্টের কম্পন), বাটন-নির্দিষ্ট নয়। তবে সম্পূর্ণ ইলেকট্রনিক সেন্সর (যেমন একটি অপটিক্যাল বা ক্যাপাসিটিভ টাচ সেন্সর) সাধারণত মেকানিক্যাল বাউন্স করে না, যদিও তাদের নিজস্ব ইলেকট্রিক্যাল নয়েজ ফিল্টারিং লাগতে পারে।

অনুশীলন

  1. চিন্তা করুন: উপরের কোড সেলে raw_signal-এর প্রথম উপাদানটি যদি 1 (0 এর বদলে) হতো, debounce()-এর stable_state এর প্রাথমিক মান কী হতো?

    stable_state = signal[0] লাইন অনুযায়ী প্রাথমিক stable_state সবসময় সিগন্যালের প্রথম উপাদানের সমান হয় — তাই সেক্ষেত্রে এটি 1 হতো, 0 নয়।

  2. পরীক্ষা করুন: উপরের কোড সেলে debounce(raw_signal, n_required=8) কল করে Run চাপুন এবং debounced_transitions-এর নতুন মান পর্যবেক্ষণ করুন — এটি কি এখনও ২, নাকি কমে যায়?

    debounced_transitions কমে ১-এ নেমে আসবে। কারণ রিলিজের পরের শেষ LOW রানটি raw_signal-এ মাত্র ৬টি স্যাম্পল লম্বা — n_required=8 সেই রানের চেয়ে বড়, তাই ফিল্টার কখনোই "৮ বার পরপর একই মান" শর্ত পূরণ হতে দেখে না এবং রিলিজ ইভেন্টটাই ধরতে পারে না (পিন চিরকালের জন্য HIGH-এ আটকে থেকে যায় আউটপুটে)। এটাই দেখায় কেন n_required খুব বড় রাখলে বৈধ ট্রানজিশনও মিস হয়ে যেতে পারে — ঠিক যেমনটা প্র ০২-এ আলোচনা হয়েছে।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

আগের পাঠ
GPIO ফান্ডামেন্টাল — ইনপুট, আউটপুট, পুল-আপ, পুল-ডাউন