GPIO ফান্ডামেন্টাল — ইনপুট, আউটপুট, পুল-আপ, পুল-ডাউন
এই পাঠে যা শিখবেন
- GPIO পিনের INPUT ও OUTPUT মোড ঠিক কী নিয়ন্ত্রণ করে
- ফ্লোটিং ইনপুট পিন কেন অনির্ভরযোগ্য রিডিং দেয় — আসল কারণ
- পুল-আপ ও পুল-ডাউন রেজিস্টার কীভাবে এই সমস্যা সমাধান করে
- একটি সত্যিকারের, চলমান সিমুলেশন — একই সংখ্যক ট্রায়ালে ফ্লোটিং পিন বনাম পুল-আপ পিনের রিডিং আচরণ
১ · GPIO পিন কীভাবে কাজ করে
Computer Architecture কোর্সে সাধারণ মেমরি-ম্যাপড I/O-র ধারণা কভার হয়েছে; এই কোর্সের L06-এ দেখানো হয়েছে কীভাবে একটি পেরিফেরাল রেজিস্টার মেমরি ম্যাপের একটি নির্দিষ্ট ঠিকানায় বসে। একটি GPIO (General-Purpose Input/Output) পিন এই ধারণারই সবচেয়ে মৌলিক প্রয়োগ — প্রতিটি পিনের পেছনে কয়েকটি ছোট রেজিস্টার-বিট থাকে যা নিয়ন্ত্রণ করে:
- মোড বিট — পিনটি OUTPUTOutput modeসফটওয়্যার থেকে পিনের ভোল্টেজ লেভেল (HIGH/LOW) সরাসরি নিয়ন্ত্রণ করা যায়। মোডে (সফটওয়্যার পিনের ভোল্টেজ নিয়ন্ত্রণ করে) নাকি INPUTInput modeবাইরের কোনো সিগন্যাল (সুইচ, সেন্সর) পিনের ভোল্টেজ নির্ধারণ করে; সফটওয়্যার শুধু পড়ে। মোডে (বাইরের সিগন্যাল পিনের ভোল্টেজ নির্ধারণ করে, সফটওয়্যার শুধু পড়ে) থাকবে।
- পুল-কনফিগ বিট — INPUT মোডে থাকলে, পিনের সাথে অভ্যন্তরীণ পুল-আপ, পুল-ডাউন, নাকি কোনো পুল রেজিস্টারই যুক্ত থাকবে না (ফ্লোটিং) তা ঠিক করে।
- আউটপুট ডেটা বিট — OUTPUT মোডে পিন HIGH (সাধারণত ৩.৩V/৫V) নাকি LOW (0V) হবে তা ধরে রাখে।
২ · ফ্লোটিং ইনপুট সমস্যা
যদি একটি INPUT পিন কোথাও নির্দিষ্টভাবে VCC বা GND-এর সাথে সংযুক্ত না থাকে (উদাহরণ — একটি সুইচের একটি প্রান্ত
পিনে যুক্ত, কিন্তু সুইচ খোলা থাকলে পিনের আর কোনো নির্দিষ্ট পথ নেই), তখন পিনটি ফ্লোটিংFloating inputএকটি ইনপুট পিন যার সাথে VCC বা GND-এর কোনো নির্দিষ্ট, কম-রেজিস্ট্যান্স পথ নেই — তাই এর ভোল্টেজ পরিবেশগত ইলেকট্রিক্যাল নয়েজ দ্বারা নির্ধারিত হয়।
থাকে। এই অবস্থায় পিনের ভোল্টেজ আশেপাশের তার, বিদ্যুৎ লাইন, এমনকি হাতের কাছাকাছি থাকার কারণে সৃষ্ট ক্যাপাসিটিভ
কাপলিং-জনিত ইলেকট্রিক্যাল নয়েজ দ্বারা নির্ধারিত হয় — ফলে read() কল করলে প্রতিবার ভিন্ন,
অপ্রত্যাশিত মান (0 অথবা 1) আসতে পারে। এটি কোনো সফটওয়্যার বাগ নয় — এটি একটি বাস্তব ইলেকট্রিক্যাল ঘটনা, এবং
নিচের সিমুলেশন এই আচরণকেই random মডিউল দিয়ে অনুকরণ করছে।
সমাধান হলো একটি পুল-আপ বা পুল-ডাউন রেজিস্টার — একটি উচ্চ-মানের রেজিস্টার (সাধারণত কয়েক kΩ থেকে ~১০০kΩ, ইলাস্ট্রেটিভ রেঞ্জ) যা পিনকে VCC (পুল-আপ) বা GND (পুল-ডাউন)-এর সাথে দুর্বলভাবে যুক্ত রাখে। কোনো বাহ্যিক সিগন্যাল (যেমন একটি চাপা বাটন) সক্রিয় না থাকলে পিন এই ডিফল্ট অবস্থাতেই স্থির থাকে; বাটন চাপলে সেই দুর্বল রেজিস্টারকে "ওভাররাইড" করে পিনকে বিপরীত অবস্থায় টেনে নেয়। রেজিস্ট্যান্স উচ্চ রাখা হয় যাতে বাটন চাপলে খুব বেশি কারেন্ট না প্রবাহিত হয়, কিন্তু যথেষ্ট কম রাখা হয় যাতে একটি স্পষ্ট, নির্ভরযোগ্য লজিক লেভেল তৈরি হয়।
import random
class GpioPin:
# একটি GPIO পিনকে মোড, পুল-কনফিগ ও রেজিস্টার-স্টাইল স্টেট দিয়ে মডেল করা হচ্ছে
def __init__(self, name):
self.name = name
self.mode = "INPUT" # "INPUT" অথবা "OUTPUT"
self.pull = "NONE" # "NONE", "PULL_UP", "PULL_DOWN"
self.output_level = 0
self._rng = random.Random(42) # ফিক্সড সিড -- রিপ্রোডিউসিবল "নয়েজ"
def set_mode(self, mode, pull="NONE"):
self.mode = mode
self.pull = pull
def write(self, level):
if self.mode != "OUTPUT":
raise RuntimeError(f"{self.name} OUTPUT মোডে নেই, write() করা যাবে না")
self.output_level = 1 if level else 0
def read(self):
if self.mode == "OUTPUT":
return self.output_level
# INPUT মোড -- বাস্তব হার্ডওয়্যারের আচরণ সিমুলেট করা হচ্ছে
if self.pull == "PULL_UP":
return 1
if self.pull == "PULL_DOWN":
return 0
# কোনো পুল নেই -> ফ্লোটিং পিন -> ইলেকট্রিক্যাল নয়েজ র্যান্ডম রিডিং দেয়
return self._rng.randint(0, 1)
TRIALS = 10
floating_pin = GpioPin("PA0")
floating_pin.set_mode("INPUT", pull="NONE")
floating_readings = [floating_pin.read() for _ in range(TRIALS)]
pullup_pin = GpioPin("PA1")
pullup_pin.set_mode("INPUT", pull="PULL_UP")
pullup_readings = [pullup_pin.read() for _ in range(TRIALS)]
print(f"ফ্লোটিং ইনপুট পিনের {TRIALS}টি রিডিং: {floating_readings}")
print(f" -> আলাদা মানের সংখ্যা: {len(set(floating_readings))}")
print(f"পুল-আপ ইনপুট পিনের {TRIALS}টি রিডিং: {pullup_readings}")
print(f" -> আলাদা মানের সংখ্যা: {len(set(pullup_readings))}")
out_pin = GpioPin("PA2")
out_pin.set_mode("OUTPUT")
out_pin.write(1)
print(f"\nআউটপুট পিন write(1) -> read() ফেরত দিলো: {out_pin.read()}")
out_pin.write(0)
print(f"আউটপুট পিন write(0) -> read() ফেরত দিলো: {out_pin.read()}")
floating_pin-এর ১০টি রিডিং-এ "আলাদা মানের
সংখ্যা" ১-এর বেশি (অর্থাৎ 0 ও 1 দুটোই এসেছে) — একটি সত্যিকারের ফ্লোটিং পিনের অস্থির আচরণ। অন্যদিকে
pullup_pin-এর প্রতিটি রিডিং সবসময় 1 — "আলাদা মানের সংখ্যা" সবসময় ঠিক ১, প্রতিবার। এটাই পুল-আপ
রেজিস্টারের কাজ — একটি নিশ্চিত, পূর্বানুমানযোগ্য ডিফল্ট অবস্থা।
GPIO পিনের মোড ঠিক করে সফটওয়্যার পিন ড্রাইভ করবে (OUTPUT) নাকি পড়বে (INPUT)। INPUT মোডে সংযোগহীন (ফ্লোটিং) পিন অনির্ভরযোগ্য, অপ্রত্যাশিত রিডিং দেয় — বাস্তব ইলেকট্রিক্যাল নয়েজের কারণে, বাগ নয়। পুল-আপ/ পুল-ডাউন রেজিস্টার এই সমস্যা সমাধান করে পিনকে একটি নির্দিষ্ট ডিফল্ট অবস্থায় বেঁধে রাখার মাধ্যমে।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।
প্র ০১ একটি বাটন সুইচ যদি "চাপলে GND-এর সাথে যুক্ত হয়" এভাবে ওয়্যার করা থাকে, তাহলে পিনে পুল-আপ নাকি পুল-ডাউন ব্যবহার করা উচিত, এবং কেন?
পুল-আপ। বাটন না চাপা অবস্থায় পিনকে একটি নির্দিষ্ট ডিফল্ট (HIGH) অবস্থায় রাখতে হবে, আর বাটন চাপলে সেটি GND-এর সাথে যুক্ত হয়ে পিনকে LOW-এ টেনে নেবে — এই "না-চাপা = HIGH, চাপা = LOW" প্যাটার্নটাই সবচেয়ে সাধারণ বাটন-ওয়্যারিং কনভেনশন, এবং এর জন্য পুল-আপ দরকার। উল্টো ওয়্যারিং (চাপলে VCC-এর সাথে যুক্ত) হলে পুল-ডাউন দরকার হতো।
প্র ০২
উপরের কোড সেলে GpioPin.write() মেথডে if self.mode != "OUTPUT": raise
RuntimeError(...) চেকটি কেন রাখা হয়েছে?
কারণ বাস্তব হার্ডওয়্যারেও একটি পিন INPUT মোডে থাকলে সেটিতে সফটওয়্যার থেকে ভোল্টেজ ড্রাইভ করার চেষ্টা করা অর্থহীন (এবং কিছু চিপে বিপজ্জনকও হতে পারে, যদি বাইরের কোনো সিগন্যাল একই সময়ে পিনটি ড্রাইভ করার চেষ্টা করে — একটি "বাস কনটেনশন")। এই চেকটি সেই ভুল ব্যবহারকে দ্রুত ধরে ফেলে, বাস্তব ফার্মওয়্যারে যেমন একটি ভুল মোড কনফিগারেশন প্রায়ই নীরবে ভুল আচরণ তৈরি করে তার চেয়ে ভালো।
প্র ০৩ পুল-আপ/পুল-ডাউন রেজিস্টারের মান অনেক বেশি (যেমন ১০০kΩ) না রেখে অনেক কম (যেমন ১০০Ω) রাখলে কী সমস্যা হতে পারে?
রেজিস্ট্যান্স খুব কম হলে, বাটন চাপার সময় VCC থেকে GND (বা উল্টো) পর্যন্ত সেই রেজিস্টারের মধ্য দিয়ে অনেক বেশি কারেন্ট প্রবাহিত হবে — অপ্রয়োজনীয় পাওয়ার অপচয় এবং সম্ভাব্য অতিরিক্ত গরম হওয়া। তাই পুল-আপ/ পুল-ডাউন রেজিস্টার ইচ্ছাকৃতভাবে উচ্চ-মানের রাখা হয় — যথেষ্ট কারেন্ট প্রবাহিত করে একটি স্পষ্ট লজিক লেভেল তৈরি করার জন্য, কিন্তু পাওয়ার অপচয় ন্যূনতম রাখার জন্য।
অনুশীলন
-
চিন্তা করুন: উপরের কোড সেলে যদি
pullup_pin.set_mode("INPUT", pull="PULL_DOWN")করেread()কল করা হতো, প্রতিটি রিডিং কী হতো?প্রতিটি রিডিং সবসময়
0হতো —read()-এর লজিক অনুযায়ীpull == "PULL_DOWN"হলে এটি বিনাশর্তে0ফেরত দেয়, ঠিক যেমন"PULL_UP"বিনাশর্তে1ফেরত দেয়। -
পরীক্ষা করুন: উপরের কোড সেলে
TRIALS-এর মান ৫০ করে Run চাপুন এবং লক্ষ্য করুনfloating_readings-এর "আলাদা মানের সংখ্যা" এখনও ১ বা ২ থাকে কিনা, আরpullup_readings-এর "আলাদা মানের সংখ্যা"-তে কোনো পরিবর্তন হয় কিনা।floating_readings-এর "আলাদা মানের সংখ্যা" ট্রায়াল সংখ্যা বাড়ালেও সর্বোচ্চ ২-ই থাকবে (যেহেতু সম্ভাব্য মান শুধু 0 আর 1), তবে অনেক বেশি ট্রায়ালে উভয় মান আসার সম্ভাবনা আরও বাড়ে।pullup_readings-এর "আলাদা মানের সংখ্যা" TRIALS যাই হোক না কেন সবসময় ঠিক ১-ই থাকবে, কারণ পুল-আপ পিনেরread()কখনও র্যান্ডম নয় — এটি নির্ধারক (deterministic)।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৭টি পাঠ মাইক্রোপ্রসেসর আর্কিটেকচার, এমবেডেড C, GPIO, টাইমার/PWM/ADC, সিরিয়াল প্রোটোকল, RTOS, সেন্সর/অ্যাকচুয়েটর, IoT আর্কিটেকচার, ওয়্যারলেস প্রোটোকল, MQTT/CoAP ও IoT সিকিউরিটি — বাকি পাঠগুলো শীঘ্রই যুক্ত হবে।
- Computer Architecture & Digital Logic কোর্স সহোদর কোর্স মেমরি-ম্যাপড I/O-র সাধারণ ভিত্তি সেই কোর্সে কভার হয়েছে — এই পাঠ তার মাইক্রোকন্ট্রোলার-স্পেসিফিক প্রয়োগ দেখায়।
- সব Courses দেখুন ABCL TECH C, C++, Python, Java, JavaScript, DSA, DBMS, Discrete Mathematics, System Design, Cybersecurity, Cloud Computing & DevOps, Computer Networks, Operating Systems, Computer Architecture, Design and Analysis of Algorithms ও আরও অনেক কোর্স — সব এক জায়গায়।