ข้ามไปยังเนื้อหา

ตัวบ่งชี้ความชื้นและอุณหภูมิจาก SHT4x

  1. อ่านความชื้นสัมพัทธ์และอุณหภูมิจาก SHT4x ผ่าน I2C แล้วแสดงเป็นตัวบ่งชี้
  2. ตั้งเกณฑ์สีของตัวบ่งชี้จากช่วงความชื้นที่สบาย และอธิบายที่มาของเกณฑ์
  3. เปรียบเทียบอุณหภูมิจาก SHT4x กับ DPS368 และอธิบายว่าทำไมอาจไม่เท่ากัน

SHT4x (SHT40/41/45) เป็นเซนเซอร์วัดความชื้นสัมพัทธ์ (RH%) และอุณหภูมิของ Sensirion รุ่น SHT40 แม่นยำ ±1.8 %RH และ ±0.2 °C วัด RH ได้ 0–100% และอุณหภูมิ -40 ถึง +125 °C กินไฟเฉลี่ยต่ำกว่า 0.4 µA ที่อัตราวัด 1 ครั้ง/วินาที ต่างจาก DPS368/BMI270 ตรงที่ SHT4x ไม่มี register map ให้อ่าน-เขียนทีละ address แต่คุยกันด้วย command-based protocol: ส่ง 1 byte สั่งวัด แล้วรอ conversion delay (สูงสุดราว 8.2 ms ที่ high precision) ก่อนอ่านผลกลับ 6 byte พร้อม CRC-8 ตรวจสอบความถูกต้อง (polynomial 0x31 ตามมาตรฐานของ Sensirion) — โปรโตคอลระดับนี้เป็นความรู้จริง ของเซนเซอร์ตระกูลนี้ แต่ ไม่ได้ถูกเขียนเองในไฟล์ของ episode นี้เลย

sht4x_driver.c ของ episode นี้ไม่ได้ส่ง command byte, รอ delay, หรือคำนวณ CRC-8/สูตรแปลงหน่วยเอง — มันเรียก mtb_sht4x_measure_high_precision(i2c_bus, &temp_milli_c, &hum_milli_rh) ของมิดเดิลแวร์ Infineon ตัวเดียว ซึ่ง ทำทุกขั้นตอน (ส่ง command 0xFD, รอ delay, อ่าน 6 byte, ตรวจ CRC, แปลงหน่วยตามสูตร Sensirion) ไว้ให้เสร็จแล้ว คืน ค่ากลับมาเป็นหน่วย milli (milli-°C, milli-%RH) — โค้ดของ episode แค่หาร 1000 เพื่อแปลงเป็นหน่วยปกติ (temperature_c, humidity_rh) โปรโตคอลระดับ byte ที่ README ต้นทางอธิบายไว้ละเอียดจึงเป็นสิ่งที่เกิดขึ้นจริง บนสาย I2C แต่ซ่อนอยู่ในมิดเดิลแวร์ ไม่ใช่โค้ดที่ episode นี้ให้นักเรียนอ่าน — เหมือนกับที่ DPS368 (บทเรียน 3.1) ใช้ xensiv_dps3xx_read() และ BMI270 (บทเรียน 3.2) ใช้ config file ของ Bosch: รูปแบบซ้ำของซีรีส์นี้คือห่อโปรโตคอล ระดับ byte ไว้ในไลบรารีของผู้ผลิตเซนเซอร์เสมอ

เกณฑ์สีจริงมีแค่ 3 โซน ไม่ใช่ 4 โซนตามที่ README ต้นทางอธิบาย

หัวข้อที่มีชื่อว่า “เกณฑ์สีจริงมีแค่ 3 โซน ไม่ใช่ 4 โซนตามที่ README ต้นทางอธิบาย”

