ภาพพื้นหลังปกบทเรียน

บทเรียน 2.7 — อนาล็อกและสัมผัส: ADC ลูกบิด และ CapSense

Potentiometer + CapSense + กรองสัญญาณให้อ่านรู้เรื่อง

โมดูล 2 — จากจอสู่ฮาร์ดแวร์

คาถาประจำบทเรียน: โลกจริงไม่ได้มีแค่ 0 กับ 1 — งานของเราคือแปลงมันให้เป็นตัวเลขที่เชื่อถือได้

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

ดูของจริงก่อน — เกจวัดของลูกบิด

เกจของลูกบิด (Eva: หน้า Controls) 62.4 % ui.Arc ตามลูกบิด Raw: 40915 Percent: 62.4 หลักสุดท้ายสั่นเอง ลูกบิดจริงบนบอร์ด มือหมุน คำถามของวันนี้ หยุดมือแล้ว ทำไมตัวเลขยังขยับ ไม่ใช่บอร์ดเสีย

Eva Kit เปิดเมนู Controls บนบอร์ด แล้วหมุนลูกบิดช้า ๆ เข็มโค้งบนจอกวาดตามมือเราทันที · TESAIoT Dev Kit ไม่มีเมนู Controls (เฟิร์มแวร์ปิดหน้านี้ไว้) แต่หน้า GPIO & RGB Matrix บนบอร์ดมีแถบ VR1-4 ให้หมุน VR1 บนฐานดูได้ทันที — แถบทำหน้าที่เดียวกับเข็ม · ส่วนแถบสัมผัสให้รัน 01_capsense_dimmer.py (ไฟล์แรกของชุดบทเรียนนี้ตามโครงหลักสูตร) แล้วลากนิ้ว

ทีนี้ หยุดมือนิ่งสนิท แล้วจ้องตัวเลขเปอร์เซ็นต์ต่ออีกสิบวินาที — มันยังขยับอยู่ ทั้งที่ไม่มีใครแตะลูกบิดเลย

นั่นไม่ใช่บอร์ดเสีย และไม่ใช่โปรแกรมผิด มันคือธรรมชาติของการอ่านค่าอนาล็อก ชุดบทเรียนนี้เราจะทำสามอย่าง: อ่านค่าให้เป็น, เข้าใจว่าทำไมมันสั่น, แล้วทำให้มันนิ่งลงโดยไม่โกงค่า

เข็มที่กวาดตามมือคือของง่าย ตัวเลขที่สั่นตอนมือหยุดต่างหากคือบทเรียนจริงของวันนี้

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

ทำไม · คืออะไร · ทำยังไง — แผนที่ของชุดบทเรียนนี้

คำถาม คำตอบของชุดบทเรียนนี้ อยู่ช่วงไหน
Why ปุ่มกับสวิตช์ก็สั่งงานได้แล้ว ทำไมต้องมาอ่านลูกบิดกับแผ่นสัมผัสอีก เพราะของที่ IoT ต้องวัดจริง ๆ — อุณหภูมิ ระดับน้ำ แรงดัน ความชื้น ตำแหน่งวาล์ว — ไม่มีตัวไหนตอบมาเป็น 0 กับ 1 มันตอบมาเป็นค่าต่อเนื่องที่สั่นตลอดเวลา และงานของวิศวกรไม่ใช่กำจัดการสั่น แต่คือ เลือกฟิลเตอร์แล้วปกป้องตัวเลือกนั้นได้ ครึ่งแรก · ADC และ CapSense · สไลด์ "ทำไมค่าดิบถึงสั่น"
What มีอะไรให้ใช้บ้าง โมดูล sensors สิบห้าชื่อบน Eva Kit — เก้าฟังก์ชัน (บน Eva สี่ตอบ ห้าปฏิเสธด้วย OSError · บน Dev Kit ห้าตัวนั้นทำงานจริง) กับหกเซนเซอร์ย่อย (Dev Kit มีเพิ่ม dps368 sht40 radar) · และโมดูล dsp ทั้งสิบหกชื่อ คือ 8 คลาสกับ 8 ฟังก์ชัน (สองตัวสเปกตรัมเพิ่ม 2026-08-20) ใช้ได้ครบทุกตัวทั้งสองบอร์ด สองสไลด์แผนที่โมดูล
How ประกอบยังไงให้ใช้งานได้จริง อ่านจาก sensors.pot กับ sensors.capsense ป้อนเข้า dsp.EMA และ dsp.Median แล้ววางค่าดิบกับค่ากรองแล้วไว้ข้างกันบนจอเดียว สิบไฟล์ตัวอย่าง + ไฟล์ฝึก

ปลายทางที่จับต้องได้ — เข็มโค้งหมุนตามลูกบิด แถบเลื่อนวิ่งตามนิ้ว และสองบรรทัดล่างที่ฟ้องด้วยตาว่าฟิลเตอร์กำลังทำงานอยู่จริง

บทเรียน 2.4–2.6 คือ "จอสั่งฮาร์ดแวร์" · ชุดบทเรียนนี้กลับด้าน ฮาร์ดแวร์เป็นฝ่ายสั่งจอ

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

