3.12. การอ่านค่าแอนะล็อกด้วย ADC¶
จนถึงตอนนี้ กล้องอ่านสัญญาณดิจิทัล -- พินอยู่ในสถานะ 0 หรือ 1 สวิตช์เปิดหรือปิด สัญญาณส่วนใหญ่ที่มาจากเซนเซอร์ในโลกจริงเป็นแอนะล็อก: แรงดันไฟฟ้าต่อเนื่องที่แปรผันอย่างราบเรียบในช่วงค่าหนึ่ง โฟโตรีซิสเตอร์กวาดผ่านทุกแรงดันระหว่างราง 0 V และ Vcc ตามความสว่างของสภาพแวดล้อม เอาต์พุตของเซนเซอร์อุณหภูมิเปลี่ยนแปลงเป็นมิลลิโวลต์ตามการเปลี่ยนแปลงของอุณหภูมิห้อง เอาต์พุตของไมโครโฟนเพิ่มและลดตามเสียงรอบข้าง
ตัวแปลงแอนะล็อกเป็นดิจิทัล (ADC) คือสะพานเชื่อม มันสุ่มตัวอย่างแรงดันบนพินและส่งคืนค่าจำนวนเต็มที่ Python อ่านได้เหมือนค่าอื่น ๆ
3.12.1. การหาปริมาณ¶
ค่าดิจิทัลไม่สามารถแทนแรงดันไฟฟ้าต่อเนื่องได้อย่างแม่นยำ หน้าที่ของ ADC คือ หาปริมาณ -- ปัดค่าแต่ละตัวอย่างให้ใกล้เคียงที่สุดจากชุดระดับที่กำหนดไว้ ADC N บิตมีระดับ 2^N ระดับ โดยตัวแปลง 12 บิตมี 4096 ระดับกระจายอยู่ทั่วช่วงอินพุต
การหาปริมาณ: แต่ละตัวอย่างของสัญญาณแอนะล็อก (เส้นทึบ) จะถูกปัดให้เป็นหนึ่งในชุดระดับดิจิทัลจำกัด (เส้นประขั้นบันได)¶
แรงดันระหว่างสองระดับที่อยู่ติดกันคือ ขนาดก้าว ของ ADC สิ่งใดที่เล็กกว่านั้นจะหายไปในการปัดเศษ ADC 12 บิตในช่วง 3.3 V มีขนาดก้าวประมาณ 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 สำหรับค่าบน cam ของคุณ ค่าใดที่สูงกว่าอ้างอิงจะอ่านเป็นสเกลเต็ม (และอาจทำลายพินหากเกินแรงดันอินพุตสูงสุดสัมบูรณ์)
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 V ปลายด้านหนึ่ง กราวด์อีกด้าน หน้าสัมผัสเลื่อนต่อพิน¶
โพทคืออุปกรณ์อินพุตมาตรฐานสำหรับทดลอง 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 V อัตราส่วน 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 µA -- โดยทั่วไปไม่มีนัยสำคัญ แต่ถ้าแหล่งจ่ายใช้แบตเตอรี่ ให้พิจารณาตัวต้านทานที่ใหญ่กว่า (100 kΩ ถึง 1 MΩ) เพื่อลดการสูญเสียพลังงานขณะว่างความคลาดเคลื่อนของตัวต้านทาน (โดยทั่วไป ±1% หรือ ±5%) ส่งผลโดยตรงต่อความแม่นยำในการวัด ตัวต้านทาน ±5% สองตัวอาจให้ค่า
V_inที่กู้คืนมาผิดพลาดในกรณีเลวร้ายสุดประมาณ ±10%อิมพีแดนซ์ต้นทางของตัวแบ่งรวมกับความจุปรสิตใด ๆ จะกรองผ่านต่ำอินพุต สำหรับสัญญาณที่เปลี่ยนเร็ว เรื่องนี้สำคัญ แต่สำหรับการตรวจสอบแรงดันแบตเตอรี่ไม่มีนัยสำคัญ