sht4x_view.c มีฟังก์ชัน hum_level_color() และ set_comfort_chip() ที่ใช้เกณฑ์เดียวกันคือ RH < 40% = Dry (สีเหลืองอำพัน), 40–60% = Comfort (สีเขียว), RH > 60% = Humid (สีน้ำเงิน) — มีแค่สองจุดตัด (40 กับ 60) ไม่ใช่ สามจุดตัด (30/60/80) และไม่มีโซน “อันตราย” สีแดงแยกต่างหากตามที่ README ต้นทางอธิบาย ช่วง comfort 40–60% ตรงกับ คำแนะนำทั่วไปของ HVAC/ASHRAE สำหรับความชื้นในอาคารที่สบายและลดการเติบโตของเชื้อรา/ไรฝุ่น

เกณฑ์สีถูกกำหนดซ้ำสองที่ ต้องแก้พร้อมกันเสมอ

หัวข้อที่มีชื่อว่า “เกณฑ์สีถูกกำหนดซ้ำสองที่ ต้องแก้พร้อมกันเสมอ”

hum_level_color() (กำหนดสีของ chip) และ set_comfort_chip() (กำหนดข้อความ “Dry”/“Comfort”/“Humid”) เป็นสอง ฟังก์ชันแยกกัน แต่ต่างก็ hard-code ค่า 40.0f และ 60.0f ของตัวเอง ไม่ได้แชร์ constant เดียวกัน — ถ้าแก้เกณฑ์ใน ฟังก์ชันเดียวโดยลืมอีกฟังก์ชัน จะได้ข้อความกับสีที่ไม่ตรงกัน (เช่น ข้อความขึ้น “Humid” แต่สียังเป็นสีเขียวของ “Comfort”)

โค้ดของ episode นี้อยู่ใน Developer Hub (อ้างอิงที่ commit 9a8e3ed) — อ่าน Why ของ README ต้นทาง เพื่อเข้าใจความรู้เรื่องโปรโตคอลของ SHT4x แต่ โค้ดตัวอย่างด้านล่างคัดลอกจากไฟล์จริง (Apache-2.0, tesaiot/developer-hub, commit เดียวกัน) เพราะโปรโตคอลระดับ byte อยู่ในมิดเดิลแวร์ ไม่ใช่ในไฟล์ของ episode และเกณฑ์สีจริงต่างจากที่ README ต้นทางอธิบาย

app_sensor/sht4x/sht4x_driver.c — เรียกมิดเดิลแวร์ตัวเดียว ไม่มี command byte/CRC ในไฟล์นี้:

cy_rslt_t sht4x_driver_read_sample(sht4x_sample_t *sample)
{
int32_t temp_milli_c = 0;
int32_t hum_milli_rh = 0;
cy_rslt_t rslt = mtb_sht4x_measure_high_precision(s_i2c_bus, &temp_milli_c, &hum_milli_rh);
if (CY_RSLT_SUCCESS != rslt)
{
return rslt;
}
/* Middleware returns milli-units; convert once here for UI/presenter layers. */
sample->temperature_c = ((float)temp_milli_c) / 1000.0f;
sample->humidity_rh = ((float)hum_milli_rh) / 1000.0f;
return CY_RSLT_SUCCESS;
}

app_ui/sht4x/sht4x_view.c — เกณฑ์สีตัวจริง สามโซน สองจุดตัด:

static lv_color_t hum_level_color(float humidity_rh)
{
if (humidity_rh < 40.0f)
{
return lv_color_hex(0xD97706); /* Dry */
}
if (humidity_rh <= 60.0f)
{
return lv_color_hex(0x16A34A); /* Comfort */
}
return lv_color_hex(0x2563EB); /* Humid */
}
  • main_example.c ส่ง I2C handle เข้า sht4x_presenter_start() ตรงตามที่ README ต้นทางอธิบาย
  • app_sensor/sht4x/sht4x_config.h — SHT4X_SAMPLE_PERIOD_MS = 1000 (poll ด้วย lv_timer เดียวบน LVGL thread แบบเดียวกับบทเรียน 3.1–3.2) และที่อยู่ I2C หลัก/สำรอง
  • ดูโฟลเดอร์เต็มที่ int_ep03_sht40_indicator/
  • คิดว่าต้องเขียน command byte/CRC-8 เองในโค้ดของ episode นี้ — โปรโตคอลระดับ byte ถูกทำใน mtb_sht4x_measure_high_precision() ของมิดเดิลแวร์แล้ว ไฟล์ sht4x_driver.c ของ episode แค่เรียกมันแล้วแปลง หน่วยจาก milli เป็นหน่วยปกติ
  • จำเกณฑ์สีผิดเป็น 4 โซน (30/60/80%) — เกณฑ์จริงมีแค่ 3 โซนที่จุดตัด 40% และ 60% ไม่มีโซนสีแดง “อันตราย” แยกต่างหาก
  • แก้เกณฑ์สีแค่ฟังก์ชันเดียว — hum_level_color() และ set_comfort_chip() มีค่า 40.0f/60.0f แยกกันคนละที่ ต้องแก้พร้อมกันเสมอ ไม่งั้นข้อความกับสีจะไม่ตรงกัน