เป้าหมายของชุดบทเรียนนี้

  1. อธิบายได้ว่า ADC ทำอะไร และเลขที่ได้มาแปลว่าอะไรเมื่อเทียบกับแรงดันจริง
  2. อ่านลูกบิดด้วย sensors.pot.read() / .percent() / .voltage() แล้วแสดงสามแถวสามสีบนจอ
  3. อ่านปุ่มสัมผัสและแถบเลื่อนด้วย sensors.capsense และเข้าใจว่าแผ่นทองแดงรู้ได้อย่างไรว่านิ้วมาแตะ
  4. ใช้ dsp.EMA และ dsp.Median ลดการสั่น แล้ว เทียบค่าดิบกับค่ากรองแล้วบนจอพร้อมกัน

ปลายทางของวันนี้: หน้าจอเดียวที่มีเข็มโค้งตามลูกบิด แถบเลื่อนตามนิ้ว และสองบรรทัดล่างที่ฟ้องให้เห็นว่าฟิลเตอร์ทำงานอยู่จริง

วัดกันที่ "อ่านค่าได้และอธิบายค่าที่ได้เป็น" ไม่ใช่แค่ทำให้เข็มขยับ

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

ปลายทางของชุดบทเรียนนี้ — จอที่ค่าจากลูกบิดวิ่งอยู่

หน้าจอจาก BENTO Emulator ของเฉลยเกจลูกบิดกับแถบสัมผัส สี่การ์ด

หน้าจอจริงจากการรันโค้ดเฉลยบน BENTO Emulator ที่ 800x480 เท่าจอของ Eva Kit และ Dev Kit — ไม่ใช่ภาพวาด ไม่ใช่ mock-up และไม่ใช่ภาพถ่ายจากบอร์ด

หน้าจอของเฉลยปัจจุบันแบ่งเป็นสี่การ์ด และทุกการ์ดตอบคำถามคนละข้อ

  • บนซ้าย ค่าจากลูกบิดเป็น ui.Bar วางทับ ui.Scale ที่มีขีดและตัวเลข 0-100 — ตัวเลขเปอร์เซ็นต์จึงไม่ได้ลอยอยู่เฉย ๆ มันมีพิสัยของตัวเองอยู่ข้าง ๆ พร้อมค่าดิบกับโวลต์กำกับ และค่าดิบเทียบค่าที่กรองแล้ว (alpha 0.2, คาบ 200 ms) ซึ่งเป็นบทเรียนหลักของครึ่งหลังของชุดบทเรียน
  • บนขวา เกณฑ์เตือนเป็น ui.Spinbox ที่ผู้ใช้ตั้งเองด้วยปุ่มเพิ่ม/ลด
  • ล่างซ้าย แถบสัมผัสวางบนไม้บรรทัดชุดเดียวกัน กับไฟสองดวงแทนสถานะปุ่มทองแดง และบรรทัดคุณภาพของค่า
  • ล่างขวา ui.Led สองดวงบอกว่าตอนนี้ต่ำกว่าเกณฑ์หรือเกิน

ค่าเดียวกันแสดงได้หลายแบบ — เลือกให้ตรงกับคำถามที่คนดูจออยากรู้ และค่าที่วัดได้ต้องมาพร้อมเกณฑ์ของมันเสมอ

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

ทบทวนบทเรียน 2.4–2.6 — ของที่ต้องหยิบมาใช้ต่อวันนี้

บทเรียน 2.4–2.6 · จอสั่งฮาร์ดแวร์ นิ้วบนกระจก โค้ดของเรา หลอด LED จริง บทเรียน 2.7–2.9 · ฮาร์ดแวร์สั่งจอ จอแสดงผล โค้ดของเรา ลูกบิด · นิ้วสัมผัส ทิศทางข้อมูล กลับด้านกัน

ชุดบทเรียนก่อนหน้าเราสร้างแผงควบคุมของทีมเอง จากบทเรียนนั้นมีสี่อย่างที่วันนี้ใช้ซ้ำทั้งหมด

ของจากบทเรียน 2.4–2.6 วันนี้ใช้ตรงไหน
ui.Label / ui.Bar / ui.Panel และ x, y, w, h, color สร้างการ์ด แถบค่า และบรรทัดตัวเลข
ui.poll() ทุกลูป ยังบังคับเหมือนเดิม ไม่เรียกแล้ว widget หายไปได้ถึง 2 วินาที และปุ่มบนจอกดไม่ติด
time.sleep_ms() คุมจังหวะ ชุดบทเรียนนี้ใช้ 200 ms เพราะจอมีของหลายชิ้น
งบของคอร์ส 32 widget (เพดานเฟิร์มแวร์ 64) เฉลยวันนี้ใช้ 33 ชิ้น เกินงบของคอร์สไปหนึ่งชิ้น ต่อยอดเมื่อไรต้องเอาชิ้นเดิมออกก่อน · ข้อเสนอ: ป้ายนิ่ง "อัลฟา 0.2" ในเฉลยบทเรียน 2.9 ตัดได้ก่อน เพราะซ้ำกับ dsp.EMA(alpha=0.2) ในโค้ด ตัดแล้วเหลือ 32 พอดีงบ

ของใหม่ที่เพิ่มเข้ามา: โมดูล sensors (ลูกบิด + สัมผัส) · โมดูล dsp (ฟิลเตอร์) · widget สามตัวของหน้าจอ HMI คือ ui.Scale (ไม้บรรทัด) ui.Led (ไฟสถานะ) ui.Spinbox (ช่องป้อนเลข) — ตัวอย่างประกอบที่ 09_scale_led_spinbox.py

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

