Forced Stylistic Changes

This commit is contained in:
2025-12-28 10:49:09 +07:00
parent 95f5cd414e
commit f37340d485
15 changed files with 2859 additions and 797 deletions
+16 -6
View File
@@ -1,5 +1,5 @@
#import "PageTemplate.typ": *
#show: page-theme
#show: chapter-page
#set enum(
indent: 3em,
numbering: n => context {
@@ -14,11 +14,19 @@
== ที่มาและความสำคัญของปัญหา
#i ความปลอดภัยนั้นเป็นเรื่องสำคัญสำหรับทุกคนแต่องค์กรแต่ละองค์กรและคนแต่ละคนมักมีความต้องการด้านความปลอดภัยไม่เหมือนกัน แต่ในบางครั้ง เมื่อมีบุคคลหรือองค์กรที่ต้องการเทคโนโลยีด้านความปลอดภัยเหล่านี้ เทคโนโลยีความปลอดภัยนั้นอาจมีราคาสูงเกินกว่าจะเอื้อมถึงได้ ส่งผลให้อาจมีการลดระดับความปลอดภัยลงมา เพิ่มความเสี่ยงของชีวิต ทรัพย์สิน เอกสาร และข้อมูลต่าง ขององค์กรหรือบุคคลนั้น
#i
ความปลอดภัยนั้นเป็นเรื่องสำคัญสำหรับทุกคนแต่องค์กรแต่ละองค์กรและคนแต่ละคนมักมีความต้องการด้านความปลอดภัยไม่เหมือนกัน
แต่ในบางครั้ง เมื่อมีบุคคลหรือองค์กรที่ต้องการเทคโนโลยีด้านความปลอดภัยเหล่านี้
เทคโนโลยีความปลอดภัยนั้นอาจมีราคาสูงเกินกว่าจะเอื้อมถึงได้ ส่งผลให้อาจมีการลดระดับความปลอดภัยลงมา
เพิ่มความเสี่ยงของชีวิต ทรัพย์สิน เอกสาร และข้อมูลต่าง ขององค์กรหรือบุคคลนั้น
#i ในโลกปัจจุบัน อินเทอร์เน็ตนั้นก็เป็นสิ่งที่สำคัญมากเช่นกัน และสถานที่ส่วนใหญ่มักจะมีอินเทอร์เน็ต จึงก่อให้เกิดการที่มีอุปกรณ์อินเทอร์เน็ตรอบตัวเพิ่มขึ้นทุกวัน และได้มีสิ่งที่เรียกว่า Internet of Things (IoT) เกิดขึ้น ซึ่งคืออุปกรณ์ที่ถูกปรับปรุงให้ใช้งานได้ดีขึ้นด้วยเทคโนโลยีไร้สายต่าง เช่น Wi-Fi, Bluetooth, Zigbee, และ Thread
#i ในโลกปัจจุบัน อินเทอร์เน็ตนั้นก็เป็นสิ่งที่สำคัญมากเช่นกัน และสถานที่ส่วนใหญ่มักจะมีอินเทอร์เน็ต
จึงก่อให้เกิดการที่มีอุปกรณ์อินเทอร์เน็ตรอบตัวเพิ่มขึ้นทุกวัน และได้มีสิ่งที่เรียกว่า Internet of Things
(IoT) เกิดขึ้น ซึ่งคืออุปกรณ์ที่ถูกปรับปรุงให้ใช้งานได้ดีขึ้นด้วยเทคโนโลยีไร้สายต่าง เช่น Wi-Fi,
Bluetooth, Zigbee, และ Thread
#i โครงงานนี้จึงมีเป้าหมายที่จะแก้ไขปัญหาที่กล่าวไปข้างต้น พร้อมศึกษาและเรียนรู้เกี่ยวกับเทคโนโลยีไร้สาย Wi-Fi และ NFC เพื่อสร้างอุปกรณ์ยืนยันตัวตนที่ต้นทุนไม่สูงมากและให้ราคาเข้าถึงได้ง่ายขึ้น
#i โครงงานนี้จึงมีเป้าหมายที่จะแก้ไขปัญหาที่กล่าวไปข้างต้น พร้อมศึกษาและเรียนรู้เกี่ยวกับเทคโนโลยีไร้สาย
Wi-Fi และ NFC เพื่อสร้างอุปกรณ์ยืนยันตัวตนที่ต้นทุนไม่สูงมากและให้ราคาเข้าถึงได้ง่ายขึ้น
== วัตถุประสงค์ของโครงงาน
@@ -40,9 +48,11 @@
== นิยามศัพท์เฉพาะ
#i เครื่องยืนยันตัวตนด้วย NFC คืออุปกรณ์ความปลอดภัยที่มีหน้าที่ในการยืนยันตัวตนบุคคลที่เข้าออกพื้นที่ โดยใช้เทคโนโลยี NFC เป็นระบบยืนยันตัวตนบุคคลและใช้เซนเซอร์ตรวจจับความเคลื่อนใหวในการตรวจสอบหากมีบุคคลเข้าไปโดยไม่ได้รับอนุญาต
#i เครื่องยืนยันตัวตนด้วย NFC คืออุปกรณ์ความปลอดภัยที่มีหน้าที่ในการยืนยันตัวตนบุคคลที่เข้าออกพื้นที่
โดยใช้เทคโนโลยี NFC
เป็นระบบยืนยันตัวตนบุคคลและใช้เซนเซอร์ตรวจจับความเคลื่อนใหวในการตรวจสอบหากมีบุคคลเข้าไปโดยไม่ได้รับอนุญาต
#pagebreak()
#show: page-theme
== ผลที่คาดว่าจะได้รับ
+204 -71
View File
@@ -3,18 +3,31 @@
= ภาษาซี (C Programming Language) <cprogramming>
#i ภาษาซีเป็นภาษาโปรแกรมสำหรับวัตถุประสงค์ทั่วไปสร้างขึ้นในช่วงทศวรรษ 1970 โดยเดนนิสริตชีและยังคงได้รับความนิยมและใช้งานอย่างกว้างขวางด้วยการออกแบบภาษาซีทำให้โปรแกรมเมอร์สามารถเข้าถึงคุณลักษณะต่างๆของสถาปัตยกรรมซีพียูทั่วไปได้โดยตรง ซึ่งปรับแต่งให้เหมาะกับชุดคำสั่ง เป้าหมาย ภาษาซี ถูกนำมาใช้และยังคงนำมาใช้ในการพัฒนาระบบปฏิบัติการไดรเวอร์อุปกรณ์และสแต็กโปรโตคอลแต่การใช้งานในซอฟต์แวร์แอปพลิเคชั่นกำลังลดลงภาษาซีถูกนำมาใช้ในคอมพิวเตอร์ตั้งแต่ซูเปอร์คอมพิวเตอร์ขนาดใหญ่ที่สุดไปจนถึงไมโครคอนโทรลเลอร์ขนาดเล็กที่สุดและระบบฝังตัว
#i ภาษาซีเป็นภาษาโปรแกรมสำหรับวัตถุประสงค์ทั่วไปสร้างขึ้นในช่วงทศวรรษ 1970
โดยเดนนิสริตชีและยังคงได้รับความนิยมและใช้งานอย่างกว้างขวางด้วยการออกแบบภาษาซีทำให้โปรแกรมเมอร์สามารถเข้าถึงคุณลักษณะต่างๆของสถาปัตยกรรมซีพียูทั่วไปได้โดยตรง
ซึ่งปรับแต่งให้เหมาะกับชุดคำสั่ง เป้าหมาย ภาษาซี
ถูกนำมาใช้และยังคงนำมาใช้ในการพัฒนาระบบปฏิบัติการไดรเวอร์อุปกรณ์และสแต็กโปรโตคอลแต่การใช้งานในซอฟต์แวร์แอปพลิเคชั่นกำลังลดลงภาษาซีถูกนำมาใช้ในคอมพิวเตอร์ตั้งแต่ซูเปอร์คอมพิวเตอร์ขนาดใหญ่ที่สุดไปจนถึงไมโครคอนโทรลเลอร์ขนาดเล็กที่สุดและระบบฝังตัว
#i
ภาษาซีเป็นภาษาเชิงกระบวนการที่จำเป็นรองรับการเขียนโปรแกรมแบบมีโครงสร้างขอบเขตตัวแปรเชิงศัพท์และการเรียกซ้ำด้วยระบบชนิดข้อมูลแบบคงที่ภาษาซีถูกออกแบบมาเพื่อการคอมไพล์เพื่อให้สามารถเข้าถึงหน่วยความจำ และโครงสร้างภาษา ในระดับต่ำซึ่งแมปกับคำสั่งเครื่องได้อย่างมีประสิทธิภาพ โดยทั้งหมดนี้รองรับรันไทม์ขั้นต่ำ แม้จะมีความสามารถในระดับต่ำ แต่ภาษาซีก็ถูกออกแบบมาเพื่อสนับสนุนการเขียนโปรแกรมข้ามแพลตฟอร์ม โปรแกรมซี ที่สอดคล้องกับมาตรฐานที่เขียนขึ้นโดยคำนึงถึงความสามารถในการพกพาสามารถคอมไพล์สำหรับแพลตฟอร์มคอมพิวเตอร์และระบบปฏิบัติการที่หลากหลาย โดยมีการเปลี่ยนแปลงซอร์สโคดเพียงเล็กน้อย
ภาษาซีเป็นภาษาเชิงกระบวนการที่จำเป็นรองรับการเขียนโปรแกรมแบบมีโครงสร้างขอบเขตตัวแปรเชิงศัพท์และการเรียกซ้ำด้วยระบบชนิดข้อมูลแบบคงที่ภาษาซีถูกออกแบบมาเพื่อการคอมไพล์เพื่อให้สามารถเข้าถึงหน่วยความจำ
และโครงสร้างภาษา ในระดับต่ำซึ่งแมปกับคำสั่งเครื่องได้อย่างมีประสิทธิภาพ โดยทั้งหมดนี้รองรับรันไทม์ขั้นต่ำ
แม้จะมีความสามารถในระดับต่ำ แต่ภาษาซีก็ถูกออกแบบมาเพื่อสนับสนุนการเขียนโปรแกรมข้ามแพลตฟอร์ม
โปรแกรมซี
ที่สอดคล้องกับมาตรฐานที่เขียนขึ้นโดยคำนึงถึงความสามารถในการพกพาสามารถคอมไพล์สำหรับแพลตฟอร์มคอมพิวเตอร์และระบบปฏิบัติการที่หลากหลาย
โดยมีการเปลี่ยนแปลงซอร์สโคดเพียงเล็กน้อย
#i แม้ว่าทั้งภาษาซีและไลบรารีมาตรฐานของภาษา ซีจะไม่ได้มีคุณสมบัติยอดนิยมบางอย่างที่พบในภาษาอื่น แต่ก็มีความยืดหยุ่นเพียงพอที่จะรองรับคุณสมบัติเหล่านั้นได้ ตัวอย่างเช่นการวางแนววัตถุและการเก็บขยะนั้นจัดทำโดยไลบรารีภายนอก GLib Object System และ Boehm garbage collector ตามลำดับ
#i แม้ว่าทั้งภาษาซีและไลบรารีมาตรฐานของภาษา ซีจะไม่ได้มีคุณสมบัติยอดนิยมบางอย่างที่พบในภาษาอื่น
แต่ก็มีความยืดหยุ่นเพียงพอที่จะรองรับคุณสมบัติเหล่านั้นได้
ตัวอย่างเช่นการวางแนววัตถุและการเก็บขยะนั้นจัดทำโดยไลบรารีภายนอก GLib Object System และ
Boehm garbage collector ตามลำดับ
#i ตั้งแต่ปี 2000 เป็นต้นมาภาษาซี ได้รับการจัดอันดับอย่างต่อเนื่องให้อยู่ในอันดับสี่ภาษาสูงสุดในดัชนี TIOBE ซึ่งเป็นการวัดความนิยมของภาษาการเขียนโปรแกรม
#i ตั้งแต่ปี 2000 เป็นต้นมาภาษาซี ได้รับการจัดอันดับอย่างต่อเนื่องให้อยู่ในอันดับสี่ภาษาสูงสุดในดัชนี TIOBE
ซึ่งเป็นการวัดความนิยมของภาษาการเขียนโปรแกรม
== ตัวอย่าง "hello, world"
#i โดยการเรียนภาษาเขียนโปรแกรมใหม่ ต้องเริ่มด้วยการเขียนโปรแกรมในภาษานั้น โดยโปรแกรมแรกที่จะเขียนนั้นเหมือน กันในทุกภาษา คือการพิมพ์ "hello, world"
#i โดยการเรียนภาษาเขียนโปรแกรมใหม่ ต้องเริ่มด้วยการเขียนโปรแกรมในภาษานั้น
โดยโปรแกรมแรกที่จะเขียนนั้นเหมือน กันในทุกภาษา คือการพิมพ์ "hello, world"
```c
#include <stdio.h>
@@ -25,41 +38,64 @@ int main()
}
```
#i คุณสามารถบันทึกไฟล์นี้เป็นไฟล์ที่มีส่วนขยายไฟล์ `.c` เช่น `hello.c` ได้เลย แต่การจะรันโปรแกรมนี้นั้นขึ้นอยู่กับระบบปฏิบัติการของคุณ ตัวอย่างเช่นบนระบบที่มีชุดคอมไพเลอร์ GCC (หรือ MinGW สำหรับเวอร์ชันบน Windows) ติดตั้งอยู่สามารถใช้คำสั่ง
#i คุณสามารถบันทึกไฟล์นี้เป็นไฟล์ที่มีส่วนขยายไฟล์ `.c` เช่น `hello.c` ได้เลย
แต่การจะรันโปรแกรมนี้นั้นขึ้นอยู่กับระบบปฏิบัติการของคุณ ตัวอย่างเช่นบนระบบที่มีชุดคอมไพเลอร์ GCC (หรือ
MinGW สำหรับเวอร์ชันบน Windows) ติดตั้งอยู่สามารถใช้คำสั่ง
```bash
cc hello.c
```
เพื่อคอมไพล์ไฟล์ได้ หากคุณไม่ได้ทำอะไรผิดพลาดไป เช่นการพิมพ์ตกหรือการสะกดผิด การคอมไพล์จะดำเนินการไปอย่างเงียบ และสร้างไฟล์ไบนารีชื่อ `a.out` ออกมา คุณสามารถรันไฟล์นั้นบนเทอร์มินัลของคุณได้โดยการพิมพ์ `./a.out` แล้วจึงจะได้ข้อความดังต่อไปนี้ออกมา
เพื่อคอมไพล์ไฟล์ได้ หากคุณไม่ได้ทำอะไรผิดพลาดไป เช่นการพิมพ์ตกหรือการสะกดผิด
การคอมไพล์จะดำเนินการไปอย่างเงียบ และสร้างไฟล์ไบนารีชื่อ `a.out` ออกมา
คุณสามารถรันไฟล์นั้นบนเทอร์มินัลของคุณได้โดยการพิมพ์ `./a.out` แล้วจึงจะได้ข้อความดังต่อไปนี้ออกมา
```
hello, world
```
#i โดยโปรแกรมภาษา C นั้น ไม่ว่าจะขนาดใด จะประกอบไปด้วยฟังก์ชันและตัวแปร โดยฟังก์ชันจะประกอบไปด้วยสเตตเมนต์ (statements) ที่ระบุสิ่งที่โปรแกรมจะต้องกระทำ และตัวแปรนั้นกำหนดค่าที่จะถูกใช้งานในการกระทำเหล่านั้น โดยในตัวอย่างมีฟังก์ชันชื่อ `main` ซึ่งปกติแล้วคุณมีอิสระในการตั้งชื่อฟังก์ชันว่าอะไรก็ได้ แต่ฟังก์ชัน `main` นั้นพิเศษ เพราะโปรแกรมของคุณนั้นมีจุดเริ่มต้นที่ `main` ดังนั้น โปรแกรมทุกโปรแกรมต้องมี `main` อยู่สักที่
#i โดยโปรแกรมภาษา C นั้น ไม่ว่าจะขนาดใด จะประกอบไปด้วยฟังก์ชันและตัวแปร
โดยฟังก์ชันจะประกอบไปด้วยสเตตเมนต์ (statements) ที่ระบุสิ่งที่โปรแกรมจะต้องกระทำ
และตัวแปรนั้นกำหนดค่าที่จะถูกใช้งานในการกระทำเหล่านั้น โดยในตัวอย่างมีฟังก์ชันชื่อ `main`
ซึ่งปกติแล้วคุณมีอิสระในการตั้งชื่อฟังก์ชันว่าอะไรก็ได้ แต่ฟังก์ชัน `main` นั้นพิเศษ
เพราะโปรแกรมของคุณนั้นมีจุดเริ่มต้นที่ `main` ดังนั้น โปรแกรมทุกโปรแกรมต้องมี `main` อยู่สักที่
#i โดยปกติแล้วฟังก์ชัน `main` นั้นจะเรียกใช้ฟังก์ชันอื่น เพื่อทำงานให้มัน โดยอาจเป็นฟังก์ชันที่คุณเขียน หรือฟังก์ชันที่มาจากไลบรารีที่คุณใช้งาน ในบรรทัดแรกของโปรแกรมตัวอย่าง
#i โดยปกติแล้วฟังก์ชัน `main` นั้นจะเรียกใช้ฟังก์ชันอื่น เพื่อทำงานให้มัน โดยอาจเป็นฟังก์ชันที่คุณเขียน
หรือฟังก์ชันที่มาจากไลบรารีที่คุณใช้งาน ในบรรทัดแรกของโปรแกรมตัวอย่าง
```c
#include <stdio.h>
```
มีหน้าที่ในการนำเข้าข้อมูลเกี่ยวกับไลบรารีอินพุต/เอาต์พุตมาตรฐาน โดยบรรทัดนี้นั้นอยู่ในไฟล์ ภาษา C หลายไฟล์ เนื่องจากการแสดงผลข้อมูลนั้นเป็นการกระทำที่ถูกกระทำบ่อย
มีหน้าที่ในการนำเข้าข้อมูลเกี่ยวกับไลบรารีอินพุต/เอาต์พุตมาตรฐาน โดยบรรทัดนี้นั้นอยู่ในไฟล์ ภาษา C
หลายไฟล์ เนื่องจากการแสดงผลข้อมูลนั้นเป็นการกระทำที่ถูกกระทำบ่อย
#i หนึ่งในวิธีการโอนถ่ายข้อมูลระหว่างฟังก์ชันคือการมอบรายการของข้อมูลที่ต้องการมอบให้แก่ฟังก์ชัน โดยค่าที่มอบให้ฟังก์ชันเหล่านั้นมีชื่อเรียกว่า อาร์กิวเมนต์ (arguments) ซึ่งวงเล็บที่ตามหลังชื่อฟังก์ชันนั้นคือวงเล็บที่จะครอบรายการอาร์กิวเมนต์ โดยในตัวอย่างฟังก์ชัน `main` นั้นไม่หวังค่าอาร์กิวเมนต์ใด สังเกตได้จาก `()` ที่เป็นรายการที่ว่างปล่าว
#i หนึ่งในวิธีการโอนถ่ายข้อมูลระหว่างฟังก์ชันคือการมอบรายการของข้อมูลที่ต้องการมอบให้แก่ฟังก์ชัน
โดยค่าที่มอบให้ฟังก์ชันเหล่านั้นมีชื่อเรียกว่า อาร์กิวเมนต์ (arguments)
ซึ่งวงเล็บที่ตามหลังชื่อฟังก์ชันนั้นคือวงเล็บที่จะครอบรายการอาร์กิวเมนต์ โดยในตัวอย่างฟังก์ชัน `main`
นั้นไม่หวังค่าอาร์กิวเมนต์ใด สังเกตได้จาก `()` ที่เป็นรายการที่ว่างปล่าว
#i สเตตเมนต์ที่อยู่ภายในฟังก์ชันนั้นจะถูกครอบด้วยวงเล็บปีกกา `{}` ซึ่งในฟังก์ชัน `main` มีแค่ 1 สเตตเมนต์ คือ
#i สเตตเมนต์ที่อยู่ภายในฟังก์ชันนั้นจะถูกครอบด้วยวงเล็บปีกกา `{}` ซึ่งในฟังก์ชัน `main` มีแค่ 1
สเตตเมนต์ คือ
```c
printf("hello, world\n");
```
#i โดยฟังก์ชันนั้นจะถูกเรียกใช้ได้โดยการเรียกชื่อมัน ตามด้วยรายการอาร์กิวเมนต์ที่ถูกครอบด้วยวงเล็บ ดังนั้น สเตตเมนต์นี้จึงมีการเรียกใช้ฟังก์ชัน `printf` ด้วยอาร์กิวเมนต์ `"hello, world\n"` โดยที่ `printf` เป็นฟังก์ชันจากไลบรารีที่ทำการพรินต์ข้อมูล (ซึ่งการพรินต์ในที่นี้คือการแสดงผลข้อความบนหน้าจอในเทอร์มินัล) และข้อมูลที่มันแสดงนั้นก็คือรายการอักขระที่ถูกครอบอยู่ด้วยเครื่องหมายอัญประกาศนั่นเอง
#i โดยฟังก์ชันนั้นจะถูกเรียกใช้ได้โดยการเรียกชื่อมัน ตามด้วยรายการอาร์กิวเมนต์ที่ถูกครอบด้วยวงเล็บ
ดังนั้น สเตตเมนต์นี้จึงมีการเรียกใช้ฟังก์ชัน `printf` ด้วยอาร์กิวเมนต์ `"hello, world\n"` โดยที่
`printf` เป็นฟังก์ชันจากไลบรารีที่ทำการพรินต์ข้อมูล
(ซึ่งการพรินต์ในที่นี้คือการแสดงผลข้อความบนหน้าจอในเทอร์มินัล)
และข้อมูลที่มันแสดงนั้นก็คือรายการอักขระที่ถูกครอบอยู่ด้วยเครื่องหมายอัญประกาศนั่นเอง
#i รายการอักขระที่ถูกครอบด้วยเครื่องหมายอัญประกาศ เช่น `"hello, world\n"` นั้นมีชื่อเรียกว่า character string หรือ string constant และในตัวอย่างนี้นั้น เราจะมีการใช้รายการอักขระนี้เป็นเพียงแค่อาร์กิวเมนต์ของ `printf` และฟังก์ชันอื่น
#i รายการอักขระที่ถูกครอบด้วยเครื่องหมายอัญประกาศ เช่น `"hello, world\n"` นั้นมีชื่อเรียกว่า
character string หรือ string constant และในตัวอย่างนี้นั้น
เราจะมีการใช้รายการอักขระนี้เป็นเพียงแค่อาร์กิวเมนต์ของ `printf` และฟังก์ชันอื่น
#i ลำดับตัวอักษร `\n` ในสตริงคือสัญกรณ์ภาษา C สำหรับ#emph[ตัวอักษรบรรทัดใหม่] ซึ่งเมื่อถูกพรินต์แล้วจะให้เอาต์พุตไปอยู่ทางด้านซ้ายของบรรทัดใหม่ โดยหากไม่ใส่ `\n` (ซึ่งคุณสามารถทดลองได้เลย) คุณจะพบว่าไม่มีการขึ้นบรรทัดใหม่ของข้อความ และคุณต้องใช้ `\n` ในการขึ้นบรรทัดใหม่ และหากคุณลองทำแบบนี้:
#i ลำดับตัวอักษร `\n` ในสตริงคือสัญกรณ์ภาษา C สำหรับ#emph[ตัวอักษรบรรทัดใหม่]
ซึ่งเมื่อถูกพรินต์แล้วจะให้เอาต์พุตไปอยู่ทางด้านซ้ายของบรรทัดใหม่ โดยหากไม่ใส่ `\n`
(ซึ่งคุณสามารถทดลองได้เลย) คุณจะพบว่าไม่มีการขึ้นบรรทัดใหม่ของข้อความ และคุณต้องใช้ `\n`
ในการขึ้นบรรทัดใหม่ และหากคุณลองทำแบบนี้:
```c
printf("Hello, world
@@ -68,7 +104,8 @@ printf("Hello, world
คอมไพเลอร์ภาษา C นั้นจะแสดงข้อความแสดงข้อผิดพลาดขึ้นมา
#i `printf` นั้นจะไม่มีทางใส่ตัวอักษรขึ้นบรรทัดใหม่ให้โดยอัตโนมัติ ดังนั้นคุณสามารถเรียกใช้ฟังก์ชันหลาย ครั้งเพื่อค่อย สร้างเอาต์พุตออกมาได้ โดยที่โปรแกรมแรกของเราจะสามารถเขียนแบบนี้ได้
#i `printf` นั้นจะไม่มีทางใส่ตัวอักษรขึ้นบรรทัดใหม่ให้โดยอัตโนมัติ ดังนั้นคุณสามารถเรียกใช้ฟังก์ชันหลาย
ครั้งเพื่อค่อย สร้างเอาต์พุตออกมาได้ โดยที่โปรแกรมแรกของเราจะสามารถเขียนแบบนี้ได้
```c
#include <stdio.h>
@@ -83,11 +120,17 @@ int main()
แล้วข้อความที่แสดงออกมาจะยังคงเดิม
#i คุณสามารถสังเกตได้ว่า `\n` นั้นจะแทนตัวอักษรตัวเดียว โดยสัญกรณ์ _escape sequence_ เช่น `\n` คือรูปแบบในการเขียนตัวอักษรที่อาจพิมพ์ได้ยากหรือตัวอักษรล่องหน โดยสัญกรณ์อื่น ในประเภทเดียวกันมีตัวอย่างเช่น `\t` สำหรับตัวอักษรแท็บ, `\b` สำหรับ backspace, `\"` สำหรับการพิมพ์สัญลักษณ์อัญประกาศ (ไม่เช่นนั้นตัวอักษรอัญประกาศจะถูกถือว่าเป็นตัวอักษรในการเริ่มต้น/สิ้นสุดของสตริง), และ `\\` สำหรับการพิมพ์ตัวอักษร backslash เอง
#i คุณสามารถสังเกตได้ว่า `\n` นั้นจะแทนตัวอักษรตัวเดียว โดยสัญกรณ์ _escape sequence_ เช่น
`\n` คือรูปแบบในการเขียนตัวอักษรที่อาจพิมพ์ได้ยากหรือตัวอักษรล่องหน โดยสัญกรณ์อื่น
ในประเภทเดียวกันมีตัวอย่างเช่น `\t` สำหรับตัวอักษรแท็บ, `\b` สำหรับ backspace, `\"`
สำหรับการพิมพ์สัญลักษณ์อัญประกาศ
(ไม่เช่นนั้นตัวอักษรอัญประกาศจะถูกถือว่าเป็นตัวอักษรในการเริ่มต้น/สิ้นสุดของสตริง), และ `\\`
สำหรับการพิมพ์ตัวอักษร backslash เอง
== ตัวแปร (Variables)
#i ตัวแปรในภาษา C เบื้องต้นแล้วประกอบไปด้วยประเภทของข้อมูล และชื่อตัวแปร โดยที่ชื่อตัวแปรนั้นสามารถเป็นรายการที่ถูกแบ่งด้วยเครื่องหมายจุลภาคได้ด้วยเช่นกัน ตัวอย่างคือ
#i ตัวแปรในภาษา C เบื้องต้นแล้วประกอบไปด้วยประเภทของข้อมูล และชื่อตัวแปร
โดยที่ชื่อตัวแปรนั้นสามารถเป็นรายการที่ถูกแบ่งด้วยเครื่องหมายจุลภาคได้ด้วยเช่นกัน ตัวอย่างคือ
```c
int data;
@@ -96,14 +139,20 @@ float a, b, c;
== ประเภทข้อมูล (Data Types)
#i ข้อมูลที่เกี่ยวข้องกับตัวเลขมักมีประเภท *unsigned* และ *signed* โดยความแตกต่างหากอธิบายสั้น คือ
#i ข้อมูลที่เกี่ยวข้องกับตัวเลขมักมีประเภท *unsigned* และ *signed* โดยความแตกต่างหากอธิบายสั้น
คือ
- *Signed (มีเครื่องหมาย):* ตัวเลขที่สามารถติดลบได้ ระยะข้อมูลตัวอย่างคือ -128 ถึง 127
- *Unsigned (ไม่มีเครื่องหมาย):* ตัวเลขที่ไม่สามารถติดลบได้ ระยะข้อมูลตัวอย่างคือ 0 ถึง 255
#i จะสังเกตได้ว่า ข้อมูลประเภท unsigned นั้นสามารถเก็บตัวเลขบวกได้จำนวนมากกว่า คือสูงสุดที่ 255 แต่หากนำค่าสัมบูรณ์ (absolute value) ของระยะข้อมูลแบบ signed มาบวกกัน เช่น\ #math.equation($|-128| + |127|$, alt: "ค่าสัมบูรณ์ของ -128 บวกค่าสัมบูรณ์ของ 127") จะพบว่าได้ค่า 255 หมายความว่า จริง แล้วข้อมูลประเภท signed สามารถเก็บข้อมูลได้ 255 ตัวเลขเช่นกัน เพียงแต่ว่าครึ่งหนึ่งของตัวเลขที่สามารถเก็บได้เป็นตัวเลขติดลบ
#i จะสังเกตได้ว่า ข้อมูลประเภท unsigned นั้นสามารถเก็บตัวเลขบวกได้จำนวนมากกว่า คือสูงสุดที่ 255
แต่หากนำค่าสัมบูรณ์ (absolute value) ของระยะข้อมูลแบบ signed มาบวกกัน เช่น\
#math.equation($|-128| + |127|$, alt: "ค่าสัมบูรณ์ของ -128 บวกค่าสัมบูรณ์ของ 127")
จะพบว่าได้ค่า 255 หมายความว่า จริง แล้วข้อมูลประเภท signed สามารถเก็บข้อมูลได้ 255
ตัวเลขเช่นกัน เพียงแต่ว่าครึ่งหนึ่งของตัวเลขที่สามารถเก็บได้เป็นตัวเลขติดลบ
*หมายเหตุ:* เลขคณิตจำนวนเต็มมีนิยามแตกต่างกันสำหรับชนิดจำนวนเต็มแบบ signed และ unsigned โปรดดูตัวดำเนินการเลขคณิต โดยเฉพาะอย่างยิ่งการโอเวอร์โฟลว์จำนวนเต็ม
*หมายเหตุ:* เลขคณิตจำนวนเต็มมีนิยามแตกต่างกันสำหรับชนิดจำนวนเต็มแบบ signed และ unsigned
โปรดดูตัวดำเนินการเลขคณิต โดยเฉพาะอย่างยิ่งการโอเวอร์โฟลว์จำนวนเต็ม
=== ประเภทบูลีน (Boolean)
@@ -119,8 +168,10 @@ float a, b, c;
- `short int` (หรืออีกชื่อหนึ่งคือ `short` และสามารถใช้คีย์เวิร์ด `signed` ได้)
- `unsigned short int` (หรือ `unsigned short`)
- `int` (หรือ `signed int`) \
คือประเภทข้อมูลตัวเลขที่ปกติที่สุด และจะถูกการันตีว่าจะมีขนาดขั้นต่ำ 16 บิตเสมอ โดยระบบทั่วไปส่วนใหญ่ในปัจจุบันจะเป็น 32 บิต
- `unsigned int` (หรือเพียงแค่ `unsigned`): คือประเภท `int` ในแบบ `unsigned`, มี modulo arithmetic, และเหมาะสมสำหรับการเปลี่ยนแปลงบิต
คือประเภทข้อมูลตัวเลขที่ปกติที่สุด และจะถูกการันตีว่าจะมีขนาดขั้นต่ำ 16 บิตเสมอ
โดยระบบทั่วไปส่วนใหญ่ในปัจจุบันจะเป็น 32 บิต
- `unsigned int` (หรือเพียงแค่ `unsigned`): คือประเภท `int` ในแบบ `unsigned`, มี
modulo arithmetic, และเหมาะสมสำหรับการเปลี่ยนแปลงบิต
- `long int` (หรือ `long`)
- `unsigned long int` (หรือ `unsigned long`)
@@ -130,10 +181,14 @@ float a, b, c;
- `long long int` (หรือ `long long`)
- `unsigned long long int` (หรือ `unsigned long long`)
- มีเพิ่มตั้งแต่ C23:
- `_BitInt(n)` (หรือ `signed _BitInt(n)`): ประเภทข้อมูล signed แบบมีขนาดชัดเจน โดย n แทนด้วยจำนวนบิต (รวมถึงบิตเครื่องหมาย และ n จะต้องไม่มากกว่า `BITINT_MAXWIDTH` จากไฟล์ `<limits.h>`)
- `unsigned _BitInt(n)`: เหมือนข้างต้น เพียงแค่เป็นประเภท unsigned (และไม่มีบิตเครื่องหมาย)
- `_BitInt(n)` (หรือ `signed _BitInt(n)`): ประเภทข้อมูล signed แบบมีขนาดชัดเจน โดย
n แทนด้วยจำนวนบิต (รวมถึงบิตเครื่องหมาย และ n จะต้องไม่มากกว่า `BITINT_MAXWIDTH`
จากไฟล์ `<limits.h>`)
- `unsigned _BitInt(n)`: เหมือนข้างต้น เพียงแค่เป็นประเภท unsigned
(และไม่มีบิตเครื่องหมาย)
และเหมือนประเภทข้อมูลอื่น คุณสามารถเรียงคีย์เวิร์ดแบบใดก็ได้ เช่น `unsigned long long int` และ `long int unsigned long` นั้นเหมือนกัน
และเหมือนประเภทข้อมูลอื่น คุณสามารถเรียงคีย์เวิร์ดแบบใดก็ได้ เช่น `unsigned long long int`
และ `long int unsigned long` นั้นเหมือนกัน
ตารางต่อไปนี้สรุปประเภทตัวเลขทั้งหมดและคุณสมบัติของมัน
@@ -247,13 +302,21 @@ float a, b, c;
และนอกจากค่าบิตขั้นต่ำ มาตรฐาน C นั้นการันตีว่า:
#i ```c 1``` == ```c sizeof(char)``` #sym.lt.eq ```c sizeof(short)``` #sym.lt.eq ```c sizeof(int)``` #sym.lt.eq ```c sizeof(long)``` #sym.lt.eq ```c sizeof(long long)```
#i ```c 1``` == ```c sizeof(char)``` #sym.lt.eq ```c sizeof(short)``` #sym.lt.eq
```c sizeof(int)``` #sym.lt.eq ```c sizeof(long)``` #sym.lt.eq
```c sizeof(long long)```
*หมายเหตุ:* เงื่อนไขนี้อนุญาตกรณีสุดขีดที่ทุกประเภทมีขนาด 64 บิตและ `sizeof` คืนค่า `1` สำหรับทุกประเภท
*หมายเหตุ:* เงื่อนไขนี้อนุญาตกรณีสุดขีดที่ทุกประเภทมีขนาด 64 บิตและ `sizeof` คืนค่า `1`
สำหรับทุกประเภท
==== รูปแบบข้อมูล (data model)
#i รูปแบบข้อมูล หรือ data model คือรูปแบบการเก็บข้อมูลของโปรแกรมซึ่งเป็นสิ่งที่กำหนดขนาดของตัวแปร โดยรูปแบบข้อมูลนั้นจะถูกกำหนดโดยแพลตฟอร์มเป้าหมาย ซึ่งมีหน่วยประมวลผลและระบบปฏิบัติการเป็นปัจจัยหลัก โดยตามตารางในหัวข้อก่อนหน้า หลัก แล้วมีรูปแบบข้อมูลอยู่ 4 รูปแบบ คือ LP32, ILP32, LLP64, และ LP64 ซึ่งหากต้องการหาความหาย L หมายถึง Long, P หมายถึง Pointer, และ I หมายถึง Integer (จำนวนเต็ม) แล้วตามด้วยเลขบิต ดังนั้น สรุปแล้วจึงจะมีความหมายดังนี้
#i รูปแบบข้อมูล หรือ data model คือรูปแบบการเก็บข้อมูลของโปรแกรมซึ่งเป็นสิ่งที่กำหนดขนาดของตัวแปร
โดยรูปแบบข้อมูลนั้นจะถูกกำหนดโดยแพลตฟอร์มเป้าหมาย
ซึ่งมีหน่วยประมวลผลและระบบปฏิบัติการเป็นปัจจัยหลัก โดยตามตารางในหัวข้อก่อนหน้า หลัก
แล้วมีรูปแบบข้อมูลอยู่ 4 รูปแบบ คือ LP32, ILP32, LLP64, และ LP64 ซึ่งหากต้องการหาความหาย L
หมายถึง Long, P หมายถึง Pointer, และ I หมายถึง Integer (จำนวนเต็ม) แล้วตามด้วยเลขบิต
ดังนั้น สรุปแล้วจึงจะมีความหมายดังนี้
ระบบ 32 บิต:
- LP32 หรือ 2/4/4: `long` และ Pointer มีขนาด 32 บิต
@@ -268,7 +331,8 @@ float a, b, c;
- LP64 หรือ 4/8/8: `long` และ Pointer มีขนาด 64 บิต
- ระบบ Unix และเสมือน Unix (Linux, Mac OS X)
#i รูปแบบอื่น นั้นหาได้ยาก ตัวอย่างเช่น ILP64 (8/8/8: `int`, `long`, และ Pointer ขนาด 64 บิต) ที่มีการใช้งานแค่ในระบบ Unix 64 บิตช่วงเริ่มต้น (เช่น Unicos บน Cray)
#i รูปแบบอื่น นั้นหาได้ยาก ตัวอย่างเช่น ILP64 (8/8/8: `int`, `long`, และ Pointer ขนาด
64 บิต) ที่มีการใช้งานแค่ในระบบ Unix 64 บิตช่วงเริ่มต้น (เช่น Unicos บน Cray)
และโปรดจำไว้ว่า ตัวเลขที่มีขนาดแน่นอนนั้นมีให้ใช้งานใน `<stdint.h>` ตั้งแต่ C99
@@ -277,12 +341,20 @@ float a, b, c;
ภาษา C นั้นมีประเภทข้อมูลสำหรับแทนตัวเลขทศนิยมจริง 3 (หรือ 6 ตั้งแต่ C23) ประเภท
- `float`: จำนวนทศนิยมความแม่นยำเดี่ยว ตรงกับฟอร์แมตมาตรฐาน IEEE-754 binary32 หากรองรับ
- `double`: จำนวนทศนิยมความแม่นยำสองเท่า ตรงกับฟอร์แมตมาตรฐาน IEEE-754 binary64 หากรองรับ
- `long double`: จำนวนทศนิยมความแม่นยำเพิ่มเติม ตรงกับฟอร์แมตมาตรฐาน IEEE-754 binary128 หากรองรับ มิฉะนั้นจะตรงกับ IEEE-754 binary64-extended หากรองรับ มิฉะนั้นจะตรงกับรูปแบบจำนวนทศนิยมที่ไม่ตรงกับมาตรฐาน IEEE-754 รูปแบบใดก็ได้ตราบใดที่มีความแม่นยำกว่า binary64 และระยะข้อมูลนั้นอย่างน้อยก็ต้องดีเท่า binary64 และหากไม่รองรับทั้งหมดนั้น จะตรงกับฟอร์แมตมาตรฐาน IEEE-754 binary64
- `double`: จำนวนทศนิยมความแม่นยำสองเท่า ตรงกับฟอร์แมตมาตรฐาน IEEE-754 binary64
หากรองรับ
- `long double`: จำนวนทศนิยมความแม่นยำเพิ่มเติม ตรงกับฟอร์แมตมาตรฐาน IEEE-754 binary128
หากรองรับ มิฉะนั้นจะตรงกับ IEEE-754 binary64-extended หากรองรับ
มิฉะนั้นจะตรงกับรูปแบบจำนวนทศนิยมที่ไม่ตรงกับมาตรฐาน IEEE-754
รูปแบบใดก็ได้ตราบใดที่มีความแม่นยำกว่า binary64 และระยะข้อมูลนั้นอย่างน้อยก็ต้องดีเท่า binary64
และหากไม่รองรับทั้งหมดนั้น จะตรงกับฟอร์แมตมาตรฐาน IEEE-754 binary64
- รูปแบบ binary128 นั้นถูกใช้โดยระบบ HP-UX, SPARC, MIPS, ARM64, และ z/OS บางระบบ
- รูปแบบ IEEE-754 binary64-extended ที่รู้จักกันอย่างแพร่หลายที่สุดคือรูปแบบความแม่นยำเพิ่มเติม 80 บิต x87 ซึ่งถูกใช้โดยสถาปัตยกรรม x86 และ x86-64 บางระบบ (การยกเว้นที่ควรพูดถึงคือ MSVC ที่กำหนดให้ `long double` อยู่ในรูปแบบเดียวกันกับ `double`, เช่น binary64)
- รูปแบบ IEEE-754 binary64-extended ที่รู้จักกันอย่างแพร่หลายที่สุดคือรูปแบบความแม่นยำเพิ่มเติม
80 บิต x87 ซึ่งถูกใช้โดยสถาปัตยกรรม x86 และ x86-64 บางระบบ (การยกเว้นที่ควรพูดถึงคือ
MSVC ที่กำหนดให้ `long double` อยู่ในรูปแบบเดียวกันกับ `double`, เช่น binary64)
เมื่อใช้มาตรฐาน C ตั้งแต่ C23 เป็นต้นไปและหากแพลตฟอร์มของคุณใช้งานคอนแสตนต์มาโคร `__STDC_IEC_60559_DFP__` ข้อมูลประเภทตัวเลขทศนิยมดังต่อไปนี้จะถูกรองรับด้วย:
เมื่อใช้มาตรฐาน C ตั้งแต่ C23 เป็นต้นไปและหากแพลตฟอร์มของคุณใช้งานคอนแสตนต์มาโคร
`__STDC_IEC_60559_DFP__` ข้อมูลประเภทตัวเลขทศนิยมดังต่อไปนี้จะถูกรองรับด้วย:
- `_Decimal32`: แทนรูปแบบมาตรฐาน IEEE-754 decimal32
- `_Decimal64`: แทนรูปแบบมาตรฐาน IEEE-754 decimal64
@@ -293,62 +365,93 @@ float a, b, c;
ข้อมูลประเภททศนิยมอาจรองรับค่าพิเศษเพิ่มเติมได้แก่
- อนันต์ (Infinity, ทั้งบวกและลบ)
- ศูนย์ติดลบ, `-0.0` โดยมีค่าเท่ากับศูยน์ที่ติดบวก แต่อาจมีความหมายในบางสมการ เช่น `1.0 / 0.0 == INFINITY` แต่ `1.0 / -0.0 == -INFINITY`
- ศูนย์ติดลบ, `-0.0` โดยมีค่าเท่ากับศูยน์ที่ติดบวก แต่อาจมีความหมายในบางสมการ เช่น
`1.0 / 0.0 == INFINITY` แต่ `1.0 / -0.0 == -INFINITY`
- ไม่ใช่ตัวเลข (not-a-number; NaN) ซึ่งไม่เท่ากับอะไรเลย (รวมถึงตัวมันเอง)
ทศนิยมจำนวนจริงสามารถถูกใช้กับตัวดำเนินการทางคณิตศาสตร์ได้ *+ - / \** และฟังก์ชันทางคณิตศาสตร์จาก `<math.h>` โดยทั้งตัวดำเนินการและฟังก์ชันจากไลบรารีนั้นสามารถก่อให้เกิดการแสดงข้อผิดพลาดของจำนวนทศนิยมได้และจะตั้งค่า `errno`
ทศนิยมจำนวนจริงสามารถถูกใช้กับตัวดำเนินการทางคณิตศาสตร์ได้ *+ - / \**
และฟังก์ชันทางคณิตศาสตร์จาก `<math.h>`
โดยทั้งตัวดำเนินการและฟังก์ชันจากไลบรารีนั้นสามารถก่อให้เกิดการแสดงข้อผิดพลาดของจำนวนทศนิยมได้และจะตั้งค่า
`errno`
=== ประเภทจำนวนทศนิยมซับซ้อน (Complex floating types)
#i ประเภทข้อมูลจำนวนทศนิยมซับซ้อนนั้นเป็นประเภทที่แทนตัวเลขเชิงซ้อน (complex number) นั้นคือ ตัวเลขที่สามารถถูกเขียนแทนเป็นผลรวมของจำนวนจริงและจำนวนจริงที่คูณด้วยจำนวนจินตภาพ: #math.equation($a + b i$, alt: "a บวก b i")
#i ประเภทข้อมูลจำนวนทศนิยมซับซ้อนนั้นเป็นประเภทที่แทนตัวเลขเชิงซ้อน (complex number) นั้นคือ
ตัวเลขที่สามารถถูกเขียนแทนเป็นผลรวมของจำนวนจริงและจำนวนจริงที่คูณด้วยจำนวนจินตภาพ:
#math.equation($a + b i$, alt: "a บวก b i")
ประเภทจำนวนเชิงซ้อนมีอยู่สามประเภท ได้แก่
- ```c float _Complex``` (และสามารถใช้ ```c float complex``` ได้เช่นกันหากนำเข้า `<complex.h>`)
- ```c double _Complex``` (และสามารถใช้ ```c double complex``` ได้เช่นกันหากนำเข้า `<complex.h>`)
- ```c long double _Complex``` (และสามารถใช้ ```c long double complex``` ได้เช่นกันหากนำเข้า `<complex.h>`)
- ```c float _Complex``` (และสามารถใช้ ```c float complex``` ได้เช่นกันหากนำเข้า
`<complex.h>`)
- ```c double _Complex``` (และสามารถใช้ ```c double complex``` ได้เช่นกันหากนำเข้า
`<complex.h>`)
- ```c long double _Complex``` (และสามารถใช้ ```c long double complex```
ได้เช่นกันหากนำเข้า `<complex.h>`)
*หมายเหตุ:* เหมือนกับประเภทอื่น ๆ สามารถพิมพ์คีย์เวิร์ดในลำดับใดก็ได้ ```c long double complex```, ```c complex long double``` และแม้แต่ ```c double complex long``` นั้นคือประเภทข้อมูลเดียวกัน
*หมายเหตุ:* เหมือนกับประเภทอื่น ๆ สามารถพิมพ์คีย์เวิร์ดในลำดับใดก็ได้
```c long double complex```, ```c complex long double``` และแม้แต่
```c double complex long``` นั้นคือประเภทข้อมูลเดียวกัน
=== ประเภทจำนวนทศนิยมจินตภาพ (Imaginary floating types)
#i ประเภทข้อมูลจำนวนทศนิยมจินตภาพนั้นเป็นประเภทที่แทนตัวเลขจินตภาพ (imaginary number) นั้นคือ ตัวเลขที่สามารถถูกเขียนแทนเป็นจำนวนจริงที่คูณด้วยจำนวนจินตภาพ: #math.equation($b i$, alt: "b i")
#i ประเภทข้อมูลจำนวนทศนิยมจินตภาพนั้นเป็นประเภทที่แทนตัวเลขจินตภาพ (imaginary number) นั้นคือ
ตัวเลขที่สามารถถูกเขียนแทนเป็นจำนวนจริงที่คูณด้วยจำนวนจินตภาพ: #math.equation(
$b i$,
alt: "b i",
)
ประเภทจำนวนเชิงซ้อนมีอยู่สามประเภท ได้แก่
- ```c float _Imaginary``` (และสามารถใช้ ```c float imaginary``` ได้เช่นกันหากนำเข้า `<complex.h>`)
- ```c double _Imaginary``` (และสามารถใช้ ```c double imaginary``` ได้เช่นกันหากนำเข้า `<complex.h>`)
- ```c long double _Imaginary``` (และสามารถใช้ ```c long double imaginary``` ได้เช่นกันหากนำเข้า `<complex.h>`)
- ```c float _Imaginary``` (และสามารถใช้ ```c float imaginary``` ได้เช่นกันหากนำเข้า
`<complex.h>`)
- ```c double _Imaginary``` (และสามารถใช้ ```c double imaginary```
ได้เช่นกันหากนำเข้า `<complex.h>`)
- ```c long double _Imaginary``` (และสามารถใช้ ```c long double imaginary```
ได้เช่นกันหากนำเข้า `<complex.h>`)
*หมายเหตุ:* เหมือนกับประเภทอื่น ๆ สามารถพิมพ์คีย์เวิร์ดในลำดับใดก็ได้ ```c long double imaginary```, ```c imaginary long double``` และแม้แต่ ```c double imaginary long``` นั้นคือประเภทข้อมูลเดียวกัน
*หมายเหตุ:* เหมือนกับประเภทอื่น ๆ สามารถพิมพ์คีย์เวิร์ดในลำดับใดก็ได้
```c long double imaginary```, ```c imaginary long double``` และแม้แต่
```c double imaginary long``` นั้นคือประเภทข้อมูลเดียวกัน
=== ประเภทตัวอักษร (Character)
- `signed char`: ประเภทสำหรับตัวอักษรแบบ signed
- `unsigned char`: ประเภทสำหรับตัวอักษรแบบ unsigned
- `char`: ประเภทสำหรับตัวอักษรแบบไม่ระบุระยะข้อมูล ซึ่งสามารถเท่ากับ `signed char` หรือ `unsigned char` ก็ได้ขึ้นอยู่กับแพลตฟอร์มและคอมไพเลอร์ แต่อย่างไรก็ตาม `char` นั้นไม่ใช่เพียงแค่มาโครที่ลิงก์ไปยังประเภทอื่น ๆ แต่ `char` คือประเภทของมันเอง
- `char`: ประเภทสำหรับตัวอักษรแบบไม่ระบุระยะข้อมูล ซึ่งสามารถเท่ากับ `signed char` หรือ
`unsigned char` ก็ได้ขึ้นอยู่กับแพลตฟอร์มและคอมไพเลอร์ แต่อย่างไรก็ตาม `char`
นั้นไม่ใช่เพียงแค่มาโครที่ลิงก์ไปยังประเภทอื่น ๆ แต่ `char` คือประเภทของมันเอง
=== คีย์เวิร์ด
- `bool`, `true`, `false`, `char`, `int`, `short`, `long`, `signed`, `unsigned`, `float`, `double`.
- `_Bool`, `_BitInt`, `_Complex`, `_Imaginary`, `_Decimal32`, `_Decimal64`, `_Decimal128`.
- `bool`, `true`, `false`, `char`, `int`, `short`, `long`, `signed`, `unsigned`,
`float`, `double`.
- `_Bool`, `_BitInt`, `_Complex`, `_Imaginary`, `_Decimal32`, `_Decimal64`,
`_Decimal128`.
=== ระยะค่าที่เก็บได้
#i ตารางต่อไปนี้ให้ข้อมูลเกี่ยวกับขอบเขตของประเภทข้อมูลต่าง ๆ
#i ก่อนมาตรฐาน C23 มาตรฐาน C อนุญาตการแทนตัวเลขแบบใดก็ได้ และระยะขั้นต่ำของตัวเลข N บิตคือ #math.equation($-(2^(N-1)-1)$, alt: "ลบ 2 ยกกำลัง N ลบ 1 ทั้งหมดลบ 1") ถึง
#math.equation($+2^(N-1)-1$, alt: "บวก 2 ยกกำลัง N ลบ 1 ทั้งหมดลบ 1") (เช่น *-127* ถึง *127* สำหรับประเภทตัวเลข 8 บิต) ซึ่งตรงกับขอบเขตของส่วนเติมเต็มหนึ่ง (one's complement) หรือการแทนจำนวนมีเครื่องหมาย (sign-and-magnitude)
#i ก่อนมาตรฐาน C23 มาตรฐาน C อนุญาตการแทนตัวเลขแบบใดก็ได้ และระยะขั้นต่ำของตัวเลข N บิตคือ
#math.equation($-(2^(N-1)-1)$, alt: "บ 2 ยกกำลัง N ลบ 1 ทั้งหมดลบ 1") ถึง
#math.equation($+2^(N-1)-1$, alt: "บวก 2 ยกกำลัง N ลบ 1 ทั้งหมดลบ 1") (เช่น *-127*
ถึง *127* สำหรับประเภทตัวเลข 8 บิต) ซึ่งตรงกับขอบเขตของส่วนเติมเต็มหนึ่ง (one's complement)
หรือการแทนจำนวนมีเครื่องหมาย (sign-and-magnitude)
#i อย่างไรก็ตาม รูปแบบข้อมูลที่ใช้กันอย่างแพร่หลายทั้งหมด (รวมถึง ILP32, LP32, LP64, และ LLP64) และคอมไพเลอร์ C เกือบทั้งหมดใช้การแทนตัวเลขแบบส่วนเติมเต็มสอง (two's complement) (มีข้อยกเว้นที่ทราบแค่บางคอมไพเลอร์สำหรับระบบ UNISYS) และตั้งแต่มาตรฐาน C23 มันคือการแทนตัวเลขแบบเดียวที่ถูกอนุญาตให้ใช้โดยมาตรฐาน และมีขอบเขตที่แน่นอนระหว่าง
#math.equation($-2^(N-1)$, alt: "ลบ 2 ยกกำลัง N ลบ 1") ถึง
#math.equation($+2^(N-1)-1$, alt: "บวก 2 ยกกำลัง N ลบ 1 ทั้งหมดลบ 1") (เช่น *-128* ถึง *127* สำหรับระเภทตัวเลข 8 บิต)
#i อย่างไรก็ตาม รูปแบบข้อมูลที่ใช้กันอย่างแพร่หลายทั้งหมด (รวมถึง ILP32, LP32, LP64, และ
LLP64) และคอมไพเลอร์ C เกือบทั้งหมดใช้การแทนตัวเลขแบบส่วนเติมเต็มสอง (two's complement)
(มีข้อยกเว้นที่ทราบแค่บางคอมไพเลอร์สำหรับระบบ UNISYS) และตั้งแต่มาตรฐาน C23
มันคือการแทนตัวเลขแบบเดียวที่ถูกอนุญาตให้ใช้โดยมาตรฐาน และมีขอบเขตที่แน่นอนระหว่าง
#math.equation($-2^(N-1)$, alt: "ลบ 2 ยกกำลัง N ลบ 1") ถึง #math.equation(
$+2^(N-1)-1$,
alt: "บวก 2 ยกกำลัง N ลบ 1 ทั้งหมดลบ 1",
) (เช่น *-128* ถึง *127* สำหรับประเภทตัวเลข 8 บิต)
(มีการเพิ่มจุลภาคในทศนิยมเพื่อเพิ่มความสะดวกในการอ่าน)
#show table.cell.where(x: 0): strong
#show math.equation.where(block: true): set block(spacing: 0.6em)
#show math.equation: set text(font: "Noto Sans Math")
#set list(indent: 0em)
#figure(
@@ -416,11 +519,20 @@ float a, b, c;
table.cell(
[
- min subnormal:
#math.equation($± 1.401,298,4 · 10^(-45)$, alt: "บวกลบ 1.4012984 คูณ 10 ยกกำลัง -45")
#math.equation(
$± 1.401,298,4 · 10^(-45)$,
alt: "บวกลบ 1.4012984 คูณ 10 ยกกำลัง -45",
)
- min normal:
#math.equation($± 1.175,494,3 · 10^(-38)$, alt: "บวกลบ 1.1754943 คูณ 10 ยกกำลัง -38")
#math.equation(
$± 1.175,494,3 · 10^(-38)$,
alt: "บวกลบ 1.1754943 คูณ 10 ยกกำลัง -38",
)
- max: \
#math.equation($± 3.402,823,4 · 10^(38)$, alt: "บวกลบ 3.4028234 คูณ 10 ยกกำลัง 38")
#math.equation(
$± 3.402,823,4 · 10^(38)$,
alt: "บวกลบ 3.4028234 คูณ 10 ยกกำลัง 38",
)
],
align: left,
),
@@ -467,8 +579,7 @@ float a, b, c;
`±0x1p-1074`
- min normal:\
`±0x1p-1022`
- max:
`±0x1` \ `.fffffffffffffp+1023`
- max: `±0x1` \ `.fffffffffffffp+1023`
],
align: left,
),
@@ -522,8 +633,7 @@ float a, b, c;
`±0x1p-16445`
- min normal:
`±0x1p-16382`
- max:
`±0x1.ffffffff`\ `fffffffep+16383`
- max: `±0x1.ffffffff`\ `fffffffep+16383`
],
align: left,
),
@@ -559,8 +669,7 @@ float a, b, c;
`±0x1p-16494`
- min normal:
`±0x1p-16382`
- max:
`±0x1.ffffffffffffff`\ `ffffffffffffffp+16383`
- max: `±0x1.ffffffffffffff`\ `ffffffffffffffp+16383`
],
align: left,
),
@@ -576,7 +685,10 @@ float a, b, c;
- min normal:\
#math.equation($± 1 · 10^(-95)$, alt: "บวกลบ 1 คูณ 10 ยกกำลัง ลบ 95")
- max:\
#math.equation($± 9.999'999 · 10^96$, alt: "บวกลบ 9.999999 คูณ 10 ยกกำลัง 96")
#math.equation(
$± 9.999'999 · 10^96$,
alt: "บวกลบ 9.999999 คูณ 10 ยกกำลัง 96",
)
],
align: left,
),
@@ -606,9 +718,15 @@ float a, b, c;
table.cell(
[
- min subnormal:\
#math.equation($± 1 · 10^(-6176)$, alt: "บวกลบ 1 คูณ 10 ยกกำลัง ลบ 6176")
#math.equation(
$± 1 · 10^(-6176)$,
alt: "บวกลบ 1 คูณ 10 ยกกำลัง ลบ 6176",
)
- min normal:\
#math.equation($± 1 · 10^(-6143)$, alt: "บวกลบ 1 คูณ 10 ยกกำลัง ลบ 6143")
#math.equation(
$± 1 · 10^(-6143)$,
alt: "บวกลบ 1 คูณ 10 ยกกำลัง ลบ 6143",
)
- max:
#math.equation(
$ ± 9.999'999'999'999'999'\ 999'999'999'999'999'999\ · 10^6144 $,
@@ -626,10 +744,25 @@ float a, b, c;
== ชุดแปลโปรแกรมของกนู (GNU Compiler Collection; GCC)
#i ในกระบวนการการพัฒนาโครงงานนี้ ชุดแปลโปรแกรมของกนูนั้นถูกใช้เป็นหลักเนื่องจากเป็นชุดแปลโปรแกรม (คอมไพเลอร์; Compiler) ที่ใช้เป็นหลักในการพัฒนาโคดที่สร้างบนพื้นฐาน Arduino และบอร์ดต่าง ๆ รวมถึงบอร์ด ESP32
#i ในกระบวนการการพัฒนาโครงงานนี้
ชุดแปลโปรแกรมของกนูนั้นถูกใช้เป็นหลักเนื่องจากเป็นชุดแปลโปรแกรม (คอมไพเลอร์; Compiler)
ที่ใช้เป็นหลักในการพัฒนาโคดที่สร้างบนพื้นฐาน Arduino และบอร์ดต่าง ๆ รวมถึงบอร์ด ESP32
#i ชุดคอมไพเลอร์ GNU (GNU Compiler Collection; GCC) (เดิมชื่อ GNU C Compiler) คือชุดคอมไพเลอร์จากโครงการ GNU ที่รองรับภาษาโปรแกรม สถาปัตยกรรมฮาร์ดแวร์ และระบบปฏิบัติการต่าง ๆ มูลนิธิซอฟต์แวร์เสรี (FSF) เผยแพร่ GCC ในฐานะซอฟต์แวร์เสรีภายใต้สัญญาอนุญาตสถูกเรียกาธารณะทั่วไปของ GNU (GNU GPL) GCC เป็นองค์ประกอบสำคัญของชุดเครื่องมือ GNU ซึ่งใช้สำหรับโครงการส่วนใหญ่ที่เกี่ยวข้องกับ GNU และเคอร์เนล Linux ด้วยโคดประมาณ 15 ล้านบรรทัดในปี 2019 GCC จึงเป็นหนึ่งในโปรแกรมฟรีที่ใหญ่ที่สุดเท่าที่เคยมีมา GCC มีบทบาทสำคัญในการเติบโตของซอฟต์แวร์เสรี ทั้งในฐานะเครื่องมือและตัวอย่าง
#i ชุดคอมไพเลอร์ GNU (GNU Compiler Collection; GCC) (เดิมชื่อ GNU C Compiler)
คือชุดคอมไพเลอร์จากโครงการ GNU ที่รองรับภาษาโปรแกรม สถาปัตยกรรมฮาร์ดแวร์
และระบบปฏิบัติการต่าง ๆ มูลนิธิซอฟต์แวร์เสรี (FSF) เผยแพร่ GCC
ในฐานะซอฟต์แวร์เสรีภายใต้สัญญาอนุญาตสถูกเรียกาธารณะทั่วไปของ GNU (GNU GPL) GCC
เป็นองค์ประกอบสำคัญของชุดเครื่องมือ GNU ซึ่งใช้สำหรับโครงการส่วนใหญ่ที่เกี่ยวข้องกับ GNU และเคอร์เนล
Linux ด้วยโคดประมาณ 15 ล้านบรรทัดในปี 2019 GCC จึงเป็นหนึ่งในโปรแกรมฟรีที่ใหญ่ที่สุดเท่าที่เคยมีมา
GCC มีบทบาทสำคัญในการเติบโตของซอฟต์แวร์เสรี ทั้งในฐานะเครื่องมือและตัวอย่าง
#i นอกจากจะเป็นคอมไพเลอร์อย่างเป็นทางการของระบบปฏิบัติการ GNU แล้ว GCC ยังได้รับการยอมรับให้เป็นคอมไพเลอร์มาตรฐานโดยระบบปฏิบัติการคอมพิวเตอร์สมัยใหม่ที่คล้ายกับ Unix อื่นๆ อีกมากมาย รวมถึงระบบปฏิบัติการ Linux ส่วนใหญ่ ระบบปฏิบัติการตระกูล BSD ส่วนใหญ่ก็เปลี่ยนมาใช้ GCC ไม่นานหลังจากเปิดตัว แม้ว่าหลังจากนั้น FreeBSD และ Apple macOS ได้เปลี่ยนมาใช้คอมไพเลอร์ Clang ส่วนใหญ่เป็นเพราะเหตุผลด้านลิขสิทธิ์ GCC ยังสามารถคอมไพเลอร์โคดสำหรับระบบปฏิบัติการ Windows, Android, iOS, Solaris, HP-UX, AIX และ MS-DOS ได้อีกด้วย
#i นอกจากจะเป็นคอมไพเลอร์อย่างเป็นทางการของระบบปฏิบัติการ GNU แล้ว GCC
ยังได้รับการยอมรับให้เป็นคอมไพเลอร์มาตรฐานโดยระบบปฏิบัติการคอมพิวเตอร์สมัยใหม่ที่คล้ายกับ Unix อื่นๆ
อีกมากมาย รวมถึงระบบปฏิบัติการ Linux ส่วนใหญ่ ระบบปฏิบัติการตระกูล BSD ส่วนใหญ่ก็เปลี่ยนมาใช้ GCC
ไม่นานหลังจากเปิดตัว แม้ว่าหลังจากนั้น FreeBSD และ Apple macOS ได้เปลี่ยนมาใช้คอมไพเลอร์ Clang
ส่วนใหญ่เป็นเพราะเหตุผลด้านลิขสิทธิ์ GCC ยังสามารถคอมไพเลอร์โคดสำหรับระบบปฏิบัติการ Windows,
Android, iOS, Solaris, HP-UX, AIX และ MS-DOS ได้อีกด้วย
#i GCC ได้รับการพอร์ตไปยังแพลตฟอร์มและสถาปัตยกรรมชุดคำสั่งต่าง ๆ มากกว่าคอมไพเลอร์อื่น ๆ และถูกนำไปใช้งานอย่างกว้างขวางในฐานะเครื่องมือในการพัฒนาซอฟต์แวร์ทั้งแบบฟรีและแบบที่เป็นกรรมสิทธิ์ นอกจากนี้ GCC ยังพร้อมใช้งานสำหรับระบบฝังตัวมากมาย รวมถึงชิปที่ใช้ ARM และ Power ISA
#i GCC ได้รับการพอร์ตไปยังแพลตฟอร์มและสถาปัตยกรรมชุดคำสั่งต่าง ๆ มากกว่าคอมไพเลอร์อื่น ๆ
และถูกนำไปใช้งานอย่างกว้างขวางในฐานะเครื่องมือในการพัฒนาซอฟต์แวร์ทั้งแบบฟรีและแบบที่เป็นกรรมสิทธิ์
นอกจากนี้ GCC ยังพร้อมใช้งานสำหรับระบบฝังตัวมากมาย รวมถึงชิปที่ใช้ ARM และ Power ISA
+8
View File
@@ -5,6 +5,11 @@
#show heading: i-figured.reset-counters.with(level: 3)
#show figure: i-figured.show-figure.with(level: 3)
#show raw.where(block: false): set text(font: "Laksaman")
#show raw.where(block: true): set block(fill: rgb("#282A36"), inset: 1.5em)
#show raw.where(block: true): set raw(theme: "../Dracula.tmTheme")
#show raw.where(block: true): set text(fill: rgb("#F8F8F2"))
#set heading(numbering: "บทที่ 1")
#include "Intro.typ"
@@ -16,6 +21,9 @@
#include "HTTPS.typ"
#include "TLS.typ"
#include "NFC.typ"
#pagebreak()
#include "Flutter.typ"
#include "Git.typ"
#include "CLanguage.typ"
+377 -192
View File
@@ -9,8 +9,8 @@
สามารถใช้พัฒนาแอปพลิเคชันข้ามแพลตฟอร์มจากฐานโคดเดียวสำหรับเว็บ Fuchsia, Android, iOS,
Linux, macOS และ Windows โดย Flutter ได้รับการพูดถึงครั้งแรกในปี 2015
และเปิดตัวในเดือนพฤษภาคม 2017 และ Flutter ถูกใช้งานภายในโดย Google ในแอปพลิเคชันต่างๆ
เช่น Google Pay และ Google Earth รวมถึงโดยนักพัฒนาซอฟต์แวร์รายอื่นๆ เช่น ByteDance
และ Alibaba
เช่น Google Pay และ Google Earth รวมถึงโดยนักพัฒนาซอฟต์แวร์รายอื่นๆ เช่น ByteDance และ
Alibaba
#i Flutter จะสร้างแอปพลิเคชันที่มีเอ็นจิ้นการเรนเดอร์ของตัวเอง ซึ่งส่งข้อมูลพิกเซลไปยังหน้าจอโดยตรง
ซึ่งแตกต่างจากเฟรมเวิร์ก UI อื่น อีกมากมายที่อาศัยแพลตฟอร์มเป้าหมายเพื่อจัดหาเอ็นจิ้นการเรนเดอร์
@@ -19,26 +19,30 @@ Linux, macOS และ Windows โดย Flutter ได้รับการพ
ช่วยลดความยุ่งยากในการรองรับหลายแพลตฟอร์ม เนื่องจากสามารถใช้โคด UI
ที่เหมือนกันได้กับทุกแพลตฟอร์มเป้าหมาย
#pagebreak()
== การติดตั้งโปรแกรมเขียนโคด
#i จริง แล้วนั้น Flutter สามารถทำงานกับโปรแกรมเขียนโคดใดก็ได้ แต่มีโปรแกรมเหล่านี้ที่อาจมีประสบการณ์การพัฒนาที่ดีกว่าโปรแกรมอื่น:
#i จริง แล้วนั้น Flutter สามารถทำงานกับโปรแกรมเขียนโคดใดก็ได้
แต่มีโปรแกรมเหล่านี้ที่อาจมีประสบการณ์การพัฒนาที่ดีกว่าโปรแกรมอื่น:
- Visual Studio Code (VS Code)
- Android Studio
- JetBrains IntelliJ
- Firebase Studio
#i โครงงานนี้ใช้โปรแกรมเขียนโคด Android Studio เป็นหลักเนื่องจากแอพลิเคชันโครงงานมี Android เป็นเป้าหมายหลัก และ Android SDK สามารถจัดการได้ง่ายกว่าใน Android Studio
#i โครงงานนี้ใช้โปรแกรมเขียนโคด Android Studio เป็นหลักเนื่องจากแอพลิเคชันโครงงานมี Android
เป็นเป้าหมายหลัก และ Android SDK สามารถจัดการได้ง่ายกว่าใน Android Studio
=== Android Studio
#i Android Studio สามารถดาวน์โหลดได้ผ่าน https://developer.android.com/studio หรือสามารถถูกติดตั้งและจัดการผ่านแอพลิเคชัน JetBrains Toolbox ได้เช่นกัน (https://www.jetbrains.com/toolbox-app/)
#i Android Studio สามารถดาวน์โหลดได้ผ่าน https://developer.android.com/studio
หรือสามารถถูกติดตั้งและจัดการผ่านแอพลิเคชัน JetBrains Toolbox ได้เช่นกัน
(https://www.jetbrains.com/toolbox-app/)
== การติดตั้ง Flutter <flInstall>
#i การติดตั้ง Flutter สามารถทำได้สองวิธีด้วยกัน คือการติดตั้งผ่าน Visual Studio Code (VS Code) และการติดตั้งด้วยตนเอง โดยหากต้องการใช้ VS Code เป็นโปรแกรมเขียนโคดอยู่แล้ว สามารถติดตั้งผ่าน VS Code ได้เลย
#i การติดตั้ง Flutter สามารถทำได้สองวิธีด้วยกัน คือการติดตั้งผ่าน Visual Studio Code (VS
Code) และการติดตั้งด้วยตนเอง โดยหากต้องการใช้ VS Code เป็นโปรแกรมเขียนโคดอยู่แล้ว
สามารถติดตั้งผ่าน VS Code ได้เลย
#i แต่ก่อนอื่น ต้องทำการติดตั้งโปรแกรมและไลบรารีพื้นฐานที่จำเป็นสำหรับ Flutter ก่อน
@@ -49,8 +53,15 @@ Linux, macOS และ Windows โดย Flutter ได้รับการพ
#grid(
columns: 2,
column-gutter: 1em,
[#i ในการพัฒนาซอฟต์แวร์บน Windows ด้วย Flutter คุณจำเป็นต้องติดตั้ง Git สำหรับ Windows ซึ่งคุณสามารถดูขั้นตอนการติดตั้งได้โดยการสแกน QR code ด้านข้าง หรือที่ https://git-scm.com/install/windows หรือเพียงแค่ใช้ WinGet ในการติดตั้งโดยการใช้คำสั่งด้านล่าง],
tiaoma.qrcode("https://git-scm.com/install/windows", width: 1in, alt: "QR โคดสำหรับหน้าการติดตั้ง Git สำหรับ Windows"),
[#i ในการพัฒนาซอฟต์แวร์บน Windows ด้วย Flutter คุณจำเป็นต้องติดตั้ง Git สำหรับ Windows
ซึ่งคุณสามารถดูขั้นตอนการติดตั้งได้โดยการสแกน QR code ด้านข้าง หรือที่
https://git-scm.com/install/windows หรือเพียงแค่ใช้ WinGet
ในการติดตั้งโดยการใช้คำสั่งด้านล่าง],
tiaoma.qrcode(
"https://git-scm.com/install/windows",
width: 1in,
alt: "QR โคดสำหรับหน้าการติดตั้ง Git สำหรับ Windows",
),
)
```sh
@@ -59,7 +70,8 @@ winget install --id Git.Git -e --source winget
==== Linux
#i Flutter ใช้ไลบรารีดังต่อไปนี้ในขั้นตอนการพัฒนาแอพลิเคชันบน Linux (development dependencies; ยังไม่รวมไลบรารีและโปรแกรมที่ต้องมีในการสร้างแอพลิเคชัน _สำหรับ_ Linux)
#i Flutter ใช้ไลบรารีดังต่อไปนี้ในขั้นตอนการพัฒนาแอพลิเคชันบน Linux (development
dependencies; ยังไม่รวมไลบรารีและโปรแกรมที่ต้องมีในการสร้างแอพลิเคชัน _สำหรับ_ Linux)
#grid(
columns: 2,
@@ -80,7 +92,8 @@ winget install --id Git.Git -e --source winget
==== macOS
#i จำเป็นต้องทำการติดตั้งเครื่องมือ command-line Xcode เพื่อเข้าถึงเครื่องมือที่ Flutter จำเป็นต้องใช้ รวมถึง Git
#i จำเป็นต้องทำการติดตั้งเครื่องมือ command-line Xcode เพื่อเข้าถึงเครื่องมือที่ Flutter
จำเป็นต้องใช้ รวมถึง Git
ในการดาวน์โหลดเครื่องมือ ใช้คำสั่งต่อไปนี้ในเทอร์มินัลที่คุณเลือก:
@@ -88,40 +101,51 @@ winget install --id Git.Git -e --source winget
xcode-select --install
```
#i หากคุณไม่ได้ติดตั้งเครื่องมืออยู่แล้ว จะมีไดอะลอกเพื่อคอนเฟิร์มว่าคุณต้องการที่จะติดตั้งมัน กด *Install* และกด *Done* เมื่อทำการติดตั้งเสร็จสิ้นแล้ว
=== การติดตั้งผ่าน Visual Studio Code
1. เปิด VSCode
2. ติดตั้งส่วนขยาย Flutter \
อยู่ภายใต้ ID `Dart-Code.flutter` ทั้งบน Visual Studio Marketplace และ OpenVSX
3. ติดตั้ง Flutter ด้วย VS Code
+ เปิด Command Palette ด้วยเมนู *View* > *Command Palette* หรือกด Ctrl + Shift + P
+ ใน Command Palette พิมพ์ `flutter`.
+ เลือก *Flutter: New Project*
+ VS Code จะให้คุณเลือก Flutter SDK บนคอมพิวเตอร์ของคุณ เลือก *Download SDK*
+ เมือหน้าไดอะลอก *Select Folder for Flutter SDK* แสดงขึ้น เลือกสถานที่ที่คุณอยากติดตั้ง Flutter
+ คลิก *Clone Flutter* \
ในระหว่างการดาวน์โหลด VS Code จะแสดงการแจ้งเตือนนี้:
```
Downloading the Flutter SDK. This may take a few minutes.
```
การดาวน์โหลดนี้จะใช้เวลาสองสามนาที หากคุณเชื่อว่าการดาวน์โหลดหยุดชะงัก คุณสามารถคลิก *Cancel* แล้วเริ่มต้นการติดตั้งใหม่ได้
+ คลิก *Add SDK to PATH* \
เมื่อเสร็จสิ้น จะมีการแจ้งเตือน
```
The Flutter SDK was added to your PATH
```
+ VS Code อาจแสดงการแจ้งเตือนเกี่ยวกับการเก็บข้อมูลของ Google หากคุณยินยอม คลิก *OK*
+ เพื่อความแน่ใจ กรุณาปิดเทอร์มินัลทุกหน้าต่างหรือรีสตาร์ท VS Code เพื่อให้แน่ใจว่า Flutter จะสามารถใช้ผ่านเทอร์มินัลได้
4. เมื่อเสร็จสิ้น ใช้คำสั่ง `flutter doctor -v` ในเทอร์มินัลที่คุณเลือกเพื่อตรวจสอบการติดตั้ง Flutter ของคุณ \
หากคำสั่งไม่เจอหรือเกิดข้อผิดพลาดขึ้น ตรวจสอบ https://docs.flutter.dev/install/troubleshoot สำหรับข้อมูลเพิ่มเติม
#i หากคุณไม่ได้ติดตั้งเครื่องมืออยู่แล้ว จะมีไดอะลอกเพื่อคอนเฟิร์มว่าคุณต้องการที่จะติดตั้งมัน กด
*Install* และกด *Done* เมื่อทำการติดตั้งเสร็จสิ้นแล้ว
#pagebreak()
=== การติดตั้งผ่าน Visual Studio Code
#[
#set enum(indent: 3em)
+ เปิด VSCode
+ ติดตั้งส่วนขยาย Flutter \
อยู่ภายใต้ ID `Dart-Code.flutter` ทั้งบน Visual Studio Marketplace และ OpenVSX
+ ติดตั้ง Flutter ด้วย VS Code
+ เปิด Command Palette ด้วยเมนู *View* > *Command Palette* หรือกด Ctrl + Shift +
P
+ ใน Command Palette พิมพ์ `flutter`.
+ เลือก *Flutter: New Project*
+ VS Code จะให้คุณเลือก Flutter SDK บนคอมพิวเตอร์ของคุณ เลือก *Download SDK*
+ เมือหน้าไดอะลอก *Select Folder for Flutter SDK* แสดงขึ้น เลือกสถานที่ที่คุณอยากติดตั้ง
Flutter
+ คลิก *Clone Flutter* \
ในระหว่างการดาวน์โหลด VS Code จะแสดงการแจ้งเตือนนี้:
```
Downloading the Flutter SDK. This may take a few minutes.
```
การดาวน์โหลดนี้จะใช้เวลาสองสามนาที หากคุณเชื่อว่าการดาวน์โหลดหยุดชะงัก คุณสามารถคลิก
*Cancel* แล้วเริ่มต้นการติดตั้งใหม่ได้
+ คลิก *Add SDK to PATH* \
เมื่อเสร็จสิ้น จะมีการแจ้งเตือน
```
The Flutter SDK was added to your PATH
```
+ VS Code อาจแสดงการแจ้งเตือนเกี่ยวกับการเก็บข้อมูลของ Google หากคุณยินยอม คลิก *OK*
+ เพื่อความแน่ใจ กรุณาปิดเทอร์มินัลทุกหน้าต่างหรือรีสตาร์ท VS Code เพื่อให้แน่ใจว่า Flutter
จะสามารถใช้ผ่านเทอร์มินัลได้
+ เมื่อเสร็จสิ้น ใช้คำสั่ง `flutter doctor -v` ในเทอร์มินัลที่คุณเลือกเพื่อตรวจสอบการติดตั้ง
Flutter ของคุณ \
หากคำสั่งไม่เจอหรือเกิดข้อผิดพลาดขึ้น ตรวจสอบ
https://docs.flutter.dev/install/troubleshoot สำหรับข้อมูลเพิ่มเติม
]
=== การติดตั้งด้วยตนเอง
#i แนะนำให้ทำตาม https://docs.flutter.dev/install/manual#install-flutter เนื่องจากกระบวนการนี้ต้องใช้ข้อมูลที่ใหม่ล่าสุด
#i แนะนำให้ทำตาม https://docs.flutter.dev/install/manual#install-flutter
เนื่องจากกระบวนการนี้ต้องใช้ข้อมูลที่ใหม่ล่าสุด
1. ดาวน์โหลด Flutter (สามารถหาปุ่มดาวน์โหลดได้จากลิงก์ด้านบน)
2. สร้างโฟลเดอร์สำหรับเก็บ Flutter SDK
@@ -131,29 +155,36 @@ xcode-select --install
== Dart
#i Dart เป็นภาษาโปรแกรมที่ออกแบบโดย Lars Bak และ Kasper Lund และพัฒนาโดย
Google สามารถใช้พัฒนาแอปพลิเคชันบนเว็บ มือถือ เซิร์ฟเวอร์ และเดสก์ท็อปได้ และยังเป็นภาษาหลักที่ใช้ในการพัฒนาแอพลิเคชัน Flutter
#i Dart เป็นภาษาโปรแกรมที่ออกแบบโดย Lars Bak และ Kasper Lund และพัฒนาโดย Google
สามารถใช้พัฒนาแอปพลิเคชันบนเว็บ มือถือ เซิร์ฟเวอร์ และเดสก์ท็อปได้
และยังเป็นภาษาหลักที่ใช้ในการพัฒนาแอพลิเคชัน Flutter
#i Dart เป็นภาษาเชิงวัตถุ อิงคลาส และรวบรวมขยะ (garbage-collection) ด้วยไวยากรณ์แบบ C สามารถคอมไพล์เป็นโค้ดเครื่อง JavaScript หรือ WebAssembly ได้ รองรับอินเทอร์เฟซ มิกซ์อิน คลาสนามธรรม เจเนอริกแบบรีไฟด์ และการอนุมานชนิดข้อมูล
#i Dart เป็นภาษาเชิงวัตถุ อิงคลาส และรวบรวมขยะ (garbage-collection) ด้วยไวยากรณ์แบบ C
สามารถคอมไพล์เป็นโค้ดเครื่อง JavaScript หรือ WebAssembly ได้ รองรับอินเทอร์เฟซ มิกซ์อิน
คลาสนามธรรม เจเนอริกแบบรีไฟด์ และการอนุมานชนิดข้อมูล
== การสร้างโปรเจกต์
#i ตั้งแต่หัวข้อนี้เป็นต้นไป จะเป็นข้อมูลสำหรับการทำงานกับ Android Studio เป็นหลักเนื่องจากเป็นโปรแกรมหลักที่ถูกใช้งานในการพัฒนาแอพลิเคชันโครงงานนี้
#i ตั้งแต่หัวข้อนี้เป็นต้นไป จะเป็นข้อมูลสำหรับการทำงานกับ Android Studio
เป็นหลักเนื่องจากเป็นโปรแกรมหลักที่ถูกใช้งานในการพัฒนาแอพลิเคชันโครงงานนี้
#i หากยังไม่ได้ติดตั้งปลั๊กอิน Flutter โปรดติดตั้งปลั๊กอินก่อน โดยหากอยู่ในหน้าต้อนรับ สามารถติดตั้งปลั๊กอินได้โดยการเข้าไปยังแท็บ *Plugins* หรือหากเปิดโปรเจกต์อื่นอยู่ สามารถเข้าถึงหน้าปลั๊กอินได้โดยการกดที่ไอคอนฟันเฟืองในแถบเครื่องมือ แล้วกด *Plugins...* หลังจากนั้น ในแท็บ *Marketplace* ของหน้าปลั๊กอิน ค้นหา *Flutter* (ผู้ผลิตปลั๊กอินคือ Google) แล้วกด *Install*
#i หากยังไม่ได้ติดตั้งปลั๊กอิน Flutter โปรดติดตั้งปลั๊กอินก่อน โดยหากอยู่ในหน้าต้อนรับ
สามารถติดตั้งปลั๊กอินได้โดยการเข้าไปยังแท็บ *Plugins* หรือหากเปิดโปรเจกต์อื่นอยู่
สามารถเข้าถึงหน้าปลั๊กอินได้โดยการกดที่ไอคอนฟันเฟืองในแถบเครื่องมือ แล้วกด *Plugins...*
หลังจากนั้น ในแท็บ *Marketplace* ของหน้าปลั๊กอิน ค้นหา *Flutter* (ผู้ผลิตปลั๊กอินคือ Google)
แล้วกด *Install*
#afigure(
image("Flutter/homePage.png", width: 65%),
attr: "ส่วนหนึ่งของโครงงาน, ศตคุณ อุตมะ, ภายใต้ CC BY-SA 4.0",
alt: "หน้ายินดีต้อนรับในแท็บ Projects ที่กำลังแสดงรายการโปรเจกต์และปุ่มในการสร้างโปรเจกต์ใหม่",
caption: [หน้ายินดีต้อนรับใน Android Studio],
)
#i เมื่อคลิก *New Flutter Project* จะมีหน้าถามสถานที่ติดตั้ง Flutter SDK หลังจากนั้น กด *Next* แล้วจะมีหน้าต่อไปนี้ขึ้นมาเพื่อให้คุณกรอกรายละเอียดโปรเจกต์
#i เมื่อคลิก *New Flutter Project* จะมีหน้าถามสถานที่ติดตั้ง Flutter SDK หลังจากนั้น กด
*Next* แล้วจะมีหน้าต่อไปนี้ขึ้นมาเพื่อให้คุณกรอกรายละเอียดโปรเจกต์
#afigure(
image("Flutter/newProjectPage.png", width: 80%),
attr: "ส่วนหนึ่งของโครงงาน, ศตคุณ อุตมะ, ภายใต้ CC BY-SA 4.0",
alt: "หน้ากรอกรายละเอียดโปรเจกต์ใหม่",
caption: [หน้าโปรเจกต์ใหม่],
)
@@ -163,16 +194,26 @@ Google สามารถใช้พัฒนาแอปพลิเคชั
- *Project name:* ชื่อโปรเจกต์
- *Project location:* โฟลเดอร์ที่ต้องการเก็บโปรเจกต์
- *Description:* รายละเอียดโปรเจกต์
- *Project type:* ประเภทโปรเจกต์ ในกรณีนี้เป็นค่า *Application* เนื่องจากเราต้องการสร้างแอพลิเคชัน
- *Organization:* โดเมนเนมย้อนหลังขององค์กรที่พัฒนา (Reverse domain name notation; Reverse-DNS)
- *Project type:* ประเภทโปรเจกต์ ในกรณีนี้เป็นค่า *Application*
เนื่องจากเราต้องการสร้างแอพลิเคชัน
- *Organization:* โดเมนเนมย้อนหลังขององค์กรที่พัฒนา (Reverse domain name notation;
Reverse-DNS)
- *Android language:* เลือกระหว่าง Java และ Kotlin เป็นภาษาหลักที่ใช้ในแอพลิเคชัน Android
- *Platforms:* แพลตฟอร์มที่โปรเจกต์จะรองรับ อย่างไรก็ตาม การสร้างไฟล์ไบนารีสำหรับแอพลิเคชันขึ้นอยู่กับแพลตฟอร์มที่พัฒนาแอพลิเคชันเช่นกัน หมายความว่า ถึงแม้ตามทฤษฎีแล้วแอพลิเคชันของคุณจะรองรับ iOS คุณต้องมีอุปกรณ์ Mac ในการสร้างไฟล์แอพลิเคชัน iOS ออกมา
- *Platforms:* แพลตฟอร์มที่โปรเจกต์จะรองรับ อย่างไรก็ตาม
การสร้างไฟล์ไบนารีสำหรับแอพลิเคชันขึ้นอยู่กับแพลตฟอร์มที่พัฒนาแอพลิเคชันเช่นกัน หมายความว่า
ถึงแม้ตามทฤษฎีแล้วแอพลิเคชันของคุณจะรองรับ iOS คุณต้องมีอุปกรณ์ Mac ในการสร้างไฟล์แอพลิเคชัน
iOS ออกมา
เมื่อทำการใส่รายละเอียดทั้งหมดแล้ว สามารถกด Create เพื่อสร้างโปรเจกต์ได้เลย
#pagebreak()
== แอพลิเคชันตัวอย่าง
เมื่อกดรันแอพลิเคชันด้วยไอคอน #box(image("Flutter/vscode_play.svg", alt: "Play"), baseline: 15%) (หรือ Shift+F10 ใน Android Studio) จะได้แอพลิเคชันดังรูปด้านล่างออกมา
เมื่อกดรันแอพลิเคชันด้วยไอคอน #box(
image("Flutter/vscode_play.svg", alt: "Play"),
baseline: 15%,
) (หรือ Shift+F10 ใน Android Studio) จะได้แอพลิเคชันดังรูปด้านล่างออกมา
#afigure(
grid(
@@ -189,7 +230,6 @@ Google สามารถใช้พัฒนาแอปพลิเคชั
alt: "โปรแกรมคอมพิวเตอร์ แถบหน้าต่างโปรแกรมสีดำ ในหน้าต่างประกอบด้วยส่วนประกอบคล้ายแอพลิเคชันบนโทรศัพท์",
),
),
attr: "ส่วนหนึ่งของโครงงาน, ศตคุณ อุตมะ, ภายใต้ CC BY-SA 4.0",
caption: [แอพลิเคชันตัวอย่างบน Android 15 และ Arch Linux],
)
@@ -201,166 +241,258 @@ _*หมายเหตุ:* โคดในห้วข้อนี้ถูก
โดยในบรรทัดแรก จะมีการนำเข้า Material UI
```dart
import 'package:flutter/material.dart';
```
#set figure(kind: "image", supplement: "รูปที่")
และถัดมา จะมีฟังก์ชันหลักชื่อ `main` ที่ทำหน้าที่ในการรันแอพลิเคชัน โดยมีการรับอาร์กิวเมนต์เป็นวิดเจ็ท ซึ่งในกรณีนี้เป็นการสร้างวัตถุจากคลาส `MyApp` ที่เป็นวิดเจ็ท
#afigure(
```dart
import 'package:flutter/material.dart';
```,
caption: [โคดนำเข้าแพคเกจ],
)
```dart
void main() {
runApp(const MyApp());
}
```
และถัดมา จะมีฟังก์ชันหลักชื่อ `main` ที่ทำหน้าที่ในการรันแอพลิเคชัน โดยมีการรับอาร์กิวเมนต์เป็นวิดเจ็ท
ซึ่งในกรณีนี้เป็นการสร้างวัตถุจากคลาส `MyApp` ที่เป็นวิดเจ็ท
ถัดมาจะมีคลาส `MyApp` ที่สืบทอดมาจาก `StatelessWidget` ซึ่งคือคลาสสำหรับวิดเจ็ทที่ไร้สถานะ ("Stateless")
#afigure(
```dart
void main() {
runApp(const MyApp());
}
```,
caption: [ฟังก์ชัน main],
)
```dart
class MyApp extends StatelessWidget {
```
ถัดมาจะมีคลาส `MyApp` ที่สืบทอดมาจาก `StatelessWidget` ซึ่งคือคลาสสำหรับวิดเจ็ทที่ไร้สถานะ
("Stateless")
#afigure(
```dart
class MyApp extends StatelessWidget {
```,
caption: [],
)
constructor :
```dart
const MyApp({super.key});
```
#afigure(
```dart
const MyApp({super.key});
```,
caption: [],
)
`@override`
```dart
@override
Widget build(BuildContext context) {
```
#afigure(
```dart
@override
Widget build(BuildContext context) {
```,
caption: [],
)
และในฟังก์ชันจะมีการสร้างวัตถุ MaterialApp ซึ่งมีหน้าที่ในการเก็บข้อมูลเกี่ยวกับแอพลิเคชัน Material UI รวมถึงข้อมูลเช่น ชื่อแอพลิเคชัน (`title`) และธีม (`theme`)
MaterialApp Material
UI (`title`) (`theme`)
```dart
return MaterialApp(
title: 'Flutter Demo',
```
#afigure(
```dart
return MaterialApp(
title: 'Flutter Demo',
```,
caption: [],
)
`ThemeData`
```dart
theme: ThemeData(
```
#afigure(
```dart
theme: ThemeData(
```,
caption: [],
)
และมีการสร้างธีมสีจากสีหลักโดยการใช้เมธอด `ColorScheme.fromSeed` แต่ในโคดด้านล่างนี้
คลาส `ColorScheme` นั้นถูกอนุมานขึ้นมา โดยใน Dart 3.10 มีฟีเจอร์ "dot shorthands" ซึ่งเป็นทางลัดในการข้ามการเขียนชื่อคลาส ซึ่งชื่อคลาสสามารถถูกอนุมานขึ้นมาได้เนื่องจากอาร์กิวเมนต์ `colorScheme` นั้นคาดหวังค่าที่เป็นวัตถุจากคลาส `ColorScheme` อยู่แล้ว
`ColorScheme.fromSeed`
`ColorScheme` Dart 3.10 "dot shorthands"
`colorScheme` `ColorScheme`
```dart
colorScheme: .fromSeed(seedColor: Colors.deepPurple),
),
```
#afigure(
```dart
colorScheme: .fromSeed(seedColor: Colors.deepPurple),
),
```,
caption: [],
)
`home`
```dart
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
#afigure(
```dart
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
}
```
```,
kind: "image",
supplement: "รูปที่",
caption: [],
)
ถัดมา มีการสร้างคลาส `MyHomePage` ที่ถูกใช้ด้านบน โดยคลาสเป็น `StatefulWidget` ซึ่งหมายความว่า เป็นคลาสที่มีสถานะ (State)
ถัดมา มีการสร้างคลาส `MyHomePage` ที่ถูกใช้ด้านบน โดยคลาสเป็น `StatefulWidget`
ซึ่งหมายความว่า เป็นคลาสที่มีสถานะ (State)
```dart
class MyHomePage extends StatefulWidget {
```
#afigure(
```dart
class MyHomePage extends StatefulWidget {
```,
caption: [],
)
constructor `title`
```dart
const MyHomePage({super.key, required this.title});
```
#afigure(
```dart
const MyHomePage({super.key, required this.title});
```,
caption: [],
)
โดยคลาสนี้เป็นคลาสที่เก็บการตั้งค่าวิดเจ็ท และเป็นคลาสที่เก็บค่าพารามิเตอร์จากวิดเจ็ทที่เหนือกว่า และตัวแปรในคลาสย่อยของ `StatefulWidget` นั้นจะมีคีย์เวิร์ด `final` เสมอ ซึ่งหมายถึงว่า ตัวแปรนี้เปลี่ยนแปลงไม่ได้หลังจากสร้างวัตถุจากคลาสแล้ว
`StatefulWidget` `final`
```dart
final String title;
```
#afigure(
```dart
final String title;
```,
caption: [],
)
ต่อมาจึงมีการสร้างวัตถุ State ซึ่งในฟังก์ชัน `createState` ที่ถูกสืบทอดมานั้น จะมีการสร้างวัตถุ State จากคลาส `_MyHomePageState` (โดยที่ `_` หมายถึงว่าคลาสนั้นเป็นส่วนตัวและไม่ควรถูกนำเข้าโดยไฟล์อื่น)
State `createState` State
`_MyHomePageState` ( `_`
)
```dart
@override
State<MyHomePage> createState() => _MyHomePageState();
}
```
```dart
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
```
โดยในฟังก์ชัน `_incrementCounter` มีการเรียกใช้ฟังก์ชัน `setState` ซึ่งจะแจ้งเตือน Flutter ว่ามีการเปลี่ยนแปลงสถานะ ซึ่งจะก่อให้เกิดการเร็นเดอร์วิดเจ็ทใหม่ และในอาร์กิวเมนต์ของ `setState` คือฟังก์ชันไม่ระบุชื่อ (anonymous functions หรืออีกชื่อหนึ่งคือ lambda) ที่เปลี่ยนแปลงสถานะของวิดเจ็ท
```dart
setState(() {
_counter++;
});
#afigure(
```dart
@override
State<MyHomePage> createState() => _MyHomePageState();
}
```
```,
caption: [],
)
โดยต่อมา มีฟังก์ชัน `build` เช่นเคยที่มีหน้าที่ในการสร้างวิดเจ็ท โดยฟังก์ชัน `build` ของวิดเจ็ทที่มีสถานะนั้นจะถูกรันใหม่ทุกครั้งที่มีการเปลี่ยนแปลงสถานะ
#afigure(
```dart
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
```dart
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
```
void _incrementCounter() {
```,
caption: [],
)
*การทดลอง:* ในระหว่างที่รันแอพลิเคชันอยู่ ลองเปลี่ยนสีพื้นหลังของวิดเจ็ท `AppBar` (เป็นค่าอื่นเช่น `Colors.amber`) แล้วทำการ hot reload โดยการกดไอคอน#box(image("Flutter/flutterHotReload.svg", alt: "สายฟ้า", width: 1.5em), baseline: 20%)เพื่อเห็นการเปลี่ยนแปลงของสีแถบแอพลิเคชันในระหว่างที่สีของวิดเจ็ทอื่น ยังคงเดิม
`_incrementCounter` `setState` Flutter
`setState`
(anonymous functions lambda)
```dart
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
```
#afigure(
```dart
setState(() {
_counter++;
});
}
```,
caption: [],
)
โดยในอาร์กิวเมนต์ `title` นี้มีการใช้ค่าที่รับมาจากวิดเจ็ทที่เหนือกว่า โดย `widget` ในที่นี้คือวัตถุของคลาส `MyHomePage` ที่ทำหน้าที่เก็บค่า `title` ของเรา แล้วเราจึงทำค่า `title` นั้นใส่ในวิดเจ็ทข้อความ (`Text`)
`build` `build`
```dart
title: Text(widget.title),
),
```
#afigure(
```dart
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
```,
caption: [],
)
*:* `AppBar` (
`Colors.amber`) hot reload #box(
image("Flutter/flutterHotReload.svg", alt: "สายฟ้า", width: 1.5em),
baseline: 20%,
)
#afigure(
```dart
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
```,
caption: [],
)
`title` `widget`
`MyHomePage` `title` `title`
(`Text`)
#afigure(
```dart
title: Text(widget.title),
),
```,
caption: [],
)
`Center` 1 (`child`)
```dart
body: Center(
```
#afigure(
```dart
body: Center(
```,
caption: [],
)
และ `Column` เป็นวิดเจ็ทจัดเลย์เอาต์เช่นกัน มันรับลูกหลายคน (`children`) แล้วจัดเรียงมันในแนวตั้ง โดยค่าเริ่มต้นแล้ว มันจะจัดให้ตัวเองกว้างเท่ากับลูก ของมัน และพยายามจัดให้ตัวเองสูงเท่าวิดเจ็ทที่สูงกว่า
`Column` (`children`)
วิดเจ็ทคอลัมน์มีหลายคุณสมบัติในการควบคุมขนาดของมันและการจัดวางลูก ของมัน โดยด้านล่างมีการใช้อาร์กิวเมนต์ `mainAxisAlignment` ในการจัดลูก ของมันให้อยู่ตรงกลางในแนวตั้ง โดย "main axis" หรือ แกนหลัก ในกรณีนี้คือแนวตั้ง เพราะคอลัมน์นั้นเป็นแนวตั้ง (และ "cross axis" หรือแกนไขว้ จะเป็นแนวนอน คือแนวตรงข้ามกับแนวหลัก)
`mainAxisAlignment`
"main axis" ( "cross axis"
)
```dart
child: Column(
mainAxisAlignment: .center,
children: [
const Text('You have pushed the button this many times:'),
Text(
'$_counter',
```
#afigure(
```dart
child: Column(
mainAxisAlignment: .center,
children: [
const Text('You have pushed the button this many times:'),
Text(
'$_counter',
```,
caption: [],
)
การเข้าถึงธีมของแอพลิเคชัน (```dart Theme.of(context)```) แล้วนำธีมข้อความ `headlineMedium` มาใช้:
(```dart Theme.of(context)```)
`headlineMedium` :
```dart
style: Theme.of(context).textTheme.headlineMedium,
), // Text
],
), // Column
), // Center
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
#afigure(
```dart
style: Theme.of(context).textTheme.headlineMedium,
), // Text
],
), // Column
), // Center
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
}
```
```,
caption: [],
)
#pagebreak()
@@ -397,18 +529,23 @@ class _MyHomePageState extends State<MyHomePage> {
==
#i ไฟล์ `pubspec.yaml` เป็นไฟล์ที่เก็บข้อมูลเกี่ยวกับโปรเจกต์ Flutter ของคุณ เช่น ชื่อ คำอธิบาย เวอร์ชัน และรวมถึงสิ่งที่จะกล่าวถึงในหัวข้อนี้ คือการติดตั้งและนำเข้าแพคเกจภายนอกมาใช้ในโปรเจกต์
#i `pubspec.yaml` Flutter
#i โดยหากไม่รวมรายละเอียดโปรเจกต์เบื้องต้นเช่นชื่อและคำอธิบายแล้ว ไฟล์ `pubspec.yaml` จะมีรายละเอียดดังนี้
#i `pubspec.yaml`
`environment` นั้นจะกล่าวถึงสิ่งแวดล้อม ซึ่งในกรณีนี้มีเพียง `sdk` ที่ระบุเวอร์ชันของ Flutter SDK ในการคอมไพล์โปรเจกต์
`environment` `sdk` Flutter SDK
```yaml
environment:
sdk: ^3.10.1
```
`dependencies` จะกล่าวถึงไลบรารีที่โปรเจกต์พึ่งพา ซึ่งโดยค่าเริ่มต้นแล้ว ในโปรเจกต์ตัวอย่างจะมีการติดตั้งเซ็ทไอคอน Cupertino มาให้ (`cupertino_icons`; หรือเรียกอย่างง่ายว่า ไอคอน iOS) ซึ่งแน่นอนว่าหากคุณไม่ใช้ สามารถลบทิ้งได้
`dependencies`
Cupertino (`cupertino_icons`;
iOS)
```yaml
dependencies:
@@ -418,7 +555,10 @@ dependencies:
cupertino_icons: ^1.0.8
```
`dev_dependencies` กล่าวถึงไลบรารีที่โปรเจกต์พึ่งพา#emph([ในการพัฒนา]) หมายความว่า ไลบรารีเหล่านี้จะไม่ถูกใส่เข้าไปยังแอพลิเคชันของคุณโดยตรง โดยตามค่าเริ่มต้นแล้ว จะมีแพคเกจ `flutter_test` ที่ถูกดึงมาจาก Flutter SDK โดยตรง และมี `flutter_lints` สำหรับการตรวจข้อผิดพลาดในโคด
`dev_dependencies` #emph([ในการพัฒนา])
`flutter_test` Flutter SDK `flutter_lints`
```yaml
dev_dependencies:
@@ -428,21 +568,25 @@ dev_dependencies:
flutter_lints: ^6.0.0
```
`flutter` เป็นการตั้งค่าเกี่ยวกับ Flutter โดยที่ตามค่าเริ่มต้นแล้วจะมีค่า `uses-material-design` มาให้เป็น `true` ซึ่งจะเป็นการบอกกับ Flutter ว่าแอพลิเคชันนั้นใช้ Material design
`flutter` Flutter `uses-material-design`
`true` Flutter Material design
```yaml
flutter:
uses-material-design: true
```
และนอกจากนั้นแล้ว ในส่วนของ `flutter` นี้จะเป็นส่วนที่ลิสต์รายการไฟล์เพิ่มเติมที่ต้องการใส่เข้าไปในแอพลิเคชันด้วยเช่นกัน ตัวอย่างเช่น โครงงานนี้มีการเพิ่มเติมในส่วน `flutter` ดังนี้:
`flutter`
`flutter` :
```yaml
assets:
- assets/certificates/rootCA.crt
```
โดยจะเป็นการเพิ่มไฟล์ใบรับรอง `rootCA.crt` เข้าไปกับแอพลิเคชันเพื่อใช้ในการส่งคำขอ HTTPS ไปยังอุปกรณ์ของโครงงาน
`rootCA.crt` HTTPS
#pagebreak()
@@ -453,15 +597,25 @@ flutter:
+ Material Design: Google Android
+ Cupertino Design: Apple iOS
*หมายเหตุ:* Cupertino Design ถูกแทนที่โดย Liquid Glass แล้ว โดยในปัจจุบันทีม Flutter กำลังทำการตรวจสอบและแก้ไขโครงสร้างระบบดีไซน์ ดังนั้น หากมีผู้พัฒนาต้องการใช้เอฟเฟกต์ Liquid Glass ในแอพลิเคชัน Flutter จึงจำเป็นต้องพึงพาแพคเกจบุคคลที่สามก่อนในขณะนี้ (Flutter เวอร์ชัน 3.38.3 เวลาที่พิมพ์)
*:* Cupertino Design Liquid Glass Flutter
Liquid
Glass Flutter (Flutter
3.38.3 )
#i แอพลิเคชันในโครงงานนี้ใช้ Material Design เนื่องจากมีเป้าหมายหลักเป็นแพลตฟอร์ม Android โดย Material Design คือภาษาการดีไซน์ที่ถูกพัฒนาโดย Google และถูกเปิดตัวครั้งแรก 25 มิถุนายน 2014 และมีเวอร์ชันหลัก 3 เวอร์ชันด้วยกัน โดยที่เวอร์ชันที่ 3 ถูกเปิดตัวในงาน Google I/O 2021 และมีชื่อว่า "Material You" (แต่ชื่อธรรมดา "Material Design 3" ก็ยังถูกใช้งานกันอย่างปกติ) และในงาน Google I/O 2025 มีการเปิดตัว "Material 3 Expressive" ซึ่งเป็นการปรับปรุงต่อจาก Material You เดิมสำหรับ Android 16 และ Wear OS 6 และสามารถดูรายละเอียดเพิ่มเติมเกี่ยวกับ Material 3 ได้ที่ https://m3.material.io/
#i Material Design Android
Material Design Google 25
2014 3 3 Google I/O 2021
"Material You" ( "Material Design 3" )
Google I/O 2025 "Material 3 Expressive"
Material You Android 16 Wear OS 6
Material 3 https://m3.material.io/
==
=== Android <flAndroid>
#i ในการพัฒนาแอพลิเคชัน Android โดยใช้เฟรมเวิร์ก Flutter จำเป็นต้องใช้ส่วนประกอบเครื่องมือพัฒนา Android ดังนี้
#i Android Flutter
Android
- Android SDK (API Level 36 )
- Android SDK Build-Tools
@@ -471,31 +625,59 @@ flutter:
Android Studio
#i ในการติดตั้ง Android SDK ควรติดตั้ง Android SDK ล่าสุดถึงแม้ว่าอุปกรณ์ของคุณจะใช้เวอร์ชันที่เก่ากว่านั้น เพื่อความมั่นใจว่าแอพลิเคชันจะสามารถใช้กับอุปกรณ์ที่ใหม่ล่าสุดได้
#i Android SDK Android SDK
#i แอพลิเคชัน Android จะมี SDK/API level เป้าหมาย (Target SDK/API level) และ SDK/API level ขั้นต่ำ (Minimum SDK/API level) โครงงานนี้ เวลาที่พิมพ์ ใช้ API level เป้าหมาย 36 (Android 16) และ API level ขั้นต่ำ 24 (Android 7) ซึ่งรวมกันแล้ว แอพลิเคชัน Android จะสามารถติดตั้งได้บนระบบตั้งแต่ API level ขั้นต่ำจนถึง API level เป้าหมาย หรือก็คือ แอพลิเคชันในโครงงานนี้สามารถติดตั้งได้ตั้งแต่บนระบบ Android 7 ถึง Android 16 นั่นเอง
#i Android SDK/API level (Target SDK/API level) SDK/API
level (Minimum SDK/API level) API level 36
(Android 16) API level 24 (Android 7) Android
API level API level
Android 7 Android 16
==== Java/Kotlin
#i Java และ Kotlin เป็นภาษาสำคัญสำหรับการพัฒนาแอพลิเคชัน Android ถึงอย่างไรก็ตาม แอพลิเคชัน Flutter นั้นถูกเขียนด้วยภาษา Dart แต่ยังจำเป็นต้องมีโคด Java และ Kotlin เล็กน้อยเพื่อเริ่มต้นแอพลิเคชัน Flutter
#i Java Kotlin Android
Flutter Dart Java Kotlin
Flutter
#i โดยปกติแล้ว Flutter จะสร้างโคดพื้นฐานขึ้นมาให้สำหรับการเริ่มแอพลิเคชันแบบพื้นฐาน (อยู่ภายในโฟลเดอร์ `java` และ `kotlin` ตามที่ถูกกล่าวถึงใน@flStructure) ดังนั้นจึงไม่จำเป็นต้องมีการเขียนโคด Java หรือ Kotlin เอง แต่ในบางกรณี อาจต้องเขียนโคดเพิ่มเองหากมีความต้องการเข้าถึงฟีเจอร์พื้นฐานระบบที่ Flutter ไม่มี API เพื่อให้เข้าถึงได้และไม่มีแพคเกจเพื่อรองรับฟีเจอร์ที่ต้องการ
#i Flutter
( `java` `kotlin` @flStructure)
Java Kotlin
Flutter API
#i โครงการนี้ใช้ Java 21 (JetBrains Runtime/Azul Zulu OpenJDK) เป็นหลักในการทำงานกับ Gradle แต่แอพลิเคชัน Android ที่ผลิตออกมานั้น เพื่อให้เข้ากับเวอร์ชันที่เก่ากว่าของระบบปฏิบัติการได้ ใช้ Java 11
#i Java 21 (JetBrains Runtime/Azul Zulu OpenJDK)
Gradle Android
Java 11
==== Gradle
#i Gradle เป็นเครื่องมือสร้างระบบอัตโนมัติสำหรับการพัฒนาซอฟต์แวร์หลายภาษา จัดการงานต่าง เช่น การคอมไพล์ การแพ็คเกจ การทดสอบ การปรับใช้ และการเผยแพร่ ภาษาที่รองรับ ได้แก่ Java (รวมถึงภาษา Kotlin, Groovy, Scala ที่ใช้ JDK), C/C++ และ JavaScript Gradle พัฒนาต่อยอดจากแนวคิดของ Apache Ant และ Apache Maven และนำเสนอภาษาเฉพาะโดเมนที่ใช้ Groovy และ Kotlin ซึ่งต่างจากการกำหนดค่าโครงการที่ใช้ XML ที่ Maven ใช้ Gradle ใช้กราฟแบบอะไซคลิกกำกับทิศทางเพื่อจัดการการอ้างอิง กราฟนี้ใช้เพื่อกำหนดลำดับของงานที่ควรดำเนินการ Gradle ทำงานบน Java Virtual Machine
#i Gradle
Java
( Kotlin, Groovy, Scala JDK), C/C++ JavaScript Gradle
Apache Ant Apache Maven
Groovy Kotlin XML Maven Gradle
Gradle Java Virtual Machine
#i Gradle คือเครื่องมือหลักที่ใช้ในการจัดการโปรเจกต์ Java ส่วนใหญ่ รวมถึงโปรเจกต์ Android โดยในโครงการนี้ จะใช้ Gradle เวอร์ชัน 8.14.3 เป็นหลัก
#i Gradle Java Android
Gradle 8.14.3
#i โดยปกติแล้ว ผู้พัฒนานั้นไม่มีความจำเป็นที่จะต้องแตะต้อง Gradle ด้วยตนเอง และ Flutter จะทำการจัดการเอง แต่หากมีความจำเป็นต้องใช้คำสั่ง Gradle ด้วยตนเอง จะมีสคริปต์ `gradlew` (หรือ `gradlew.bat` สำหรับผู้ใช้ Windows) ภายในโฟลเดอร์ `android` ของโปรเจกต์ Flutter เสมอเพื่อเรียกใช้ Gradle ที่ถูกดาวน์โหลดมาสำหรับโปรเจกต์นั้น
#i Gradle Flutter
Gradle `gradlew` (
`gradlew.bat` Windows) `android` Flutter
Gradle
=== Linux <flLinuxDetails>
#i เช่นเดียวกับ Android ที่กล่าวไปข้างต้น Flutter มีการสร้างโคดสำหรับการเปิดแอพลิเคชันแบบพื้นฐาน แต่สำหรับ Linux แล้วนั้น Flutter ใช้โคด C++ และเฟรมเวิร์ก CMake ในการสร้างรากฐานของแอพลิเคชัน
#i Android Flutter
Linux Flutter C++ CMake
#i ในการพัฒนาแอพลิเคชันสำหรับ Linux ต้องติดตั้งโปรแกรมเพิ่มเติม (build dependencies) ขยายความคือ ด้านบนคือสิ่งที่จำเป็นหากมีระบบอื่นเป็นเป้าหมาย แต่หากต้องการพัฒนาแอพลิเคชัน Linux ต้องติดตั้งโปรแกรมในรายการด้านล่างเพิ่ม
#i Linux (build dependencies)
Linux
#grid(
columns: 2,
@@ -512,7 +694,8 @@ flutter:
],
)
#i การติดตั้งไลบรารีและโปรแกรมที่กล่าวไปข้างต้นจะแตกต่างกันไปแต่ละการแจกจ่าย Linux และ Flutter ใช้ไลบรารีพื้นฐานดังกล่าวในการทำงานของแอพลิเคชัน (runtime dependencies)
#i Linux
Flutter (runtime dependencies)
- GTK 3
- blkid
@@ -561,4 +744,6 @@ sudo pacman -S --needed util-linux-libs xz gtk3
=== macOS/iOS
#i การพัฒนาแอพลิเคชันสำหรับ macOS และ iOS นั้นต้องทำบน macOS เท่านั้นและจำเป็นต้องพึ่งพาเครื่องมือ Xcode แต่เนื่องจากในโครงงานนี้ไม่มีผู้ใช้ macOS จึงไม่สามารถสร้างไบนารีสำหรับ macOS และ iOS ออกมาได้ และไม่ใช่เป้าหมายของโครงงานนี้เช่นกัน
#i macOS iOS macOS
Xcode macOS
macOS iOS
+182 -32
View File
@@ -2,87 +2,237 @@
= เกณฑ์วิธีขนส่งข้อความหลายมิติแบบมั่นคง (Hypertext Transfer Protocol Secure; HTTPS)
#i เกณฑ์วิธีขนส่งข้อความหลายมิติแบบมั่นคง (Hypertext Transfer Protocol Secure; HTTPS) คือส่วนต่อขยายของโปรโตคอลเกณฑ์วิธีขนส่งข้อความหลายมิติ (Hypertext Transfer Protocol; HTTP) ซึ่งใช้การเข้ารหัสเพื่อการสื่อสารที่ปลอดภัยผ่านเครือข่ายคอมพิวเตอร์ และถูกใช้อย่างแพร่หลายบนอินเทอร์เน็ต โดยโปรโตคอลเครือข่าย HTTPS จะถูกเข้ารหัสด้วยเกณฑ์วิธีความมั่นคงของชั้นขนส่ง (Transport Layer Security; TLS) หรือก่อนหน้านี้คือเกณฑ์วิธีชั้นซ็อกเก็ตปลอดภัย (Secure Sockets Layer; SSL) ด้วยเหตุนั้น โปรโตคอลนี้สามารถเรียกด้วยชื่อ HTTP over TLS หรือ HTTP over SSL ได้เช่นกัน
#i เกณฑ์วิธีขนส่งข้อความหลายมิติแบบมั่นคง (Hypertext Transfer Protocol Secure; HTTPS)
คือส่วนต่อขยายของโปรโตคอลเกณฑ์วิธีขนส่งข้อความหลายมิติ (Hypertext Transfer Protocol; HTTP)
ซึ่งใช้การเข้ารหัสเพื่อการสื่อสารที่ปลอดภัยผ่านเครือข่ายคอมพิวเตอร์ และถูกใช้อย่างแพร่หลายบนอินเทอร์เน็ต
โดยโปรโตคอลเครือข่าย HTTPS จะถูกเข้ารหัสด้วยเกณฑ์วิธีความมั่นคงของชั้นขนส่ง (Transport Layer
Security; TLS) หรือก่อนหน้านี้คือเกณฑ์วิธีชั้นซ็อกเก็ตปลอดภัย (Secure Sockets Layer; SSL)
ด้วยเหตุนั้น โปรโตคอลนี้สามารถเรียกด้วยชื่อ HTTP over TLS หรือ HTTP over SSL ได้เช่นกัน
#i แรงจูงใจหลักของ HTTPS คือการยืนยันตัวตนของเว็บไซต์ที่เข้าถึง และการปกป้องความเป็นส่วนตัวและความสมบูรณ์ของข้อมูลที่แลกเปลี่ยนระหว่างการรับส่งข้อมูล HTTPS ป้องกันการโจมตีแบบ man-in-the-middle และการเข้ารหัสบล็อกไซเฟอร์แบบสองทิศทางในการสื่อสารระหว่างไคลเอนต์และเซิร์ฟเวอร์ ช่วยป้องกันการสื่อสารจากการดักฟังและการปลอมแปลง ประเด็นการพิสูจน์ตัวตนของ HTTPS จำเป็นต้องมีบุคคลที่สามที่เชื่อถือได้ลงนามในใบรับรองดิจิทัลฝั่งเซิร์ฟเวอร์ เดิมทีการดำเนินการนี้มีค่าใช้จ่ายสูง ซึ่งหมายความว่าการเชื่อมต่อ HTTPS ที่ผ่านการรับรองความถูกต้องอย่างสมบูรณ์มักจะพบได้เฉพาะในบริการธุรกรรมการชำระเงินที่ปลอดภัยและระบบสารสนเทศขององค์กรที่ปลอดภัยอื่นๆ บนเวิลด์ไวด์เว็บเท่านั้น ในปี 2016 แคมเปญโดยมูลนิธิพรมแดนอิเล็กทรอนิกส์ (Electronic Frontier Foundation; EFF) ด้วยการสนับสนุนจากนักพัฒนาเว็บเบราว์เซอร์ ทำให้โปรโตคอลนี้แพร่หลายมากขึ้น นับตั้งแต่ปี 2018 เป็นต้นมา HTTPS ถูกใช้โดยผู้ใช้เว็บบ่อยกว่า HTTP ดั้งเดิมที่ไม่ปลอดภัย โดยส่วนใหญ่เพื่อปกป้องความถูกต้องของหน้าเว็บบนเว็บไซต์ทุกประเภท รักษาความปลอดภัยบัญชี และรักษาความเป็นส่วนตัวของการสื่อสาร การระบุตัวตน และการท่องเว็บของผู้ใช้
#i แรงจูงใจหลักของ HTTPS คือการยืนยันตัวตนของเว็บไซต์ที่เข้าถึง
และการปกป้องความเป็นส่วนตัวและความสมบูรณ์ของข้อมูลที่แลกเปลี่ยนระหว่างการรับส่งข้อมูล HTTPS
ป้องกันการโจมตีแบบ man-in-the-middle
และการเข้ารหัสบล็อกไซเฟอร์แบบสองทิศทางในการสื่อสารระหว่างไคลเอนต์และเซิร์ฟเวอร์
ช่วยป้องกันการสื่อสารจากการดักฟังและการปลอมแปลง ประเด็นการพิสูจน์ตัวตนของ HTTPS
จำเป็นต้องมีบุคคลที่สามที่เชื่อถือได้ลงนามในใบรับรองดิจิทัลฝั่งเซิร์ฟเวอร์ เดิมทีการดำเนินการนี้มีค่าใช้จ่ายสูง
ซึ่งหมายความว่าการเชื่อมต่อ HTTPS
ที่ผ่านการรับรองความถูกต้องอย่างสมบูรณ์มักจะพบได้เฉพาะในบริการธุรกรรมการชำระเงินที่ปลอดภัยและระบบสารสนเทศขององค์กรที่ปลอดภัยอื่นๆ
บนเวิลด์ไวด์เว็บเท่านั้น ในปี 2016 แคมเปญโดยมูลนิธิพรมแดนอิเล็กทรอนิกส์ (Electronic Frontier
Foundation; EFF) ด้วยการสนับสนุนจากนักพัฒนาเว็บเบราว์เซอร์ ทำให้โปรโตคอลนี้แพร่หลายมากขึ้น
นับตั้งแต่ปี 2018 เป็นต้นมา HTTPS ถูกใช้โดยผู้ใช้เว็บบ่อยกว่า HTTP ดั้งเดิมที่ไม่ปลอดภัย
โดยส่วนใหญ่เพื่อปกป้องความถูกต้องของหน้าเว็บบนเว็บไซต์ทุกประเภท รักษาความปลอดภัยบัญชี
และรักษาความเป็นส่วนตัวของการสื่อสาร การระบุตัวตน และการท่องเว็บของผู้ใช้
== โดยรวม
#i รูปแบบ Uniform Resource Identifier (URI) ของ HTTPS มีรูปแบบการใช้งานที่เหมือนกันกับรูปแบบ HTTP อย่างไรก็ตาม HTTPS จะส่งสัญญาณให้เบราว์เซอร์ใช้ชั้นการเข้ารหัสเพิ่มเติมของ SSL/TLS เพื่อปกป้องการรับส่งข้อมูลซึ่ง SSL/TLS เหมาะอย่างยิ่งสำหรับ HTTP เนื่องจากสามารถให้การป้องกันได้แม้ว่าจะมีการตรวจสอบความถูกต้องเพียงด้านเดียวของการสื่อสาร ในกรณีนี้คือธุรกรรม HTTP บนอินเทอร์เน็ต ซึ่งโดยทั่วไปมีเพียงเซิร์ฟเวอร์เท่านั้นที่ได้รับการรับรองความถูกต้อง (โดยไคลเอนต์ตรวจสอบใบรับรองของเซิร์ฟเวอร์)
#i รูปแบบ Uniform Resource Identifier (URI) ของ HTTPS
มีรูปแบบการใช้งานที่เหมือนกันกับรูปแบบ HTTP อย่างไรก็ตาม HTTPS
จะส่งสัญญาณให้เบราว์เซอร์ใช้ชั้นการเข้ารหัสเพิ่มเติมของ SSL/TLS เพื่อปกป้องการรับส่งข้อมูลซึ่ง SSL/TLS
เหมาะอย่างยิ่งสำหรับ HTTP
เนื่องจากสามารถให้การป้องกันได้แม้ว่าจะมีการตรวจสอบความถูกต้องเพียงด้านเดียวของการสื่อสาร
ในกรณีนี้คือธุรกรรม HTTP บนอินเทอร์เน็ต
ซึ่งโดยทั่วไปมีเพียงเซิร์ฟเวอร์เท่านั้นที่ได้รับการรับรองความถูกต้อง
(โดยไคลเอนต์ตรวจสอบใบรับรองของเซิร์ฟเวอร์)
#i HTTPS สร้างช่องทางที่ปลอดภัยบนเครือข่ายที่ไม่ปลอดภัย วิธีนี้ช่วยให้มั่นใจได้ถึงการป้องกันที่เหมาะสมจากผู้ดักฟังและการโจมตีแบบ man-in-the-middle โดยมีเงื่อนไขว่ามีการใช้ชุดการเข้ารหัสที่เหมาะสม และใบรับรองเซิร์ฟเวอร์ได้รับการตรวจสอบและเชื่อถือได้
#i HTTPS สร้างช่องทางที่ปลอดภัยบนเครือข่ายที่ไม่ปลอดภัย
วิธีนี้ช่วยให้มั่นใจได้ถึงการป้องกันที่เหมาะสมจากผู้ดักฟังและการโจมตีแบบ man-in-the-middle
โดยมีเงื่อนไขว่ามีการใช้ชุดการเข้ารหัสที่เหมาะสม และใบรับรองเซิร์ฟเวอร์ได้รับการตรวจสอบและเชื่อถือได้
#i เนื่องจาก HTTPS เชื่อมโยง HTTP ทั้งหมดเข้ากับ TLS โดยตรงจึงสามารถเข้ารหัสโปรโตคอล HTTP พื้นฐานทั้งหมดได้ ซึ่งรวมถึง URL ของคำขอ พารามิเตอร์การค้นหา ส่วนหัว และคุกกี้ (ซึ่งมักจะมีข้อมูลระบุตัวตนของผู้ใช้) อย่างไรก็ตาม เนื่องจากที่อยู่เว็บไซต์และหมายเลขพอร์ตเป็นส่วนหนึ่งของโปรโตคอล TCP/IP พื้นฐาน HTTPS จึงไม่สามารถปกป้องการเปิดเผยข้อมูลเหล่านี้ได้ ในทางปฏิบัติ หมายความว่าแม้แต่บนเว็บเซิร์ฟเวอร์ที่กำหนดค่าอย่างถูกต้อง ผู้ดักฟังก็สามารถอนุมานที่อยู่ IP และหมายเลขพอร์ตของเว็บเซิร์ฟเวอร์ และบางครั้งอาจรวมถึงชื่อโดเมน (เช่น www.example.org แต่ไม่สามารถอนุมานส่วนที่เหลือของ URL) ที่ผู้ใช้กำลังสื่อสารด้วย รวมถึงปริมาณข้อมูลที่ถ่ายโอนและระยะเวลาของการสื่อสาร แต่อย่างไรก็ตามไม่รวมถึงเนื้อหาของการสื่อสาร
#i เนื่องจาก HTTPS เชื่อมโยง HTTP ทั้งหมดเข้ากับ TLS โดยตรงจึงสามารถเข้ารหัสโปรโตคอล HTTP
พื้นฐานทั้งหมดได้ ซึ่งรวมถึง URL ของคำขอ พารามิเตอร์การค้นหา ส่วนหัว และคุกกี้
(ซึ่งมักจะมีข้อมูลระบุตัวตนของผู้ใช้) อย่างไรก็ตาม
เนื่องจากที่อยู่เว็บไซต์และหมายเลขพอร์ตเป็นส่วนหนึ่งของโปรโตคอล TCP/IP พื้นฐาน HTTPS
จึงไม่สามารถปกป้องการเปิดเผยข้อมูลเหล่านี้ได้ ในทางปฏิบัติ
หมายความว่าแม้แต่บนเว็บเซิร์ฟเวอร์ที่กำหนดค่าอย่างถูกต้อง ผู้ดักฟังก็สามารถอนุมานที่อยู่ IP
และหมายเลขพอร์ตของเว็บเซิร์ฟเวอร์ และบางครั้งอาจรวมถึงชื่อโดเมน (เช่น www.example.org
แต่ไม่สามารถอนุมานส่วนที่เหลือของ URL) ที่ผู้ใช้กำลังสื่อสารด้วย
รวมถึงปริมาณข้อมูลที่ถ่ายโอนและระยะเวลาของการสื่อสาร แต่อย่างไรก็ตามไม่รวมถึงเนื้อหาของการสื่อสาร
#i เว็บเบราว์เซอร์รู้วิธีเชื่อถือเว็บไซต์ HTTPS โดยอ้างอิงจากผู้ให้บริการออกใบรับรอง (Certificate Authority) ที่ติดตั้งไว้ล่วงหน้าในซอฟต์แวร์ ผู้สร้างเว็บเบราว์เซอร์จึงไว้วางใจผู้ให้บริการออกใบรับรองในการออกใบรับรองที่ถูกต้อง ดังนั้น ผู้ใช้ควรเชื่อถือการเชื่อมต่อ HTTPS ไปยังเว็บไซต์ก็ต่อเมื่อเป็นไปตามเงื่อนไขทั้งหมดต่อไปนี้:
#i เว็บเบราว์เซอร์รู้วิธีเชื่อถือเว็บไซต์ HTTPS โดยอ้างอิงจากผู้ให้บริการออกใบรับรอง (Certificate
Authority) ที่ติดตั้งไว้ล่วงหน้าในซอฟต์แวร์
ผู้สร้างเว็บเบราว์เซอร์จึงไว้วางใจผู้ให้บริการออกใบรับรองในการออกใบรับรองที่ถูกต้อง ดังนั้น
ผู้ใช้ควรเชื่อถือการเชื่อมต่อ HTTPS ไปยังเว็บไซต์ก็ต่อเมื่อเป็นไปตามเงื่อนไขทั้งหมดต่อไปนี้:
- ผู้ใช้เชื่อมั่นว่าอุปกรณ์ของตน โฮสต์เบราว์เซอร์ และวิธีการเข้าถึงเบราว์เซอร์นั้นไม่ถูกบุกรุก (กล่าวคือ ไม่มีการโจมตีซัพพลายเชน)
- ผู้ใช้เชื่อมั่นว่าซอฟต์แวร์เบราว์เซอร์ใช้งาน HTTPS ได้อย่างถูกต้องพร้อมกับผู้ให้บริการออกใบรับรองที่ติดตั้งไว้ล่วงหน้าอย่างถูกต้อง
- ผู้ใช้เชื่อมั่นว่าผู้ให้บริการออกใบรับรองจะรับรองเฉพาะเว็บไซต์ที่ถูกต้องตามกฎหมายเท่านั้น (กล่าวคือ ผู้ให้บริการออกใบรับรองจะไม่ถูกบุกรุกและไม่มีการออกใบรับรองที่ผิดพลาด)
- ผู้ใช้เชื่อมั่นว่าอุปกรณ์ของตน โฮสต์เบราว์เซอร์ และวิธีการเข้าถึงเบราว์เซอร์นั้นไม่ถูกบุกรุก (กล่าวคือ
ไม่มีการโจมตีซัพพลายเชน)
- ผู้ใช้เชื่อมั่นว่าซอฟต์แวร์เบราว์เซอร์ใช้งาน HTTPS
ได้อย่างถูกต้องพร้อมกับผู้ให้บริการออกใบรับรองที่ติดตั้งไว้ล่วงหน้าอย่างถูกต้อง
- ผู้ใช้เชื่อมั่นว่าผู้ให้บริการออกใบรับรองจะรับรองเฉพาะเว็บไซต์ที่ถูกต้องตามกฎหมายเท่านั้น (กล่าวคือ
ผู้ให้บริการออกใบรับรองจะไม่ถูกบุกรุกและไม่มีการออกใบรับรองที่ผิดพลาด)
- เว็บไซต์มีใบรับรองที่ถูกต้อง ซึ่งหมายความว่าได้รับการลงนามโดยผู้ให้บริการที่เชื่อถือได้
- ใบรับรองระบุเว็บไซต์ได้อย่างถูกต้อง (เช่น เมื่อเบราว์เซอร์เข้าชม https://example.com ใบรับรองที่ได้รับนั้นถูกต้องสำหรับ example.com และไม่ใช่ของหน่วยงานอื่น)
- ใบรับรองระบุเว็บไซต์ได้อย่างถูกต้อง (เช่น เมื่อเบราว์เซอร์เข้าชม https://example.com
ใบรับรองที่ได้รับนั้นถูกต้องสำหรับ example.com และไม่ใช่ของหน่วยงานอื่น)
- ผู้ใช้เชื่อมั่นว่าเลเยอร์การเข้ารหัสของโปรโตคอล (SSL/TLS) มีความปลอดภัยเพียงพอจากการดักฟัง
#i HTTPS มีความสำคัญอย่างยิ่งต่อเครือข่ายที่ไม่ปลอดภัยและเครือข่ายที่อาจถูกแทรกแซง เครือข่ายที่ไม่ปลอดภัย เช่น จุดเชื่อมต่อ Wi-Fi สาธารณะ ซึ่งเปิดโอกาสให้ทุกคนในเครือข่ายท้องถิ่นเดียวกันสามารถดักจับแพ็กเก็ตและค้นพบข้อมูลสำคัญที่ไม่ได้รับการป้องกันโดย HTTPS นอกจากนี้ ยังพบว่าเครือข่าย WLAN ทั้งแบบฟรีและแบบเสียเงินบางเครือข่ายได้แทรกแซงหน้าเว็บโดยการแทรกแพ็กเก็ตเพื่อแสดงโฆษณาของตนเองบนเว็บไซต์อื่น การกระทำเช่นนี้สามารถถูกนำไปใช้ในทางที่ผิดได้หลายวิธี เช่น การฉีดมัลแวร์ลงในหน้าเว็บและการขโมยข้อมูลส่วนบุคคลของผู้ใช้
#i HTTPS มีความสำคัญอย่างยิ่งต่อเครือข่ายที่ไม่ปลอดภัยและเครือข่ายที่อาจถูกแทรกแซง
เครือข่ายที่ไม่ปลอดภัย เช่น จุดเชื่อมต่อ Wi-Fi สาธารณะ
ซึ่งเปิดโอกาสให้ทุกคนในเครือข่ายท้องถิ่นเดียวกันสามารถดักจับแพ็กเก็ตและค้นพบข้อมูลสำคัญที่ไม่ได้รับการป้องกันโดย
HTTPS นอกจากนี้ ยังพบว่าเครือข่าย WLAN
ทั้งแบบฟรีและแบบเสียเงินบางเครือข่ายได้แทรกแซงหน้าเว็บโดยการแทรกแพ็กเก็ตเพื่อแสดงโฆษณาของตนเองบนเว็บไซต์อื่น
การกระทำเช่นนี้สามารถถูกนำไปใช้ในทางที่ผิดได้หลายวิธี เช่น
การฉีดมัลแวร์ลงในหน้าเว็บและการขโมยข้อมูลส่วนบุคคลของผู้ใช้
#i เมื่อมีข้อมูลมากขึ้นเกี่ยวกับการเฝ้าระวังมวลชนทั่วโลกและการขโมยข้อมูลส่วนบุคคลของอาชญากร การใช้ระบบรักษาความปลอดภัย HTTPS บนเว็บไซต์ทั้งหมดจึงมีความสำคัญเพิ่มมากขึ้นเรื่อยๆ โดยไม่คำนึงถึงประเภทของการเชื่อมต่ออินเทอร์เน็ตที่ใช้งาน แม้ว่าข้อมูลเมตาเกี่ยวกับหน้าเว็บแต่ละหน้าที่ผู้ใช้เข้าชมอาจไม่ถือว่ามีความละเอียดอ่อน แต่เมื่อนำมารวมกันแล้ว ข้อมูลเมตาเหล่านี้อาจเปิดเผยข้อมูลเกี่ยวกับผู้ใช้ได้มาก และกระทบต่อความเป็นส่วนตัวของผู้ใช้
#i เมื่อมีข้อมูลมากขึ้นเกี่ยวกับการเฝ้าระวังมวลชนทั่วโลกและการขโมยข้อมูลส่วนบุคคลของอาชญากร
การใช้ระบบรักษาความปลอดภัย HTTPS บนเว็บไซต์ทั้งหมดจึงมีความสำคัญเพิ่มมากขึ้นเรื่อยๆ
โดยไม่คำนึงถึงประเภทของการเชื่อมต่ออินเทอร์เน็ตที่ใช้งาน
แม้ว่าข้อมูลเมตาเกี่ยวกับหน้าเว็บแต่ละหน้าที่ผู้ใช้เข้าชมอาจไม่ถือว่ามีความละเอียดอ่อน
แต่เมื่อนำมารวมกันแล้ว ข้อมูลเมตาเหล่านี้อาจเปิดเผยข้อมูลเกี่ยวกับผู้ใช้ได้มาก
และกระทบต่อความเป็นส่วนตัวของผู้ใช้
#i การปรับใช้ HTTPS ยังอนุญาตให้ใช้ HTTP/2 และ HTTP/3 (และรุ่นก่อนหน้าอย่าง SPDY และ QUIC) ซึ่งเป็น HTTP เวอร์ชันใหม่ที่ออกแบบมาเพื่อลดเวลา ขนาด และความหน่วงในการโหลดหน้าเว็บ
#i การปรับใช้ HTTPS ยังอนุญาตให้ใช้ HTTP/2 และ HTTP/3 (และรุ่นก่อนหน้าอย่าง SPDY และ QUIC)
ซึ่งเป็น HTTP เวอร์ชันใหม่ที่ออกแบบมาเพื่อลดเวลา ขนาด และความหน่วงในการโหลดหน้าเว็บ
#i และมีการแนะนำให้ใช้ HTTP Strict Transport Security (HSTS) ร่วมกับ HTTPS เพื่อป้องกันผู้ใช้จากการโจมตีแบบ man-in-the-middle โดยเฉพาะอย่างยิ่ง SSL stripping
#i และมีการแนะนำให้ใช้ HTTP Strict Transport Security (HSTS) ร่วมกับ HTTPS
เพื่อป้องกันผู้ใช้จากการโจมตีแบบ man-in-the-middle โดยเฉพาะอย่างยิ่ง SSL stripping
== ความปลอดภัย
#i ความปลอดภัยของ HTTPS อยู่ที่ TLS พื้นฐาน ซึ่งโดยทั่วไปจะใช้คีย์สาธารณะและคีย์ส่วนตัวระยะยาวเพื่อสร้างคีย์เซสชันระยะสั้น ซึ่งจะถูกนำไปใช้ในการเข้ารหัสการไหลของข้อมูลระหว่างไคลเอนต์และเซิร์ฟเวอร์ ใบรับรอง X.509 ถูกใช้เพื่อยืนยันตัวตนของเซิร์ฟเวอร์ (และบางครั้งรวมถึงไคลเอนต์ด้วย) ด้วยเหตุนี้ ผู้ให้บริการออกใบรับรองและใบรับรองคีย์สาธารณะจึงจำเป็นต่อการตรวจสอบความสัมพันธ์ระหว่างใบรับรองและเจ้าของ รวมถึงการสร้าง ลงนาม และดูแลความถูกต้องของใบรับรอง แม้ว่าวิธีนี้อาจมีประโยชน์มากกว่าการตรวจสอบตัวตนผ่านเครือข่ายที่เชื่อถือได้ แต่การเปิดเผยข้อมูลการเฝ้าระวังข้อมูลจำนวนมากในปี 2013 ได้ชี้ให้เห็นถึงผู้ให้บริการออกใบรับรองว่าเป็นจุดอ่อนที่อาจนำไปสู่การโจมตีแบบ man-in-the-middle คุณสมบัติที่สำคัญในบริบทนี้คือความลับแบบส่งต่อ (Forward Secrecy) ซึ่งรับประกันว่าการสื่อสารที่เข้ารหัสที่บันทึกไว้ในอดีตจะไม่สามารถดึงข้อมูลและถอดรหัสได้ หากคีย์ลับหรือรหัสผ่านระยะยาวถูกบุกรุกในอนาคต ไม่ใช่ทุกเว็บเซิร์ฟเวอร์ที่จะมีระบบความลับแบบส่งต่อ
#i ความปลอดภัยของ HTTPS อยู่ที่ TLS พื้นฐาน
ซึ่งโดยทั่วไปจะใช้คีย์สาธารณะและคีย์ส่วนตัวระยะยาวเพื่อสร้างคีย์เซสชันระยะสั้น
ซึ่งจะถูกนำไปใช้ในการเข้ารหัสการไหลของข้อมูลระหว่างไคลเอนต์และเซิร์ฟเวอร์ ใบรับรอง X.509
ถูกใช้เพื่อยืนยันตัวตนของเซิร์ฟเวอร์ (และบางครั้งรวมถึงไคลเอนต์ด้วย) ด้วยเหตุนี้
ผู้ให้บริการออกใบรับรองและใบรับรองคีย์สาธารณะจึงจำเป็นต่อการตรวจสอบความสัมพันธ์ระหว่างใบรับรองและเจ้าของ
รวมถึงการสร้าง ลงนาม และดูแลความถูกต้องของใบรับรอง
แม้ว่าวิธีนี้อาจมีประโยชน์มากกว่าการตรวจสอบตัวตนผ่านเครือข่ายที่เชื่อถือได้
แต่การเปิดเผยข้อมูลการเฝ้าระวังข้อมูลจำนวนมากในปี 2013
ได้ชี้ให้เห็นถึงผู้ให้บริการออกใบรับรองว่าเป็นจุดอ่อนที่อาจนำไปสู่การโจมตีแบบ man-in-the-middle
คุณสมบัติที่สำคัญในบริบทนี้คือความลับแบบส่งต่อ (Forward Secrecy)
ซึ่งรับประกันว่าการสื่อสารที่เข้ารหัสที่บันทึกไว้ในอดีตจะไม่สามารถดึงข้อมูลและถอดรหัสได้
หากคีย์ลับหรือรหัสผ่านระยะยาวถูกบุกรุกในอนาคต ไม่ใช่ทุกเว็บเซิร์ฟเวอร์ที่จะมีระบบความลับแบบส่งต่อ
#i เพื่อให้ HTTPS มีประสิทธิภาพ เว็บไซต์จะต้องโฮสต์ผ่าน HTTPS ทั้งหมด หากเนื้อหาบางส่วนของเว็บไซต์ถูกโหลดผ่าน HTTP (เช่น สคริปต์หรือรูปภาพ) หรือหากโหลดเฉพาะหน้าที่มีข้อมูลละเอียดอ่อน เช่น หน้าเข้าสู่ระบบ ผ่าน HTTPS ขณะที่ส่วนอื่นๆ ของเว็บไซต์ผ่าน HTTP ธรรมดา ผู้ใช้จะเสี่ยงต่อการถูกโจมตีและการเฝ้าระวัง นอกจากนี้ คุกกี้บนเว็บไซต์ที่รันผ่าน HTTPS จะต้องเปิดใช้งานแอตทริบิวต์ secure ในเว็บไซต์ที่มีข้อมูลละเอียดอ่อน ผู้ใช้และเซสชันจะถูกเปิดเผยทุกครั้งที่เข้าถึงเว็บไซต์นั้นด้วย HTTP แทนที่จะเป็น HTTPS
#i เพื่อให้ HTTPS มีประสิทธิภาพ เว็บไซต์จะต้องโฮสต์ผ่าน HTTPS ทั้งหมด
หากเนื้อหาบางส่วนของเว็บไซต์ถูกโหลดผ่าน HTTP (เช่น สคริปต์หรือรูปภาพ)
หรือหากโหลดเฉพาะหน้าที่มีข้อมูลละเอียดอ่อน เช่น หน้าเข้าสู่ระบบ ผ่าน HTTPS ขณะที่ส่วนอื่นๆ
ของเว็บไซต์ผ่าน HTTP ธรรมดา ผู้ใช้จะเสี่ยงต่อการถูกโจมตีและการเฝ้าระวัง นอกจากนี้
คุกกี้บนเว็บไซต์ที่รันผ่าน HTTPS จะต้องเปิดใช้งานแอตทริบิวต์ secure ในเว็บไซต์ที่มีข้อมูลละเอียดอ่อน
ผู้ใช้และเซสชันจะถูกเปิดเผยทุกครั้งที่เข้าถึงเว็บไซต์นั้นด้วย HTTP แทนที่จะเป็น HTTPS
== รายละเอียดทางเทคนิค
=== ความแตกต่างจาก HTTP
#i URL แบบ HTTPS เริ่มต้นด้วย "https://" และใช้พอร์ต 443 ตามค่าเริ่มต้น ในขณะที่ URL แบบ HTTP เริ่มต้นด้วย "http://" และใช้พอร์ต 80 ตามค่าเริ่มต้น
#iiii URL แบบ HTTPS เริ่มต้นด้วย "https://" และใช้พอร์ต 443 ตามค่าเริ่มต้น ในขณะที่ URL แบบ
HTTP เริ่มต้นด้วย "http://" และใช้พอร์ต 80 ตามค่าเริ่มต้น
#i HTTP ไม่ได้เข้ารหัส จึงมีความเสี่ยงต่อการโจมตีแบบ man-in-the-middle และการดักฟังซึ่งอาจทำให้ผู้โจมตีสามารถเข้าถึงบัญชีเว็บไซต์และข้อมูลสำคัญ และแก้ไขหน้าเว็บเพื่อแทรกมัลแวร์หรือโฆษณาได้ HTTPS ได้รับการออกแบบมาให้ทนทานต่อการโจมตีประเภทนี้ และถือว่าปลอดภัย (ยกเว้นการใช้งาน HTTPS ที่ใช้ SSL เวอร์ชันที่ล้าสมัย)
#iiii HTTP ไม่ได้เข้ารหัส จึงมีความเสี่ยงต่อการโจมตีแบบ man-in-the-middle
และการดักฟังซึ่งอาจทำให้ผู้โจมตีสามารถเข้าถึงบัญชีเว็บไซต์และข้อมูลสำคัญ
และแก้ไขหน้าเว็บเพื่อแทรกมัลแวร์หรือโฆษณาได้ HTTPS ได้รับการออกแบบมาให้ทนทานต่อการโจมตีประเภทนี้
และถือว่าปลอดภัย (ยกเว้นการใช้งาน HTTPS ที่ใช้ SSL เวอร์ชันที่ล้าสมัย)
=== ชั้นเครือข่าย
#i HTTP ทำงานที่เลเยอร์สูงสุดของโมเดล TCP/IP นั่นคือเลเยอร์แอปพลิเคชัน เช่นเดียวกับโปรโตคอลความปลอดภัย TLS (ซึ่งทำงานเป็นเลเยอร์ย่อยที่ต่ำกว่าของเลเยอร์เดียวกัน) ซึ่งเข้ารหัสข้อความ HTTP ก่อนส่ง และถอดรหัสเมื่อข้อความมาถึง โดยเคร่งครัดแล้ว HTTPS ไม่ใช่โปรโตคอลใหม่ที่แยกจากกัน แต่หมายถึงการใช้ HTTP ทั่วไปบนการเชื่อมต่อ SSL/TLS ที่เข้ารหัส (เป็นส่วนต่อขยายจาก HTTP อย่างที่กล่าวไปข้างต้น)
#iiii HTTP ทำงานที่เลเยอร์สูงสุดของโมเดล TCP/IP นั่นคือเลเยอร์แอปพลิเคชัน
เช่นเดียวกับโปรโตคอลความปลอดภัย TLS (ซึ่งทำงานเป็นเลเยอร์ย่อยที่ต่ำกว่าของเลเยอร์เดียวกัน)
ซึ่งเข้ารหัสข้อความ HTTP ก่อนส่ง และถอดรหัสเมื่อข้อความมาถึง โดยเคร่งครัดแล้ว HTTPS
ไม่ใช่โปรโตคอลใหม่ที่แยกจากกัน แต่หมายถึงการใช้ HTTP ทั่วไปบนการเชื่อมต่อ SSL/TLS ที่เข้ารหัส
(เป็นส่วนต่อขยายจาก HTTP อย่างที่กล่าวไปข้างต้น)
#i HTTPS เข้ารหัสเนื้อหาข้อความทั้งหมด รวมถึงส่วนหัว HTTP และข้อมูลคำขอ/การตอบกลับ ยกเว้นการโจมตีด้วยการเข้ารหัส CCA ที่อาจเกิดขึ้นตามที่อธิบายไว้ในส่วนข้อจำกัดด้านล่าง ผู้โจมตีควรจะสามารถตรวจพบการเชื่อมต่อระหว่างสองฝ่ายได้มากที่สุด รวมถึงชื่อโดเมนและที่อยู่ IP ของฝ่ายนั้นด้วย
#iiii HTTPS เข้ารหัสเนื้อหาข้อความทั้งหมด รวมถึงส่วนหัว HTTP และข้อมูลคำขอ/การตอบกลับ
ยกเว้นการโจมตีด้วยการเข้ารหัส CCA ที่อาจเกิดขึ้นตามที่อธิบายไว้ในส่วนข้อจำกัดด้านล่าง
ผู้โจมตีควรจะสามารถตรวจพบการเชื่อมต่อระหว่างสองฝ่ายได้มากที่สุด รวมถึงชื่อโดเมนและที่อยู่ IP
ของฝ่ายนั้นด้วย
=== การตั้งค่าเซิร์ฟเวอร์
เพื่อเตรียมเว็บเซิร์ฟเวอร์ให้ยอมรับการเชื่อมต่อ HTTPS ผู้ดูแลระบบต้องสร้างใบรับรองคีย์สาธารณะสำหรับเว็บเซิร์ฟเวอร์ ใบรับรองนี้ต้องได้รับการลงนามโดยผู้ออกใบรับรองที่เชื่อถือได้เพื่อให้เว็บเบราว์เซอร์ยอมรับโดยไม่มีการแจ้งเตือน ผู้ออกใบรับรองจะรับรองว่าผู้ถือใบรับรองคือผู้ดำเนินการของเว็บเซิร์ฟเวอร์ที่นำเสนอใบรับรองนั้น โดยทั่วไปเว็บเบราว์เซอร์จะเผยแพร่รายชื่อใบรับรองการลงนามของผู้ออกใบรับรองหลักๆ เพื่อให้สามารถตรวจสอบใบรับรองที่ลงนามโดยผู้ออกใบรับรองเหล่านั้นได้
#iiii เพื่อเตรียมเว็บเซิร์ฟเวอร์ให้ยอมรับการเชื่อมต่อ HTTPS
ผู้ดูแลระบบต้องสร้างใบรับรองคีย์สาธารณะสำหรับเว็บเซิร์ฟเวอร์
ใบรับรองนี้ต้องได้รับการลงนามโดยผู้ออกใบรับรองที่เชื่อถือได้เพื่อให้เว็บเบราว์เซอร์ยอมรับโดยไม่มีการแจ้งเตือน
ผู้ออกใบรับรองจะรับรองว่าผู้ถือใบรับรองคือผู้ดำเนินการของเว็บเซิร์ฟเวอร์ที่นำเสนอใบรับรองนั้น
โดยทั่วไปเว็บเบราว์เซอร์จะเผยแพร่รายชื่อใบรับรองการลงนามของผู้ออกใบรับรองหลักๆ
เพื่อให้สามารถตรวจสอบใบรับรองที่ลงนามโดยผู้ออกใบรับรองเหล่านั้นได้
==== การขอใบรับรอง
#i มีผู้ให้บริการออกใบรับรองเชิงพาณิชย์จำนวนหนึ่งที่เสนอใบรับรอง SSL/TLS แบบชำระเงินหลายประเภท รวมถึงใบรับรองการตรวจสอบขยาย
#iiiii มีผู้ให้บริการออกใบรับรองเชิงพาณิชย์จำนวนหนึ่งที่เสนอใบรับรอง SSL/TLS
แบบชำระเงินหลายประเภท รวมถึงใบรับรองการตรวจสอบขยาย
#i Let's Encrypt เปิดตัวในเดือนเมษายน 2559 ให้บริการใบรับรอง SSL/TLS พื้นฐานแบบอัตโนมัติฟรีแก่เว็บไซต์ มูลนิธิ Electronic Frontier Foundation ระบุว่า Let's Encrypt จะทำให้การเปลี่ยนจาก HTTP เป็น HTTPS "ง่ายดายเพียงแค่ออกคำสั่งหรือคลิกปุ่ม" ปัจจุบันผู้ให้บริการเว็บโฮสต์และผู้ให้บริการคลาวด์ส่วนใหญ่ใช้ประโยชน์จาก Let's Encrypt เพื่อมอบใบรับรองฟรีให้กับลูกค้า
#iiiii Let's Encrypt เปิดตัวในเดือนเมษายน 2559 ให้บริการใบรับรอง SSL/TLS
พื้นฐานแบบอัตโนมัติฟรีแก่เว็บไซต์ มูลนิธิ Electronic Frontier Foundation ระบุว่า Let's Encrypt
จะทำให้การเปลี่ยนจาก HTTP เป็น HTTPS "ง่ายดายเพียงแค่ออกคำสั่งหรือคลิกปุ่ม"
ปัจจุบันผู้ให้บริการเว็บโฮสต์และผู้ให้บริการคลาวด์ส่วนใหญ่ใช้ประโยชน์จาก Let's Encrypt
เพื่อมอบใบรับรองฟรีให้กับลูกค้า
==== ใช้เป็นการควบคุมการเข้าถึง
#i ระบบนี้ยังสามารถใช้สำหรับการตรวจสอบสิทธิ์ไคลเอ็นต์เพื่อจำกัดการเข้าถึงเว็บเซิร์ฟเวอร์เฉพาะผู้ใช้ที่ได้รับอนุญาตเท่านั้น ในการดำเนินการนี้ ผู้ดูแลระบบเว็บไซต์มักจะสร้างใบรับรองสำหรับผู้ใช้แต่ละราย ซึ่งผู้ใช้จะโหลดใบรับรองลงในเบราว์เซอร์ โดยปกติใบรับรองจะมีชื่อและที่อยู่อีเมลของผู้ใช้ที่ได้รับอนุญาต และจะถูกตรวจสอบโดยเซิร์ฟเวอร์โดยอัตโนมัติในแต่ละการเชื่อมต่อเพื่อยืนยันตัวตนของผู้ใช้ ซึ่งอาจไม่จำเป็นต้องใช้รหัสผ่านด้วยซ้ำ
#iiiii
ระบบนี้ยังสามารถใช้สำหรับการตรวจสอบสิทธิ์ไคลเอ็นต์เพื่อจำกัดการเข้าถึงเว็บเซิร์ฟเวอร์เฉพาะผู้ใช้ที่ได้รับอนุญาตเท่านั้น
ในการดำเนินการนี้ ผู้ดูแลระบบเว็บไซต์มักจะสร้างใบรับรองสำหรับผู้ใช้แต่ละราย
ซึ่งผู้ใช้จะโหลดใบรับรองลงในเบราว์เซอร์ โดยปกติใบรับรองจะมีชื่อและที่อยู่อีเมลของผู้ใช้ที่ได้รับอนุญาต
และจะถูกตรวจสอบโดยเซิร์ฟเวอร์โดยอัตโนมัติในแต่ละการเชื่อมต่อเพื่อยืนยันตัวตนของผู้ใช้
ซึ่งอาจไม่จำเป็นต้องใช้รหัสผ่านด้วยซ้ำ
==== ในกรณีที่คีย์ลับถูกบุกรุก
#i คุณสมบัติที่สำคัญในบริบทนี้คือการเข้ารหัสแบบส่งต่อที่สมบูรณ์แบบ (PFS) การมีคีย์ลับแบบอสมมาตรระยะยาวตัวใดตัวหนึ่งที่ใช้สร้างเซสชัน HTTPS ไม่น่าจะทำให้การได้มาซึ่งคีย์เซสชันระยะสั้นเพื่อถอดรหัสการสนทนาทำได้ง่ายขึ้น แม้ในภายหลังก็ตาม ในปี 2013 มีเพียงการแลกเปลี่ยนคีย์ DiffieHellman (DHE) และการแลกเปลี่ยนคีย์ DiffieHellman แบบเส้นโค้งวงรี (ECDHE) เท่านั้นที่ทราบว่ามีคุณสมบัตินี้ ในปี 2013 มีเพียง 30% ของเซสชัน Firefox, Opera และ Chromium Browser เท่านั้นที่ใช้คุณสมบัตินี้ และเกือบ 0% ของเซสชัน Safari และ Microsoft Internet Explorer ของ Apple ที่ใช้คุณสมบัตินี้ TLS 1.3 ซึ่งเผยแพร่ในเดือนสิงหาคม 2018 ได้ยกเลิกการสนับสนุนการเข้ารหัสแบบไม่มีการเข้ารหัสแบบส่งต่อ เดือนกุมภาพันธ์ พ.ศ. 2562 เว็บเซิร์ฟเวอร์ที่สำรวจ 96.6% รองรับการรักษาความลับแบบ Forward ในรูปแบบใดรูปแบบหนึ่ง และ 52.1% จะใช้การรักษาความลับแบบ Forward กับเบราว์เซอร์ส่วนใหญ่ เดือนกรกฎาคม พ.ศ. 2566 เว็บเซิร์ฟเวอร์ที่สำรวจ 99.6% รองรับการรักษาความลับแบบ Forward ในรูปแบบใดรูปแบบหนึ่ง และ 75.2% จะใช้การรักษาความลับแบบ Forward กับเบราว์เซอร์ส่วนใหญ่
#iiiii คุณสมบัติที่สำคัญในบริบทนี้คือการเข้ารหัสแบบส่งต่อที่สมบูรณ์แบบ (PFS)
การมีคีย์ลับแบบอสมมาตรระยะยาวตัวใดตัวหนึ่งที่ใช้สร้างเซสชัน HTTPS
ไม่น่าจะทำให้การได้มาซึ่งคีย์เซสชันระยะสั้นเพื่อถอดรหัสการสนทนาทำได้ง่ายขึ้น แม้ในภายหลังก็ตาม ในปี
2013 มีเพียงการแลกเปลี่ยนคีย์ Diffie--Hellman (DHE) และการแลกเปลี่ยนคีย์ Diffie--Hellman
แบบเส้นโค้งวงรี (ECDHE) เท่านั้นที่ทราบว่ามีคุณสมบัตินี้ ในปี 2013 มีเพียง 30% ของเซสชัน Firefox,
Opera และ Chromium Browser เท่านั้นที่ใช้คุณสมบัตินี้ และเกือบ 0% ของเซสชัน Safari และ
Microsoft Internet Explorer ของ Apple ที่ใช้คุณสมบัตินี้ TLS 1.3 ซึ่งเผยแพร่ในเดือนสิงหาคม
2018 ได้ยกเลิกการสนับสนุนการเข้ารหัสแบบไม่มีการเข้ารหัสแบบส่งต่อ เดือนกุมภาพันธ์ พ.ศ. 2562
เว็บเซิร์ฟเวอร์ที่สำรวจ 96.6% รองรับการรักษาความลับแบบ Forward ในรูปแบบใดรูปแบบหนึ่ง และ
52.1% จะใช้การรักษาความลับแบบ Forward กับเบราว์เซอร์ส่วนใหญ่ เดือนกรกฎาคม พ.ศ. 2566
เว็บเซิร์ฟเวอร์ที่สำรวจ 99.6% รองรับการรักษาความลับแบบ Forward ในรูปแบบใดรูปแบบหนึ่ง และ
75.2% จะใช้การรักษาความลับแบบ Forward กับเบราว์เซอร์ส่วนใหญ่
===== การเพิกถอนใบรับรอง
ใบรับรองอาจถูกเพิกถอนก่อนหมดอายุได้ เช่น เนื่องจากความลับของคีย์ส่วนตัวถูกละเมิด เบราว์เซอร์ยอดนิยมเวอร์ชันที่ใหม่พอเช่น Firefox Opera และ Internet Explorer บน Windows Vista จะใช้ Online Certificate Status Protocol (OCSP) เพื่อตรวจสอบว่าไม่เป็นเช่นนั้น เบราว์เซอร์จะส่งหมายเลขซีเรียลของใบรับรองไปยังผู้ออกใบรับรองหรือผู้แทนผ่าน OCSP และผู้ออกใบรับรองจะตอบกลับ โดยแจ้งให้เบราว์เซอร์ทราบว่าใบรับรองยังคงใช้ได้อยู่หรือไม่ นอกจากนี้ CA อาจออกรายการเพิกถอนใบรับรอง (Certificate Revocation List; CRL) เพื่อแจ้งให้ผู้ใช้ทราบว่าใบรับรองเหล่านี้ถูกเพิกถอนแล้ว อย่างไรก็ตาม CRL ไม่จำเป็นสำหรับฟอรัม CA/Browser (“ฟอรัม CA/Browser” ดังกล่าวคือองค์กร) อีกต่อไป อย่างไรก็ตาม CA ยังคงใช้ CRL กันอย่างแพร่หลาย สถานะการเพิกถอนส่วนใหญ่บนอินเทอร์เน็ตจะหายไปในไม่ช้าหลังจากใบรับรองหมดอายุ
#iiiiii ใบรับรองอาจถูกเพิกถอนก่อนหมดอายุได้ เช่น เนื่องจากความลับของคีย์ส่วนตัวถูกละเมิด
เบราว์เซอร์ยอดนิยมเวอร์ชันที่ใหม่พอเช่น Firefox Opera และ Internet Explorer บน Windows
Vista จะใช้ Online Certificate Status Protocol (OCSP) เพื่อตรวจสอบว่าไม่เป็นเช่นนั้น
เบราว์เซอร์จะส่งหมายเลขซีเรียลของใบรับรองไปยังผู้ออกใบรับรองหรือผู้แทนผ่าน OCSP
และผู้ออกใบรับรองจะตอบกลับ โดยแจ้งให้เบราว์เซอร์ทราบว่าใบรับรองยังคงใช้ได้อยู่หรือไม่ นอกจากนี้ CA
อาจออกรายการเพิกถอนใบรับรอง (Certificate Revocation List; CRL)
เพื่อแจ้งให้ผู้ใช้ทราบว่าใบรับรองเหล่านี้ถูกเพิกถอนแล้ว อย่างไรก็ตาม CRL ไม่จำเป็นสำหรับฟอรัม
CA/Browser (“ฟอรัม CA/Browser” ดังกล่าวคือองค์กร) อีกต่อไป อย่างไรก็ตาม CA ยังคงใช้ CRL
กันอย่างแพร่หลาย สถานะการเพิกถอนส่วนใหญ่บนอินเทอร์เน็ตจะหายไปในไม่ช้าหลังจากใบรับรองหมดอายุ
=== ข้อจำกัด
#i การเข้ารหัส SSL (Secure Sockets Layer) และ TLS (Transport Layer Security) สามารถกำหนดค่าได้สองโหมด ได้แก่ โหมดธรรมดาและโหมด Mutual ในโหมดธรรมดา การตรวจสอบสิทธิ์จะดำเนินการโดยเซิร์ฟเวอร์เท่านั้น โหมด Mutual กำหนดให้ผู้ใช้ต้องติดตั้งใบรับรองไคลเอ็นต์ส่วนบุคคลในเว็บเบราว์เซอร์เพื่อการตรวจสอบสิทธิ์ผู้ใช้ ไม่ว่าในกรณีใด ระดับการป้องกันจะขึ้นอยู่กับความถูกต้องของการใช้งานซอฟต์แวร์และอัลกอริทึมการเข้ารหัสที่ใช้
#iiii การเข้ารหัส SSL (Secure Sockets Layer) และ TLS (Transport Layer Security)
สามารถกำหนดค่าได้สองโหมด ได้แก่ โหมดธรรมดาและโหมด Mutual ในโหมดธรรมดา
การตรวจสอบสิทธิ์จะดำเนินการโดยเซิร์ฟเวอร์เท่านั้น โหมด Mutual
กำหนดให้ผู้ใช้ต้องติดตั้งใบรับรองไคลเอ็นต์ส่วนบุคคลในเว็บเบราว์เซอร์เพื่อการตรวจสอบสิทธิ์ผู้ใช้
ไม่ว่าในกรณีใด
ระดับการป้องกันจะขึ้นอยู่กับความถูกต้องของการใช้งานซอฟต์แวร์และอัลกอริทึมการเข้ารหัสที่ใช้
#i SSL/TLS ไม่ป้องกันการจัดทำดัชนีของเว็บไซต์โดยเว็บครอว์เลอร์ และในบางกรณี URI ของทรัพยากรที่เข้ารหัสสามารถอนุมานได้โดยการทราบขนาดคำขอ/การตอบสนองที่ถูกสกัดกั้นเท่านั้น วิธีนี้ช่วยให้ผู้โจมตีสามารถเข้าถึงข้อความธรรมดา (เนื้อหาคงที่ที่เปิดเผยต่อสาธารณะ) และข้อความที่เข้ารหัส (เนื้อหาคงที่เวอร์ชันเข้ารหัส) ทำให้สามารถโจมตีด้วยการเข้ารหัสได้
#iiii SSL/TLS ไม่ป้องกันการจัดทำดัชนีของเว็บไซต์โดยเว็บครอว์เลอร์ และในบางกรณี URI
ของทรัพยากรที่เข้ารหัสสามารถอนุมานได้โดยการทราบขนาดคำขอ/การตอบสนองที่ถูกสกัดกั้นเท่านั้น
วิธีนี้ช่วยให้ผู้โจมตีสามารถเข้าถึงข้อความธรรมดา (เนื้อหาคงที่ที่เปิดเผยต่อสาธารณะ) และข้อความที่เข้ารหัส
(เนื้อหาคงที่เวอร์ชันเข้ารหัส) ทำให้สามารถโจมตีด้วยการเข้ารหัสได้
#i เนื่องจาก TLS ทำงานที่ระดับโปรโตคอลที่ต่ำกว่า HTTP และไม่มีความรู้เกี่ยวกับโปรโตคอลระดับสูงกว่า เซิร์ฟเวอร์ TLS จึงสามารถแสดงใบรับรองได้เพียงใบเดียวสำหรับที่อยู่และพอร์ตที่กำหนดเท่านั้น ในอดีต นั่นหมายความว่าไม่สามารถใช้การโฮสต์เสมือนแบบอิงชื่อกับ HTTPS ได้ มีโซลูชันที่เรียกว่า Server Name Indication (SNI) ซึ่งส่งชื่อโฮสต์ไปยังเซิร์ฟเวอร์ก่อนเข้ารหัสการเชื่อมต่อ แม้ว่าเบราว์เซอร์รุ่นเก่าจะไม่รองรับส่วนขยายนี้ก็ตาม การรองรับ SNI มีให้ใช้งานตั้งแต่ Firefox 2, Opera 8, Apple Safari 2.1, Google Chrome 6 และ Internet Explorer 7 บน Windows Vista
#iiii เนื่องจาก TLS ทำงานที่ระดับโปรโตคอลที่ต่ำกว่า HTTP
และไม่มีความรู้เกี่ยวกับโปรโตคอลระดับสูงกว่า เซิร์ฟเวอร์ TLS
จึงสามารถแสดงใบรับรองได้เพียงใบเดียวสำหรับที่อยู่และพอร์ตที่กำหนดเท่านั้น ในอดีต
นั่นหมายความว่าไม่สามารถใช้การโฮสต์เสมือนแบบอิงชื่อกับ HTTPS ได้ มีโซลูชันที่เรียกว่า Server Name
Indication (SNI) ซึ่งส่งชื่อโฮสต์ไปยังเซิร์ฟเวอร์ก่อนเข้ารหัสการเชื่อมต่อ
แม้ว่าเบราว์เซอร์รุ่นเก่าจะไม่รองรับส่วนขยายนี้ก็ตาม การรองรับ SNI มีให้ใช้งานตั้งแต่ Firefox 2,
Opera 8, Apple Safari 2.1, Google Chrome 6 และ Internet Explorer 7 บน Windows
Vista
#i การโจมตีแบบ man-in-the-middle ที่ซับซ้อนประเภทหนึ่งที่เรียกว่า SSL stripping ถูกนำเสนอในงานประชุม Blackhat Conference ปี 2009 การโจมตีประเภทนี้ทำลายความปลอดภัยของ HTTPS โดยการเปลี่ยนลิงก์ https: ให้เป็นลิงก์ http: โดยใช้ประโยชน์จากข้อเท็จจริงที่ว่าผู้ใช้อินเทอร์เน็ตเพียงไม่กี่คนเท่านั้นที่พิมพ์ "https" ลงในอินเทอร์เฟซเบราว์เซอร์ พวกเขาจึงเข้าสู่เว็บไซต์ที่ปลอดภัยได้โดยการคลิกลิงก์ และถูกหลอกให้คิดว่ากำลังใช้ HTTPS ในขณะที่จริงๆ แล้วกำลังใช้ HTTP ผู้โจมตีจึงสื่อสารกับไคลเอ็นต์อย่างชัดเจน สิ่งนี้กระตุ้นให้เกิดการพัฒนามาตรการรับมือใน HTTP ที่เรียกว่า HTTP Strict Transport Security
#iiii การโจมตีแบบ man-in-the-middle ที่ซับซ้อนประเภทหนึ่งที่เรียกว่า SSL stripping
ถูกนำเสนอในงานประชุม Blackhat Conference ปี 2009 การโจมตีประเภทนี้ทำลายความปลอดภัยของ
HTTPS โดยการเปลี่ยนลิงก์ https: ให้เป็นลิงก์ http:
โดยใช้ประโยชน์จากข้อเท็จจริงที่ว่าผู้ใช้อินเทอร์เน็ตเพียงไม่กี่คนเท่านั้นที่พิมพ์ "https"
ลงในอินเทอร์เฟซเบราว์เซอร์ พวกเขาจึงเข้าสู่เว็บไซต์ที่ปลอดภัยได้โดยการคลิกลิงก์
และถูกหลอกให้คิดว่ากำลังใช้ HTTPS ในขณะที่จริงๆ แล้วกำลังใช้ HTTP
ผู้โจมตีจึงสื่อสารกับไคลเอ็นต์อย่างชัดเจน สิ่งนี้กระตุ้นให้เกิดการพัฒนามาตรการรับมือใน HTTP ที่เรียกว่า
HTTP Strict Transport Security
#i HTTPS ได้รับการพิสูจน์แล้วว่ามีความเสี่ยงต่อการโจมตีวิเคราะห์ทราฟฟิกหลากหลายรูปแบบ การโจมตีวิเคราะห์ทราฟฟิกเป็นการโจมตีแบบ Side-Channel ประเภทหนึ่งที่อาศัยการเปลี่ยนแปลงเวลาและขนาดของทราฟฟิกเพื่ออนุมานคุณสมบัติของทราฟฟิกที่เข้ารหัส การวิเคราะห์ทราฟฟิกเป็นไปได้เนื่องจากการเข้ารหัส SSL/TLS เปลี่ยนแปลงเนื้อหาของทราฟฟิก แต่มีผลกระทบน้อยมากต่อขนาดและระยะเวลาของทราฟฟิก ในเดือนพฤษภาคม 2553 งานวิจัยโดยนักวิจัยจาก Microsoft Research และ Indiana University ค้นพบว่าข้อมูลผู้ใช้ที่ละเอียดอ่อนโดยละเอียดสามารถอนุมานได้จากช่องทางด้านข้าง เช่น ขนาดแพ็กเก็ต นักวิจัยพบว่าแม้จะมีการป้องกัน HTTPS ในแอปพลิเคชันเว็บชั้นนำที่มีชื่อเสียงหลายตัวในด้านการดูแลสุขภาพ ภาษี การลงทุน และการค้นหาเว็บ แต่ผู้แอบฟังสามารถอนุมานโรค/ยา/การผ่าตัดของผู้ใช้ รายได้ของครอบครัว และความลับในการลงทุนได้
#iiii HTTPS ได้รับการพิสูจน์แล้วว่ามีความเสี่ยงต่อการโจมตีวิเคราะห์ทราฟฟิกหลากหลายรูปแบบ
การโจมตีวิเคราะห์ทราฟฟิกเป็นการโจมตีแบบ Side-Channel
ประเภทหนึ่งที่อาศัยการเปลี่ยนแปลงเวลาและขนาดของทราฟฟิกเพื่ออนุมานคุณสมบัติของทราฟฟิกที่เข้ารหัส
การวิเคราะห์ทราฟฟิกเป็นไปได้เนื่องจากการเข้ารหัส SSL/TLS เปลี่ยนแปลงเนื้อหาของทราฟฟิก
แต่มีผลกระทบน้อยมากต่อขนาดและระยะเวลาของทราฟฟิก ในเดือนพฤษภาคม 2553 งานวิจัยโดยนักวิจัยจาก
Microsoft Research และ Indiana University
ค้นพบว่าข้อมูลผู้ใช้ที่ละเอียดอ่อนโดยละเอียดสามารถอนุมานได้จากช่องทางด้านข้าง เช่น ขนาดแพ็กเก็ต
นักวิจัยพบว่าแม้จะมีการป้องกัน HTTPS ในแอปพลิเคชันเว็บชั้นนำที่มีชื่อเสียงหลายตัวในด้านการดูแลสุขภาพ
ภาษี การลงทุน และการค้นหาเว็บ แต่ผู้แอบฟังสามารถอนุมานโรค/ยา/การผ่าตัดของผู้ใช้
รายได้ของครอบครัว และความลับในการลงทุนได้
#i ความจริงที่ว่าเว็บไซต์สมัยใหม่ส่วนใหญ่ รวมถึง Google, Yahoo! และ Amazon ใช้ HTTPS ทำให้เกิดปัญหาสำหรับผู้ใช้จำนวนมากที่พยายามเข้าถึงจุดเชื่อมต่อ Wi-Fi สาธารณะ เนื่องจากหน้าเข้าสู่ระบบจุดเชื่อมต่อ Wi-Fi ของพอร์ทัลแบบแคปทีฟไม่สามารถโหลดได้หากผู้ใช้พยายามเปิดทรัพยากร HTTPS และเว็บไซต์หลายแห่ง เช่น NeverSSL รับประกันว่าเว็บไซต์เหล่านั้นจะสามารถเข้าถึงได้ผ่าน HTTP เสมอ
#iiii ความจริงที่ว่าเว็บไซต์สมัยใหม่ส่วนใหญ่ รวมถึง Google, Yahoo! และ Amazon ใช้ HTTPS
ทำให้เกิดปัญหาสำหรับผู้ใช้จำนวนมากที่พยายามเข้าถึงจุดเชื่อมต่อ Wi-Fi สาธารณะ
เนื่องจากหน้าเข้าสู่ระบบจุดเชื่อมต่อ Wi-Fi
ของพอร์ทัลแบบแคปทีฟไม่สามารถโหลดได้หากผู้ใช้พยายามเปิดทรัพยากร HTTPS และเว็บไซต์หลายแห่ง เช่น
NeverSSL รับประกันว่าเว็บไซต์เหล่านั้นจะสามารถเข้าถึงได้ผ่าน HTTP เสมอ
+8 -6
View File
@@ -27,15 +27,17 @@
อุปกรณ์ควบคุมขนาดเล็ก ซึ่งบรรจุความสามารถที่คล้ายคลึงกับระบบคอมพิวเตอร์ โดยใน
ไมโครคอนโทรลเลอร์ได้รวม เอาซีพียูหน่วยความจำและพอร์ต ซึ่งเป็นส่วนประกอบหลักสำคัญของ
ระบบคอมพิวเตอร์เข้าไว้ด้วยกัน โดยทำการบรรจุเข้าไว้ในตัวถังเดียวกัน ไมโครคอนโทรลเลอร์ถ้าแปล
ความหมายแบบตรงตัวก็คือ ระบบคอนโทรลขนาดเล็กเรียกอีกอย่างหนึ่งคือเป็นระบบคอมพิวเตอร์ ขนาดเล็ก
ความหมายแบบตรงตัวก็คือ ระบบคอนโทรลขนาดเล็กเรียกอีกอย่างหนึ่งคือเป็นระบบคอมพิวเตอร์ ขนาดเล็ก#jb
ที่สามารถนำมาประยุกต์ใช้งานได้หลากหลาย โดยผ่านการออกแบบวงจรให้เหมาะกับงาน ต่างๆ
และยังสามารถเขียนโปรแกรมคำสั่งเพื่อควบคุมขา Input/Output เพื่อสั่งงานให้ไป ควบคุม อุปกรณ์ต่าง
ได้อีกด้วย ซึ่งก็นับว่าเป็นระบบที่สามารถนำมาประยุกต์ใช้งานได้หลากหลาย ทั้ง ทางด้าน Digital และ
Analog ยกตัวอย่างเช่น ระบบสัญญาณตอบรับอัตโนมัติ, ระบบบัตรคิว, ระบบ ตอกบัตรพนักงาน และอื่นๆ
และยังสามารถเขียนโปรแกรมคำสั่งเพื่อควบคุมขา Input/Output เพื่อสั่งงานให้ไป ควบคุม อุปกรณ์ต่าง
#jb ได้อีกด้วย ซึ่งก็นับว่าเป็นระบบที่สามารถนำมาประยุกต์ใช้งานได้หลากหลาย ทั้ง ทางด้าน Digital
และ Analog ยกตัวอย่างเช่น ระบบสัญญาณตอบรับอัตโนมัติ, ระบบบัตรคิว, ระบบ ตอกบัตรพนักงาน และอื่นๆ
ยิ่งระบบไมโครคอนโทรลเลอร์ในยุคปัจจุบันนั้นสามารถทำการเชื่อต่อกับ ระบบ Network
ของคอมพิวเตอร์ทั่วไปได้อีกด้วย ดังนั้นการสั่งงานจึงไม่ใช่แค่หน้าแผงวงจร แต่ อาจจะเป็นการสั่งงานอยู่คนละ
ซีกโลกผ่านเครือข่ายอินเตอร์เน็ตก็ได้โครงสร้างโดยทั่วไปของไมโครคอนโทรลเลอร์นั้น
สามารถแบ่งออกมาได้เป็น 5 ส่วนใหญ่ ได้แก่ หน่วยประมวลผลกลาง หรือ ซีพียู, หน่วยความจำ,
ส่วนติดต่อกับอุปกรณ์ภายนอก หรือพอร์ต, ช่องทางเดินของสัญญาณ หรือบัส และ วงจรกำเนิดสัญญาณนาฬิกา#jb
หน่วยความจำนั้น สามารถแบ่งออกเป็น 2 ส่วนคือ หน่วยความจำที่มีไว้สำหรับเก็บ โปรแกรมหลัก
เปรียบเสมือนฮาร์ดดิสก์และหน่วยความจำข้อมูล ใช้เป็นเหมือนกับ กระดาษทดในการ คำนวณของ#jb
หน่วยความจำนั้น สามารถแบ่งออกเป็น 2 ส่วนคือ หน่วยความจำที่มีไว้สำหรับเก็บ โปรแกรมหลัก#jb
เปรียบเสมือนฮาร์ดดิสก์และหน่วยความจำข้อมูล ใช้เป็นเหมือนกับ กระดาษทดในการ คำนวณของ#jb ซีพียู
โดย ESP32 เป็นไมโครคอนโทรลเลอร์แบบ System-on-a-Chip (SoC) ที่มีการรวมส่วนประกอบ#jb
ทั้งหมดที่จำเป็นสำหรับการประมวลผลและการสื่อสารไร้สายไว้ในชิปเดียว ที่มีคุณสมบัติเด่นด้านการ#jb
+80 -83
View File
@@ -1,10 +1,7 @@
#import "../PageTemplate.typ": i, jb
#import "../PageTemplate.typ": *
ซีพียู โดย ESP32 เป็นไมโครคอนโทรลเลอร์แบบ System-on-a-Chip (SoC)
ที่มีการรวมส่วนประกอบทั้งหมดที่จำเป็นสำหรับการประมวลผลและการสื่อสารไร้สายไว้ในชิปเดียว
ที่มีคุณสมบัติเด่นด้านการเชื่อมต่อ Wi-Fi และ Bluetooth ในตัว เป็นชิปไมโครคอนโทรลเลอร์แบบ 32 บิต
ที่มีความสามารถสูง พัฒนาและผลิตโดย บริษัท Espressif Systems จากประเทศจีน
ส่วนประกอบหลักของบอร์ด ESP32
เชื่อมต่อ Wi-Fi และ Bluetooth ในตัว เป็นชิปไมโครคอนโทรลเลอร์แบบ 32 บิต ที่มีความสามารถสูง
พัฒนาและผลิตโดย บริษัท Espressif Systems จากประเทศจีน ส่วนประกอบหลักของบอร์ด ESP32
#i ESP32 คือ ไมโครคอนโทรลเลอร์ราคาประหยัดและประหยัดพลังงานที่ผสานรวมความสามารถทั้ง Wi-Fi
และ Bluetooth ชิปเหล่านี้มีตัวเลือกการประมวลผลที่หลากหลาย รวมถึง ไมโครโปรเซสเซอร์#jb
@@ -38,26 +35,30 @@ Tensilica Xtensa LX6 ที่มีทั้งแบบดูอัลคอ
#let partition-table = csv("PartitionTable.csv")
#table(
columns: 6,
table.header([Name], [Type], [SubType], [Offset], [Size], [Flags]),
..partition-table.flatten().slice(6),
#figure(
table(
columns: 6,
align: left,
table.header([Name], [Type], [SubType], [Offset], [Size], [Flags]),
..partition-table.flatten().slice(6),
),
caption: [รายการพาร์ทิชัน],
)
ซึ่งคือตารางค่าเริ่มต้นของ ESP32 ใน Arduino platform
อย่างไรก็ตามมีการเปลี่ยนแปลงระบบเก็บไฟล์จาก SPIFFS เป็น LittleFS โดยที่:
+ *Name:* ชื่อของพาร์ทิชัน ห้ามซ้ำกัน ชื่อนั้นไม่สำคัญต่อระบบและต้องขนาดไม่เกิน 16 ตัวอักษร
+ Name: ชื่อของพาร์ทิชัน ห้ามซ้ำกัน ชื่อนั้นไม่สำคัญต่อระบบและต้องขนาดไม่เกิน 16 ตัวอักษร
(ไม่มีอักขระพิเศษ)
+ *Type:* ประเภทของพาร์ทัชัน สามารถเป็น `data` หรือ `app` ได้
- `app` คือพาร์ทิชันที่ใช้ในการเก็บแอพลิเคชัน
- `data` คือพาร์ทิชันที่ใช้ในการเก็บข้อมูลทั่วไป
+ *SubType:* ประเภทย่อย ระบุการใช้งานของพาร์ทิชัน `app` และ `data`
- `data`
- `ota`: พาร์ทัชันเก็บข้อมูล OTA (สำหรับการอัพเดททางอากาศ, Over-the-air update)
+ Type: ประเภทของพาร์ทัชัน สามารถเป็น data หรือ app ได้
- app คือพาร์ทิชันที่ใช้ในการเก็บแอพลิเคชัน
- data คือพาร์ทิชันที่ใช้ในการเก็บข้อมูลทั่วไป
+ SubType: ประเภทย่อย ระบุการใช้งานของพาร์ทิชัน app และ data
- data
- ota: พาร์ทัชันเก็บข้อมูล OTA (สำหรับการอัพเดททางอากาศ, Over-the-air update)
โดยหากไม่ใช้งาน OTA สามารถนำออกได้ โดยขนาดของพาร์ทิชันนี้ควรจะมีขนาดที่แน่นอนอยู่ที่ 8 KiB
(0x2000 ไบต์)
- `nvs`: พาร์ทิชันเก็บข้อมูลทั่วไปเช่น ข้อมูล Wi-Fi, ข้อมูลการสอบเทียบ PHY ของอุปกรณ์,
- nvs: พาร์ทิชันเก็บข้อมูลทั่วไปเช่น ข้อมูล Wi-Fi, ข้อมูลการสอบเทียบ PHY ของอุปกรณ์,
และข้อมูลอื่น ที่ต้องถูกเก็บบนหน่วยความจำถาวร (Non-volatile memory)
โดยพาร์ทิชันประเภทนี้เหมาะสมสำหรับการเก็บข้อมูลการตั้งค่าเล็กน้อย ใบรองรับคลาวด์ ฯลฯ
และการใช้งาน NVS อีกอย่างคือการเก็บข้อมูลที่ละเอียดอ่อน เนื่องจาก NVS รองรับการเข้ารหัส
@@ -65,64 +66,52 @@ Tensilica Xtensa LX6 ที่มีทั้งแบบดูอัลคอ
และหากจำเป็น คุณสามารถขยายขนาดเพิ่มได้ โดยขนาดที่แนะนำนั้นอยู่ระหว่าง 12 KiB และ 64
KiB ถึงแม้ว่าคุณจะสามารถขยายให้มันใหญ่กว่านี้ได้ การใช้งานระบบไฟล์เช่น FAT หรือ SPIFFS
นั้นจะเหมาะสมสำหรับข้อมูลที่ใหญ่กว่า
- `coredump`: ประเภทพาร์ทิชันย่อยนี้มีหน้าที่ในการเก็บข้อมูล core dump บนหน่วยความจำแฟลช
โดย core dump
นั้นคือข้อมูลที่ถูกใช้งานสำหรับการตรวจสอบข้อผิด-พลาดร้ายแรงเช่นการแครชและแพนิค
- coredump: ประเภทพาร์ทิชันย่อยนี้มีหน้าที่ในการเก็บข้อมูล core dump บนหน่วยความจำแฟลช โดย
core dump นั้นคือข้อมูลที่ถูกใช้งานสำหรับการตรวจสอบข้อผิด-พลาดร้ายแรงเช่นการแครชและแพนิค
โดยฟังก์ชันนี้จะต้องถูกเปิดในการตั้งค่าโปรเจกต์และตั้งที่หมายในการแฟลช
และพาร์ทิชันนี้มีขนาดที่แนะนำอยู่ที่ 64 KiB (0x10000)
- `nvs_keys`: พาร์ทิชันที่เป็นประเภทย่อยนี้เก็บคีย์การเข้ารหัสของพาร์ทัชัน NVS
- nvs_keys: พาร์ทิชันที่เป็นประเภทย่อยนี้เก็บคีย์การเข้ารหัสของพาร์ทัชัน NVS
เมื่อการเข้ารหัสถูกใช้งาน โดยมีขนาดอยู่ที่ 4 KiB (0x1000)
- `fat`: กำหนดพาร์ทิชันสำหรับระบบไฟล์ FAT โดยที่จะเหมาะสมสำหรับข้อมูลใหญ่
- fat: กำหนดพาร์ทิชันสำหรับระบบไฟล์ FAT โดยที่จะเหมาะสมสำหรับข้อมูลใหญ่
และหากข้อมูลนั้นถูกเปลี่ยนแปลงบ่อย โดยระบบไฟล์ FAT สามารถใช้ฟีเจอร์ wear leveling
และการเข้ารหัสได้
- `spiffs`: กำหนดพาร์ทิชันสำหรับระบบไฟล์ SPIFFS เหมาะสำหรับไฟล์ใหญ่เช่นกันและรองรับ
wear leveling อย่างไรก็ตาม ระบบไฟล์นี้ไม่รองรับการเข้ารหัส
- `app`
- `factory`: พาร์ทิชันเก็บแอพลิเคชันเริ่มต้น
- spiffs: กำหนดพาร์ทิชันสำหรับระบบไฟล์ SPIFFS เหมาะสำหรับไฟล์ใหญ่เช่นกันและรองรับ wear
leveling อย่างไรก็ตาม ระบบไฟล์นี้ไม่รองรับการเข้ารหัส
- app
- factory: พาร์ทิชันเก็บแอพลิเคชันเริ่มต้น
โปรแกรมบูตโหลดเดอร์จะเลือกพาร์ทิชันนี้เป็นแอพลิเคชันเริ่มต้นหากไม่มีพาร์ทิชัน OTA หรือพาร์ทิชัน
OTA นั้นว่างเปล่า หากมีการใช้พาร์ทิชัน OTA พาร์ทิชัน `ota_0`
สามารถถูกใช้เป็นแอพลิเคชันเริ่มต้นได้และพาร์ทิชัน `factory` สามารถถูกนำออกได้
- `ota_0` ถึง `ota_15`: พาร์ทิชัน ota_x นั้นถูกใช้สำหรับอัพเดท OTA โดยฟีเจอร์ OTA
OTA นั้นว่างเปล่า หากมีการใช้พาร์ทิชัน OTA พาร์ทิชัน ota_0
สามารถถูกใช้เป็นแอพลิเคชันเริ่มต้นได้และพาร์ทิชัน factory สามารถถูกนำออกได้
- ota_0 ถึง ota_15: พาร์ทิชัน ota_x นั้นถูกใช้สำหรับอัพเดท OTA โดยฟีเจอร์ OTA
นั้นจำเป็นต้องใช้พาร์ทิชัน OTA อย่างน้อย 2 พาร์ทิชัน (โดยปกติคือ ota_0 และ ota_1)
และจำเป็นต้องใช้พาร์ทิชัน ota ด้วยเช่นกันในการเก็บข้อมูลเกี่ยวกับ OTA โดยสามารถมีพาร์ทิชัน
OTA ได้สูงสุด 16 พาร์ทิชัน แต่ 2 พาร์ทิชันคือจำนวนขั้นต่ำที่ต้องใช้สำหรับฟีเจอร์ OTA แบบเบสิค
- `test`: ใช้สำหรับการทดสอบในโรงงาน
+ *Offset:* กำหนดพื้นที่ที่พาร์ทิชันนั้นเริ่มต้น โดย Offset นั้นถูกกำหนดโดยการรวมค่า Offset
- test: ใช้สำหรับการทดสอบในโรงงาน
+ Offset: กำหนดพื้นที่ที่พาร์ทิชันนั้น เริ่มต้น โดย Offset นั้นถูกกำหนดโดยการรวมค่า Offset
และขนาดของพาร์ทิชันก่อนหน้า \
*หมายเหตุ:* Offset จะต้องเป็นทวีคูณของ 4 KiB (0x1000)
หมายเหตุ: Offset จะต้องเป็นทวีคูณของ 4 KiB (0x1000)
และพาร์ทิชันแอพจะต้องจัดตำแหน่งให้มีขนาด 64 KiB (0x10000) โดยหากปล่อยให้ว่าง ค่า Offset
จะถูกคำนวนโดยอัตโนมัติตามตำแหน่งท้ายของพาร์ทิชันก่อนหน้า รวมถึงการจัดตำแหน่งใด ที่จำเป็น
อย่างไรก็ตาม Offset ของพาร์ทิชันแรกนั้นจะต้องเป็น *0x9000* และ *0x10000*
อย่างไรก็ตาม Offset ของพาร์ทิชันแรกนั้นจะต้องเป็น 0x9000 และ 0x10000
สำหรับพาร์ทิชันแอพลิเคชันแรก
+ *Size:* ขนาดของพาร์ทิชัน โดยค่านี้สามารถเป็นเลขทศนิยม, ตัวเลข Hex (นำหน้าด้วย `0x`),
+ Size: ขนาดของพาร์ทิชัน โดยค่านี้สามารถเป็นเลขทศนิยม, ตัวเลข Hex (นำหน้าด้วย 0x),
หรือใช้ตัวอักษรต่อท้ายเพื่อบ่งบอกหน่วย K (กิโล) หรือ M (เมกา) เช่น 4096 = 4K = 0x1000
+ *Flags:* ในปัจจุบันคอลัมน์นี้ใช้เพียงแค่เพื่อบ่งบอกว่าพาร์ทิชันนั้นถูกเข้ารหัสหรือไม่
+ Flags: ในปัจจุบันคอลัมน์นี้ใช้เพียงแค่เพื่อบ่งบอกว่าพาร์ทิชันนั้น ถูกเข้ารหัสหรือไม่
== LittleFS
#i LittleFS คือระบบไฟล์ขนาดเล็กที่ปลอดภัยต่อความล้มเหลวที่ออกแบบมาสำหรับ#jb
== littlefs
#i littlefs คือระบบไฟล์ขนาดเล็กที่ปลอดภัยต่อความล้มเหลวที่ออกแบบมาสำหรับ#jb
ไมโครคอนโทรลเลอร์
#show raw: set par(leading: 0.5em)
```
| | | .---._____
.-----. | |
--|o |---| littlefs |
--| |---| |
'-----' '----------'
| | |
```
*ความยืดหยุ่นในการป้องกันการสูญเสียพลังงาน* littlefs ออกแบบมาเพื่อรับมือกับปัญหาไฟฟ้าดับแบบสุ่ม
ความยืดหยุ่นในการป้องกันการสูญเสียพลังงาน littlefs ออกแบบมาเพื่อรับมือกับปัญหาไฟฟ้าดับแบบสุ่ม
การดำเนินการไฟล์ทั้งหมดมีการรับประกันการคัดลอกข้อมูลเมื่อเขียนข้อมูล (copy-on-write) ที่แข็งแกร่ง
และหากไฟฟ้าดับ ระบบไฟล์จะกลับสู่สถานะปกติล่าสุดที่ทราบ
*การปรับระดับการสึกหรอแบบไดนามิก* littlefs ออกแบบมาเพื่อแฟลชโดยเฉพาะ
การปรับระดับการสึกหรอแบบไดนามิก littlefs ออกแบบมาเพื่อแฟลชโดยเฉพาะ
และมอบการปรับระดับการสึกหรอบนบล็อกแบบไดนามิก นอกจากนี้ littlefs
ยังสามารถตรวจจับบล็อกเสียและแก้ไขปัญหาได้
*RAM/ROM แบบมีขอบเขต* littlefs ออกแบบมาเพื่อทำงานกับหน่วยความจำขนาดเล็ก การใช้งาน#jb
RAM ถูกจำกัดอย่างเข้มงวด ซึ่งหมายความว่าการใช้ RAM จะไม่เปลี่ยนแปลงเมื่อระบบไฟล์เติบโตขึ้น#jb
RAM/ROM แบบมีขอบเขต littlefs ออกแบบมาเพื่อทำงานกับหน่วยความจำขนาดเล็ก การใช้งาน#jb RAM
ถูกจำกัดอย่างเข้มงวด ซึ่งหมายความว่าการใช้ RAM จะไม่เปลี่ยนแปลงเมื่อระบบไฟล์เติบโตขึ้น#jb
ระบบไฟล์ไม่มีการเรียกซ้ำแบบไม่มีขอบเขต
และหน่วยความจำแบบไดนามิกถูกจำกัดให้อยู่ในบัฟเฟอร์ที่กำหนดค่าได้ซึ่งสามารถจัดเตรียมแบบคงที่ได้
@@ -140,33 +129,41 @@ RAM ถูกจำกัดอย่างเข้มงวด ซึ่งห
โดยการจำกัดจำนวนการลบข้อมูลที่อนุญาตบนบล็อกต่อการจัดสรรแต่ละครั้ง
ตัวจัดสรรจะปรับระดับการสึกหรอแบบไดนามิกทั่วทั้งระบบไฟล์
```
root
.--------.--------.
| A'| B'| |
| | |-> |
| | | |
'--------'--------'
.----' '--------------.
A v B v
.--------.--------. .--------.--------.
| C'| D'| | | E'|new| |
| | |-> | | | E'|-> |
| | | | | | | |
'--------'--------' '--------'--------'
.-' '--. | '------------------.
v v .-' v
.--------. .--------. v .--------.
| C | | D | .--------. write | new E |
| | | | | E | ==> | |
| | | | | | | |
'--------' '--------' | | '--------'
'--------' .-' |
.-' '-. .-------------|------'
v v v v
.--------. .--------. .--------.
| F | | G | | new F |
| | | | | |
| | | | | |
'--------' '--------' '--------'
```
#show raw: set par(leading: 0.4em)
#show raw: set text(size: 8pt)
#afigure(
```
root
.--------.--------.
| A'| B'| |
| | |-> |
| | | |
'--------'--------'
.----' '--------------.
A v B v
.--------.--------. .--------.--------.
| C'| D'| | | E'|new| |
| | |-> | | | E'|-> |
| | | | | | | |
'--------'--------' '--------'--------'
.-' '--. | '------------------.
v v .-' v
.--------. .--------. v .--------.
| C | | D | .--------. write | new E |
| | | | | E | ==> | |
| | | | | | | |
'--------' '--------' | | '--------'
'--------' .-' |
.-' '-. .-------------|------'
v v v v
.--------. .--------. .--------.
| F | | G | | new F |
| | | | | |
| | | | | |
'--------' '--------' '--------'
```,
kind: "image",
supplement: "รูปที่",
caption: [แสดงการทำงานเบื้องต้นของ LittleFS],
)
+164 -48
View File
@@ -5,79 +5,145 @@
= เซ็นเซอร์อินฟราเรดแบบพาสซีฟ (PIR sensor)
#i เซ็นเซอร์อินฟราเรดแบบพาสซีฟ (PIR sensor) คือ เซ็นเซอร์อิเล็กทรอนิกส์ที่วัดแสงอินฟราเรด (IR) ที่แผ่ออกมาจากวัตถุในระยะการมองเห็น เซ็นเซอร์ชนิดนี้มักใช้ในเครื่องตรวจจับความเคลื่อนไหว แบบ PIR เซ็นเซอร์ PIR มักใช้ในสัญญาณเตือนภัยและระบบไฟส่องสว่างอัตโนมัติ
#iii เซ็นเซอร์อินฟราเรดแบบพาสซีฟ (PIR sensor) คือ เซ็นเซอร์อิเล็กทรอนิกส์ที่วัดแสงอินฟราเรด
(IR) ที่แผ่ออกมาจากวัตถุในระยะการมองเห็น เซ็นเซอร์ชนิดนี้มักใช้ในเครื่องตรวจจับความเคลื่อนไหว แบบ
PIR เซ็นเซอร์ PIR มักใช้ในสัญญาณเตือนภัยและระบบไฟส่องสว่างอัตโนมัติ
#afigure(
image("PIR/Front-Fresnel_type.jpg", height: image-height),
attr: [Jack LaRosa, Public Domain, https://commons.wikimedia.org/w/index.php?curid=4479143],
attr: [Jack LaRosa, Public Domain,
https://commons.wikimedia.org/w/index.php?curid=4479143],
alt: "เซนเซอร์ตรวจจับการเคลื่อนไหวทรงสี่เหลี่ยมผืนผ้าแนวตั้ง",
caption: [เครื่องตรวจจับการเคลื่อนไหวแบบ PIR ทั่วไปสำหรับที่พักอาศัย/เชิงพาณิชย์],
)
#i เซ็นเซอร์ PIR ตรวจจับการเคลื่อนไหวทั่วไป แต่ไม่ได้ให้ข้อมูลว่าใครหรือสิ่งใดเคลื่อนไหว ดังนั้น จึงจำเป็นต้องใช้ เซ็นเซอร์ IR แบบสร้างภาพ เซ็นเซอร์ PIR มักเรียกสั้นๆ ว่า "PIR" หรือบางครั้งเรียกว่า "PID" ซึ่งย่อมาจาก "เครื่องตรวจจับอินฟราเรดแบบพาสซีฟ" เซ็นเซอร์ PIR ตรวจจับการเคลื่อนไหวทั่วไป แต่ไม่ได้ให้ข้อมูลว่าใครหรือสิ่งใดเคลื่อนไหว ดังนั้น จึงจำเป็นต้องใช้ เซ็นเซอร์ IR แบบสร้างภาพ เซ็นเซอร์ PIR มักเรียกสั้นๆ ว่า "PIR" หรือบางครั้งเรียกว่า "PID" ซึ่งย่อมาจาก "เครื่องตรวจจับอินฟราเรดแบบพาสซีฟ" คำว่าพาสซีฟหมายถึงข้อเท็จจริงที่ว่าอุปกรณ์ PIR ไม่ได้แผ่พลังงานเพื่อจุดประสงค์ในการตรวจจับ แต่ทำงานโดยการตรวจจับรังสีอินฟราเรด (ความร้อนจากการแผ่รังสี) ที่แผ่ออกมาจากหรือสะท้อนจากวัตถุ เท่านั้นซีฟ" คำว่าพาสซีฟหมายถึงข้อเท็จจริงที่ว่าอุปกรณ์ PIR ไม่ได้แผ่พลังงานเพื่อจุดประสงค์ในการตรวจจับ แต่ทำงานโดยการตรวจจับรังสีอินฟราเรด (ความร้อนจากการแผ่รังสี) ที่แผ่ออกมาจากหรือสะท้อนจากวัตถุ เท่านั้น
#i เซ็นเซอร์ PIR ตรวจจับการเคลื่อนไหวทั่วไป แต่ไม่ได้ให้ข้อมูลว่าใครหรือสิ่งใดเคลื่อนไหว ดังนั้น
จึงจำเป็นต้องใช้ เซ็นเซอร์ IR แบบสร้างภาพ เซ็นเซอร์ PIR มักเรียกสั้นๆ ว่า "PIR"
หรือบางครั้งเรียกว่า "PID" ซึ่งย่อมาจาก "เครื่องตรวจจับอินฟราเรดแบบพาสซีฟ" เซ็นเซอร์ PIR
ตรวจจับการเคลื่อนไหวทั่วไป แต่ไม่ได้ให้ข้อมูลว่าใครหรือสิ่งใดเคลื่อนไหว ดังนั้น จึงจำเป็นต้องใช้ เซ็นเซอร์
IR แบบสร้างภาพ เซ็นเซอร์ PIR มักเรียกสั้นๆ ว่า "PIR" หรือบางครั้งเรียกว่า "PID" ซึ่งย่อมาจาก
"เครื่องตรวจจับอินฟราเรดแบบพาสซีฟ" คำว่าพาสซีฟหมายถึงข้อเท็จจริงที่ว่าอุปกรณ์ PIR
ไม่ได้แผ่พลังงานเพื่อจุดประสงค์ในการตรวจจับ แต่ทำงานโดยการตรวจจับรังสีอินฟราเรด
(ความร้อนจากการแผ่รังสี) ที่แผ่ออกมาจากหรือสะท้อนจากวัตถุ เท่านั้นซีฟ"
คำว่าพาสซีฟหมายถึงข้อเท็จจริงที่ว่าอุปกรณ์ PIR ไม่ได้แผ่พลังงานเพื่อจุดประสงค์ในการตรวจจับ
แต่ทำงานโดยการตรวจจับรังสีอินฟราเรด (ความร้อนจากการแผ่รังสี) ที่แผ่ออกมาจากหรือสะท้อนจากวัตถุ
เท่านั้น
== หลักการทำงาน
#i วัตถุทุกชนิดที่มีอุณหภูมิสูงกว่าศูนย์องศาสัมบูรณ์จะปล่อยพลังงานความร้อนออกมาในรูปของรังสีแม่เหล็กไฟฟ้า โดยปกติแล้วรังสีนี้มองไม่เห็นด้วยตาเปล่าเนื่องจากแผ่รังสีในช่วงความยาวคลื่นอินฟราเรด แต่อุปกรณ์อิเล็กทรอนิกส์ที่ออกแบบมาเพื่อจุดประสงค์นี้ สามารถตรวจจับได้
#iiii
วัตถุทุกชนิดที่มีอุณหภูมิสูงกว่าศูนย์องศาสัมบูรณ์จะปล่อยพลังงานความร้อนออกมาในรูปของรังสีแม่เหล็กไฟฟ้า
โดยปกติแล้วรังสีนี้มองไม่เห็นด้วยตาเปล่าเนื่องจากแผ่รังสีในช่วงความยาวคลื่นอินฟราเรด
แต่อุปกรณ์อิเล็กทรอนิกส์ที่ออกแบบมาเพื่อจุดประสงค์นี้ สามารถตรวจจับได้
== เครื่องตรวจจับการเคลื่อนไหวแบบ PIR
#afigure(
image("PIR/Motion_detector.jpg", height: image-height),
alt: "เครื่องตรวจจับความเคลื่อนไหว ติดตั้งบนเพดาน",
attr: [CHG, Public Domain, https://commons.wikimedia.org/w/index.php?curid=6087132],
caption: [เครื่องตรวจจับความเคลื่อนไหว PIR
ใช้สำหรับควบคุมไฟภายนอกอาคารแบบอัตโนมัติ],
attr: [CHG, Public Domain,
https://commons.wikimedia.org/w/index.php?curid=6087132],
caption: [เครื่องตรวจจับความเคลื่อนไหว PIR ใช้สำหรับควบคุมไฟภายนอกอาคารแบบอัตโนมัติ],
)
#afigure(
image("PIR/Camera_trap,_fotopułapka,_kamera_leśna,_kamera_obserwacyjna.jpg"),
attr: [Dariusz Kowalczyk, CC BY-SA 4.0, https://commons.wikimedia.org/w/index.php?curid=96211951],
attr: [Dariusz Kowalczyk, CC BY-SA 4.0,
https://commons.wikimedia.org/w/index.php?curid=96211951],
alt: "กล้องดักถ่ายที่ถูกพันรอบต้นไม้",
caption: [กล้องดักถ่ายพร้อมระบบตรวจจับความเคลื่อนไหวแบบ PIR],
)
#afigure(
image("PIR/Light_switch_with_passive_infrared_sensor.jpg", height: image-height),
image(
"PIR/Light_switch_with_passive_infrared_sensor.jpg",
height: image-height,
),
alt: "สวิตช์ไฟทรงสี่เหลี่ยมผืนผ้าแนวตั้งที่ติดตั้งเซนเซอร์ตรวจจับคน",
attr: [Z22, CC BY-SA 4.0, https://commons.wikimedia.org/w/index.php?curid=35183184],
attr: [Z22, CC BY-SA 4.0,
https://commons.wikimedia.org/w/index.php?curid=35183184],
caption: [สวิตช์ไฟภายในอาคารที่ติดตั้งเซนเซอรตรวจจับการครอบครองแบบ PIR],
)
#i เครื่องตรวจจับความเคลื่อนไหวแบบ PIR ใช้เพื่อตรวจจับการเคลื่อนไหวของคน สัตว์ หรือวัตถุอื่นๆ มักใช้กับสัญญาณกันขโมยและระบบไฟส่องสว่างแบบอัตโนมัติ
#i เครื่องตรวจจับความเคลื่อนไหวแบบ PIR ใช้เพื่อตรวจจับการเคลื่อนไหวของคน สัตว์ หรือวัตถุอื่นๆ
มักใช้กับสัญญาณกันขโมยและระบบไฟส่องสว่างแบบอัตโนมัติ
== การดำเนินการ
#i เซ็นเซอร์ PIR สามารถตรวจจับการเปลี่ยนแปลงของปริมาณรังสีอินฟราเรดที่กระทบกับวัตถุ ซึ่งจะแตกต่างกันไปขึ้นอยู่กับอุณหภูมิและลักษณะพื้นผิวของวัตถุที่อยู่ด้านหน้าเซ็นเซอร์เมื่อวัตถุ เช่น บุคคล ผ่านด้านหน้าพื้นหลัง เช่น กำแพง อุณหภูมิ จุดนั้นในมุมมองของเซ็นเซอร์จะเพิ่มขึ้นจากอุณหภูมิห้องเป็นอุณหภูมิร่างกายแล้วกลับมาอีกครั้ง เซ็นเซอร์จะแปลงการเปลี่ยนแปลงที่เกิดขึ้นของรังสีอินฟราเรดที่เข้ามาเป็นการเปลี่ยนแปลงของแรงดันไฟฟ้าขาออก และสิ่งนี้จะกระตุ้นการตรวจจับ วัตถุที่มีอุณหภูมิใกล้เคียงกันแต่มีลักษณะพื้นผิวต่างกันอาจมีรูปแบบการปล่อยรังสีอินฟราเรดที่แตกต่างกัน ดังนั้นการเคลื่อนย้ายวัตถุเทียบกับพื้นหลังอาจกระตุ้นเครื่องตรวจจับได้เช่นกัน
#iiii เซ็นเซอร์ PIR สามารถตรวจจับการเปลี่ยนแปลงของปริมาณรังสีอินฟราเรดที่กระทบกับวัตถุ
ซึ่งจะแตกต่างกันไปขึ้นอยู่กับอุณหภูมิและลักษณะพื้นผิวของวัตถุที่อยู่ด้านหน้าเซ็นเซอร์เมื่อวัตถุ เช่น บุคคล
ผ่านด้านหน้าพื้นหลัง เช่น กำแพง อุณหภูมิ
จุดนั้นในมุมมองของเซ็นเซอร์จะเพิ่มขึ้นจากอุณหภูมิห้องเป็นอุณหภูมิร่างกายแล้วกลับมาอีกครั้ง
เซ็นเซอร์จะแปลงการเปลี่ยนแปลงที่เกิดขึ้นของรังสีอินฟราเรดที่เข้ามาเป็นการเปลี่ยนแปลงของแรงดันไฟฟ้าขาออก
และสิ่งนี้จะกระตุ้นการตรวจจับ
วัตถุที่มีอุณหภูมิใกล้เคียงกันแต่มีลักษณะพื้นผิวต่างกันอาจมีรูปแบบการปล่อยรังสีอินฟราเรดที่แตกต่างกัน
ดังนั้นการเคลื่อนย้ายวัตถุเทียบกับพื้นหลังอาจกระตุ้นเครื่องตรวจจับได้เช่นกัน
#i PIR มีหลายรูปแบบการใช้งานที่หลากหลาย รุ่นที่นิยมใช้กันมากที่สุดมีเลนส์เฟรสเนลหรือส่วนกระจกจำนวนมาก ระยะการทำงานประมาณ 10 เมตร (30 ฟุต) และมุมมองภาพน้อยกว่า 180° มีรุ่นที่มีมุมมองภาพกว้างกว่า รวมถึง 360° ซึ่งโดยทั่วไปออกแบบมาเพื่อติดตั้งบนเพดาน PIR ขนาดใหญ่บางรุ่นผลิตด้วยกระจกส่วนเดียวและสามารถตรวจจับการเปลี่ยนแปลงของพลังงานอินฟราเรดได้ในระยะ 30 เมตร (100 ฟุต) จาก PIR นอกจากนี้ยังมี PIR ที่ออกแบบด้วยกระจกแบบปรับทิศทางได้ ซึ่งสามารถครอบคลุมพื้นที่ได้กว้าง (110°) หรือครอบคลุมพื้นที่แคบมากแบบ "ม่าน" หรือสามารถเลือกส่วนกระจกแยกแต่ละส่วนเพื่อ "ปรับแต่ง" พื้นที่ครอบคลุมได้
#i PIR มีหลายรูปแบบการใช้งานที่หลากหลาย
รุ่นที่นิยมใช้กันมากที่สุดมีเลนส์เฟรสเนลหรือส่วนกระจกจำนวนมาก ระยะการทำงานประมาณ 10 เมตร (30
ฟุต) และมุมมองภาพน้อยกว่า 180° มีรุ่นที่มีมุมมองภาพกว้างกว่า รวมถึง 360°
ซึ่งโดยทั่วไปออกแบบมาเพื่อติดตั้งบนเพดาน PIR
ขนาดใหญ่บางรุ่นผลิตด้วยกระจกส่วนเดียวและสามารถตรวจจับการเปลี่ยนแปลงของพลังงานอินฟราเรดได้ในระยะ
30 เมตร (100 ฟุต) จาก PIR นอกจากนี้ยังมี PIR ที่ออกแบบด้วยกระจกแบบปรับทิศทางได้
ซึ่งสามารถครอบคลุมพื้นที่ได้กว้าง (110°) หรือครอบคลุมพื้นที่แคบมากแบบ "ม่าน"
หรือสามารถเลือกส่วนกระจกแยกแต่ละส่วนเพื่อ "ปรับแต่ง" พื้นที่ครอบคลุมได้
== การตรวจจับความแตกต่าง
#i เซ็นเซอร์หลายตัวอาจเชื่อมต่อเป็นอินพุตตรงข้ามกับเครื่องขยายสัญญาณดิฟเฟอเรนเชียล ในรูปแบบนี้ การวัดค่า PIR จะหักล้างกันเอง ทำให้อุณหภูมิเฉลี่ยของระยะการมองเห็นถูกตัดออกจากสัญญาณไฟฟ้า การเพิ่มขึ้นของพลังงานอินฟราเรดทั่วทั้งเซ็นเซอร์จะหักล้างตัวเองและจะไม่กระตุ้นอุปกรณ์ วิธีนี้ช่วยให้อุปกรณ์ต้านทานการเปลี่ยนแปลงที่ผิดพลาดในกรณีที่ได้รับแสงแฟลชสั้นๆ หรือแสงที่ส่องสว่างทั่วทั้งสนาม (การได้รับพลังงานสูงอย่างต่อเนื่องอาจทำให้วัสดุเซ็นเซอร์อิ่มตัวและทำให้เซ็นเซอร์ไม่สามารถบันทึกข้อมูลเพิ่มเติมได้) ในขณะเดียวกัน การจัดเรียงแบบดิฟเฟอเรนเชียลนี้ยังช่วยลดสัญญาณรบกวนโหมดทั่วไปทำให้อุปกรณ์ต้านทานการกระตุ้นเนื่องจากสนามไฟฟ้าใกล้เคียง อย่างไรก็ตาม เซ็นเซอร์แบบดิฟเฟอเรนเชียลคู่ไม่สามารถวัดอุณหภูมิได้ในรูปแบบนี้ ดังนั้นจึงมีประโยชน์เฉพาะสำหรับการตรวจจับการเคลื่อนไหวเท่านั้น
#iiii เซ็นเซอร์หลายตัวอาจเชื่อมต่อเป็นอินพุตตรงข้ามกับเครื่องขยายสัญญาณดิฟเฟอเรนเชียล ในรูปแบบนี้
การวัดค่า PIR จะหักล้างกันเอง ทำให้อุณหภูมิเฉลี่ยของระยะการมองเห็นถูกตัดออกจากสัญญาณไฟฟ้า
การเพิ่มขึ้นของพลังงานอินฟราเรดทั่วทั้งเซ็นเซอร์จะหักล้างตัวเองและจะไม่กระตุ้นอุปกรณ์
วิธีนี้ช่วยให้อุปกรณ์ต้านทานการเปลี่ยนแปลงที่ผิดพลาดในกรณีที่ได้รับแสงแฟลชสั้นๆ
หรือแสงที่ส่องสว่างทั่วทั้งสนาม
(การได้รับพลังงานสูงอย่างต่อเนื่องอาจทำให้วัสดุเซ็นเซอร์อิ่มตัวและทำให้เซ็นเซอร์ไม่สามารถบันทึกข้อมูลเพิ่มเติมได้)
ในขณะเดียวกัน
การจัดเรียงแบบดิฟเฟอเรนเชียลนี้ยังช่วยลดสัญญาณรบกวนโหมดทั่วไปทำให้อุปกรณ์ต้านทานการกระตุ้นเนื่องจากสนามไฟฟ้าใกล้เคียง
อย่างไรก็ตาม เซ็นเซอร์แบบดิฟเฟอเรนเชียลคู่ไม่สามารถวัดอุณหภูมิได้ในรูปแบบนี้
ดังนั้นจึงมีประโยชน์เฉพาะสำหรับการตรวจจับการเคลื่อนไหวเท่านั้น
== การปฏิบัติจริง
#i เมื่อเซ็นเซอร์ PIR ถูกกำหนดค่าในโหมดดิฟเฟอเรนเชียล เซ็นเซอร์จะสามารถใช้งานได้เฉพาะในฐานะอุปกรณ์ตรวจจับการเคลื่อนไหว ในโหมดนี้ เมื่อตรวจจับการเคลื่อนไหวภายใน "แนวสายตา" ของเซ็นเซอร์ พัลส์เสริมคู่หนึ่งจะถูกประมวลผลที่ขาเอาต์พุตของเซ็นเซอร์ เพื่อนำสัญญาณเอาต์พุตนี้ไปใช้งานจริงในการกระตุ้นโหลด เช่น รีเลย์หรือเครื่องบันทึกข้อมูลหรือสัญญาณเตือนสัญญาณดิฟเฟอเรน-เชียลจะถูกแก้ไขโดยใช้วงจรเรียงกระแสแบบบริดจ์และป้อนเข้าสู่วงจรขับรีเลย์แบบทรานซิสเตอร์ หน้าสัมผัสของรีเลย์นี้จะปิดและเปิดเพื่อตอบสนองต่อสัญญาณจาก PIR โดยกระตุ้นโหลดที่เชื่อมต่ออยู่ผ่านหน้าสัมผัสของมัน รับรู้ถึงการตรวจจับบุคคลภายในพื้นที่จำกัดที่กำหนดไว้ล่วงหน้า
#iiii เมื่อเซ็นเซอร์ PIR ถูกกำหนดค่าในโหมดดิฟเฟอเรนเชียล
เซ็นเซอร์จะสามารถใช้งานได้เฉพาะในฐานะอุปกรณ์ตรวจจับการเคลื่อนไหว ในโหมดนี้
เมื่อตรวจจับการเคลื่อนไหวภายใน "แนวสายตา" ของเซ็นเซอร์
พัลส์เสริมคู่หนึ่งจะถูกประมวลผลที่ขาเอาต์พุตของเซ็นเซอร์
เพื่อนำสัญญาณเอาต์พุตนี้ไปใช้งานจริงในการกระตุ้นโหลด เช่น
รีเลย์หรือเครื่องบันทึกข้อมูลหรือสัญญาณเตือนสัญญาณดิฟเฟอเรน-เชียลจะถูกแก้ไขโดยใช้วงจรเรียงกระแสแบบบริดจ์และป้อนเข้าสู่วงจรขับรีเลย์แบบทรานซิสเตอร์
หน้าสัมผัสของรีเลย์นี้จะปิดและเปิดเพื่อตอบสนองต่อสัญญาณจาก PIR
โดยกระตุ้นโหลดที่เชื่อมต่ออยู่ผ่านหน้าสัมผัสของมัน
รับรู้ถึงการตรวจจับบุคคลภายในพื้นที่จำกัดที่กำหนดไว้ล่วงหน้า
== การออกแบบผลิตภัณฑ์
#afigure(
image("PIR/PIR_Motion_Sensor-Sensinova_(SN-PR11).png", height: image-height),
attr: [Versatile Techno - http://www.sensinova.in/pir-motion-sensor/SNPR11.php, CC BY-SA 4.0, https://commons.wikimedia.org/w/index.php?curid=48377787],
attr: [Versatile Techno -
http://www.sensinova.in/pir-motion-sensor/SNPR11.php, CC BY-SA 4.0,
https://commons.wikimedia.org/w/index.php?curid=48377787],
alt: "ผลิตภัณฑ์เซนเซอร์สีขาว มีเครื่องหมายแบรนด์ Sensinova",
caption: [การออกแบบเซ็นเซอร์ตรวจจับการเคลื่อนไหว PIR],
)
#i โดยทั่วไปเซ็นเซอร์ PIR จะติดตั้งอยู่บนแผงวงจรพิมพ์ซึ่งมีอุปกรณ์อิเล็กทรอนิกส์ที่จำเป็นสำหรับการตีความสัญญาณจากตัวเซ็นเซอร์เอง โดยทั่วไปแล้วชุดประกอบทั้งหมดจะบรรจุอยู่ภายในตัวเรือน ซึ่งติดตั้งในตำแหน่งที่เซ็นเซอร์สามารถครอบคลุมพื้นที่ที่ต้องการตรวจสอบได้ ตัวเรือนมักจะมี "หน้าต่าง" พลาสติกที่พลังงานอินฟราเรดสามารถผ่านเข้ามาได้ แม้ว่ามักจะโปร่งแสงต่อแสงที่มองเห็น แต่พลังงานอินฟราเรดสามารถผ่านเข้ามายังเซ็นเซอร์ได้ผ่านหน้าต่าง เนื่องจากพลาสติกที่ใช้นั้นโปร่งใสต่อรังสีอินฟราเรด หน้าต่างพลาสติกช่วยลดโอกาสที่วัตถุแปลกปลอม (ฝุ่น แมลง ฝน ฯลฯ) จะบดบังมุมมองของเซ็นเซอร์ ทำให้กลไกเสียหาย และอาจทำให้เกิดสัญญาณเตือนที่ผิดพลาด หน้าต่างนี้สามารถใช้เป็นตัวกรองเพื่อจำกัดความยาวคลื่นให้อยู่ที่ 8-14 ไมโครเมตร ซึ่งใกล้เคียงกับรังสีอินฟราเรดที่มนุษย์ปล่อยออกมามากที่สุด นอกจากนี้ยังสามารถใช้เป็นกลไกโฟกัสได้อีกด้วย (ดูด้านล่าง)
#i โดยทั่วไปเซ็นเซอร์ PIR
จะติดตั้งอยู่บนแผงวงจรพิมพ์ซึ่งมีอุปกรณ์อิเล็กทรอนิกส์ที่จำเป็นสำหรับการตีความสัญญาณจากตัวเซ็นเซอร์เอง
โดยทั่วไปแล้วชุดประกอบทั้งหมดจะบรรจุอยู่ภายในตัวเรือน
ซึ่งติดตั้งในตำแหน่งที่เซ็นเซอร์สามารถครอบคลุมพื้นที่ที่ต้องการตรวจสอบได้ ตัวเรือนมักจะมี "หน้าต่าง"
พลาสติกที่พลังงานอินฟราเรดสามารถผ่านเข้ามาได้ แม้ว่ามักจะโปร่งแสงต่อแสงที่มองเห็น
แต่พลังงานอินฟราเรดสามารถผ่านเข้ามายังเซ็นเซอร์ได้ผ่านหน้าต่าง
เนื่องจากพลาสติกที่ใช้นั้นโปร่งใสต่อรังสีอินฟราเรด หน้าต่างพลาสติกช่วยลดโอกาสที่วัตถุแปลกปลอม (ฝุ่น
แมลง ฝน ฯลฯ) จะบดบังมุมมองของเซ็นเซอร์ ทำให้กลไกเสียหาย และอาจทำให้เกิดสัญญาณเตือนที่ผิดพลาด
หน้าต่างนี้สามารถใช้เป็นตัวกรองเพื่อจำกัดความยาวคลื่นให้อยู่ที่ 8-14 ไมโครเมตร
ซึ่งใกล้เคียงกับรังสีอินฟราเรดที่มนุษย์ปล่อยออกมามากที่สุด นอกจากนี้ยังสามารถใช้เป็นกลไกโฟกัสได้อีกด้วย
(ดูด้านล่าง)
== การโฟกัส
#i สามารถใช้กลไกที่แตกต่างกันเพื่อโฟกัสพลังงานอินฟราเรดระยะไกลลงบนพื้นผิวเซ็นเซอร์ได้
#iiii สามารถใช้กลไกที่แตกต่างกันเพื่อโฟกัสพลังงานอินฟราเรดระยะไกลลงบนพื้นผิวเซ็นเซอร์ได้
== เลนส์
#i ม่านพลาสติกอาจหล่อขึ้นรูปหลายเหลี่ยมเพื่อรวมพลังงานอินฟราเรดไปยังเซ็นเซอร์ แต่ละเหลี่ยมคือเลนส์เฟรสเนล
#iiii ม่านพลาสติกอาจหล่อขึ้นรูปหลายเหลี่ยมเพื่อรวมพลังงานอินฟราเรดไปยังเซ็นเซอร์
แต่ละเหลี่ยมคือเลนส์เฟรสเนล
=== เลนส์มัลติเฟรสเนลของ PIR
@@ -85,63 +151,72 @@
image("PIR/FacetLensOfMotionDetector_animation2.gif", height: 2in),
attr: [CC BY-SA 3.0, https://en.wikipedia.org/w/index.php?curid=14193664],
alt: "เครื่องตรวจจับความเคลื่อนไหวทรงกระบอก",
caption: [ตัวเรือนเครื่องตรวจจับความเคลื่อนไหว PIR พร้อมช่องหน้าต่างทรงกระบอกเหลี่ยมโดยแต่ละเหลี่ยมเป็นเลนส์เฟรสเนล โฟกัสแสงไปที่ชิ้นส่วนเซ็นเซอร์ไพโรอิเล็กทริกที่อยู่ด้านล่าง],
caption: [ตัวเรือนเครื่องตรวจจับความเคลื่อนไหว PIR
พร้อมช่องหน้าต่างทรงกระบอกเหลี่ยมโดยแต่ละเหลี่ยมเป็นเลนส์เฟรสเนล
โฟกัสแสงไปที่ชิ้นส่วนเซ็นเซอร์ไพโรอิเล็กทริกที่อยู่ด้านล่าง],
)
#afigure(
image("PIR/Fresnel_only.jpg", height: 2in),
attr: [Jack LaRosa, Public Domain, https://commons.wikimedia.org/w/index.php?curid=4463018],
attr: [Jack LaRosa, Public Domain,
https://commons.wikimedia.org/w/index.php?curid=4463018],
alt: "ฝาครอบของเซนเซอร์ตรวจจับความเคลื่อนไหว",
caption: [ฝาครอบด้านหน้า PIR เท่านั้น (ถอดอุปกรณ์อิเล็กทรอนิกส์ออก) โดยมีแหล่งกำเนิดแสงจุดอยู่ด้านหลัง เพื่อแสดงเลนส์แต่ละตัว],
caption: [ฝาครอบด้านหน้า PIR เท่านั้น (ถอดอุปกรณ์อิเล็กทรอนิกส์ออก)
โดยมีแหล่งกำเนิดแสงจุดอยู่ด้านหลัง เพื่อแสดงเลนส์แต่ละตัว],
)
#afigure(
image("PIR/Circuit_board_revealed.jpg", height: 2in),
attr: [Jack LaRosa, Public Domain, https://commons.wikimedia.org/w/index.php?curid=4478366],
attr: [Jack LaRosa, Public Domain,
https://commons.wikimedia.org/w/index.php?curid=4478366],
alt: "แผงวงจร PIR ลูกศรสีเขียวชี้ไปยังเซนเซอร์ภายในบอร์ด",
caption: [PIR ที่ถอดฝาครอบด้านหน้าออก แสดงตำแหน่งของ
เซ็นเซอร์ไพโรอิเล็กทริก (ลูกศรสีเขียว)],
caption: [PIR ที่ถอดฝาครอบด้านหน้าออก แสดงตำแหน่งของ เซ็นเซอร์ไพโรอิเล็กทริก
(ลูกศรสีเขียว)],
)
== กระจก PIR
#i บางรุ่นผลิตขึ้นโดยใช้กระจกพาราโบลา แบบแบ่งส่วนภายใน เพื่อรวมพลังงานอินฟราเรด ในกรณีที่ใช้กระจก ฝาครอบกระจกพลาสติกโดยทั่วไปจะไม่มีเลนส์เฟรสเนลหล่อขึ้นรูป
#iiii บางรุ่นผลิตขึ้นโดยใช้กระจกพาราโบลา แบบแบ่งส่วนภายใน เพื่อรวมพลังงานอินฟราเรด
ในกรณีที่ใช้กระจก ฝาครอบกระจกพลาสติกโดยทั่วไปจะไม่มีเลนส์เฟรสเนลหล่อขึ้นรูป
=== PIR ชนิดกระจกแบ่งส่วน
#afigure(
image("PIR/Front-(mirror_type).jpg", height: 2in),
attr: [Jack LaRosa, Public Domain, https://commons.wikimedia.org/w/index.php?curid=4501665],
attr: [Jack LaRosa, Public Domain,
https://commons.wikimedia.org/w/index.php?curid=4501665],
alt: "เซนเซอร์ทรงคล้ายทรงกลม",
caption: [PID ทั่วไปสำหรับที่พักอาศัย/เชิงพาณิชย์ที่
ใช้กระจกแบ่งส่วนภายในเพื่อการโฟกัส],
caption: [PID ทั่วไปสำหรับที่พักอาศัย/เชิงพาณิชย์ที่ ใช้กระจกแบ่งส่วนภายในเพื่อการโฟกัส],
)
#afigure(
image("PIR/Mirror_type_opened.jpg", height: 2in),
attr: [Deuxdad, Public Domain, https://commons.wikimedia.org/w/index.php?curid=4501724],
attr: [Deuxdad, Public Domain,
https://commons.wikimedia.org/w/index.php?curid=4501724],
alt: "เซนเซอร์ก่อนหน้าเมื่อถูกถอดฝาครอบออก",
caption: [ถอดฝาครอบออกแล้ว กระจกแบ่งส่วน
ด้านล่างมีแผงวงจรพิมพ์ (PC) อยู่ด้านบน],
caption: [ถอดฝาครอบออกแล้ว กระจกแบ่งส่วน ด้านล่างมีแผงวงจรพิมพ์ (PC) อยู่ด้านบน],
)
#afigure(
image("PIR/Mirror_in_place.jpg", height: 2in),
attr: [Jack LaRosa, Public Domain, https://commons.wikimedia.org/w/index.php?curid=4502198],
attr: [Jack LaRosa, Public Domain,
https://commons.wikimedia.org/w/index.php?curid=4502198],
alt: "เซนเซอร์ก่อนหน้าเมื่อถอดแผงวงจรให้เห็นกระจกแบ่งส่วนด้านใน",
caption: [แผงวงจรพิมพ์ถูกถอดออกเพื่อแสดงกระจกแบบแบ่งส่วน],
)
#afigure(
image("PIR/Segmented-parabolic_mirror.jpg", height: 2in),
attr: [Deuxdad, Public Domain, https://commons.wikimedia.org/w/index.php?curid=4502224],
attr: [Deuxdad, Public Domain,
https://commons.wikimedia.org/w/index.php?curid=4502224],
alt: "กระจกแบ่งส่วนที่ถูกถอดออก",
caption: [กระจกพาราโบลาแบบแบ่งส่วนถอดออกจากตัวเครื่อง],
)
#afigure(
image("PIR/Rear_of_circuit_board2.jpg", height: 2in),
attr: [Jack LaRosa, Public Domain, https://commons.wikimedia.org/w/index.php?curid=4508036],
attr: [Jack LaRosa, Public Domain,
https://commons.wikimedia.org/w/index.php?curid=4508036],
alt: "ด้านหลังของแผงวงจรก่อนหน้า ลูกศรสีเขียวชี้ไปยังเซนเซอร์",
caption: [ด้านหลังของแผงวงจรที่หันเข้าหากระจกเมื่อติดตั้ง
เซ็นเซอร์ไพโรอิเล็กทริกแสดงด้วยลูกศรสีเขียว],
@@ -151,37 +226,78 @@
#afigure(
image("PIR/Motion_Detector_with_Beam_Pattern.jpg", height: 2in),
attr: [AndreasCT, CC BY-SA 4.0, https://commons.wikimedia.org/w/index.php?curid=84066723],
attr: [AndreasCT, CC BY-SA 4.0,
https://commons.wikimedia.org/w/index.php?curid=84066723],
alt: "กราฟิกแสดงลำแสงจำลองการทำงานของเครื่องตรวจจับความเคลื่อนไหว",
caption: [เครื่องตรวจจับความเคลื่อนไหวที่มีรูปแบบลำแสงซ้อนทับ ความยาวของลำแสงเป็นตัวชี้วัดความไวของเครื่องตรวจจับในทิศทางนั้น],
caption: [เครื่องตรวจจับความเคลื่อนไหวที่มีรูปแบบลำแสงซ้อนทับ
ความยาวของลำแสงเป็นตัวชี้วัดความไวของเครื่องตรวจจับในทิศทางนั้น],
)
#i จากการโฟกัส ทำให้มุมมองของเครื่องตรวจจับกลายเป็นรูปแบบลำแสง ภายใต้มุมบางมุม (โซน)\ เซ็นเซอร์ PIR แทบจะไม่ได้รับพลังงานรังสีใด และภายใต้มุมอื่น PIR จะได้รับพลังงานอินฟราเรดในปริมาณที่เข้มข้น การแยกนี้ช่วยให้เครื่องตรวจจับความเคลื่อนไหวสามารถแยกแยะระหว่างแสงสว่างที่กว้างและวัตถุที่กำลังเคลื่อนที่ได้
#i จากการโฟกัส ทำให้มุมมองของเครื่องตรวจจับกลายเป็นรูปแบบลำแสง ภายใต้มุมบางมุม (โซน)\
เซ็นเซอร์ PIR แทบจะไม่ได้รับพลังงานรังสีใด และภายใต้มุมอื่น PIR
จะได้รับพลังงานอินฟราเรดในปริมาณที่เข้มข้น
การแยกนี้ช่วยให้เครื่องตรวจจับความเคลื่อนไหวสามารถแยกแยะระหว่างแสงสว่างที่กว้างและวัตถุที่กำลังเคลื่อนที่ได้
#i เมื่อบุคคลเดินจากมุมหนึ่ง (ลำแสง) ไปยังอีกมุมหนึ่ง เครื่องตรวจจับจะมองเห็นบุคคลที่กำลังเคลื่อนไหวเป็นระยะ เท่านั้น ส่งผลให้สัญญาณเซ็นเซอร์เปลี่ยนแปลงอย่างรวดเร็ว ซึ่งระบบอิเล็กทรอนิกส์จะใช้เพื่อส่งสัญญาณเตือนภัยหรือเปิดไฟ ระบบอิเล็กทรอนิกส์จะไม่สนใจสัญญาณที่เปลี่ยนแปลงช้า
#i เมื่อบุคคลเดินจากมุมหนึ่ง (ลำแสง) ไปยังอีกมุมหนึ่ง
เครื่องตรวจจับจะมองเห็นบุคคลที่กำลังเคลื่อนไหวเป็นระยะ เท่านั้น
ส่งผลให้สัญญาณเซ็นเซอร์เปลี่ยนแปลงอย่างรวดเร็ว
ซึ่งระบบอิเล็กทรอนิกส์จะใช้เพื่อส่งสัญญาณเตือนภัยหรือเปิดไฟ
ระบบอิเล็กทรอนิกส์จะไม่สนใจสัญญาณที่เปลี่ยนแปลงช้า
#i จำนวน รูปร่าง การกระจาย และความไวของโซนเหล่านี้ถูกกำหนดโดยเลนส์และกระจก ผู้ผลิตพยายามอย่างเต็มที่เพื่อสร้างรูปแบบลำแสงความไวที่เหมาะสมที่สุดสำหรับการใช้งานแต่ละประเภท
#i จำนวน รูปร่าง การกระจาย และความไวของโซนเหล่านี้ถูกกำหนดโดยเลนส์และกระจก
ผู้ผลิตพยายามอย่างเต็มที่เพื่อสร้างรูปแบบลำแสงความไวที่เหมาะสมที่สุดสำหรับการใช้งานแต่ละประเภท
== การใช้งานระบบไฟอัตโนมัติ
#i เมื่อใช้เป็นส่วนหนึ่งของระบบไฟส่องสว่าง ระบบอิเล็กทรอนิกส์ใน PIR มักจะควบคุมรีเลย์ในตัวที่สามารถสลับแรงดันไฟฟ้าหลักได้ ซึ่งหมายความว่า PIR สามารถตั้งค่าให้เปิดไฟที่เชื่อมต่อกับ PIR เมื่อตรวจพบการเคลื่อนไหวได้ วิธีนี้มักใช้ในสถานการณ์กลางแจ้ง ทั้งเพื่อป้องกันอาชญากร (ไฟรักษาความปลอดภัย) หรือเพื่อการใช้งานจริง เช่น การเปิดไฟประตูหน้าบ้านเพื่อให้คุณหากุญแจเจอในความมืด\ การใช้งานเพิ่มเติมสามารถทำได้ในห้องน้ำสาธารณะ ห้องเตรียมอาหารแบบวอล์กอิน ทางเดิน หรือบริเวณใดก็ตามที่สามารถควบคุมไฟอัตโนมัติได้ วิธีนี้ช่วยประหยัดพลังงานได้ เพราะไฟจะเปิดเฉพาะเมื่อจำเป็นเท่านั้น และผู้ใช้ไม่จำเป็นต้องปิดไฟเมื่อออกจากพื้นที่
#h(9.75em) เมื่อใช้เป็นส่วนหนึ่งของระบบไฟส่องสว่าง ระบบอิเล็กทรอนิกส์ใน PIR
มักจะควบคุมรีเลย์ในตัวที่สามารถสลับแรงดันไฟฟ้าหลักได้ ซึ่งหมายความว่า PIR
สามารถตั้งค่าให้เปิดไฟที่เชื่อมต่อกับ PIR เมื่อตรวจพบการเคลื่อนไหวได้ วิธีนี้มักใช้ในสถานการณ์กลางแจ้ง
ทั้งเพื่อป้องกันอาชญากร (ไฟรักษาความปลอดภัย) หรือเพื่อการใช้งานจริง เช่น
การเปิดไฟประตูหน้าบ้านเพื่อให้คุณหากุญแจเจอในความมืด\
การใช้งานเพิ่มเติมสามารถทำได้ในห้องน้ำสาธารณะ ห้องเตรียมอาหารแบบวอล์กอิน ทางเดิน
หรือบริเวณใดก็ตามที่สามารถควบคุมไฟอัตโนมัติได้ วิธีนี้ช่วยประหยัดพลังงานได้
เพราะไฟจะเปิดเฉพาะเมื่อจำเป็นเท่านั้น และผู้ใช้ไม่จำเป็นต้องปิดไฟเมื่อออกจากพื้นที่
== แอปพลิเคชั่นด้านความปลอดภัย
#i เมื่อใช้เป็นส่วนหนึ่งของระบบรักษาความปลอดภัย วงจรอิเล็กทรอนิกส์ใน PIR มักจะควบคุมรีเลย์ ขนาดเล็ก รีเลย์นี้จะทำหน้าที่เชื่อมต่อวงจรไฟฟ้าผ่านหน้า สัมผัสไฟฟ้าคู่หนึ่งที่เชื่อมต่อกับโซนอินพุตตรวจจับของแผงควบคุมสัญญาณกันขโมยโดยทั่วไประบบจะออกแบบให้หากไม่มีการเคลื่อนไหว หน้าสัมผัสรีเลย์จะปิดอยู่ ซึ่งเรียกว่ารีเลย์แบบ 'ปกติปิด' (NC) หากตรวจพบการเคลื่อนไหว รีเลย์จะเปิดวงจรเพื่อส่งสัญญาณเตือนภัย หรือหากสายไฟถูกตัดการเชื่อมต่อ สัญญาณเตือนภัยก็จะทำงานเช่นกัน
#h(9.75em) เมื่อใช้เป็นส่วนหนึ่งของระบบรักษาความปลอดภัย วงจรอิเล็กทรอนิกส์ใน PIR
มักจะควบคุมรีเลย์ ขนาดเล็ก รีเลย์นี้จะทำหน้าที่เชื่อมต่อวงจรไฟฟ้าผ่านหน้า
สัมผัสไฟฟ้าคู่หนึ่งที่เชื่อมต่อกับโซนอินพุตตรวจจับของแผงควบคุมสัญญาณกันขโมยโดยทั่วไประบบจะออกแบบให้หากไม่มีการเคลื่อนไหว
หน้าสัมผัสรีเลย์จะปิดอยู่ ซึ่งเรียกว่ารีเลย์แบบ 'ปกติปิด' (NC) หากตรวจพบการเคลื่อนไหว
รีเลย์จะเปิดวงจรเพื่อส่งสัญญาณเตือนภัย หรือหากสายไฟถูกตัดการเชื่อมต่อ สัญญาณเตือนภัยก็จะทำงานเช่นกัน
== การจัดวาง
#i ผู้ผลิตแนะนำให้วางผลิตภัณฑ์อย่างระมัดระวังเพื่อป้องกันการแจ้งเตือนที่ผิดพลาด (เช่น การตรวจจับใดๆ ที่ไม่ได้เกิดจากผู้บุกรุก)
#h(9.75em) ผู้ผลิตแนะนำให้วางผลิตภัณฑ์อย่างระมัดระวังเพื่อป้องกันการแจ้งเตือนที่ผิดพลาด (เช่น
การตรวจจับใดๆ ที่ไม่ได้เกิดจากผู้บุกรุก)
#i พวกเขาแนะนำให้ติดตั้ง PIR ในลักษณะที่ PIR ไม่สามารถ "มองเห็น" ออกจากหน้าต่างได้ แม้ว่าความยาวคลื่นของรังสีอินฟราเรดที่ชิปมีความไวต่อแสงจะทะลุผ่านกระจกได้ไม่ดีนัก แต่แหล่งกำเนิดแสงอินฟราเรดที่แรง (เช่น จากไฟหน้ารถยนต์หรือแสงแดด) อาจทำให้เซ็นเซอร์รับภาพเกินพิกัดและทำให้เกิดสัญญาณเตือนภัยผิดพลาดได้ บุคคลที่เคลื่อนไหวอยู่อีกฝั่งของกระจกจะไม่ถูก PID "มองเห็น" ซึ่งอาจเป็นผลดีสำหรับหน้าต่างที่หันหน้าไปทางทางเท้าสาธารณะ หรือเป็นผลเสียสำหรับหน้าต่างในฉากกั้นภายใน
#i พวกเขาแนะนำให้ติดตั้ง PIR ในลักษณะที่ PIR ไม่สามารถ "มองเห็น" ออกจากหน้าต่างได้
แม้ว่าความยาวคลื่นของรังสีอินฟราเรดที่ชิปมีความไวต่อแสงจะทะลุผ่านกระจกได้ไม่ดีนัก
แต่แหล่งกำเนิดแสงอินฟราเรดที่แรง (เช่น จากไฟหน้ารถยนต์หรือแสงแดด)
อาจทำให้เซ็นเซอร์รับภาพเกินพิกัดและทำให้เกิดสัญญาณเตือนภัยผิดพลาดได้
บุคคลที่เคลื่อนไหวอยู่อีกฝั่งของกระจกจะไม่ถูก PID "มองเห็น"
ซึ่งอาจเป็นผลดีสำหรับหน้าต่างที่หันหน้าไปทางทางเท้าสาธารณะ
หรือเป็นผลเสียสำหรับหน้าต่างในฉากกั้นภายใน
#i ขอแนะนำว่าไม่ควรติดตั้ง PIR ในตำแหน่งที่ ช่องระบายอากาศ HVAC จะเป่าลมร้อนหรือเย็นลงบนพื้นผิวพลาสติกที่ปิดหน้าต่างของตัวบ้าน แม้ว่าอากาศจะมีค่าการแผ่รังสี ต่ำมาก (ปล่อยพลังงานอินฟราเรดในปริมาณน้อยมาก) แต่ลมที่พัดผ่านฝาครอบหน้าต่างพลาสติกอาจทำให้อุณหภูมิของพลาสติกเปลี่ยนแปลงจนทำให้เกิดสัญญาณเตือนที่ผิดพลาดได้
#i ขอแนะนำว่าไม่ควรติดตั้ง PIR ในตำแหน่งที่ ช่องระบายอากาศ HVAC
จะเป่าลมร้อนหรือเย็นลงบนพื้นผิวพลาสติกที่ปิดหน้าต่างของตัวบ้าน แม้ว่าอากาศจะมีค่าการแผ่รังสี ต่ำมาก
(ปล่อยพลังงานอินฟราเรดในปริมาณน้อยมาก)
แต่ลมที่พัดผ่านฝาครอบหน้าต่างพลาสติกอาจทำให้อุณหภูมิของพลาสติกเปลี่ยนแปลงจนทำให้เกิดสัญญาณเตือนที่ผิดพลาดได้
#i เซ็นเซอร์มักได้รับการออกแบบมาให้ "เพิกเฉย" สัตว์เลี้ยงในบ้าน เช่น สุนัขหรือแมว โดยการตั้งค่าความไวให้สูงขึ้น หรือทำให้แน่ใจว่าพื้นห้องจะไม่อยู่ในโฟกัส
#i เซ็นเซอร์มักได้รับการออกแบบมาให้ "เพิกเฉย" สัตว์เลี้ยงในบ้าน เช่น สุนัขหรือแมว
โดยการตั้งค่าความไวให้สูงขึ้น หรือทำให้แน่ใจว่าพื้นห้องจะไม่อยู่ในโฟกัส
#i เนื่องจากเซ็นเซอร์ PIR มีระยะการทำงานสูงสุด 10 เมตร (30 ฟุต) ดังนั้นการติดตั้งเครื่องตรวจจับเพียงตัวเดียวใกล้ทางเข้าจึงเพียงพอสำหรับห้องที่มีทางเข้าเพียงทางเดียว ระบบรักษาความปลอดภัยที่ใช้ PIR ยังใช้งานได้ดีกับระบบรักษาความปลอดภัยภายนอกอาคารและระบบไฟที่ไวต่อการเคลื่อนไหว ข้อดีอย่างหนึ่งคือใช้พลังงานต่ำ ซึ่งทำให้สามารถใช้พลังงานแสงอาทิตย์ได้
#i เนื่องจากเซ็นเซอร์ PIR มีระยะการทำงานสูงสุด 10 เมตร (30 ฟุต)
ดังนั้นการติดตั้งเครื่องตรวจจับเพียงตัวเดียวใกล้ทางเข้าจึงเพียงพอสำหรับห้องที่มีทางเข้าเพียงทางเดียว
ระบบรักษาความปลอดภัยที่ใช้ PIR
ยังใช้งานได้ดีกับระบบรักษาความปลอดภัยภายนอกอาคารและระบบไฟที่ไวต่อการเคลื่อนไหว
ข้อดีอย่างหนึ่งคือใช้พลังงานต่ำ ซึ่งทำให้สามารถใช้พลังงานแสงอาทิตย์ได้
== เทอร์โมมิเตอร์แบบควบคุมระยะไกลด้วย PIR
#i มีการออกแบบวงจร PIR ที่ใช้วัดอุณหภูมิของวัตถุที่อยู่ห่างไกลในวงจรดังกล่าว จะใช้เอาต์พุต PIR แบบไม่มีค่าความแตกต่าง สัญญาณเอาต์พุตจะถูกประเมินตามการสอบเทียบสเปกตรัม IR ของสสารชนิดเฉพาะที่ต้องการตรวจวัด ด้วยวิธีนี้ การวัดอุณหภูมิจากระยะไกลจึงค่อนข้างแม่นยำและแม่นยำ หากไม่มีการสอบเทียบกับชนิดของวัสดุที่ตรวจวัด อุปกรณ์เทอร์โมมิเตอร์ PIR จะสามารถวัดการเปลี่ยนแปลงของการแผ่รังสี IR ซึ่งสอดคล้องกับการเปลี่ยนแปลงของอุณหภูมิโดยตรง แต่ไม่สามารถคำนวณค่าอุณหภูมิที่แท้จริงได้
#h(9.75em) มีการออกแบบวงจร PIR ที่ใช้วัดอุณหภูมิของวัตถุที่อยู่ห่างไกลในวงจรดังกล่าว จะใช้เอาต์พุต
PIR แบบไม่มีค่าความแตกต่าง สัญญาณเอาต์พุตจะถูกประเมินตามการสอบเทียบสเปกตรัม IR
ของสสารชนิดเฉพาะที่ต้องการตรวจวัด ด้วยวิธีนี้ การวัดอุณหภูมิจากระยะไกลจึงค่อนข้างแม่นยำและแม่นยำ
หากไม่มีการสอบเทียบกับชนิดของวัสดุที่ตรวจวัด อุปกรณ์เทอร์โมมิเตอร์ PIR
จะสามารถวัดการเปลี่ยนแปลงของการแผ่รังสี IR ซึ่งสอดคล้องกับการเปลี่ยนแปลงของอุณหภูมิโดยตรง
แต่ไม่สามารถคำนวณค่าอุณหภูมิที่แท้จริงได้
+76 -26
View File
@@ -2,15 +2,29 @@
== X.509 (รูปแบบใบรับรอง TLS/SSL) <x509>
#i ในการเข้ารหัส X.509 เป็นมาตรฐานของสหภาพโทรคมนาคมระหว่างประเทศ (ITU) ที่กำหนดรูปแบบของใบรับรองคีย์สาธารณะใบรับรอง X.509 ถูกใช้ในโปรโตคอลอินเทอร์เน็ตมากมายรวมถึง TLS/SSL ซึ่งเป็นพื้นฐานของ HTTPS โปรโตคอลที่ปลอดภัยสำหรับการท่องเว็บ นอกจากนี้ยังใช้ในแอปพลิเคชันออฟไลน์เช่น ลาย เซ็นอิเล็กทรอนิกส์
ใบรับรอง X.509 เชื่อมโยงข้อมูลประจำตัวกับคีย์สาธารณะโดยใช้ลายเซ็นดิจิทัล ใบรับรองประกอบด้วยข้อมูลประจำตัว (ชื่อโฮสต์องค์กร หรือบุคคล) และคีย์สาธารณะ (RSA, DSA, ECDSA, ed25519 เป็นต้น) ซึ่งลงนามโดยผู้ออกใบรับรองหรือลงนามด้วยตนเอง เมื่อใบรับรองได้รับการลงนามโดยผู้ออกใบรับรองที่เชื่อถือได้หรือผ่านการตรวจสอบความถูกต้องด้วยวิธีอื่น ผู้ถือใบรับรองนั้นสามารถใช้คีย์สาธารณะที่มีอยู่เพื่อสร้างการสื่อสารที่ปลอดภัยกับบุคคลอื่น หรือตรวจสอบความถูกต้องของเอกสารที่ลงนามดิจิทัลด้วย คีย์ส่วนตัวที่เกี่ยวข้องได้
#i ในการเข้ารหัส X.509 เป็นมาตรฐานของสหภาพโทรคมนาคมระหว่างประเทศ (ITU)
ที่กำหนดรูปแบบของใบรับรองคีย์สาธารณะใบรับรอง X.509 ถูกใช้ในโปรโตคอลอินเทอร์เน็ตมากมายรวมถึง
TLS/SSL ซึ่งเป็นพื้นฐานของ HTTPS โปรโตคอลที่ปลอดภัยสำหรับการท่องเว็บ
นอกจากนี้ยังใช้ในแอปพลิเคชันออฟไลน์เช่น ลาย เซ็นอิเล็กทรอนิกส์ ใบรับรอง X.509
เชื่อมโยงข้อมูลประจำตัวกับคีย์สาธารณะโดยใช้ลายเซ็นดิจิทัล ใบรับรองประกอบด้วยข้อมูลประจำตัว
(ชื่อโฮสต์องค์กร หรือบุคคล) และคีย์สาธารณะ (RSA, DSA, ECDSA, ed25519 เป็นต้น)
ซึ่งลงนามโดยผู้ออกใบรับรองหรือลงนามด้วยตนเอง
เมื่อใบรับรองได้รับการลงนามโดยผู้ออกใบรับรองที่เชื่อถือได้หรือผ่านการตรวจสอบความถูกต้องด้วยวิธีอื่น
ผู้ถือใบรับรองนั้นสามารถใช้คีย์สาธารณะที่มีอยู่เพื่อสร้างการสื่อสารที่ปลอดภัยกับบุคคลอื่น
หรือตรวจสอบความถูกต้องของเอกสารที่ลงนามดิจิทัลด้วย คีย์ส่วนตัวที่เกี่ยวข้องได้
#i X.509 ยังกำหนดรายการเพิกถอนใบรับรองซึ่งเป็นวิธีการแจกจ่ายข้อมูลเกี่ยวกับใบรับรองที่ถือว่าไม่ถูกต้องโดยผู้มีอำนาจลงนาม ตลอดจนอัลกอริทึมการตรวจสอบเส้นทางการรับรองซึ่งช่วยให้ใบรับรองได้รับการลงนามโดยใบรับรอง CA ตัวกลาง ซึ่งใบรับรองเหล่านี้จะได้รับการลงนามโดยใบรับรองอื่นๆ ต่อไปจนไปถึงจุดยึดที่เชื่อถือได้ในที่สุด
#i X.509
ยังกำหนดรายการเพิกถอนใบรับรองซึ่งเป็นวิธีการแจกจ่ายข้อมูลเกี่ยวกับใบรับรองที่ถือว่าไม่ถูกต้องโดยผู้มีอำนาจลงนาม
ตลอดจนอัลกอริทึมการตรวจสอบเส้นทางการรับรองซึ่งช่วยให้ใบรับรองได้รับการลงนามโดยใบรับรอง CA
ตัวกลาง ซึ่งใบรับรองเหล่านี้จะได้รับการลงนามโดยใบรับรองอื่นๆ ต่อไปจนไปถึงจุดยึดที่เชื่อถือได้ในที่สุด
#i X.509 ถูกกำหนดโดย "Standardization Sector" ของ ITU (SG17 ของ ITU-T) ใน ITU-T Study Group 17 และมีพื้นฐานมาจาก Abstract Syntax Notation One (ASN.1) ซึ่งเป็นมาตรฐานอีกประการหนึ่งของ ITU-T
#i X.509 ถูกกำหนดโดย "Standardization Sector" ของ ITU (SG17 ของ ITU-T) ใน ITU-T
Study Group 17 และมีพื้นฐานมาจาก Abstract Syntax Notation One (ASN.1)
ซึ่งเป็นมาตรฐานอีกประการหนึ่งของ ITU-T
=== โครงสร้างของใบรับรอง
#i โครงสร้างที่กำหนดไว้โดยมาตรฐานจะแสดงอยู่ในภาษาทางการที่เรียกว่า Abstract Syntax Notation One (ASN.1)
#i โครงสร้างที่กำหนดไว้โดยมาตรฐานจะแสดงอยู่ในภาษาทางการที่เรียกว่า Abstract Syntax
Notation One (ASN.1)
โครงสร้างของใบรับรองดิจิทัล X.509 v3 มีดังนี้:
@@ -25,39 +39,75 @@
- ชื่อเรื่อง
- ข้อมูลคีย์สาธารณะของเรื่อง
- อัลกอริทึมคีย์สาธารณะ
- คีย์สาธารณะของเรื่อง
รหัสประจำตัวผู้ออก (ทางเลือก)
รหัสประจำตัวเฉพาะเรื่อง (ทางเลือก)
- คีย์สาธารณะของเรื่อง รหัสประจำตัวผู้ออก (ทางเลือก) รหัสประจำตัวเฉพาะเรื่อง (ทางเลือก)
ส่วนขยาย (ทางเลือก)
- อัลกอริทึมลายเซ็นใบรับรอง
- ลายเซ็นใบรับรอง
#i ฟิลด์ส่วนขยาย (ถ้ามี) จะเป็นลำดับของส่วนขยายใบรับรองอย่างน้อยหนึ่งรายการ แต่ละส่วนขยายมีรหัสประจำตัวเฉพาะของตัวเอง ซึ่งแสดงเป็นตัวระบุวัตถุ (OID) ซึ่งเป็นชุดค่าพร้อมกับข้อบ่งชี้ที่สำคัญหรือไม่สำคัญ ระบบที่ใช้ใบรับรองต้องปฏิเสธใบรับรองหากพบส่วนขยายที่สำคัญที่ไม่รู้จักหรือส่วนขยายที่สำคัญซึ่งมีข้อมูลที่ไม่สามารถประมวลผลได้ ส่วนขยายที่ไม่สำคัญอาจถูกละเว้นหากไม่รู้จัก แต่จะต้องได้รับการประมวลผลหากรู้จักส่วนขยายใบรับรอง
#i ฟิลด์ส่วนขยาย (ถ้ามี) จะเป็นลำดับของส่วนขยายใบรับรองอย่างน้อยหนึ่งรายการ
แต่ละส่วนขยายมีรหัสประจำตัวเฉพาะของตัวเอง ซึ่งแสดงเป็นตัวระบุวัตถุ (OID)
ซึ่งเป็นชุดค่าพร้อมกับข้อบ่งชี้ที่สำคัญหรือไม่สำคัญ
ระบบที่ใช้ใบรับรองต้องปฏิเสธใบรับรองหากพบส่วนขยายที่สำคัญที่ไม่รู้จักหรือส่วนขยายที่สำคัญซึ่งมีข้อมูลที่ไม่สามารถประมวลผลได้
ส่วนขยายที่ไม่สำคัญอาจถูกละเว้นหากไม่รู้จัก แต่จะต้องได้รับการประมวลผลหากรู้จักส่วนขยายใบรับรอง
#i โครงสร้างของเวอร์ชัน 1 มีอยู่ ใน RFC 1422
#i รูปแบบภายในของตัวระบุเฉพาะของผู้เผยแพร่และเรื่องที่ระบุไว้ใน X.520 ไดเร็กทอรี:คำแนะนำ ประเภทแอตทริบิวต์ที่เลือก
#i รูปแบบภายในของตัวระบุเฉพาะของผู้เผยแพร่และเรื่องที่ระบุไว้ใน X.520 ไดเร็กทอรี:คำแนะนำ
ประเภทแอตทริบิวต์ที่เลือก
#i ITU-T ได้นำตัวระบุเฉพาะของผู้ออกหลักทรัพย์และบุคคลมาใช้ในเวอร์ชัน 2 เพื่ออนุญาตให้นำชื่อผู้ออกหลักทรัพย์หรือบุคคลมาใช้ซ้ำได้หลังจากระยะเวลาหนึ่ง ตัวอย่างหนึ่งของการนำกลับมาใช้ซ้ำคือเมื่อ CA ล้มละลายและชื่อถูกลบออกจากรายชื่อสาธารณะของประเทศ หลังจากนั้น CA อื่นที่มีชื่อเดียวกันอาจลงทะเบียนตัวเองได้ แม้ว่าจะไม่เกี่ยวข้องกับ CA แรกก็ตาม อย่างไรก็ตาม IETF แนะนำว่าไม่ควรนำชื่อผู้ออกหลักทรัพย์และบุคคลมาใช้ซ้ำ ดังนั้นเวอร์ชัน 2 จึงยังไม่แพร่หลายในอินเทอร์เน็ต
#i ITU-T ได้นำตัวระบุเฉพาะของผู้ออกหลักทรัพย์และบุคคลมาใช้ในเวอร์ชัน 2
เพื่ออนุญาตให้นำชื่อผู้ออกหลักทรัพย์หรือบุคคลมาใช้ซ้ำได้หลังจากระยะเวลาหนึ่ง
ตัวอย่างหนึ่งของการนำกลับมาใช้ซ้ำคือเมื่อ CA ล้มละลายและชื่อถูกลบออกจากรายชื่อสาธารณะของประเทศ
หลังจากนั้น CA อื่นที่มีชื่อเดียวกันอาจลงทะเบียนตัวเองได้ แม้ว่าจะไม่เกี่ยวข้องกับ CA แรกก็ตาม
อย่างไรก็ตาม IETF แนะนำว่าไม่ควรนำชื่อผู้ออกหลักทรัพย์และบุคคลมาใช้ซ้ำ ดังนั้นเวอร์ชัน 2
จึงยังไม่แพร่หลายในอินเทอร์เน็ต
#i ส่วนขยายได้รับการแนะนำในเวอร์ชัน 3 CA สามารถใช้ส่วนขยายเพื่อออกใบรับรองได้เฉพาะสำหรับจุดประสงค์เฉพาะ (เช่น สำหรับการลงนามในวัตถุดิจิทัล เท่านั้น)
#i ส่วนขยายได้รับการแนะนำในเวอร์ชัน 3 CA
สามารถใช้ส่วนขยายเพื่อออกใบรับรองได้เฉพาะสำหรับจุดประสงค์เฉพาะ (เช่น
สำหรับการลงนามในวัตถุดิจิทัล เท่านั้น)
#i ในทุกเวอร์ชันหมายเลขซีเรียลจะต้องไม่ซ้ำกันสำหรับใบรับรองแต่ละใบที่ออกโดย CA เฉพาะ (ดังที่กล่าวถึงใน RFC 5280)
#i ในทุกเวอร์ชันหมายเลขซีเรียลจะต้องไม่ซ้ำกันสำหรับใบรับรองแต่ละใบที่ออกโดย CA เฉพาะ
(ดังที่กล่าวถึงใน RFC 5280)
=== นามสกุลไฟล์ใบรับรอง
#i นามสกุลไฟล์ที่ใช้กันทั่วไปสำหรับใบรับรอง X.509 มีหลายประเภทนามสกุลไฟล์เหล่านี้ยังใช้สำหรับข้อมูลอื่นๆ เช่น คีย์ส่วนตัวด้วย
#iiii นามสกุลไฟล์ที่ใช้กันทั่วไปสำหรับใบรับรอง X.509
มีหลายประเภทนามสกุลไฟล์เหล่านี้ยังใช้สำหรับข้อมูลอื่นๆ เช่น คีย์ส่วนตัวด้วย
- `.pem` -- (อีเมลอิเล็กทรอนิกส์ที่เพิ่มความเป็นส่วนตัว) ใบรับรอง DER ที่เข้ารหัส Base64 แนบระหว่าง `-----BEGIN CERTIFICATE-----` และ `-----END CERTIFICATE-----`
- `.cer`, `.crt`, `.der` -- โดยปกติจะอยู่ในรูปแบบไบนารี DER แต่ใบรับรองที่เข้ารหัส Base64 ก็เป็นเรื่องปกติเช่นกัน (ดู `.pem` ด้านบน)
- `.p8`, `.p8e`, `.pk8` -- คีย์ส่วนตัวที่ส่งออกตามที่ระบุไว้ใน PKCS\#8 อาจอยู่ในรูปแบบ DER หรือ PEM ที่ขึ้นต้นด้วย `-----BEGIN PRIVATE KEY-----` คีย์ที่เข้ารหัสจะขึ้นต้นด้วย `-----BEGIN ENCRYPTED PRIVATE KEY-----` และอาจมี `.p8e` เป็นนามสกุลไฟล์
- `.p10`, `.csr` -- PKCS\#10 เป็นคำขอลงนามใบรับรอง (CSR) ในรูปแบบ PEM ขึ้นต้นด้วย `-----BEGIN CERTIFICATE REQUEST-----` แบบฟอร์มเหล่านี้สร้างขึ้นเพื่อส่งไปยังผู้ออกใบรับรอง (CA) แบบฟอร์มประกอบด้วยรายละเอียดสำคัญของใบรับรองที่ร้องขอ เช่น ชื่อสามัญ (/CN), หัวเรื่อง, องค์กร, รัฐ, ประเทศ รวมถึงคีย์สาธารณะของใบรับรองที่ต้องการให้ลงนาม คีย์เหล่านี้จะได้รับการลงนามโดย CA และใบรับรองจะถูกส่งกลับคืน ใบรับรองที่ส่งคืนคือใบรับรอง สาธารณะ (ซึ่งมีคีย์สาธารณะแต่ไม่มีคีย์ส่วนตัว) ซึ่งตัวใบรับรองเองสามารถอยู่ในรูปแบบต่างๆ ได้หลายรูปแบบ แต่โดยปกติจะเป็น `.p7r`
- `.p7r` -- คำตอบ ของ PKCS\#7 ต่อ CSR ประกอบด้วยใบรับรองที่เพิ่งลงนาม และใบรับรองของ CA เอง
- `.p7s` -- ลายเซ็นดิจิทัล PKCS\#7 อาจมีไฟล์หรือข้อความที่ลงนามต้นฉบับ ใช้ใน S/MIME สำหรับการลงนามในอีเมลกำหนดไว้ใน RFC 2311
- `.p7m` -- PKCS\#7 (SignedData, EnvelopedData) ข้อความ เช่น ไฟล์ที่เข้ารหัส ("enveloped") ข้อความ หรือจดหมายอีเมล MIME กำหนดไว้ใน RFC 2311
- `.p7c` -- โครงสร้าง SignedData แบบ "certs-only" ของ PKCS\#7 ที่เสื่อมลง โดยไม่มีข้อมูลใดๆ ให้ลงนาม กำหนดไว้ใน RFC 2311
- `.p7b` -- โครงสร้าง SignedData ของ PKCS\#7 ที่ไม่มีข้อมูล มีเพียงใบรับรองแบบบันเดิลหรือ CRL (ไม่ค่อยเกิดขึ้น) แต่ไม่มีคีย์ส่วนตัว ใช้รูปแบบ DER หรือ BER หรือ PEM ที่ขึ้นต้นด้วย `-----BEGIN PKCS7-----` รูปแบบที่ Windows ใช้สำหรับการแลกเปลี่ยนใบรับรอง รองรับโดย Java แต่มักใช้นามสกุล `.keystore` แทน ซึ่งแตกต่างจากใบรับรองแบบ `.pem` รูปแบบนี้มีวิธีที่กำหนดไว้สำหรับการรวมใบรับรองเส้นทางการรับรอง
- `.p12`, `.pfx`, `.pkcs12` -- PKCS\#12 อาจมีใบรับรอง (สาธารณะ) และคีย์ส่วนตัว (ป้องกันด้วยรหัสผ่าน) ในไฟล์เดียว `.pfx` - _Personal Information eXchange_ PFX ซึ่งเป็นรุ่นก่อนของ PKCS\#12 (โดยปกติจะมีข้อมูลในรูปแบบ PKCS\#12 เช่น ไฟล์ PFX ที่สร้างใน IIS)
- `.crl` -- รายการเพิกถอนใบรับรอง (CRL) หน่วยงานที่ออกใบรับรองจะจัดทำรายการเหล่านี้ขึ้นเพื่อใช้ในการเพิกถอนใบรับรองก่อนหมดอายุ
- `.pem` -- (อีเมลอิเล็กทรอนิกส์ที่เพิ่มความเป็นส่วนตัว) ใบรับรอง DER ที่เข้ารหัส Base64
แนบระหว่าง `-----BEGIN CERTIFICATE-----` และ `-----END CERTIFICATE-----`
- `.cer`, `.crt`, `.der` -- โดยปกติจะอยู่ในรูปแบบไบนารี DER แต่ใบรับรองที่เข้ารหัส Base64
ก็เป็นเรื่องปกติเช่นกัน (ดู `.pem` ด้านบน)
- `.p8`, `.p8e`, `.pk8` -- คีย์ส่วนตัวที่ส่งออกตามที่ระบุไว้ใน PKCS\#8 อาจอยู่ในรูปแบบ DER หรือ
PEM ที่ขึ้นต้นด้วย `-----BEGIN PRIVATE KEY-----` คีย์ที่เข้ารหัสจะขึ้นต้นด้วย
`-----BEGIN ENCRYPTED PRIVATE KEY-----` และอาจมี `.p8e` เป็นนามสกุลไฟล์
- `.p10`, `.csr` -- PKCS\#10 เป็นคำขอลงนามใบรับรอง (CSR) ในรูปแบบ PEM ขึ้นต้นด้วย
`-----BEGIN CERTIFICATE REQUEST-----` แบบฟอร์มเหล่านี้สร้างขึ้นเพื่อส่งไปยังผู้ออกใบรับรอง
(CA) แบบฟอร์มประกอบด้วยรายละเอียดสำคัญของใบรับรองที่ร้องขอ เช่น ชื่อสามัญ (/CN), หัวเรื่อง,
องค์กร, รัฐ, ประเทศ รวมถึงคีย์สาธารณะของใบรับรองที่ต้องการให้ลงนาม
คีย์เหล่านี้จะได้รับการลงนามโดย CA และใบรับรองจะถูกส่งกลับคืน ใบรับรองที่ส่งคืนคือใบรับรอง
สาธารณะ (ซึ่งมีคีย์สาธารณะแต่ไม่มีคีย์ส่วนตัว) ซึ่งตัวใบรับรองเองสามารถอยู่ในรูปแบบต่างๆ
ได้หลายรูปแบบ แต่โดยปกติจะเป็น `.p7r`
- `.p7r` -- คำตอบ ของ PKCS\#7 ต่อ CSR ประกอบด้วยใบรับรองที่เพิ่งลงนาม และใบรับรองของ CA
เอง
- `.p7s` -- ลายเซ็นดิจิทัล PKCS\#7 อาจมีไฟล์หรือข้อความที่ลงนามต้นฉบับ ใช้ใน S/MIME
สำหรับการลงนามในอีเมลกำหนดไว้ใน RFC 2311
- `.p7m` -- PKCS\#7 (SignedData, EnvelopedData) ข้อความ เช่น ไฟล์ที่เข้ารหัส
("enveloped") ข้อความ หรือจดหมายอีเมล MIME กำหนดไว้ใน RFC 2311
- `.p7c` -- โครงสร้าง SignedData แบบ "certs-only" ของ PKCS\#7 ที่เสื่อมลง
โดยไม่มีข้อมูลใดๆ ให้ลงนาม กำหนดไว้ใน RFC 2311
- `.p7b` -- โครงสร้าง SignedData ของ PKCS\#7 ที่ไม่มีข้อมูล มีเพียงใบรับรองแบบบันเดิลหรือ CRL
(ไม่ค่อยเกิดขึ้น) แต่ไม่มีคีย์ส่วนตัว ใช้รูปแบบ DER หรือ BER หรือ PEM ที่ขึ้นต้นด้วย
`-----BEGIN PKCS7-----` รูปแบบที่ Windows ใช้สำหรับการแลกเปลี่ยนใบรับรอง รองรับโดย Java
แต่มักใช้นามสกุล `.keystore` แทน ซึ่งแตกต่างจากใบรับรองแบบ `.pem`
รูปแบบนี้มีวิธีที่กำหนดไว้สำหรับการรวมใบรับรองเส้นทางการรับรอง
- `.p12`, `.pfx`, `.pkcs12` -- PKCS\#12 อาจมีใบรับรอง (สาธารณะ) และคีย์ส่วนตัว
(ป้องกันด้วยรหัสผ่าน) ในไฟล์เดียว `.pfx` - _Personal Information eXchange_ PFX
ซึ่งเป็นรุ่นก่อนของ PKCS\#12 (โดยปกติจะมีข้อมูลในรูปแบบ PKCS\#12 เช่น ไฟล์ PFX ที่สร้างใน IIS)
- `.crl` -- รายการเพิกถอนใบรับรอง (CRL)
หน่วยงานที่ออกใบรับรองจะจัดทำรายการเหล่านี้ขึ้นเพื่อใช้ในการเพิกถอนใบรับรองก่อนหมดอายุ
#i PKCS\#7 เป็นมาตรฐานสำหรับการลงนามหรือเข้ารหัสข้อมูล (เรียกอย่างเป็นทางการว่า "enveloping") เนื่องจากจำเป็นต้องใช้ใบรับรองเพื่อตรวจสอบข้อมูลที่ลงนามแล้วจึงสามารถรวมใบรับรองไว้ในโครงสร้าง SignedData ได้
#iiii PKCS\#7 เป็นมาตรฐานสำหรับการลงนามหรือเข้ารหัสข้อมูล (เรียกอย่างเป็นทางการว่า
"enveloping")
เนื่องจากจำเป็นต้องใช้ใบรับรองเพื่อตรวจสอบข้อมูลที่ลงนามแล้วจึงสามารถรวมใบรับรองไว้ในโครงสร้าง
SignedData ได้
+70 -44
View File
@@ -117,6 +117,8 @@
[นำเสนอโครงงาน], [], [], [], [], [], [], [], [], [], [], [],
)
#show: page-theme
=== ผังการดำเนินงาน
#diagram(
@@ -233,35 +235,58 @@
== ขั้นตอนการประกอบ
โครงงานแบ่งออกเป็น 3 โมดูล
+ โมดูลเซนเซอร์ NFC ขาเข้าและบอร์ด ESP32
+ โมดูลเซนเซอร์ NFC ขาออก
+ โมดูลเซนเซอร์ PIR
#show heading: it => {
if it.level > 2 {
block(
it,
inset: (left: -3em),
)
} else {
it
}
}
=== โมดูลเซนเซอร์ NFC ขาออก
#i ดำเนินการเจาะรูบริเวณตัวกล่องเพื่อใช้เป็นช่องสำหรับสายไฟ
จากนั้นนำสายไฟร้อยผ่านช่องดังกล่าวและต่อเข้ากับเซนเซอร์ NFC ให้เรียบร้อยตามขั้นตอน
=== การติดตั้งอุปกรณ์
=== การเขียนเฟิร์มแวร์
โครงงานนี้ใช้ซอฟต์แวร์ PlatformIO ในการสร้างและจัดการโปรเจกต์เฟิร์มแวร์
#i โครงงานนี้ใช้ซอฟต์แวร์ PlatformIO ในการสร้างและจัดการโปรเจกต์เฟิร์มแวร์
โดยหากต้องการเพียงแค่เขียนเฟิร์มแวร์ลงไปยังบอร์ด ESP32 คุณจำเป็นต้องใช้ซอฟต์แวร์หลัก คือ
PlatformIO Core และ Git (ไม่จำเป็น แต่เพื่อความสะดวกสบาย)
PlatformIO Core และ Git (ไม่จำเป็น แต่เพื่อความสะดวกสบาย) อย่างไรก็ตาม PlatformIO
จำเป็นต้องใช้ Python เวอร์ชัน 3.6 ขึ้นไปด้วยเช่นกัน ดังนั้นคุณจำเป็นต้องติดตั้ง Python
ด้วยหากคุณยังไม่มี
อย่างไรก็ตาม PlatformIO จำเป็นต้องใช้ Python เวอร์ชัน 3.6 ขึ้นไปด้วยเช่นกัน
ดังนั้นคุณจำเป็นต้องติดตั้ง Python ด้วยหากคุณยังไม่มี
#i ในขั้นตอนแรก โปรดเปิดเทอร์มินัลของคุณ ซึ่งโดยทั่วไปแล้วคุณสามารถค้นหาแอพลิเคชัน#jb "Terminal"
ได้เลย โดยบน Windows 10 เวอร์ชั่นใหม่ และ Windows 11 จะมาพร้อมกับแอพลิเคชัน Windows
Terminal อย่างไรก็ตาม เมื่อเปิดแล้ว โปรดตรวจสอบให้แน่ใจว่าคุณกำลังใช้ PowerShell และไม่ใช่
Command Prompt
ในขั้นตอนแรก โปรดเปิดเทอร์มินัลของคุณ ซึ่งโดยทั่วไปแล้วคุณสามารถค้นหาแอพลิเคชัน "Terminal" ได้เลย
โดยบน Windows 10 เวอร์ชั่นใหม่ และ Windows 11 จะมาพร้อมกับแอพลิเคชัน Windows Terminal
อย่างไรก็ตาม เมื่อเปิดแล้ว โปรดตรวจสอบให้แน่ใจว่าคุณกำลังใช้ PowerShell และไม่ใช่ Command
Prompt
โดยในปัจจุบัน Python เวอร์ชันล่าสุดคือ Python 3.14.2 โดยคุณสามารถติดตั้ง Python และ Git บน
Windows ได้ด้วยการใช้คำสั่งต่อไปนี้
#i โดยในปัจจุบัน Python เวอร์ชันล่าสุดคือ Python 3.14.2 โดยคุณสามารถติดตั้ง Python และ Git
บน Windows ได้ด้วยการใช้คำสั่งต่อไปนี้
```sh
winget install Python.Python.3.14 Git.Git -e -s winget
```
สำหรับระบบปฏิบัติการอื่นนั้น โดยปกติแล้วจะไม่ต้องติดตั้ง Python
#i สำหรับระบบปฏิบัติการอื่นนั้น โดยปกติแล้วจะไม่ต้องติดตั้ง Python
เพิ่มเนื่องจากมีติดมากับระบบปฏิบัติการอยู่แล้ว อย่างไรก็ตาม บน Linux อาจต้องมีการติดตั้งการรองรับ
Virtual Environment แยก โดยแต่ละระบบจะมีชื่อแพคเกจไม่เหมือนกัน โดยบน Debian, Fedora,
และ Arch สามารถใช้คำสั่งต่อไปนี้ในการติดตั้งทั้ง Python Virtual Environment และ Git
พร้อมกันได้
#pagebreak()
```sh
# Debian
sudo apt install python3-venv git
@@ -271,13 +296,11 @@ sudo dnf install python3-virtualenv git
sudo pacman -S python-virtualenv git
```
#pagebreak()
#show raw.where(block: true): set block(below: 2em)
==== การติดตั้ง PlatformIO Core ผ่านแพคเกจ
หากคุณใช้ Fedora Linux หรือ Arch Linux (หรือลูก ของมัน) คุณสามารถติดตั้งแพคเกจ
#i หากคุณใช้ Fedora Linux หรือ Arch Linux (หรือลูก ของมัน) คุณสามารถติดตั้งแพคเกจ
PlatformIO ได้โดยตรง โดยมีคำสั่งดังนี้:
```sh
@@ -287,18 +310,16 @@ sudo dnf install platformio
sudo pacman -S platformio-core
```
หากคุณติดตั้งแพคเกจ Fedora นั้นแล้ว คุณไม่จำเป็นที่จะต้องติดตั้งกฎ udev ด้วยตนเอง
- หากคุณติดตั้งแพคเกจ Fedora นั้นแล้ว คุณไม่จำเป็นที่จะต้องติดตั้งกฎ udev ด้วยตนเอง
(ที่จะถูกกล่าวถึงใน@pioudev)
หากคุณใช้ Arch คุณสามารถติดตั้งแพคเกจกฎ udev ได้โดยตรงโดยไม่ต้องดาวน์โหลดเอง
```sh
sudo pacman -S --asdeps platformio-core-udev
```
- หากคุณใช้ Arch คุณสามารถติดตั้งแพคเกจกฎ udev ได้โดยตรงโดยไม่ต้องดาวน์โหลดเอง
```sh
sudo pacman -S --asdeps platformio-core-udev
```
==== การติดตั้ง PlatformIO Core ผ่านสคริปต์
ถัดไป ในการติดตั้ง PlatformIO Core สามารถทำได้โดยการใช้สคริปต์ติดตั้ง โดยสำหรับ `curl`
#i ถัดไป ในการติดตั้ง PlatformIO Core สามารถทำได้โดยการใช้สคริปต์ติดตั้ง โดยสำหรับ `curl`
สามารถใช้คำสั่งนี้ได้:
```sh
@@ -319,20 +340,22 @@ iwr -OutFile get-platformio.py -Uri https://raw.githubusercontent.com/platformio
(มีการเว้นบรรทัดใหม่เนื่องจากพื้นที่ไม่เพียงพอ โปรดอย่าเว้นบรรทัดเมื่อพิมพ์คำสั่งจริง)
แล้วดังนั้นจึงใช้คำสั่ง `python3 get-platformio.py` ในการรันสคริปต์ติดตั้งที่ได้ทำการดาวน์โหลดมา
โดยค่าเริ่มต้นแล้ว PlatformIO จะไม่เพิ่มตนเองเข้าไปยังตัวแปรสิ่งแวดล้อม PATH
#i แล้วดังนั้นจึงใช้คำสั่ง `python3 get-platformio.py`
ในการรันสคริปต์ติดตั้งที่ได้ทำการดาวน์โหลดมา โดยค่าเริ่มต้นแล้ว PlatformIO
จะไม่เพิ่มตนเองเข้าไปยังตัวแปรสิ่งแวดล้อม PATH
ซึ่งจำเป็นในการใช้คำสั่งจากที่ใหนก็ได้โดยไม่ต้องกล่าวถึงไฟล์พาธ
โดยสำหรับ Linux แล้วนั้น คุณต้องเพิ่ม `$HOME/.local/bin/` เข้าไปยัง PATH ของคุณ โดยหากคุณใช้
Bash คุณสามารถแก้ไข `~/.bash_profile` และเพิ่มบรรทัดนี้เข้าไปได้:
#pagebreak()
#i โดยสำหรับ Linux แล้วนั้น คุณต้องเพิ่ม `$HOME/.local/bin/` เข้าไปยัง PATH ของคุณ
โดยหากคุณใช้ Bash คุณสามารถแก้ไข `~/.bash_profile` และเพิ่มบรรทัดนี้เข้าไปได้:
```sh
export PATH=$PATH:$HOME/.local/bin
```
หากคุณใช้ Zsh สามารถใช้โคดเดียวกันได้ เพียงแต่คุณต้องแก้ไขไฟล์ `~/.zprofile` หรือ `~/.zshrc`
แทน
#i หากคุณใช้ Zsh สามารถใช้โคดเดียวกันได้ เพียงแต่คุณต้องแก้ไขไฟล์ `~/.zprofile` หรือ
`~/.zshrc` แทน
โดยบน Windows มีขั้นตอนดังนี้:
@@ -346,14 +369,15 @@ export PATH=$PATH:$HOME/.local/bin
==== 99-platformio-udev.rules <pioudev>
ผู้ใช้ Linux จำเป็นที่จะต้องติดตั้งกฎ udev โดยสามารถดูไฟล์กฎ udev เวอร์ชันล่าสุดได้ที่\
#i ผู้ใช้ Linux จำเป็นที่จะต้องติดตั้งกฎ udev โดยสามารถดูไฟล์กฎ udev เวอร์ชันล่าสุดได้ที่#jb
https://raw.githubusercontent.com/platformio/platformio-core/develop/platformio/assets/system/99-platformio-udev.rules
*หมายเหตุ:* โปรดตรวจสอบว่า PID และ VID ของบอร์ดคุณอยู่ในไฟล์กฎนั้น โดยคุณสามารถดู PID/VID
ของบอร์ดคุณได้ผ่านคำสั่ง `pio device list`
โดยไฟล์นั้นต้องถูกวางอยู่ที่ `/etc/udev/rules.d/99-platformio-udev.rules` (ตำแหน่งที่ดีที่สุด)
หรือ `/lib/udev/rules.d/99-platformio-udev.rules` (อาจจำเป็นสำหรับบางระบบที่พัง)
#i โดยไฟล์นั้นต้องถูกวางอยู่ที่ `/etc/udev/rules.d/99-platformio-udev.rules`
(ตำแหน่งที่ดีที่สุด) หรือ `/lib/udev/rules.d/99-platformio-udev.rules`
(อาจจำเป็นสำหรับบางระบบที่พัง)
โปรดใช้คำสั่งต่อไปนี้ในการดาวน์โหลดและวางไฟล์นั้นไว้ในสถานที่ที่ถูกต้อง:
@@ -382,28 +406,30 @@ sudo udevadm trigger
==== การดาวน์โหลดโปรเจกต์
สามารถใช้ Git ในการ clone โปรเจกต์ได้ด้วยคำสั่งต่อไปนี้:
#i สามารถใช้ Git ในการ clone โปรเจกต์ได้ด้วยคำสั่งต่อไปนี้:
```sh
git clone https://gitskette.dailitation.xyz/linesofcodes/liteauth-firmware32.git
```
โดย Git นั้นจะทำการโคลนโปรเจกต์ไปที่โฟลเดอร์ `liteauth-firmware32` เนื่องจากเป็นชื่อของ Git
repository
หรือไปที่ https://gitskette.dailitation.xyz/linesofcodes/liteauth-firmware32
และทำการคลิกปุ่ม *Code* แล้วกด *Download ZIP* หรือ *Download TAR.GZ*
แล้วทำการแตกไฟล์ได้ตามปกติ
#i โดย Git นั้นจะทำการโคลนโปรเจกต์ไปที่โฟลเดอร์ `liteauth-firmware32` เนื่องจากเป็นชื่อของ
Git repository หรือหากไม่ต้องการใช้ Git กรุณาไปที่
https://gitskette.dailitation.xyz/linesofcodes/liteauth-firmware32 และทำการคลิกปุ่ม
*Code* แล้วกด *Download ZIP* หรือ *Download TAR.GZ* แล้วทำการแตกไฟล์ได้ตามปกติ
หลังจากนั้น ไปที่โฟลเดอร์ของคุณในเทอร์มินัลโดยใช้คำสั่ง `cd`
==== คำสั่ง PlatformIO เบื้องต้น
- `pio run --list-targets`: ดูรายการเป้าหมายคำสั่งรัน
- `pio run upload`: รันเป้าหมายอัพโหลด ซึ่งนี่คือคำสั่งที่คุณควรจะใช้ในการเขียนเฟิร์มแวร์ลงบนบอร์ด
- `pio device monitor`: เปิด Serial Monitor
#[
#set list(indent: 3em)
- `pio run --list-targets`: ดูรายการเป้าหมายคำสั่งรัน
- `pio run upload`: รันเป้าหมายอัพโหลด
ซึ่งนี่คือคำสั่งที่คุณควรจะใช้ในการเขียนเฟิร์มแวร์ลงบนบอร์ด
- `pio device monitor`: เปิด Serial Monitor
]
*หมายเหตุ:* โปรดใช้คำสั่งประเภท `pio run` ในโฟลเดอร์ของโปรเจกต์
#i *หมายเหตุ:* โปรดใช้คำสั่งประเภท `pio run` ในโฟลเดอร์ของโปรเจกต์
== การทดสอบ
+940
View File
@@ -0,0 +1,940 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Dracula Theme v1.4.3
#
# https://github.com/dracula/sublime
#
# Copyright 2013-present, All rights reserved
#
# Code licensed under the MIT license
#
# @author Zeno Rocha <hi@zenorocha.com>
-->
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>name</key>
<string>Dracula</string>
<key>settings</key>
<array>
<dict>
<key>settings</key>
<dict>
<key>background</key>
<string>#282a36</string>
<key>caret</key>
<string>#f8f8f0</string>
<key>block_caret</key>
<string>#999a9e</string>
<key>foreground</key>
<string>#f8f8f2</string>
<key>invisibles</key>
<string>#3B3A32</string>
<key>lineHighlight</key>
<string>#44475a</string>
<key>selection</key>
<string>#44475a</string>
<key>findHighlight</key>
<string>#effb7b</string>
<key>findHighlightForeground</key>
<string>#000000</string>
<key>selectionBorder</key>
<string>#222218</string>
<key>activeGuide</key>
<string>#9D550FB0</string>
<key>bracketsForeground</key>
<string>#F8F8F2A5</string>
<key>bracketsOptions</key>
<string>underline</string>
<key>bracketContentsForeground</key>
<string>#F8F8F2A5</string>
<key>bracketContentsOptions</key>
<string>underline</string>
<key>tagsOptions</key>
<string>stippled_underline</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Comment</string>
<key>scope</key>
<string>comment</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#6272a4</string>
<key>fontStyle</key>
<string></string>
</dict>
</dict>
<dict>
<key>name</key>
<string>String</string>
<key>scope</key>
<string>string</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#f1fa8c</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Number</string>
<key>scope</key>
<string>constant.numeric</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#bd93f9</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Built-in constant</string>
<key>scope</key>
<string>constant.language</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#bd93f9</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>User-defined constant</string>
<key>scope</key>
<string>constant.character, constant.other</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#bd93f9</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Variable</string>
<key>scope</key>
<string>variable</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Ruby's @variable</string>
<key>scope</key>
<string>variable.other.readwrite.instance</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#ffb86c</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>String interpolation</string>
<key>scope</key>
<string>constant.character.escaped, constant.character.escape, string source, string source.ruby</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#ff79c6</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Ruby Regexp</string>
<key>scope</key>
<string>source.ruby string.regexp.classic.ruby,source.ruby string.regexp.mod-r.ruby</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#ff5555</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Keyword</string>
<key>scope</key>
<string>keyword</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#ff79c6</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Storage</string>
<key>scope</key>
<string>storage</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#ff79c6</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Storage type</string>
<key>scope</key>
<string>storage.type</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>italic</string>
<key>foreground</key>
<string>#8be9fd</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Storage Type Namespace</string>
<key>scope</key>
<string>storage.type.namespace</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>italic</string>
<key>foreground</key>
<string>#8be9fd</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Storage Type Class</string>
<key>scope</key>
<string>storage.type.class</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>italic</string>
<key>foreground</key>
<string>#ff79c6</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Class name</string>
<key>scope</key>
<string>entity.name.class</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>underline</string>
<key>foreground</key>
<string>#8be9fd</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Meta Path</string>
<key>scope</key>
<string>meta.path</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>underline</string>
<key>foreground</key>
<string>#66d9ef</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Inherited class</string>
<key>scope</key>
<string>entity.other.inherited-class</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>italic underline</string>
<key>foreground</key>
<string>#8be9fd</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Function name</string>
<key>scope</key>
<string>entity.name.function</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#50fa7b</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Function argument</string>
<key>scope</key>
<string>variable.parameter</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>italic</string>
<key>foreground</key>
<string>#ffb86c</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Tag name</string>
<key>scope</key>
<string>entity.name.tag</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#ff79c6</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Tag attribute</string>
<key>scope</key>
<string>entity.other.attribute-name</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#50fa7b</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Library function</string>
<key>scope</key>
<string>support.function</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#8be9fd</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Library constant</string>
<key>scope</key>
<string>support.constant</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#6be5fd</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Library class&#x2f;type</string>
<key>scope</key>
<string>support.type, support.class</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>italic</string>
<key>foreground</key>
<string>#66d9ef</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Library variable</string>
<key>scope</key>
<string>support.other.variable</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Support Other Namespace</string>
<key>scope</key>
<string>support.other.namespace</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>italic</string>
<key>foreground</key>
<string>#66d9ef</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Invalid</string>
<key>scope</key>
<string>invalid</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#ff79c6</string>
<key>fontStyle</key>
<string></string>
<key>foreground</key>
<string>#F8F8F0</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Invalid deprecated</string>
<key>scope</key>
<string>invalid.deprecated</string>
<key>settings</key>
<dict>
<key>background</key>
<string>#bd93f9</string>
<key>foreground</key>
<string>#F8F8F0</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>JSON String</string>
<key>scope</key>
<string>meta.structure.dictionary.json string.quoted.double.json</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#CFCFC2</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>diff.header</string>
<key>scope</key>
<string>meta.diff, meta.diff.header</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#6272a4</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>diff.deleted</string>
<key>scope</key>
<string>markup.deleted</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#ff79c6</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>diff.inserted</string>
<key>scope</key>
<string>markup.inserted</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#50fa7b</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>diff.changed</string>
<key>scope</key>
<string>markup.changed</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#E6DB74</string>
</dict>
</dict>
<dict>
<key>scope</key>
<string>constant.numeric.line-number.find-in-files - match</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#bd93f9</string>
</dict>
</dict>
<dict>
<key>scope</key>
<string>entity.name.filename</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#E6DB74</string>
</dict>
</dict>
<dict>
<key>scope</key>
<string>message.error</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#F83333</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>JSON Punctuation</string>
<key>scope</key>
<string>punctuation.definition.string.begin.json - meta.structure.dictionary.value.json, punctuation.definition.string.end.json - meta.structure.dictionary.value.json</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#EEEEEE</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>JSON Structure</string>
<key>scope</key>
<string>meta.structure.dictionary.json string.quoted.double.json</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#8be9fd</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>JSON String</string>
<key>scope</key>
<string>meta.structure.dictionary.value.json string.quoted.double.json</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#f1fa8c</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>JSON: 6 deep</string>
<key>scope</key>
<string>meta meta meta meta meta meta meta.structure.dictionary.value string</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#50fa7b</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>JSON: 5 deep</string>
<key>scope</key>
<string>meta meta meta meta meta meta.structure.dictionary.value string</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#ffb86c</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>JSON: 4 deep</string>
<key>scope</key>
<string>meta meta meta meta meta.structure.dictionary.value string</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#ff79c6</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>JSON: 3 deep</string>
<key>scope</key>
<string>meta meta meta meta.structure.dictionary.value string</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#bd93f9</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>JSON: 2 deep</string>
<key>scope</key>
<string>meta meta meta.structure.dictionary.value string</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#50fa7b</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>JSON: 1 deep</string>
<key>scope</key>
<string>meta meta.structure.dictionary.value string</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#ffb86c</string>
</dict>
</dict>
<!-- Markdown Tweaks -->
<dict>
<key>name</key>
<string>Markup: strike</string>
<key>scope</key>
<string>markup.strike</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>italic</string>
<key>foreground</key>
<string>#FFB86C</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Markup: bold</string>
<key>scope</key>
<string>markup.bold</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>bold</string>
<key>foreground</key>
<string>#FFB86C</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Markup: italic</string>
<key>scope</key>
<string>markup.italic</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>italic</string>
<key>foreground</key>
<string>#FFB86C</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Markdown: heading</string>
<key>scope</key>
<string>markup.heading</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#8BE9FD</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Markdown: List Items Punctuation</string>
<key>scope</key>
<string>punctuation.definition.list_item.markdown</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#FF79C6</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Markdown: Blockquote</string>
<key>scope</key>
<string>markup.quote</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>italic</string>
<key>foreground</key>
<string>#6272A4</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Markdown: Blockquote Punctuation</string>
<key>scope</key>
<string>punctuation.definition.blockquote.markdown</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>italic</string>
<key>background</key>
<string>#6272A4</string>
<key>foreground</key>
<string>#6272A4</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Markdown: Separator</string>
<key>scope</key>
<string>meta.separator</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#6272A4</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Markup: raw inline</string>
<key>scope</key>
<string>text.html.markdown markup.raw.inline</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#50FA7B</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Markup: underline</string>
<key>scope</key>
<string>markup.underline</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>underline</string>
<key>foreground</key>
<string>#BD93F9</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Markup: Raw block</string>
<key>scope</key>
<string>markup.raw.block</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#CFCFC2</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Markdown: Raw Block fenced source</string>
<key>scope</key>
<string>markup.raw.block.fenced.markdown source</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#F8F8F2</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Markdown: Fenced Bode Block</string>
<key>scope</key>
<string>punctuation.definition.fenced.markdown, variable.language.fenced.markdown</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>italic</string>
<key>foreground</key>
<string>#6272A4</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Markdown: Fenced Language</string>
<key>scope</key>
<string>variable.language.fenced.markdown</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string>italic</string>
<key>foreground</key>
<string>#6272A4</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Punctuation Accessor</string>
<key>scope</key>
<string>punctuation.accessor</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#FF79C6</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Meta Function Return Type</string>
<key>scope</key>
<string>meta.function.return-type</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#FF79C6</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Punctuation Section Block Begin</string>
<key>scope</key>
<string>punctuation.section.block.begin</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#ffffff</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Punctuation Section Block End</string>
<key>scope</key>
<string>punctuation.section.block.end</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#ffffff</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Punctuation Section Embedded Begin</string>
<key>scope</key>
<string>punctuation.section.embedded.begin</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#ff79c6</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Punctuation Section Embedded End</string>
<key>scope</key>
<string>punctuation.section.embedded.end</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#ff79c6</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Punctuation Separator Namespace</string>
<key>scope</key>
<string>punctuation.separator.namespace</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#ff79c6</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Variable Function</string>
<key>scope</key>
<string>variable.function</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#50fa7b</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Variable Other</string>
<key>scope</key>
<string>variable.other</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#ffffff</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Variable Language</string>
<key>scope</key>
<string>variable.language</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#bd93f9</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Entity Name Module Ruby</string>
<key>scope</key>
<string>entity.name.module.ruby</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#8be9fd</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Entity Name Constant Ruby</string>
<key>scope</key>
<string>entity.name.constant.ruby</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#bd93f9</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Support Function Builtin Ruby</string>
<key>scope</key>
<string>support.function.builtin.ruby</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#ffffff</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Storage Type Namespace CS</string>
<key>scope</key>
<string>storage.type.namespace.cs</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#ff79c6</string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Entity Name Namespace CS</string>
<key>scope</key>
<string>entity.name.namespace.cs</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#8be9fd</string>
</dict>
</dict>
</array>
<key>uuid</key>
<string>83091B89-765E-4F0D-9275-0EC6CB084126</string>
<key>colorSpaceName</key>
<string>sRGB</string>
<key>semanticClass</key>
<string>theme.dracula</string>
<key>author</key>
<string>Zeno Rocha</string>
</dict>
</plist>
+34 -9
View File
@@ -16,14 +16,28 @@
right: 1in,
bottom: 1in,
),
header: context [
#h(1fr)
#counter(page).display(thai-numbering)
],
header: none,
)
doc
}
/// Sane indentation
#let i = h(3em)
/// Insane shit forced upon by my teacher
/// For indenting in 3rd level subheadings
#let iii = h(3em)
// #let iii = h(5.5em)
/// For indenting in 4th level subheadings
#let iiii = h(6em)
// #let iiii = h(9.25em)
#let iiiii = h(9em)
#let iiiiii = h(12em)
#let page-theme(doc) = {
set page(
paper: "a4",
@@ -51,12 +65,25 @@
leading: 1em,
)
set list(indent: 1em)
show heading: set text(size: 10.5pt)
show heading: set text(size: 10.5pt, weight: "regular")
show heading: set block(below: 1em)
show heading.where(level: 1): set text(size: 12pt)
show heading.where(level: 1): set text(size: 12pt, weight: "bold")
show heading.where(level: 1): set align(center)
show heading.where(level: 2): set text(weight: "bold")
show heading: it => {
if it.level > 2 {
block(
it,
inset: (left: 3em * (it.level - 2)),
)
} else {
it
}
}
show math.equation: set text(font: "Laksaman")
show raw: set text(font: "Cascadia Code", size: 10pt)
show table.cell.where(y: 0): strong
set enum(number-align: start + top)
set ref(supplement: "หัวข้อ")
doc
}
@@ -64,7 +91,7 @@
// Figure with attribution information
#let afigure(
body,
attr: "",
attr: none,
..args,
) = [
#figure(body, ..args)
@@ -75,6 +102,4 @@
) <afig>
]
#let i = h(3em)
#let jb = linebreak(justify: true)
+278 -277
View File
@@ -1,353 +1,354 @@
wkNodeMcu:
type: Web
title: NodeMCU
date: 2025-08-15
language: en
publisher: มูลนิธิวิกิมีเดีย (ภายใต้ CC BY-SA 4.0)
url:
date: 2025-12-8
value: https://en.wikipedia.org/w/index.php?title=NodeMCU&oldid=1306030712
type: Web
title: NodeMCU
date: 2025-08-15
language: en
publisher: มูลนิธิวิกิมีเดีย (ภายใต้ CC BY-SA 4.0)
url:
date: 2025-12-8
value: https://en.wikipedia.org/w/index.php?title=NodeMCU&oldid=1306030712
wkEsp32:
type: Web
title: ESP32
date: 2025-11-2
language: en
publisher: มูลนิธิวิกิมีเดีย (ภายใต้ CC BY-SA 4.0)
url:
date: 2025-12-8
value: https://en.wikipedia.org/w/index.php?title=ESP32&oldid=1320113248
type: Web
title: ESP32
date: 2025-11-2
language: en
publisher: มูลนิธิวิกิมีเดีย (ภายใต้ CC BY-SA 4.0)
url:
date: 2025-12-8
value: https://en.wikipedia.org/w/index.php?title=ESP32&oldid=1320113248
wkEspressif:
type: Web
title: Espressif Systems
date: 2025-10-6
language: en
publisher: มูลนิธิวิกิมีเดีย (ภายใต้ CC BY-SA 4.0)
url:
date: 2025-12-8
value: https://en.wikipedia.org/w/index.php?title=Espressif_Systems&oldid=1315427960
type: Web
title: Espressif Systems
date: 2025-10-6
language: en
publisher: มูลนิธิวิกิมีเดีย (ภายใต้ CC BY-SA 4.0)
url:
date: 2025-12-8
value: https://en.wikipedia.org/w/index.php?title=Espressif_Systems&oldid=1315427960
wkFlutter:
type: Web
title: Flutter
date: 2025-11-12
language: en
publisher: มูลนิธิวิกิมีเดีย (ภายใต้ CC BY-SA 4.0)
url:
date: 2025-11-30
value: https://en.wikipedia.org/w/index.php?title=Flutter_(software)&oldid=1321794260
type: Web
title: Flutter
date: 2025-11-12
language: en
publisher: มูลนิธิวิกิมีเดีย (ภายใต้ CC BY-SA 4.0)
url:
date: 2025-11-30
value: https://en.wikipedia.org/w/index.php?title=Flutter_(software)&oldid=1321794260
wkGit:
type: Web
title: Git
date: 2025-11-1
language: en
publisher: มูลนิธิวิกิมีเดีย (ภายใต้ CC BY-SA 4.0)
url:
date: 2025-11-30
value: https://en.wikipedia.org/w/index.php?title=Git&oldid=1319901866
type: Web
title: Git
date: 2025-11-1
language: en
publisher: มูลนิธิวิกิมีเดีย (ภายใต้ CC BY-SA 4.0)
url:
date: 2025-11-30
value: https://en.wikipedia.org/w/index.php?title=Git&oldid=1319901866
wkGitea:
type: Web
title: Gitea
date: 2025-11-17
language: en
publisher: มูลนิธิวิกิมีเดีย (ภายใต้ CC BY-SA 4.0)
url:
date: 2025-11-30
value: https://en.wikipedia.org/w/index.php?title=Gitea&oldid=1322631603
type: Web
title: Gitea
date: 2025-11-17
language: en
publisher: มูลนิธิวิกิมีเดีย (ภายใต้ CC BY-SA 4.0)
url:
date: 2025-11-30
value: https://en.wikipedia.org/w/index.php?title=Gitea&oldid=1322631603
wkHttps:
type: Web
title: HTTPS
date: 2025-11-30
language: en
publisher: มูลนิธิวิกิมีเดีย (ภายใต้ CC BY-SA 4.0)
url:
type: Web
title: HTTPS
date: 2025-11-30
value: https://en.wikipedia.org/w/index.php?title=HTTPS&oldid=1324964055
language: en
publisher: มูลนิธิวิกิมีเดีย (ภายใต้ CC BY-SA 4.0)
url:
date: 2025-11-30
value: https://en.wikipedia.org/w/index.php?title=HTTPS&oldid=1324964055
wkTls:
type: Web
title: Transport Layer Security
date: 2025-11-24
language: en
publisher: มูลนิธิวิกิมีเดีย (ภายใต้ CC BY-SA 4.0)
url:
date: 2025-11-30
value: https://en.wikipedia.org/w/index.php?title=Transport_Layer_Security&oldid=1323879251
type: Web
title: Transport Layer Security
date: 2025-11-24
language: en
publisher: มูลนิธิวิกิมีเดีย (ภายใต้ CC BY-SA 4.0)
url:
date: 2025-11-30
value: https://en.wikipedia.org/w/index.php?title=Transport_Layer_Security&oldid=1323879251
wkC:
type: Web
title: C (programming language)
date: 2025-11-26
language: en
publisher: มูลนิธิวิกิมีเดีย (ภายใต้ CC BY-SA 4.0)
url:
date: 2025-11-30
value: https://en.wikipedia.org/w/index.php?title=C_(programming_language)&oldid=1324211766
type: Web
title: C (programming language)
date: 2025-11-26
language: en
publisher: มูลนิธิวิกิมีเดีย (ภายใต้ CC BY-SA 4.0)
url:
date: 2025-11-30
value: https://en.wikipedia.org/w/index.php?title=C_(programming_language)&oldid=1324211766
wkGcc:
type: Web
title: GNU Compiler Collection
date: 2025-11-30
language: en
publisher: มูลนิธิวิกิมีเดีย (ภายใต้ CC BY-SA 4.0)
url:
type: Web
title: GNU Compiler Collection
date: 2025-11-30
value: https://en.wikipedia.org/w/index.php?title=GNU_Compiler_Collection&oldid=1324929423
language: en
publisher: มูลนิธิวิกิมีเดีย (ภายใต้ CC BY-SA 4.0)
url:
date: 2025-11-30
value: https://en.wikipedia.org/w/index.php?title=GNU_Compiler_Collection&oldid=1324929423
wkDart:
type: Web
title: Dart (programming language)
date: 2025-11-21
language: en
publisher: มูลนิธิวิกิมีเดีย (ภายใต้ CC BY-SA 4.0)
url:
date: 2025-12-8
value: https://en.wikipedia.org/w/index.php?title=Dart_(programming_language)&oldid=1323401675
type: Web
title: Dart (programming language)
date: 2025-11-21
language: en
publisher: มูลนิธิวิกิมีเดีย (ภายใต้ CC BY-SA 4.0)
url:
date: 2025-12-8
value: https://en.wikipedia.org/w/index.php?title=Dart_(programming_language)&oldid=1323401675
wkX509:
type: Web
title: X.509
date: 2025-11-11
language: en
publisher: มูลนิธิวิกิมีเดีย (ภายใต้ CC BY-SA 4.0)
url:
date: 2025-11-29
value: https://en.wikipedia.org/w/index.php?title=X.509&oldid=1321610537
type: Web
title: X.509
date: 2025-11-11
language: en
publisher: มูลนิธิวิกิมีเดีย (ภายใต้ CC BY-SA 4.0)
url:
date: 2025-11-29
value: https://en.wikipedia.org/w/index.php?title=X.509&oldid=1321610537
wkDerEncoding:
type: Web
title: X.690
language: en
publisher: มูลนิธิวิกิมีเดีย (ภายใต้ CC BY-SA 4.0)
date: 2025-10-6
url:
date: 2025-12-3
value: https://en.wikipedia.org/w/index.php?title=X.690&oldid=1315457524#DER_encoding
type: Web
title: X.690
language: en
publisher: มูลนิธิวิกิมีเดีย (ภายใต้ CC BY-SA 4.0)
date: 2025-10-6
url:
date: 2025-12-3
value: https://en.wikipedia.org/w/index.php?title=X.690&oldid=1315457524#DER_encoding
wkOpenSSL:
type: Web
title: OpenSSL
date: 2025-12-1
language: en
publisher: มูลนิธิวิกิมีเดีย (ภายใต้ CC BY-SA 4.0)
url:
date: 2025-12-3
value: https://en.wikipedia.org/w/index.php?title=OpenSSL&oldid=1325138239
type: Web
title: OpenSSL
date: 2025-12-1
language: en
publisher: มูลนิธิวิกิมีเดีย (ภายใต้ CC BY-SA 4.0)
url:
date: 2025-12-3
value: https://en.wikipedia.org/w/index.php?title=OpenSSL&oldid=1325138239
wkMaterial:
type: Web
title: Material Design
date: 2025-11-15
language: en
publisher: มูลนิธิวิกิมีเดีย (ภายใต้ CC BY-SA 4.0)
url:
date: 2025-12-6
value: https://en.wikipedia.org/w/index.php?title=Material_Design&oldid=1322252287
type: Web
title: Material Design
date: 2025-11-15
language: en
publisher: มูลนิธิวิกิมีเดีย (ภายใต้ CC BY-SA 4.0)
url:
date: 2025-12-6
value: https://en.wikipedia.org/w/index.php?title=Material_Design&oldid=1322252287
wkBuzzer:
type: Web
title: Buzzer
date: 2025-11-13
language: en
publisher: มูลนิธิวิกิมีเดีย (ภายใต้ CC BY-SA 4.0)
url:
date: 2025-12-10
value: https://en.wikipedia.org/w/index.php?title=Buzzer&oldid=1321902450
type: Web
title: Buzzer
date: 2025-11-13
language: en
publisher: มูลนิธิวิกิมีเดีย (ภายใต้ CC BY-SA 4.0)
url:
date: 2025-12-10
value: https://en.wikipedia.org/w/index.php?title=Buzzer&oldid=1321902450
wkNFC:
type: Web
title: Near-field communication
date: 2025-11-5
language: en
publisher: มูลนิธิวิกิมีเดีย (ภายใต้ CC BY-SA 4.0)
url:
date: 2025-12-10
value: https://en.wikipedia.org/w/index.php?title=Near-field_communication&oldid=1320616102
type: Web
title: Near-field communication
date: 2025-11-5
language: en
publisher: มูลนิธิวิกิมีเดีย (ภายใต้ CC BY-SA 4.0)
url:
date: 2025-12-10
value: https://en.wikipedia.org/w/index.php?title=Near-field_communication&oldid=1320616102
androidJdkVersion:
type: Web
title: Java versions in Android builds
publisher: Android Developers (ภายใต้สัญญาอนุญาต Apache License 2.0)
language: en
# Publishing date/Last updated
date: 2025-11-21
url:
value: https://developer.android.com/build/jdks
# Date of research
date: 2025-11-26
type: Web
title: Java versions in Android builds
publisher: Android Developers (ภายใต้สัญญาอนุญาต Apache License 2.0)
language: en
# Publishing date/Last updated
date: 2025-11-21
url:
value: https://developer.android.com/build/jdks
# Date of research
date: 2025-11-26
sofFlutterMinSdk:
type: Web
title: Where is the value of "flutter.minSdkVersion" in Flutter project initialized?
date: 2025-08-26
language: en
publisher: Stackoverflow (ภายใต้ CC BY-SA 4.0)
url:
date: 2025-11-26
value: https://stackoverflow.com/a/79746636
type: Web
title: Where is the value of "flutter.minSdkVersion" in Flutter project initialized?
date: 2025-08-26
language: en
publisher: Stackoverflow (ภายใต้ CC BY-SA 4.0)
url:
date: 2025-11-26
value: https://stackoverflow.com/a/79746636
sofCDataModel:
type: Web
title: Are data models - ILP32 or LP64 decided by OS or the Hardware Architecture?
date: 2020-10-14
language: en
publisher: Stackoverflow (ภายใต้ CC BY-SA 4.0)
url:
date: 2025-12-9
value: https://stackoverflow.com/a/79746636
type: Web
title: Are data models - ILP32 or LP64 decided by OS or the Hardware Architecture?
date: 2020-10-14
language: en
publisher: Stackoverflow (ภายใต้ CC BY-SA 4.0)
url:
date: 2025-12-9
value: https://stackoverflow.com/a/79746636
flInstallManually:
type: Web
title: Install Flutter manually
date: 2025-10-28
language: en
publisher: Flutter (ภายใต้ CC BY 3.0 และ BSD License)
url:
date: 2025-12-6
value: https://docs.flutter.dev/install/manual
type: Web
title: Install Flutter manually
date: 2025-10-28
language: en
publisher: Flutter (ภายใต้ CC BY 3.0 และ BSD License)
url:
date: 2025-12-6
value: https://docs.flutter.dev/install/manual
flVsCode:
type: Web
title: Install Flutter using VS Code
date: 2025-10-28
language: en
publisher: Flutter (ภายใต้ CC BY 3.0 และ BSD License)
url:
date: 2025-12-6
value: https://docs.flutter.dev/install/with-vs-code
type: Web
title: Install Flutter using VS Code
date: 2025-10-28
language: en
publisher: Flutter (ภายใต้ CC BY 3.0 และ BSD License)
url:
date: 2025-12-6
value: https://docs.flutter.dev/install/with-vs-code
flLinuxDev:
type: Web
title: Set up Linux development
date: 2025-9-25
language: en
publisher: Flutter (ภายใต้ CC BY 3.0 และ BSD License)
url:
date: 2025-12-6
value: https://docs.flutter.dev/platform-integration/linux/setup
type: Web
title: Set up Linux development
date: 2025-9-25
language: en
publisher: Flutter (ภายใต้ CC BY 3.0 และ BSD License)
url:
date: 2025-12-6
value: https://docs.flutter.dev/platform-integration/linux/setup
flLinuxBuild:
type: Web
title: Build Linux apps with Flutter
date: 2025-9-5
language: en
publisher: Flutter (ภายใต้ CC BY 3.0 และ BSD License)
url:
date: 2025-12-6
value: https://docs.flutter.dev/platform-integration/linux/building
type: Web
title: Build Linux apps with Flutter
date: 2025-9-5
language: en
publisher: Flutter (ภายใต้ CC BY 3.0 และ BSD License)
url:
date: 2025-12-6
value: https://docs.flutter.dev/platform-integration/linux/building
archPkgs:
type: Web
title: Arch Linux - Package Search
date: 2025-12-15
language: en
url:
type: Web
title: Arch Linux - Package Search
date: 2025-12-15
value: https://archlinux.org/packages/
language: en
url:
date: 2025-12-15
value: https://archlinux.org/packages/
fedoraPkgs:
type: Web
title: Fedora Packages
date: 2025-12-15
language: en
url:
type: Web
title: Fedora Packages
date: 2025-12-15
value: https://packages.fedoraproject.org/
language: en
url:
date: 2025-12-15
value: https://packages.fedoraproject.org/
debianPkgs:
type: Web
title: Debian -- Packages
date: 2025-12-15
language: en
url:
type: Web
title: Debian -- Packages
date: 2025-12-15
value: https://www.debian.org/distrib/packages
language: en
url:
date: 2025-12-15
value: https://www.debian.org/distrib/packages
gitWindows:
type: Web
title: Git - Install for Windows
date: 2025-11-30
language: en
url:
date: 2025-12-1
value: https://git-scm.com/install/windows
type: Web
title: Git - Install for Windows
date: 2025-11-30
language: en
url:
date: 2025-12-1
value: https://git-scm.com/install/windows
twMaterialYou:
type: Post
title: "The latest in Material Design is NOW available"
date: 2021-10-28
author: Material Design [@materialdesign]
url:
date: 2025-12-1
value: https://x.com/materialdesign/status/1453409331697885192
type: Post
title: "The latest in Material Design is NOW available"
date: 2021-10-28
author: Material Design [@materialdesign]
url:
date: 2025-12-1
value: https://x.com/materialdesign/status/1453409331697885192
cpprefCBasics:
type: Web
title: Declarations
date: 2025-02-09
publisher: cppreference.com (ภายใต้ CC BY-SA 3.0 Unported)
url:
date: 2025-12-08
value: https://cppreference.com/w/c/language/declarations.html
type: Web
title: Declarations
date: 2025-02-09
publisher: cppreference.com (ภายใต้ CC BY-SA 3.0 Unported)
url:
date: 2025-12-08
value: https://cppreference.com/w/c/language/declarations.html
cpprefATypes:
type: Web
title: Arithmetic types
date: 2025-02-09
publisher: cppreference.com (ภายใต้ CC BY-SA 3.0 Unported)
url:
date: 2025-12-09
value: https://cppreference.com/w/c/language/arithmetic_types.html
type: Web
title: Arithmetic types
date: 2025-02-09
publisher: cppreference.com (ภายใต้ CC BY-SA 3.0 Unported)
url:
date: 2025-12-09
value: https://cppreference.com/w/c/language/arithmetic_types.html
ansiC:
type: Book
title: The ANSI C Programming Language
page-total: 238
author:
- Brian W. Kernighan
- Dennis M. Ritchie
publisher: Prentice Hall
language: en
edition: ฉบับที่สอง (Second edition)
date: 1988
url: https://archive.org/details/the-ansi-c-programming-language-by-brian-w.-kernighan-dennis-m.-ritchie.org
type: Book
title: The ANSI C Programming Language
page-total: 238
author:
- Brian W. Kernighan
- Dennis M. Ritchie
publisher: Prentice Hall
language: en
edition: ฉบับที่สอง (Second edition)
date: 1988
serial-number:
isbn: 0131101633
url: https://archive.org/details/the-ansi-c-programming-language-by-brian-w.-kernighan-dennis-m.-ritchie.org
ghEsp32Partition:
type: Web
title: default.csv
date: 2024-4-15
url:
date: 2025-12-9
value: https://github.com/espressif/arduino-esp32/blob/2ede5ac10923afd1e3a42ce1fb41930a9de05d16/tools/partitions/default.csv
type: Web
title: default.csv
date: 2024-4-15
url:
date: 2025-12-9
value: https://github.com/espressif/arduino-esp32/blob/2ede5ac10923afd1e3a42ce1fb41930a9de05d16/tools/partitions/default.csv
pioPython:
type: Web
title: Install Python Interpreter
date: 2024-9-14
publisher: PlatformIO Docs (ภายใต้ Apache License 2.0)
url:
date: 2025-12-15
value: https://docs.platformio.org/en/latest/faq/install-python.html
type: Web
title: Install Python Interpreter
date: 2024-9-14
publisher: PlatformIO Docs (ภายใต้ Apache License 2.0)
url:
date: 2025-12-15
value: https://docs.platformio.org/en/latest/faq/install-python.html
pioSysReq:
type: Web
date: 2022-5-30
title: System Requirements
publisher: PlatformIO Docs (ภายใต้ Apache License 2.0)
url:
date: 2025-12-15
value: https://docs.platformio.org/en/latest/core/installation/requirements.html
type: Web
date: 2022-5-30
title: System Requirements
publisher: PlatformIO Docs (ภายใต้ Apache License 2.0)
url:
date: 2025-12-15
value: https://docs.platformio.org/en/latest/core/installation/requirements.html
pioInsScript:
type: Web
date: 2023-8-14
title: Installer Script (Recommended)
publisher: PlatformIO Docs (ภายใต้ Apache License 2.0)
url:
date: 2025-12-15
value: https://docs.platformio.org/en/latest/core/installation/methods/installer-script.html
type: Web
date: 2023-8-14
title: Installer Script (Recommended)
publisher: PlatformIO Docs (ภายใต้ Apache License 2.0)
url:
date: 2025-12-15
value: https://docs.platformio.org/en/latest/core/installation/methods/installer-script.html
+16 -3
View File
@@ -52,7 +52,12 @@
#include "Chapter4.typ"
#include "Chapter5.typ"
#bibliography("References.yaml", title: "บรรณานุกรม", full: true, style: "chicago-author-date")
#bibliography(
"References.yaml",
title: "บรรณานุกรม",
full: true,
style: "nong-khai-technical-college-project-guidelines.csl",
)
#pagebreak()
@@ -61,16 +66,24 @@
#let image-credits() = context {
let figures = query(figure.where(kind: "i-figured-image"))
let attributions = query(<afig>)
let offset = 0
for (idx, f) in figures.enumerate() {
if (idx >= attributions.len()) {
return
}
if attributions.at(idx).body.body == [] {
offset += 1
if attributions.at(idx + offset).body.body == [] {
continue
}
}
f.caption
// f.counter.display(f.numbering)
h(2.2em)
attributions.at(idx).body.body
attributions.at(idx + offset).body.body
}
}
@@ -0,0 +1,406 @@
<?xml version="1.0" encoding="utf-8"?>
<style xmlns="http://purl.org/net/xbiblio/csl" class="in-text" version="1.0" demote-non-dropping-particle="sort-only">
<!-- This style was edited with the Visual CSL Editor (https://editor.citationstyles.org/visualEditor/) -->
<info>
<title>Nong Khai Technical College Project Guidelines</title>
<title-short>NKTC</title-short>
<id>http://www.zotero.org/styles/nong-khai-technical-college-project-guidelines</id>
<link rel="self" href="http://www.zotero.org/styles/nong-khai-technical-college-project-guidelines"/>
<link href="https://staticlines.dailitation.xyz/Documents/NKTCProjectGuidelines.pdf" rel="documentation"/>
<author>
<email>linesofcodes@dailitation.xyz</email>
<name>Satakun Utama</name>
</author>
<category citation-format="numeric"/>
<category field="engineering"/>
<category field="generic-base"/>
<summary>NKTC College Project Bibliography (Modified from IEEE)</summary>
<updated>2025-12-27T05:32:04+00:00</updated>
<rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights>
</info>
<locale xml:lang="en">
<date form="text">
<date-part name="month" form="short" suffix=" "/>
<date-part name="day" form="numeric-leading-zeros" suffix=", "/>
<date-part name="year"/>
</date>
<terms>
<term name="chapter" form="short">ch.</term>
<term name="presented at">presented at the</term>
<term name="available at">available</term>
</terms>
</locale>
<macro name="status">
<choose>
<if variable="page issue volume" match="none">
<text variable="status" text-case="capitalize-first" suffix="" font-weight="bold"/>
</if>
</choose>
</macro>
<macro name="edition">
<choose>
<if type="bill book chapter graphic legal_case legislation motion_picture paper-conference report song" match="any">
<choose>
<if is-numeric="edition">
<group delimiter=" ">
<number variable="edition" form="ordinal"/>
<text term="edition" form="short"/>
</group>
</if>
<else>
<text variable="edition" text-case="capitalize-first" suffix="."/>
</else>
</choose>
</if>
</choose>
</macro>
<macro name="issued">
<choose>
<if type="article-journal report" match="any">
<date variable="issued">
<date-part name="month" form="short" suffix=" "/>
<date-part name="year" form="long"/>
</date>
</if>
<else-if type="bill book chapter graphic legal_case legislation song thesis" match="any">
<date date-parts="year" variable="issued">
<date-part name="year" form="long"/>
</date>
</else-if>
<else-if type="paper-conference" match="any">
<date variable="issued">
<date-part name="month" form="short"/>
<date-part name="year" prefix=" "/>
</date>
</else-if>
<else-if type="motion_picture" match="any">
<date variable="issued" form="text" prefix="(" suffix=")"/>
</else-if>
<else>
<date variable="issued" form="text"/>
</else>
</choose>
</macro>
<macro name="author">
<names variable="author">
<name and="text" et-al-min="7" et-al-use-first="1" initialize="false" initialize-with=". "/>
<label form="short" prefix=", " text-case="capitalize-first"/>
<et-al font-style="italic"/>
<substitute>
<names variable="editor"/>
<names variable="translator"/>
</substitute>
</names>
</macro>
<macro name="editor">
<names variable="editor">
<name initialize-with=". " delimiter=", " and="text"/>
<label form="short" prefix=", " text-case="capitalize-first"/>
</names>
</macro>
<macro name="locators">
<group delimiter=", ">
<text macro="edition"/>
<group delimiter=" ">
<text term="volume" form="short"/>
<number variable="volume" form="numeric"/>
</group>
<group delimiter=" ">
<number variable="number-of-volumes" form="numeric"/>
<text term="volume" form="short" plural="true"/>
</group>
<group delimiter=" ">
<text term="issue" form="short"/>
<number variable="issue" form="numeric"/>
</group>
</group>
</macro>
<macro name="title">
<choose>
<if type="bill book graphic legal_case legislation motion_picture song" match="any">
<text variable="title" font-style="normal" font-weight="bold"/>
</if>
<else>
<text variable="title" quotes="false" font-weight="bold" suffix=" "/>
</else>
</choose>
</macro>
<macro name="publisher">
<choose>
<if type="bill book chapter graphic legal_case legislation motion_picture paper-conference song" match="any">
<group delimiter="; ">
<text variable="publisher-place"/>
<text variable="publisher"/>
</group>
</if>
<else>
<group delimiter=", ">
<text variable="publisher"/>
<text variable="publisher-place"/>
</group>
</else>
</choose>
</macro>
<macro name="event">
<choose>
<if type="paper-conference speech" match="any">
<choose>
<if variable="container-title" match="any">
<group delimiter=", ">
<group delimiter=" ">
<text term="in"/>
<text variable="container-title" font-style="italic"/>
</group>
<text variable="event-place"/>
</group>
</if>
<else>
<group delimiter=", ">
<group delimiter=" ">
<text term="presented at"/>
<text variable="event"/>
</group>
<text variable="event-place"/>
</group>
</else>
</choose>
</if>
</choose>
</macro>
<macro name="access">
<choose>
<if type="webpage post post-weblog" match="any">
<choose>
<if variable="URL">
<group delimiter=" . " prefix=" ">
<text variable="URL"/>
<group delimiter=" ">
<text term="accessed" text-case="capitalize-first"/>
<date variable="accessed" form="text"/>
</group>
</group>
</if>
</choose>
</if>
<else-if match="any" variable="DOI">
<text variable="DOI" prefix=" doi: " suffix="."/>
</else-if>
<else-if variable="URL">
<group delimiter=". " prefix=" " suffix=". ">
<group delimiter=" ">
<text term="accessed" text-case="capitalize-first"/>
<date variable="accessed" form="text"/>
</group>
<group prefix="[" suffix="]" delimiter=" ">
<choose>
<if variable="medium" match="any">
<text variable="medium" text-case="capitalize-first"/>
</if>
<else>
<text term="online" text-case="capitalize-first"/>
<choose>
<if type="motion_picture">
<text term="video" text-case="capitalize-first"/>
</if>
</choose>
</else>
</choose>
</group>
</group>
<group delimiter=": " prefix=" ">
<text term="available at" text-case="capitalize-first"/>
<text variable="URL"/>
</group>
</else-if>
</choose>
</macro>
<macro name="page">
<choose>
<if type="article-journal" variable="number" match="all">
<group delimiter=" ">
<text value="Art."/>
<text term="issue" form="short"/>
<text variable="number"/>
</group>
</if>
<else>
<group delimiter=" ">
<label variable="page" form="short"/>
<text variable="page"/>
</group>
</else>
</choose>
</macro>
<macro name="citation-locator">
<group delimiter=" ">
<choose>
<if locator="page">
<label variable="locator" form="short"/>
</if>
<else>
<label variable="locator" form="short" text-case="capitalize-first"/>
</else>
</choose>
<text variable="locator"/>
</group>
</macro>
<macro name="geographic-location">
<group delimiter=", " suffix=".">
<choose>
<if variable="publisher-place">
<text variable="publisher-place" text-case="title"/>
</if>
<else-if variable="event-place">
<text variable="event-place" text-case="title"/>
</else-if>
</choose>
</group>
</macro>
<citation collapse="citation-number">
<sort>
<key variable="citation-number"/>
</sort>
<layout delimiter=", ">
<group delimiter=", " prefix="(" suffix=")">
<text variable="citation-number"/>
<text macro="citation-locator"/>
</group>
</layout>
</citation>
<bibliography entry-spacing="0" second-field-align="flush">
<layout>
<text variable="citation-number" prefix="(" suffix=")"/>
<text macro="author" suffix=" . "/>
<choose>
<if type="article-journal">
<group delimiter=", ">
<text macro="title"/>
<text variable="container-title" font-style="italic" form="short"/>
<text macro="locators"/>
<text macro="page"/>
<text macro="issued"/>
<text macro="status"/>
</group>
<choose>
<if variable="URL DOI" match="none">
<text value="."/>
</if>
<else>
<text value=","/>
</else>
</choose>
<text macro="access"/>
</if>
<else-if type="paper-conference speech" match="any">
<group delimiter=", " suffix=".">
<text macro="title"/>
<text macro="event"/>
<text macro="issued"/>
<text macro="locators"/>
<text macro="page"/>
<text macro="status"/>
</group>
<text macro="access"/>
</else-if>
<else-if type="report">
<group delimiter=", " suffix=".">
<text macro="title"/>
<text macro="publisher"/>
<group delimiter=" ">
<text variable="genre"/>
<text variable="number"/>
</group>
<text macro="issued"/>
</group>
<text macro="access"/>
</else-if>
<else-if type="thesis">
<group delimiter=", " suffix=".">
<text macro="title"/>
<text variable="genre"/>
<text macro="publisher"/>
<text macro="issued"/>
</group>
<text macro="access"/>
</else-if>
<else-if type="webpage post-weblog post" match="any">
<group delimiter=". " suffix=".">
<text macro="title"/>
<text variable="container-title" font-style="normal"/>
<text macro="issued"/>
</group>
<text macro="access"/>
</else-if>
<else-if type="patent">
<group delimiter=", ">
<text macro="title"/>
<text variable="number"/>
<text macro="issued"/>
</group>
<text macro="access"/>
</else-if>
<else-if type="motion_picture">
<text macro="geographic-location" suffix=". "/>
<group delimiter=", " suffix=".">
<text macro="title"/>
<text macro="issued"/>
</group>
<text macro="access"/>
</else-if>
<else-if type="bill book graphic legal_case legislation report song" match="any">
<group delimiter=" . " suffix=". ">
<text macro="title"/>
<text macro="locators"/>
</group>
<group delimiter=". " suffix=".">
<text macro="publisher"/>
<text macro="issued"/>
<text macro="page"/>
</group>
<text macro="access"/>
</else-if>
<else-if type="article-magazine article-newspaper broadcast interview manuscript map patent personal_communication song speech thesis webpage" match="any">
<group delimiter=", " suffix=".">
<text macro="title"/>
<text variable="container-title" font-style="italic"/>
<text macro="locators"/>
<text macro="publisher"/>
<text macro="page"/>
<text macro="issued"/>
</group>
<text macro="access"/>
</else-if>
<else-if type="chapter paper-conference" match="any">
<group delimiter=". " suffix=". ">
<text macro="title"/>
<group delimiter=" ">
<text term="in"/>
<text variable="container-title" font-style="italic"/>
</group>
<text macro="locators"/>
</group>
<text macro="editor" suffix=" "/>
<group delimiter=", " suffix=".">
<text macro="publisher"/>
<text macro="issued"/>
<text macro="page"/>
</group>
<text macro="access"/>
</else-if>
<else>
<group delimiter=", " suffix=". ">
<text macro="title"/>
<text variable="container-title" font-style="italic"/>
<text macro="locators"/>
</group>
<group delimiter=", " suffix=".">
<text macro="publisher"/>
<text macro="page"/>
<text macro="issued"/>
</group>
<text macro="access"/>
</else>
</choose>
</layout>
</bibliography>
</style>