Terminal window
# ในโฟลเดอร์ master template (ดูบทเรียน 1.1)
# 1) ลบไฟล์ของ episode เก่าใน proj_cm55/apps/
# 2) คัดลอกไฟล์ทั้งหมดของ episode นี้ลงใน proj_cm55/apps/
make build
make program # flash ผ่าน KitProg3

หรือเปิด ตัวอย่างนี้บน Developer Hub แล้ว flash เฟิร์มแวร์สำเร็จรูป

หน้าจอของ EP03 — SHT40 Indicator บน TESAIoT Dev Kit

ก่อนอ่านโค้ด ให้ทายว่าหน้าจอนี้มี object อะไรบ้าง และอะไรเปลี่ยนเมื่อผู้ใช้แตะหรือเมื่อค่าเซนเซอร์เปลี่ยน

  1. ทาย ก่อนแก้: เลือกค่าหนึ่งค่าที่ README ของตัวอย่างอธิบายไว้ในส่วน How แล้วเขียนว่าจะเห็นอะไรเปลี่ยนบนจอหรือใน log
  2. แก้และรัน build + flash แล้วเทียบกับที่ทายไว้ ถ้าไม่ตรง ให้หาว่าเข้าใจส่วนไหนผิด
  3. ทำเพิ่ม ต่อยอดหนึ่งอย่างที่ตัวอย่างยังไม่มี แล้วเก็บภาพหรือวิดีโอไว้ใน portfolio
  • ความชื้นสัมพัทธ์ขึ้นกับอุณหภูมิอย่างไร
  • ทำไมเซนเซอร์สองตัวบนบอร์ดเดียวกันอ่านอุณหภูมิไม่เท่ากัน
  • เกณฑ์สีของคุณใช้ช่วงความชื้นเท่าไร และอ้างอิงจากอะไร

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

คำถามทบทวน