เข้าใจฮาร์ดแวร์ · ADC หั่นแรงดันต่อเนื่องเป็นขั้นบันได

ลูกบิดบนบอร์ดไม่ได้ส่งตัวเลขออกมา มันส่ง แรงดันไฟ ที่ไล่ต่อเนื่องจาก 0 V ขึ้นไปถึงแรงดันอ้างอิงของวงจร (ตัวเลขจริงของบอร์ดนี้ยังไม่ลงตัว — สองสไลด์ถัดไปว่าด้วยเรื่องนี้โดยเฉพาะ) วงจร SAR ADC ในชิปมีหน้าที่วัดแรงดันนั้นเป็นจังหวะ ๆ แล้วปัดลงขั้นบันไดที่ใกล้ที่สุด

V_ref 0 V เวลา — ADC สุ่มวัดทุก ๆ จังหวะ (จุดวงกลม) · เส้นแดงคือหัวอ่านที่กวาดไปตามเวลา เส้นส้ม = แรงดันจริงต่อเนื่อง · แท่งน้ำเงิน = ตัวเลขที่โปรแกรมเราได้เห็น

ตัวเลขที่ Python อ่านได้ ไม่ใช่แรงดันจริง แต่เป็น ค่าที่ถูกปัดเข้าขั้นบันไดที่ใกล้ที่สุด ณ วินาทีที่วัด

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

หนึ่งลูกบิด สามหน้าตา — เลือกใช้ให้ถูกงาน

import sensors
# ไม่ต้องเรียก sensors.init() ทั้งสองบอร์ด - บน Eva Kit เรียกแล้วขึ้น OSError
# ทันที (คอร์จอเป็นเจ้าของบัส) ส่วนบน Dev Kit ผ่าน แต่ก็ไม่จำเป็นอยู่ดี

raw   = sensors.pot.read()      # 0 - 65535   จำนวนเต็ม ทั้งสองบอร์ด (Dev Kit = VR1)
pct   = sensors.pot.percent()   # 0.0 - 100.0 เปอร์เซ็นต์ของช่วงเต็มสเกล
volts = sensors.pot.voltage()   # ทศนิยม หน่วยโวลต์ (ดูสไลด์ถัดไปก่อนเชื่อตัวเลข)

สัญลักษณ์โพเทนชิโอมิเตอร์ในผังวงจร: ตัวต้านทานพร้อมลูกศร wiper ตรงกลาง ภาพถ่ายลูกบิดโพเทนชิโอมิเตอร์ที่มีหน้าปัดตัวเลข

ซ้าย: สัญลักษณ์ในผังวงจร ปลายสองข้างคือปลายแทร็กตัวต้านทาน ลูกศรตรงกลางคือ wiper ที่เลื่อนไปตามแทร็ก — ภาพ: “Potentiometer linear” · สาธารณสมบัติ · Wikimedia Commons  |  ขวา: ของจริงที่มือเราหมุน — ภาพ: “23mm knob with numbered dials with potentiometers 01(DXO)” โดย Retired electrician · CC0 1.0 · Wikimedia Commons

ทั้งสามค่ามาจากการวัดครั้งเดียวกัน ต่างกันแค่หน่วยที่เอามาเสิร์ฟ — read() ดูความละเอียดดิบและความสั่น · percent() เข้ากับ ui.Arc / ui.Bar ที่คิดเป็น 0-100 อยู่แล้ว · voltage() ไว้เทียบกับมัลติมิเตอร์

เปลี่ยนจากที่เคยสอน: สามคำสั่งข้างบน ไม่ได้ตั้งค่า ADC เอง — บน Eva Kit คอร์จอ (CM55) อ่านลูกบิดแล้ว Python หยิบค่าจาก snapshot · บน Dev Kit CM33 อ่าน VR1 บนฐาน QWA309 ตรง (อีกสามตัวอยู่ที่ pots.read(1..3) คืน 0-4095 คนละสเกล) · ทั้งสองทางคืน 0-65535 หน้าตาเดียวกัน — ไม่ต้องมี init() ไม่ต้องหน่วง 500 ms

เลือกหน่วยตาม คนอ่าน ไม่ใช่ตามความสะดวกของโปรแกรม — เกจเป็นเปอร์เซ็นต์ รายงานวิศวกรรมเป็นโวลต์

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

เข้าใจฮาร์ดแวร์ · ลูกบิดของ Eva Kit ต่ออยู่กับอะไรจริง ๆ

ผังวงจรลูกบิดและเทอร์มิสเตอร์ของบอร์ด Eva Kit ที่ต่อเข้าขา ADC

ภาพ: KIT_PSE84_EVAL PSOC™ Edge E84 Evaluation Kit guide, Infineon 002-39007 Rev.*B, รูปที่ 77 (หน้า 88) — ใช้เพื่อการเรียนการสอน · ผังนี้เป็นของ Eva Kit เท่านั้น

R34 คือ pot 10 kΩ แบบ linear ต่อคร่อมระหว่างรางไฟกับกราวด์ ขากลาง (wiper) ออกมาเป็น POT_OUT — ตัวแบ่งแรงดันที่ปรับได้ด้วยมือ ตรงตามสัญลักษณ์ในสไลด์ที่แล้ว · กล่องขวา: thermistor TH1 ใช้เส้นทางเดียวกันผ่านตัวต้านทาน 0 Ω ที่ mark ว่า DNI — Eva Kit ใช้ pot กับ thermistor พร้อมกันไม่ได้ ค่าเริ่มต้นคือ pot

