บทเรียน 4.1 — ปุ่มกดบนบอร์ดฐานและเมนูที่ไม่ใช้จอสัมผัส

ปุ่มกดบนบอร์ดฐานและเมนูที่ไม่ใช้จอสัมผัส

TESAIoT Dev Kit · PSoC Edge E84 · ภาษา C · ModusToolbox

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

เป้าหมาย

เมื่อจบบทเรียนนี้ คุณจะ

  1. อ่านปุ่ม active-low แบบ pull-up และนับจำนวนครั้งที่กดได้ถูกต้อง
  2. นำทางเมนู LVGL ด้วยปุ่มกายภาพสองปุ่ม (Move / Select) แบบ kiosk
TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

ก่อนเริ่ม

  • ผ่านบทเรียนก่อนหน้ามาแล้ว: fw-stack.m01.l01
  • บอร์ด: TESAIoT Dev Kit
  • แพลตฟอร์ม: PSoC Edge E84 · ModusToolbox
  • เวลาโดยประมาณ: เนื้อหา 10 + ฝึกตาม 25 + แล็บ 30 + เช็กความเข้าใจ 5 = 70 นาที
TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

ดูของจริงก่อน

แบบฝึกของ Developer Hub ที่เขียนไว้สำหรับบอร์ดฐาน QWA309 โดยตรง — เปิดบน Developer Hub แล้ว flash เฟิร์มแวร์สำเร็จรูปดูก่อนว่าหน้าจอเป็นอย่างไร

  • QWA309 — Push Button Monitor — อ่านปุ่มกด SW9 (P17.5) และ SW10 (P17.7) แบบ active-low pull-up แสดงสถานะกด/ปล่อย + นับจำนวนครั้งบน LVGL
    README · โค้ด · Developer Hub
  • QWA309 — Hardware Button Menu — นำทางเมนู LVGL ด้วยปุ่มกายภาพ SW6=Move SW5=Select (ไม่ใช้ touch) — headless/kiosk UX pattern
    README · โค้ด · Developer Hub
TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

แนวคิด — บอร์ดฐาน QWA309 มีอะไรให้ฝึก

ปุ่มกด potentiometer 4 ตัว CAN transceiver และ header สำหรับต่ออุปกรณ์ภายนอก — บทเรียนนี้ใช้แบบฝึกของ Developer Hub ที่เขียนไว้สำหรับบอร์ดนี้โดยตรง

สองแบบฝึกแรกใช้ปุ่มกดสองตัวเดียวกันเป็นข้อมูลเข้า แต่อ่านค่าคนละแบบ: อ่าน สถานะปัจจุบัน (level) เทียบกับจับ จังหวะที่เพิ่งเปลี่ยน (edge)

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

แนวคิด — ปุ่มกด active-low พร้อม internal pull-up

Cy_GPIO_Pin_FastInit(port, pin, CY_GPIO_DM_PULLUP, 1UL, HSIOM_SEL_GPIO) เปิด pull-up ในตัวชิป ดึงขาขึ้น HIGH เมื่อไม่มีอะไรมาแตะ

ปุ่มต่อลงกราวด์เมื่อกด ขาจึงลง LOW และ Cy_GPIO_Read() คืนค่า 0 — เขียนเงื่อนไข "กด" เป็น 0U == Cy_GPIO_Read(...)

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

แนวคิด — debounce แบบนับรอบ (Push Button Monitor)

โพลทุก BUTTON_REFRESH_PERIOD_MS = 25 ms ค่าต้องอ่านได้ระดับเดียวกันติดกัน 3 ครั้ง (BUTTON_DEBOUNCE_TICKS = 2) ≈ 50 ms จึงยอมรับว่าสถานะเปลี่ยนจริง

press_count เพิ่มเฉพาะตอนสถานะเสถียรเปลี่ยนเป็นกด · hold_time_ms สะสมทีละ 25 ms ขณะกดค้าง

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

แนวคิด — จับ "ขอบขาลง" แทนสถานะค้าง (Hardware Button Menu)

btn_pressed_edge() debounce แบบเดียวกัน (MENU_DEBOUNCE = 2 ที่ 30 ms) แต่คืน true แค่รอบที่เพิ่งเปลี่ยนจากปล่อยเป็นกด

กดค้างนานเท่าไร highlight ก็เลื่อนแค่ครั้งเดียวต่อการกด — วนด้วย (s_sel + 1U) % MENU_ITEMS (4 รายการ)

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

แนวคิด — ชื่อปุ่มไม่ตรงกัน: SW9/SW10 เทียบกับ SW5/SW6

metadata.json และคอมเมนต์ของ Push Button Monitor เขียนว่า "SW9 (P17.5) และ SW10 (P17.7)"

แต่โค้ดจริงใน buttons[] ใช้ "SW5" (P17.7) และ "SW6" (P17.5) — ตรงกับ Hardware Button Menu และลายพิมพ์บนบอร์ด ให้ยึดตามโค้ด

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

แนวคิด — ทักษะที่ฝึกในบทเรียนนี้

บทเรียนนี้พัฒนาทักษะต่อไปนี้ (ตามระดับ 1–5 ของหลักสูตร)

  • mcu.gpio (ระดับ 2)
  • gui.hmi (ระดับ 2)
TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

ตัวอย่างสมบูรณ์ — debounce แบบนับรอบ (level)

button_monitor_ui.c

bool sampled_pressed =
    (0U == Cy_GPIO_Read(button->port, button->pin_num));

if (sampled_pressed == button->last_sample_pressed) {
    if (button->debounce_count < BUTTON_DEBOUNCE_TICKS) {
        button->debounce_count++;
    }
} else {
    button->last_sample_pressed = sampled_pressed;
    button->debounce_count = 0U;
}

if ((button->debounce_count >= BUTTON_DEBOUNCE_TICKS) &&
    (sampled_pressed != button->stable_pressed)) {
    button->stable_pressed = sampled_pressed;   /* commit */
}
TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

ตัวอย่างสมบูรณ์ — จับขอบขาลง (edge)

hw_button_menu_ui.c

static bool btn_pressed_edge(btn_t *b)
{
    bool raw = (0U == Cy_GPIO_Read(b->port, b->pin));
    bool edge = false;
    if (raw == b->last) {
        if (b->cnt < MENU_DEBOUNCE) { b->cnt++; }
        if ((b->cnt >= MENU_DEBOUNCE) && (raw != b->stable)) {
            b->stable = raw;
            if (raw) { edge = true; }   /* press edge */
        }
    } else {
        b->cnt = 0U;
    }
    b->last = raw;
    return edge;
}
TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

จุดที่มักพลาด

  • ลืมตั้ง pull-up แล้วปล่อยขาเป็น high-Z — ขาลอยตอนปล่อย ค่าจะแกว่งตามสัญญาณรบกวน
  • คิดว่ากดค้างแล้วเมนูเลื่อนซ้ำ — จริงคือเลื่อนครั้งเดียวต่อการกด เพราะจับที่ edge ไม่ใช่ level
  • ผสมสองรูปแบบเข้าด้วยกัน — ต้องเลือก level หรือ edge ให้ตรงกับพฤติกรรมที่ต้องการ
TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

ตัวอย่างสมบูรณ์ — build และ flash

แบบฝึกชุด QWA309 ของ Developer Hub (อ้างอิงที่ commit e5c7722) รันบน TESAIoT Dev Kit เท่านั้น เพราะใช้อุปกรณ์บนบอร์ดฐาน

# ในโฟลเดอร์ master template (ดูบทเรียน 1.1)
# 1) ลบไฟล์ของ episode เก่าใน proj_cm55/apps/
# 2) คัดลอกไฟล์ทั้งหมดของ episode นี้ลงใน proj_cm55/apps/
make build
make program     # flash ผ่าน KitProg3

ชื่อปุ่มในคำอธิบายของ Developer Hub (SW9/SW10) ไม่ตรงกับโค้ดของแบบฝึก (SW5/SW6) ให้ยึดตามโค้ดและลายพิมพ์บนบอร์ด

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

ฝึกเติม / แล็บ

  1. ทาย ก่อนแก้: เลือกค่าหนึ่งค่าที่ README ของตัวอย่างอธิบายไว้ในส่วน How แล้วเขียนว่าจะเห็นอะไรเปลี่ยนบนจอหรือใน log
  2. แก้และรัน build + flash แล้วเทียบกับที่ทายไว้ ถ้าไม่ตรง ให้หาว่าเข้าใจส่วนไหนผิด
  3. ทำเพิ่ม ต่อยอดหนึ่งอย่างที่ตัวอย่างยังไม่มี แล้วเก็บภาพหรือวิดีโอไว้ใน portfolio
TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

เช็กความเข้าใจ

  • ทำไมปุ่ม active-low อ่านได้ 0 ตอนกด
  • กดครั้งเดียวแต่ตัวนับขึ้นสองครั้ง สาเหตุคืออะไรและแก้อย่างไร

คำตอบอยู่ใน README ของตัวอย่างและในโค้ด ถ้าตอบข้อใดไม่ได้ ให้กลับไปอ่านส่วน Why / What / How อีกครั้ง

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

ไปต่อ

  • ทบทวนเป้าหมายทั้ง 2 ข้อของบทเรียนนี้ก่อนไปต่อ
  • ถ้าตอบคำถามหน้าที่แล้วไม่ได้ครบ กลับไปอ่าน README ของตัวอย่างส่วน Why / What / How อีกครั้ง
  • พร้อมแล้วไปเปิดบทเรียนถัดไปในโมดูลเดียวกัน
TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

แหล่งอ้างอิง

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

เครดิต

"TESAIoT Firmware Stack: เฟิร์มแวร์ภาษา C บน TESAIoT Dev Kit" จาก TESA Open Knowledge โดยสมาคมสมองกลฝังตัวไทย (Thai Embedded Systems Association: TESA) https://github.com/tesaiot/tesa-qualification-program สัญญาอนุญาต CC BY-NC 4.0

ตัวอย่างโค้ดเป็นผลงานของ TESAIoT Firmware Stack โดยสมาคมสมองกลฝังตัวไทย (TESA) ใน tesaiot/developer-hub รายละเอียดการให้เครดิตอยู่ที่ ATTRIBUTION.md

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0