ลองตอบเองก่อน แล้วค่อยเปิดดูเฉลย

  1. เปิดเครื่องทำความชื้นในห้องแห้ง ค่า RH ไต่จาก 35 → 50 → 65 %RH ชิปสถานะ comfort จะแสดงข้อความตามลำดับใด (เป้าหมายข้อ 2)

    1. Comfort → Comfort → Humid
    2. Dry → Comfort → Comfort
    3. Dry → Comfort → Humid
    4. Dry → Humid → Humid
    ดูเฉลย

    คำตอบ: C. Dry → Comfort → Humid

    set_comfort_chip() ใช้เกณฑ์ < 40 = Dry, 40–60 = Comfort, > 60 = Humid (ข้อความ range_hint บนจอเขียนไว้ตรงกัน) README ของ episode ยังเขียนเกณฑ์ 30/60/80 ซึ่งไม่ตรงกับโค้ดที่ commit นี้

  2. ถ้าแก้เกณฑ์บนจาก 60 เป็น 65 เฉพาะใน hum_level_color() เมื่อ RH = 62 %RH จอจะแสดงอย่างไร (เป้าหมายข้อ 2)

    1. ชิปขึ้น Comfort สีเขียว ตรงกันทั้งหมด
    2. ชิปขึ้นข้อความ Humid แต่เป็นสีเขียว เพราะข้อความใน set_comfort_chip() ยังใช้เกณฑ์ 60 ของตัวเอง
    3. ชิปขึ้น Humid สีน้ำเงิน ตรงกันทั้งหมด
    4. build ไม่ผ่าน
    ดูเฉลย

    คำตอบ: B. ชิปขึ้นข้อความ Humid แต่เป็นสีเขียว เพราะข้อความใน set_comfort_chip() ยังใช้เกณฑ์ 60 ของตัวเอง

    สีมาจาก hum_level_color() แต่ข้อความมาจาก if ใน set_comfort_chip() และ range_hint ก็พิมพ์ตัวเลขไว้อีกที่ เกณฑ์เดียวกันจึงซ้ำอยู่สามจุด การย้ายเกณฑ์ไปเป็นค่าคงที่ตัวเดียวแล้วให้ทุกจุดอ่านจากที่เดียวกันป้องกันความไม่ตรงกันแบบนี้ และทำให้อธิบายที่มาของเกณฑ์ได้ในที่เดียว

  3. ระหว่างทำงาน สายหลวมจนอ่านเซนเซอร์ไม่ได้ติดต่อกันหลายวินาที แล้วกลับมาอ่านได้ presenter ทำอะไร (เป้าหมายข้อ 1)

    1. แสดง error ใหม่ทุกวินาทีจนกว่าจะหาย
    2. หยุด timer ถาวรหลัง error แรก
    3. รีเซ็ตบอร์ด
    4. ขึ้นข้อความ error และ log READ_FAIL ครั้งเดียวเมื่อรหัสเปลี่ยน อ่านต่อทุก 1 วินาที และเมื่ออ่านได้อีกครั้งจะกลับเป็นสถานะ ready พร้อมค่าใหม่
    ดูเฉลย

    คำตอบ: D. ขึ้นข้อความ error และ log READ_FAIL ครั้งเดียวเมื่อรหัสเปลี่ยน อ่านต่อทุก 1 วินาที และเมื่ออ่านได้อีกครั้งจะกลับเป็นสถานะ ready พร้อมค่าใหม่

    sht4x_poll_sensor_cb() ถูกเรียกทุก SHT4X_SAMPLE_PERIOD_MS (1000 ms) ตลอด การแสดง error ถูกกันซ้ำด้วย s_last_status_error และเมื่อ has_new_sample เป็น true จะเรียก sht4x_view_set_ready() อีกครั้ง ผู้ใช้จึงเห็นสถานะจริงโดยจอไม่กระพริบ

  4. บนบอร์ดเดียวกัน SHT4x อ่านได้ 31.2 °C แต่ DPS368 อ่านได้ 33.0 °C ข้อใดอธิบายได้สมเหตุสมผลที่สุด (เป้าหมายข้อ 3)

    1. เซนเซอร์แต่ละตัววัดอุณหภูมิของตัวเองตรงตำแหน่งที่มันอยู่บนบอร์ด ความร้อนจากชิ้นส่วนใกล้เคียง เช่นตัวประมวลผล วงจร Wi-Fi หรือจอ ไม่เท่ากัน และความแม่นยำของแต่ละตัวก็ต่างกัน
    2. DPS368 เสีย เพราะสองตัวควรอ่านได้เท่ากันทุกครั้ง
    3. ตัวหนึ่งรายงานเป็น °F
    4. โค้ดแปลงหน่วยจาก milli-degree ผิด
    ดูเฉลย

    คำตอบ: A. เซนเซอร์แต่ละตัววัดอุณหภูมิของตัวเองตรงตำแหน่งที่มันอยู่บนบอร์ด ความร้อนจากชิ้นส่วนใกล้เคียง เช่นตัวประมวลผล วงจร Wi-Fi หรือจอ ไม่เท่ากัน และความแม่นยำของแต่ละตัวก็ต่างกัน

    SHT4x ออกแบบมาวัดอุณหภูมิและความชื้นของอากาศ (README ระบุ ±0.2 °C) ส่วน DPS368 วัดอุณหภูมิเพื่อใช้ชดเชยการวัดความดันด้วย ทั้งคู่อยู่คนละตำแหน่งบน PCB ที่มีความร้อนสะสม ถ้าต้องการอุณหภูมิห้องจริงควรแยกเซนเซอร์ออกจากแหล่งความร้อน หรือเทียบกับเทอร์โมมิเตอร์อ้างอิง

  5. ถ้าความร้อนจากบอร์ดทำให้อากาศรอบ SHT4x อุ่นกว่าอากาศในห้อง ค่า RH ที่อ่านได้จะเป็นอย่างไรเมื่อเทียบกับ RH ของห้อง (เป้าหมายข้อ 3)

    1. สูงกว่า เพราะอากาศร้อนมีไอน้ำมากกว่า
    2. ต่ำกว่า เพราะปริมาณไอน้ำเท่าเดิม แต่อากาศที่อุ่นขึ้นรับไอน้ำได้มากขึ้น ความชื้นสัมพัทธ์จึงลดลง
    3. เท่ากัน เพราะ RH ไม่ขึ้นกับอุณหภูมิ
    4. สุ่ม ขึ้นกับจังหวะการอ่าน
    ดูเฉลย

    คำตอบ: B. ต่ำกว่า เพราะปริมาณไอน้ำเท่าเดิม แต่อากาศที่อุ่นขึ้นรับไอน้ำได้มากขึ้น ความชื้นสัมพัทธ์จึงลดลง

    RH คือสัดส่วนไอน้ำที่มีอยู่เทียบกับไอน้ำที่อากาศอุณหภูมินั้นรับได้เต็มที่ อากาศอุ่นรับได้มากขึ้น ถ้าไอน้ำเท่าเดิม RH จึงลดลง นี่คือเหตุที่ต้องอ่านอุณหภูมิคู่กับ RH เสมอ และต้องระวังความร้อนจากบอร์ดเมื่อเทียบกับเครื่องวัดในห้อง