บน TESAIoT Dev Kit ลูกบิดที่ sensors.pot อ่านคือ VR1 บนฐาน QWA309 — ผัง QWA309 ระบุแรงดันอ้างอิงของ VR1-4 ไว้ 0-1.8 V (SAR 12 บิต) ขณะที่ voltage() คูณด้วย 3.3 V — ขัดกันแบบเดียวกับ Eva · ส่วนค่าความต้านทาน ทิศหมุน และ taper ของ VR1 ยังไม่ได้วัด ให้ทีมจดจากบอร์ดจริงลงบันทึกการเรียน อย่าเอาตัวเลขของ R34 ไปใช้

หมายเหตุผู้สอน (ต้องเคลียร์ก่อนสอน): ผัง Eva ต่อ R34 กับ VDD_1V8 และผัง QWA309 ก็ระบุ 0-1.8 V แต่ sensors.pot.voltage() คูณด้วย 3.3 V ที่สมมติไว้ ทั้งสองบอร์ด — ยังไม่มีใครเอามิเตอร์ไปยืนยันบนบอร์ดไหนเลย ห้ามพูดตัวเลขใดตัวเลขหนึ่งเป็นความจริงบนกระดาน ให้หมุนสุดแล้วอ่าน pot.read() / pot.voltage() เทียบกับมัลติมิเตอร์ที่ขาลูกบิดของบอร์ดจริงก่อน (Eva: ขา P15[1] · Dev Kit: ขากลางของ VR1) แล้วค่อยเขียนตัวเลขลงสไลด์

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

จากเลขดิบเป็นเปอร์เซ็นต์และเป็นโวลต์ — สูตรที่ไม่ผูกกับตัวเลขใดตัวเลขหนึ่ง

read() คืนจำนวนเต็ม 0 - 65535 นั่นคือ "สเกลของ API" (n=16n = 16) ไม่ได้แปลว่าฮาร์ดแวร์ละเอียด 65536 ขั้นจริง

p=raw2n−1×100%V=raw2n−1⋅Vrefp = \frac{\text{raw}}{2^{n}-1}\times 100\% \qquad V = \frac{\text{raw}}{2^{n}-1}\cdot V_{\text{ref}}

VLSB=VFS2nεq≤VLSB2V_{\text{LSB}} = \frac{V_{\text{FS}}}{2^{n}} \qquad \varepsilon_q \le \frac{V_{\text{LSB}}}{2}

ไทย: ค่าที่อ่านได้ไม่ต่อเนื่อง มันกระโดดทีละขั้น ขั้นหนึ่งใหญ่แค่ไหนขึ้นกับจำนวนบิต และความคลาดเคลื่อนจากการปัดไม่เกินครึ่งขั้น

คิดให้ดูจริง ๆ สมมติ read() คืน 40915

p=4091565535×100=62.43%p = \frac{40915}{65535}\times 100 = 62.43\%

ส่วน VV ตอบเป็นโวลต์ไม่ได้จนกว่าจะรู้ VrefV_{\text{ref}} ของบอร์ดจริง

ตัวส่วนมีสองแบบ อย่าสลับ: แปลงเป็นค่าอ่านใช้ 2n−12^{n}-1 (ratiometric) · ขนาดหนึ่งขั้นใช้ 2n2^{n}

กราฟความคลาดเคลื่อนจากการปัดค่า (quantization error) ระหว่างสัญญาณจริงกับขั้นดิจิทัล

ภาพ: “Quantization error” โดย Gregory Maxwell — CC BY 3.0 · Wikimedia Commons

สิ่งที่ต้องวัดเอง: เลื่อนลูกบิดช้า ๆ แล้วดูว่า read() เดินทีละเท่าไร ถ้ากระโดดเป็นก้อนละ kk เท่ากันทุกก้อน ความละเอียดจริงคือ 65536/k65536/k ขั้น — ก้อนละ 16 ก็คือ 4096 ขั้น จดลงบันทึกการเรียน อย่าเดาจากสเปกที่ยังไม่ได้อ่าน

สิ่งที่รู้จากซอร์สเฟิร์มแวร์: ADC ของทั้งสองบอร์ดอ่านได้ 12 บิต (0-4095) แล้วเฟิร์มแวร์คูณขยายเป็น 0-65535 ก่อนส่งให้เรา — 65535 จึงเป็นสเกลของ API ไม่ใช่ความละเอียดของ ADC

"เลขใหญ่" กับ "เลขละเอียด" เป็นคนละเรื่องกัน สเกลขยายได้ แต่ความจริงที่วัดมามีอยู่เท่าเดิม

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

เกร็ด: ข้างใน SAR ADC คือการ "ทายเลข" แบบไบนารีเสิร์ช

ภาพเคลื่อนไหว ADC แบบ successive approximation ไล่ทายค่าทีละบิตจนได้เลขดิจิทัล

ภาพ: “ADC animation 20” โดย Russ Puskarcik — CC BY 3.0 · Wikimedia Commons

SAR ย่อมาจาก Successive Approximation Register — แปลตรงตัวคือ "ทะเบียนของการประมาณทีละขั้น"

