3.12. قراءة الإشارة التماثلية باستخدام ADC¶
حتى الآن كانت الكاميرا تقرأ إشارات رقمية -- فالدبوس إما 0 أو 1، والمفتاح إما مفتوح أو مغلق. لكن معظم الإشارات الصادرة عن المستشعرات الواقعية تكون تماثلية: جهد مستمر يتغير بسلاسة ضمن نطاق معين. فالمقاومة الضوئية تمر عبر كل قيمة جهد بين القطبين مع تغير سطوع المحيط. وخرج مستشعر درجة الحرارة ينزاح بضعة ميلي فولت مع ارتفاع حرارة الغرفة. وخرج الميكروفون يرتفع وينخفض مع الصوت المحيط به.
المحول التماثلي إلى الرقمي (ADC) هو الجسر الواصل. فهو يأخذ عينة من الجهد على دبوس ويعيد عددًا صحيحًا يمكن لـ Python قراءته مثل أي قيمة أخرى.
3.12.1. التكميم¶
لا يمكن لقيمة رقمية أن تمثل جهدًا مستمرًا تمثيلاً دقيقًا. ومهمة ADC هي التكميم -- أي ضبط كل عينة على أقرب مستوى من مجموعة ثابتة من المستويات. فالمحول ذو N بت يملك 2^N مستوى؛ والمحول ذو 12 بت يملك 4096 مستوى موزعة على نطاق دخله.
التكميم: كل عينة من الإشارة التماثلية (الخط المتصل) تُقرّب إلى أحد عدد محدود من المستويات الرقمية (الخط المتقطع المتدرج).¶
الجهد بين مستويين متجاورين هو حجم الخطوة للـ ADC؛ وأي شيء أصغر من ذلك يتلاشى في التقريب. فالمحول ذو 12 بت على نطاق 3.3 فولت يكون حجم خطوته نحو 3.3 / 4096 ≈ 0.8 mV -- وهذا دقيق بما يكفي لجعل معظم الإشارات تبدو مستمرة فعليًا في البرمجيات.
3.12.2. الصنف machine.ADC¶
يغلّف machine.ADC قناة دخل تماثلي واحدة. أنشئه بالدبوس الذي تريد قراءته، ثم استدعِ read_u16():
from machine import ADC
adc = ADC("P6")
value = adc.read_u16()
print(value)
يعيد read_u16() دائمًا عددًا صحيحًا بلا إشارة بعرض 16 بت بين 0 و 65535. وتختلف دقة ADC الأصلية حسب اللوحة (12 بت على STM32، وتعتمد على المنفذ في غير ذلك)؛ وتُحاذى النتيجة إلى اليسار ضمن 16 بت بحيث لا تتسرب تفاصيل العتاد إلى Python -- فالقيمة 65535 تمثل المدى الكامل بغض النظر عن الشريحة.
جهد المرجع -- وهو الدخل المقابل للمدى الكامل -- يعتمد على اللوحة. راجع لوحات OpenMV لمعرفة القيمة الخاصة بكاميرتك. وأي شيء يتجاوز المرجع يُقرأ على أنه المدى الكامل (وقد يتلف الدبوس إذا تجاوز جهد الدخل الأقصى المطلق).
3.12.2.1. تحويل العدّات إلى جهد¶
العلاقة بين العدّات والجهد خطية، حيث تتطابق عدّات المدى الكامل تمامًا مع Vref:
voltage = counts × Vref / 65535
في الكود:
VREF = 3.3 # cam-dependent; see the quickref
counts = adc.read_u16()
voltage = counts * VREF / 65535
print(voltage, "V")
3.12.3. مقسمات الجهد¶
مقاومتان على التوالي بين قضيب جهد والأرضي تشكلان مقسم جهد. والعقدة بينهما تستقر عند جهد تحدده نسبة المقاومتين:
مقسم جهد: R1 و R2 على التوالي يخفضان Vin إلى V_out.¶
V_out = Vin × R2 / (R1 + R2)
المقاومتان المتساويتان تعطيان نصف جهد القضيب؛ و R2 الأصغر بكثير من R1 يجعل نقطة الأخذ قريبة من الأرضي؛ و R2 الأكبر بكثير يجعلها قريبة من القضيب.
تفترض الصيغة أنه لا شيء آخر يسحب تيارًا ملموسًا من V_out. ودبوس ADC عالي الممانعة (ميغا أوم، نانو أمبير) ويحقق هذا الشرط بسهولة، لذا فإن مقسمًا يغذي ADC يتصرف كما تتنبأ الصيغة.
3.12.4. المقاومات المتغيرة¶
المقاومة المتغيرة هي مكوّن مادي واحد يمثل بالضبط مقسم جهد، مع ماسح منزلق يحرك نقطة الأخذ بين الطرفين. وإدارة المقبض تغير R1 و R2 معًا مع إبقاء مجموعهما (المقاومة الكلية للمقاومة المتغيرة) ثابتًا.
مقاومة متغيرة موصولة كمصدر جهد يدوي للـ ADC: 3.3 فولت على أحد الطرفين، والأرضي على الطرف الآخر، والماسح إلى الدبوس.¶
المقاومة المتغيرة هي جهاز الدخل النموذجي لتجربة ADC. صِل أحد الطرفين بـ 3.3 V، والآخر بالأرضي، والماسح بدبوس يدعم ADC؛ وإدارة المقبض تجعل الماسح يمر عبر كل جهد بين القطبين.
import time
from machine import ADC
pot = ADC("P6")
VREF = 3.3
while True:
counts = pot.read_u16()
voltage = counts * VREF / 65535
print(voltage, "V")
time.sleep_ms(100)
3.12.5. قراءة جهود أعلى باستخدام مقسم¶
أي جهد أعلى من Vref سيثبّت ADC عند المدى الكامل وقد يتلف الدخل إذا تجاوز التصنيف الأقصى المطلق. ولقراءة مصدر أعلى -- بطارية، أو خرج مستشعر يتجاوز Vref -- اخفضه بمقسم جهد ثابت قبل وصوله إلى الدبوس:
تخفيض مصدر عالي الجهد ليناسب ADC: R1 و R2 يشكلان مقسم جهد ثابتًا تغذي نقطة أخذه دبوس ADC.¶
اختر R1 و R2 بحيث يبقى الجهد المقسوم داخل نطاق ADC عند أعلى جهد دخل تتوقعه:
V_adc = V_in × R2 / (R1 + R2)
بالنسبة إلى V_in = 12 V كحد أقصى ومرجع 3.3 فولت، يجب ألا تتجاوز النسبة R2 / (R1 + R2) القيمة 3.3 / 12 ≈ 0.275. واختيار شائع مع هامش بسيط هو R1 = 33 kΩ، R2 = 10 kΩ. والنسبة هي 10 / 43 ≈ 0.233، لذا يبلغ V_adc حده الأقصى عند نحو 12 × 0.233 ≈ 2.79 V -- أدنى بأمان من Vref.
لاستعادة قيمة V_in الأصلية من قراءة ADC، اعكس صيغة المقسم:
V_in = V_adc × (R1 + R2) / R2
في الكود:
from machine import ADC
R1 = 33_000
R2 = 10_000
VREF = 3.3
adc = ADC("P6")
counts = adc.read_u16()
v_adc = counts * VREF / 65535
v_in = v_adc * (R1 + R2) / R2
print(v_in, "V")
بضع ملاحظات عملية:
يسحب المقسم
V_in / (R1 + R2)باستمرار. فمعR1 + R2 = 43 kΩوV_in = 12 V، يكون ذلك نحو 280 ميكرو أمبير -- وهو عادةً ضئيل جدًا، لكن إذا كان المصدر يعمل بالبطارية ففكر في مقاومات أكبر (100 kΩ إلى 1 MΩ) لتقليل الاستنزاف في وضع الخمول.تنعكس سماحية المقاومة (نموذجيًا ±1 % أو ±5 %) مباشرةً على دقة القياس. فمقاومتان بسماحية ±5 % يمكن أن تعطيا قيمة
V_inالمستعادة خطأً يبلغ في أسوأ الحالات نحو ±10 %.تتحد ممانعة مصدر المقسم مع أي سعة طفيلية لترشيح الدخل ترشيحًا منخفض التمرير. وهذا يهم بالنسبة للإشارات سريعة التغير؛ أما لفحص جهد بطارية فلا يهم.