อ้างอิงบทเรียนนี้

ถ้านำบทเรียนนี้ไปสอน ทำสไลด์ หรือทำเอกสารต่อ ให้อ้างอิงด้วยข้อความนี้ ถ้าดัดแปลงเนื้อหา ให้เติม (ดัดแปลง)ต่อท้ายชื่อบทเรียน

"ตัวบ่งชี้ความชื้นและอุณหภูมิจาก SHT4x" จาก TESA Open Knowledge โดยสมาคมสมองกลฝังตัวไทย (Thai Embedded Systems Association: TESA) https://github.com/tesaiot/tesa-qualification-program สัญญาอนุญาต CC BY-NC 4.0

ข้อความอ้างอิงภาษาอังกฤษ: "Humidity and temperature indicator from the SHT4x" from TESA Open Knowledge by the Thai Embedded Systems Association (TESA), https://github.com/tesaiot/tesa-qualification-program, licensed under CC BY-NC 4.0

ลิงก์บทเรียน: https://tesaiot.github.io/tesa-qualification-program/courses/tesaiot-firmware-stack/m03-interactive-sensors/l03-sht40-indicator/

บทเรียนนี้ดัดแปลงจากต้นฉบับด้านล่าง เมื่ออ้างอิงให้คงเครดิตต้นฉบับไว้ด้วย
https://github.com/tesaiot/developer-hub/blob/9a8e3ed1d813bfd67fabf6b7ac15c6ff9750b465/int_ep03_sht40_indicator · Code stays in the Developer Hub and is linked at pinned commits, never copied: the episodes, practice codes and main-branch examples are Apache-2.0; the master template and the OPTIGA client carry Infineon/Cypress EULAs.

วิธีอ้างอิง TESA ฉบับเต็ม

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

เนื้อหาเผยแพร่ภายใต้ CC BY-NC 4.0 นำไปใช้ต่อในงานที่ไม่ใช่เพื่อการค้าได้ โปรดอ้างอิงสมาคมสมองกลฝังตัวไทย (TESA) ทุกครั้ง · วิธีอ้างอิง TESA