วิธีทำงานเหมือนเกมทายเลข 1-100 ที่เราเล่นกันตอนเด็ก: เดาครึ่งทางก่อน ถ้าสูงไปก็ตัดครึ่งบนทิ้ง แล้วเดาครึ่งของที่เหลือต่อไป

  1. ตรึงค่าแรงดันไว้ก่อนด้วยวงจร sample-and-hold (ถ้าไม่ตรึง ค่าจะเปลี่ยนระหว่างที่กำลังทาย)
  2. ทายบิตบนสุด: แรงดันมากกว่าครึ่งของเต็มสเกลไหม → ได้ 1 บิต
  3. ทำซ้ำลงมาทีละบิตจนครบ n บิต

ทำไมต้องรู้: เพราะการแปลงหนึ่งครั้ง กินเวลา n รอบนาฬิกา ไม่ใช่ทันที นี่คือเหตุผลที่ ADC ทุกตัวมีเพดานอัตราการสุ่ม และเป็นที่มาของกฎ Nyquist ที่เราจะเจอเต็ม ๆ ในบทเรียน 3.4–3.6

ภาพเคลื่อนไหว DAC สี่บิตภายใน SAR ADC ที่ไล่ทายค่าทีละบิต

DAC ภายในที่ไล่ทายทีละบิตจริง ๆ ขั้นบันไดที่ขยับทีละครั้งคือหัวใจของคำว่าไบนารีเสิร์ช ภาพนิ่งเห็นแค่ผลลัพธ์ — ภาพ: “4-bit Successive Approximation DAC” โดย Uwezi — CC BY-SA 4.0 — Wikimedia Commons

เชื่อมกับวันนี้: ตัวเลขที่ sensors.pot.read() คืนมา คือผลของการทายแบบนี้ที่จบไปแล้วเมื่อเสี้ยววินาทีก่อน ไม่ใช่แรงดัน ณ วินาทีที่เราอ่านตัวแปร

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

ดูเพิ่ม · ลูกบิดกับตัวแบ่งแรงดันทำงานอย่างไร

ผังวงจรตัวแบ่งแรงดันจากตัวต้านทานสองตัว

วงจรที่อยู่ข้างในลูกบิด — ภาพ: “Voltage divider” · สาธารณสมบัติ · Wikimedia Commons
How Potentiometers Work · CircuitBread
ทำไมต้องต่อครบสามขาถึงจะได้ "แรงดันที่ปรับได้" ต่อสองขาได้แค่ความต้านทานที่ปรับได้เฉย ๆ
Voltage divider · Khan Academy
อนุมานสูตร Vout = Vin × R2 / (R1 + R2) จากกฎของโอห์มทีละขั้น

สูตรที่ทั้งสองคลิปพาไปถึง Vout=Vin⋅R2R1+R2V_{out} = V_{in}\cdot\dfrac{R_2}{R_1+R_2} — ในลูกบิด R1R_1 กับ R2R_2 คือแทร็กสองท่อนที่ wiper แบ่งเอาไว้ หมุนไปครึ่งทางจึงได้แรงดันครึ่งหนึ่ง · ทั้งสองคลิปเป็นของนอกเวลา (ต้องมีอินเทอร์เน็ต) เนื้อหาในบทเรียนเข้าใจได้ครบโดยไม่ต้องเปิดดู

ลูกบิดคือตัวแบ่งแรงดันที่เราหมุนเปลี่ยนอัตราส่วนได้ด้วยมือ ทุกอย่างที่เหลือในชุดบทเรียนนี้ต่อยอดจากประโยคนี้

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

CapSense — รู้ได้อย่างไรว่านิ้วมาแตะ ทั้งที่ไม่มีสวิตช์

ใต้แผ่นพลาสติกของปุ่มสัมผัส (บน Eva Kit คือตรงที่เขียนว่า BTN0 / BTN1 · บน Dev Kit ตำแหน่งและป้ายของแผ่นสัมผัสยังไม่ได้บันทึกในเอกสารชุดนี้ ให้หาบนบอร์ดของทีม — ในโค้ดชื่อ btn0 btn1 slider เหมือนกันทั้งสองบอร์ด) ไม่มีปุ่มกดอยู่เลย มีแค่ แผ่นทองแดงบนแผ่นวงจร ที่เก็บประจุได้จำนวนหนึ่ง เรียกว่า capacitance ชิปจะอัดประจุเข้าไปแล้วจับเวลาว่ามันเต็มเร็วแค่ไหน

ไม่มีนิ้ว แผ่นทองแดงใต้กระจก ความจุ = C₀ มีนิ้วเข้ามาใกล้ นิ้วดึงเส้นสนามส่วนหนึ่งไป ความจุ = C₀ + ΔC นิ้วคือตัวนำที่ต่อลงกราวด์ผ่านร่างกาย — มันเพิ่มความจุให้แผ่น

นิ้วคนเป็นตัวนำที่ต่อลงกราวด์ผ่านร่างกาย พอนิ้วเข้ามาใกล้ ค่า capacitance ของแผ่นนั้น เพิ่มขึ้น เวลาที่ใช้อัดประจุจึงนานขึ้นเล็กน้อย ชิปวัดความต่างนั้นได้ และสรุปว่า "มีนิ้ว"

แถบเลื่อนใช้หลักการเดียวกัน แต่วางแผ่นทองแดงเรียงกันหลายแผ่น แล้วดูว่านิ้วทำให้แผ่นไหนเปลี่ยนมากที่สุด เอามาถัวเฉลี่ยเป็นตำแหน่ง 0-100

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

CapSense (ต่อ) — ผิวสัมผัสของจริง ไม่มีสวิตช์ ไม่มีชิ้นส่วนขยับ

ภาพถ่ายแผ่นจอสัมผัสแบบ capacitive ที่ไม่มีสวิตช์หรือชิ้นส่วนขยับ

ภาพถ่ายผิวสัมผัสแบบ capacitive ของจริง ไม่มีสวิตช์ ไม่มีชิ้นส่วนขยับ มีแต่แผ่นตัวนำ นี่คือสิ่งที่นิ้วไปเปลี่ยนค่าของมัน — ภาพ: “Capacitive touchscreen” โดย Medvedev — CC BY 3.0 — Wikimedia Commons

ปุ่มสัมผัสไม่ได้วัด "แรงกด" มันวัด ความใกล้ของตัวนำ — นี่คือเหตุผลที่ใส่ถุงมือยางหนา ๆ แล้วมันไม่ติด

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

อิเล็กโทรดจริงบน Eva Kit — และวิดีโอจากผู้ผลิตชิป

ผังวงจร CapSense ของบอร์ด Eva Kit: อิเล็กโทรดปุ่มสัมผัสสองปุ่มและแถบเลื่อนต่อเข้าชิป PSoC 4000T

ภาพ: KIT_PSE84_EVAL PSOC™ Edge E84 Evaluation Kit guide, Infineon 002-39007 Rev.*B, รูปที่ 52 (หน้า 65) — ใช้เพื่อการเรียนการสอน
PSoC 101 Lesson 13: CapSense
วิดีโอสอนจากผู้ผลิตชิปเดิม (ของนอกเวลา ต้องมีเน็ต)

บน Eva Kit ปุ่มสองปุ่ม CSB1 / CSB2 เป็นแบบ CSX (mutual-capacitance) — สังเกตว่าแต่ละปุ่มมีขา Tx กับ Rx แยกกัน ไม่ใช่ขาเดียว ประจุถูกส่งจาก Tx ไป Rx และนิ้วเข้ามา "ขโมย" ส่วนหนึ่งไป · แถบเลื่อนคือ 5 อิเล็กโทรด (RX0-RX4) ที่ชิปถัวเฉลี่ยออกมาเป็นตำแหน่งเดียว 0-100 · ผังอิเล็กโทรดของ Dev Kit ยังไม่มีในเอกสารชุดนี้ — แต่ค่าที่โค้ดได้รับคือชุดเดียวกัน

ในโค้ดเราเห็นแค่ btn0 / btn1 / slider สามค่า เหมือนกันทั้งสองบอร์ด — ข้างใต้มันคืออิเล็กโทรดหลายแผ่นกับชิปอีกตัวหนึ่งที่ทำงานให้ตลอดเวลา

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

เข้าใจฮาร์ดแวร์ · ชิปคนละตัว คุยกันผ่าน I2C สามไบต์

งานสัมผัสไม่ได้ทำโดยชิปหลัก แต่ทำโดย PSoC 4000T อีกตัวหนึ่งบนบอร์ด ทำหน้าที่นี้อย่างเดียวตลอดเวลา — ทั้ง Eva Kit และ Dev Kit ใช้ทางเดียวกัน คือชิปตัวนี้ส่งค่าให้คอร์จอ (CM55) แล้ว Python ขอต่อจากคอร์จอ

แผ่นทองแดง BTN0 · BTN1 แถบเลื่อนหลายช่อง PSoC 4000T อัดประจุ จับเวลา เทียบกับ baseline สรุปเป็นแตะ/ไม่แตะ ต้องถูก flash เฟิร์มแวร์มาก่อน คอร์จอ CM55 → CM33 Python sensors.capsense.read() ขอ dict สามช่องต่อจากคอร์จอ I2C แอดเดรส 0x08 คอร์จออ่านรวด 3 ไบต์ ไบต์ 0 = ปุ่ม 0 · ไบต์ 1 = ปุ่ม 1 · ไบต์ 2 = ตำแหน่งแถบเลื่อน 0-100

หมายเหตุผู้สอน: ถ้าชิป 4000T ยังไม่ถูก flash ทุกค่าที่อ่านได้จะเป็น 255 หรือโยน OSError — ต้องตรวจให้ครบทุกบอร์ดก่อนเข้าชุดบทเรียนนี้

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

baseline — เหตุผลที่ต้อง "ปล่อยมือ" ตอนโปรแกรมเริ่ม

ค่าความจุของแผ่นทองแดงไม่ได้คงที่ตายตัว มันเปลี่ยนตามความชื้น อุณหภูมิ และแม้แต่ฝุ่นบนหน้าจอ ชิปจึงไม่ตัดสินจากค่าดิบ แต่ตัดสินจาก ส่วนต่างเทียบกับค่าตอนไม่มีนิ้ว ค่านั้นเรียกว่า baseline

raw count difference count = ระยะนี้ finger threshold baseline ไล่ตามช้า ๆ (อุณหภูมิ/ความชื้น) ค่าดิบจริง baseline ไล่ทันการเปลี่ยนช้า ๆ แต่ไล่ไม่ทันการแตะ — นั่นคือวิธีแยกสองอย่างออกจากกัน สิ่งที่ซอฟต์แวร์เห็นจริง ๆ ไม่ใช่ "แตะ/ไม่แตะ" แต่เป็นตัวเลขที่ค่อย ๆ เลื่อน

บนบอร์ดของเรา baseline ถูกเก็บ ครั้งแรกที่ไดรเวอร์อ่านชิปตัวนี้ และไดรเวอร์นั้นอยู่บนคอร์จอ ไม่ใช่ในสคริปต์ของเรา — แปลว่า baseline ถูกเก็บ ตอนบอร์ดบูต ไม่ใช่ตอนเรากด Program to Device · เผลอวางนิ้วค้างบนปุ่มตอนบูต ชิปจะจำ "สภาพมีนิ้ว" ว่าเป็นสภาพปกติ แล้วรายงานกลับด้านทั้งบทเรียน

b0, b1 = sensors.capsense.buttons()   # (True/False, True/False) เทียบกับ baseline แล้ว
pos    = sensors.capsense.slider()    # 0 - 100
d      = sensors.capsense.read()      # {'btn0': bool, 'btn1': bool, 'slider': int}

เจอปุ่มรายงานกลับด้านเมื่อไร อย่าไปแก้โค้ด ให้ยกนิ้วออกให้หมดแล้ว ถอดสาย USB แล้วเสียบกลับ — บน Dev Kit ห้ามโยกสวิตช์บนฐาน สวิตช์พวกนั้นคือสวิตช์ไฟ ไม่ใช่ปุ่มรีเซ็ต · รันสคริปต์ใหม่เฉย ๆ ไม่ได้เก็บ baseline ใหม่

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

แผนที่โมดูล sensors (1/2) — สิบห้าชื่อบน Eva Kit และสองบอร์ดตอบไม่เหมือนกัน

สิบห้าชื่อแบ่งเป็นสองพวก — เก้าตัวเป็นฟังก์ชันที่เรียกตรงได้ และอีกหกตัวเป็นเซนเซอร์ย่อยกับตัววินิจฉัย ซึ่งมีเมธอดของตัวเองอีกชั้น · หน้านี้คือหกแถวที่ สองบอร์ดตอบเหมือนกัน ห้าตัวที่ตอบต่างกันอยู่หน้าถัดไป

ชื่อ ทำอะไร บน Eva Kit บน Dev Kit
snapshot() ขอค่าทั้งชุดครั้งเดียว คืน dict สามกลุ่ม bmi270 capsense pot ทางหลัก — ค่าทั้งชุดมาจากคอร์จอ ทางหลักเหมือนกัน dict หน้าตาเดียวกัน — IMU อ่านสดจาก CM33 · pot กับ capsense ใน snapshot มาจากคอร์จอที่อ่านทุก 200 ms (sensors.pot.read() ต่างหากที่อ่านตรง)
read_all() อ่านทุกเซนเซอร์ที่มี เรียก snapshot() ต่อให้ตรง ๆ คืนของเหมือนกันเป๊ะ คืน pot เป็น float ไม่ใช่ dict — คนละหน้าตากับ snapshot()
auto_status() สถานะงานเบื้องหลัง คืน running rate_ms push_count mask เรียกได้ ใช้ดูว่ามีใครถูกเปิดไว้ เรียกได้
auto_rate(ms) ตั้งจังหวะงานเบื้องหลัง หนีบไว้ 20-5000 ms เงียบ ๆ เรียกได้ แต่ไม่มีผล เพราะ auto() เปิดไม่ได้ เรียกได้ และมีผลเมื่อ auto() เปิดอยู่
bmi270 bmm350 capsense pot สี่กลุ่มเซนเซอร์ที่มีทั้งสองบอร์ด — แต่ละตัวมีเมธอดของตัวเอง ใช้ได้ทุกตัว ใช้ได้ทุกตัว + มี dps368 sht40 radar เพิ่ม
bmm350_diag bmm350_debug ตัววินิจฉัยเข็มทิศ ใช้ตอนหาสาเหตุว่าทำไมค่าเพี้ยน เรียกได้ เรียกได้

dps368 sht40 และ radar ไม่มีอยู่ในโมดูลเลยบน Eva Kit — พิมพ์ sensors.sht40 จะได้ AttributeError เพราะธง BSP ตั้งไว้ 0 ตั้งแต่คอมไพล์ (Eva ไม่มีชิปพวกนั้น) · บน Dev Kit สามชื่อนี้มีจริง จึงเป็นสามชื่อที่ print(dir(sensors)) บนสองบอร์ดให้ผลต่างกัน — รายชื่อบนบอร์ดคือความจริง ตารางนี้คือแผนที่

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

แผนที่โมดูล sensors (2/2) — ห้าตัวที่ Eva ปฏิเสธ และทำไม

ห้าในเก้าฟังก์ชันตอบต่างกันตามบอร์ด — บน Eva Kit ปฏิเสธด้วย OSError บน Dev Kit ทำงานจริง

ชื่อ ทำอะไร บน Eva Kit บน Dev Kit
init() ปลุกเซนเซอร์และตั้งค่าบัส OSError ผ่าน (ไฟล์ทัวร์พิมพ์ค่าที่คืนให้ดู) — แต่ไม่ต้องเรียก เฟิร์มแวร์ปลุกให้ตั้งแต่บูต
scan() ไล่หาอุปกรณ์บนบัส I2C ทีละแอดเดรส OSError ผ่าน คืนรายการที่อยู่ที่พบ
push() ยัดค่าที่อ่านได้ข้ามไปให้คอร์จอ OSError ส่งค่าจริงหนึ่งครั้ง
live_push() ทำแบบ push() วนไปเรื่อย ๆ OSError วนไม่รู้จบจนกด Ctrl+C — อย่าเรียกเล่น
auto() เปิดงานเบื้องหลังให้อ่านเซนเซอร์เอง OSError เปิด background task ค้างไว้

ห้าตัวที่ Eva ปฏิเสธ ปฏิเสธด้วยเหตุผลเดียวกันหมด ทั้งห้าจบลงที่การขับบัส SCB0 ซึ่งบน Eva คอร์จอถือไว้ ตัวที่อันตรายที่สุดคือ auto() เพราะมันไม่ได้ขับบัสเอง มันไปเปิดงานเบื้องหลังที่ขับบัสแทน อาการค้างจึงอยู่ต่อหลังบรรทัดนั้นจบไปแล้ว และไม่มี try/except ไหนช่วยได้ เพราะการค้างไม่ใช่ exception · บน Dev Kit บัส I2C ของ IMU เป็นของ CM33 เอง ห้าตัวนี้จึง "ทำงาน" — ซึ่งไม่ได้แปลว่าควรเรียก: live_push() วนจนกด Ctrl+C และ auto() เปิดงานค้างไว้หลังสคริปต์จบ

ลองเรียกเก้าตัวที่เรียกตรงได้ด้วยตัวเองที่ 09_sensors_api_tour.py — มันเรียกจริงแล้ว ให้บอร์ดเป็นคนบอก ว่าใครตอบ ใครปฏิเสธ ไม่ใช่ตารางที่พิมพ์ค้างไว้ (บน Dev Kit ไฟล์นี้ตั้งใจข้าม push() live_push() auto() ด้วยเหตุผลข้างบน)

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

snapshot() คืนอะไรมาบ้าง — และคำว่า sequence มีไว้ทำไม

d = sensors.snapshot()          # dict หน้าตาเดียวกันทั้งสองบอร์ด
d['pot']       # {'raw': 0-65535, 'percent': 0.0-100.0, 'voltage': float, 'sequence': int}
d['capsense']  # {'btn0': bool, 'btn1': bool, 'slider': 0-100, 'sequence': int}
d['bmi270']    # {'ax','ay','az' m/s2, 'gx','gy','gz' deg/s, 'sequence': int}

การเรียกครั้งเดียวได้ครบทั้งสามกลุ่ม จากการอ่านจังหวะเดียวกัน ต่างจากเรียก pot.percent() แล้ว capsense.slider() ซึ่งเป็นการถามแยกสองรอบ ได้ค่าคนละจังหวะ และช้ากว่าเท่าตัว · read_all() บน Eva Kit คืนของเดียวกับ snapshot() เป๊ะ แต่บน Dev Kit มันคืน pot เป็น float — ในคอร์สนี้ใช้ snapshot() ให้ตรงกันทั้งสองบอร์ด

ช่อง sequence คือเลขนับตัวอย่างของเซนเซอร์กลุ่มนั้น ถ้าเลขนี้ไม่ขยับระหว่างสองรอบ แปลว่าเราอ่านค่าเดิมซ้ำ ไม่ใช่ว่าโลกหยุดนิ่ง — บน Eva Kit คอร์จออ่านทุก 200 ms ถ้าลูปของเราเร็วกว่านั้น เราจะเจอค่าเดิมแน่นอน (บน Dev Kit ค่า IMU ใน snapshot อ่านสดจาก CM33 ส่วน pot กับ capsense ยังมาจากคอร์จอทุก 200 ms ตัวเลขจึงเดินคนละจังหวะกัน) นี่คือเครื่องมือที่บอกได้ว่าจังหวะลูปเราเร็วเกินความจริงของข้อมูลหรือยัง

ยังมีอีกสองชื่อสำหรับงานซ่อม sensors.bmm350_diag() คืน dict สิบสองช่องสำหรับไล่ปัญหาเข็มทิศ และ sensors.bmm350_debug() พิมพ์ค่ารีจิสเตอร์ออกคอนโซล ทั้งคู่เป็นเครื่องมือของผู้สอนตอนบอร์ดมีปัญหา ไม่ใช่ของที่ใช้ในงานปกติ — และทั้งคู่ หยุดงานเบื้องหลังแล้ว re-init ชิป จึงกินเวลาและกวนค่าที่กำลังอ่านอยู่

read_all() บน Eva Kit เป็นบทเรียนเงียบ ๆ อีกข้อ: ชื่อที่ฟังดูทรงพลังกว่า ไม่ได้แปลว่าทำมากกว่า — เปิดซอร์สดูจึงรู้ว่ามันคือบรรทัดเดียวที่เรียก snapshot() ต่อ (บน Dev Kit มันเป็นคนละฟังก์ชันและคืน pot เป็น float)

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

บทเรียน 2.4–2.6 คือ "จอสั่งฮาร์ดแวร์" บทเรียน 2.7–2.9 คือ "ฮาร์ดแวร์สั่งจอ" — ทิศทางข้อมูลกลับด้านกัน