อุปกรณ์อิเล็กทรอนิกส์ จะใช้สัญญาณในการทำงาน 2 แบบ คือสัญญาณดิจิตอล และสัญญาณอนาล็อก ในบทนี้เราจะมาทดลองใช้คำสั่งต่าง ๆ ในการควบคุมอุปกรณ์กัน
อินพุต / เอาต์พุตแบบดิจิตอล คือการใช้งานขา GPIO ในการอ่านค่า หรือเขียนค่าสถานะแบบดิจิตอล ซึ่งใช้งานตั้งอยู่บนพื้นฐานดิจิตอล คือค่าที่ได้หรือค่าที่เขียนจะมีแค่ 2 สถานะ คือสถานะ HIGH และสถานะ LOW
ในการใช้งานขา GPIO แบบดิจิตอล จำเป็นต้องมีการควบคุมหรือบอกให้ขา GPIO นั้น ๆ ได้รู้ว่าต้องการจะให้ใช้รับค่าดิจิตอลเข้ามา หรือจะให้เขียนค่าออกไป ซึ่งจะใช้ฟังก์ชั่น pinMode() ในการกำหนด
ฟังก์ชั่น pinMode() มีรูปแบบการใช้งานดังนี้
void pinMode(int pin, int mode);
จะเห็นได้ว่าฟังก์ชั่นมีค่าพารามิเตอร์ 2 ตัว คือ
และไม่มีค่าที่ส่งกลับมา
เอาต์พุตแบบดิจิตอล ใช้ในการควบคุมอุปกรณ์แบบ 2 สถานะ คือเปิด และปิดเท่านั้น โดยการควบคุมจะใช้ขา GPIO ในการควบคุมการจ่ายจ่ายลอจิก ซึ่งขา GPIO จะรองรับการจ่ายกระแสสูงสุดเพียง 12mA เท่านั้น หากต้องการควบคุมอุปกรณ์ที่ใช้กระแสไฟฟ้ามาก จำเป็นต้องใช้วงจร หรืออุปกรณ์เช่น รีเลย์ ในการช่วยขับ ซึ่งการเขียนค่าเอาต์พุตแบบดิจิตอลจะใช้ฟังก์ชั่น digitalWrite() มีรูปแบบการใช้งานดังนี้
void digitalWrite(int pin, int value);
มีค่าพารามิเตอร์ 2 ตัว คือ
ไม่มีค่าที่ส่งกลับมา ทั้งนี้คำสั่ง digitalWrite() จะใช้คู่กับ pinMode() ที่ใช้กำหนดให้ขา GPIO มีสถานะเป็น OUTPUT หากไม่มีการใช้คำสั่ง pinMode() ก่อน หรือกำหนดโหมดเป็น INPUT จะทำให้ขานั้นเปิดใช้งานวงจร Pull-up ภายในที่ขานั้น ๆ แทน ซึ่งจะสามารถสังเกตได้จากขา GPIO จะไม่สามารถทำงานได้เต็มที่ หากต่อกับหลอด LED จะทำให้หลอด LED มีความสว่างน้อย
อุปกรณ์บางอย่างจำพวกสวิตซ์ และเซ็นเซอร์บางชนิด จะให้เอาต์พุตออกมาในรูปแบบดิจิตอล เราสามารถใช้คำสั่ง digitalRead() ในการอ่านค่าสถานะอินพุตแบบดิจิตอลได้ โดยมีรูปแบบการใช้งานดังนี้
int digitalRead(int pin);
มีค่าพารามิเตอร์ตัวเดียว ดังนี้
มีค่าที่ส่งกลับเป็นชนิด int มีค่าเป็น 1 (HIGH) หรือ 0 (LOW) ซึ่งจะเป็นค่าที่อ่านได้จากขา GPIO
อินเตอร์รัพท์ คือการขัดจังหวะการทำงานแบบปกติโปรแกรม โดยเมื่อมีการเกิดอินเตอร์รัพท์ จะทำให้โปรแกรมวิ่งเข้าไปทำงานในส่วนที่กำหนดไว้ การใช้งานอินเตอร์รัพท์จะมี 2 แบบ คือแบบภายใน และแบบภายนอก ในหัวข้อนี้เราจะมาลองใช้อินเตอร์รัพท์แบบภายนอกกัน
อินเตอร์รัพท์แบบภายนอก คือ การใช้สิ่งภายนอกมากระตุ้นทำให้เกิดการขัดจังหวะขึ้น นิยมใช้งานกับเซ็นเซอร์ต่าง ๆ เมื่อเซ็นเซอร์สามารถตรวจจับ หรือส่งสัญญาณ จะทำให้โปรแกรมสามารถตอบสนองได้ทันที โดยจะวิ่งออกจากโปรแกรมที่ทำอยู่ แล้วไปทำในส่วนของโปรแกรมที่กำหนดไว้จนเสร็จ แล้วจึงวิ่งกลับมาทำงานต่อจากจุดเดิม
การใช้งานอินเตอร์รัพท์แบบภายนอก สามารถใช้งานได้โดยใช้งานฟังก์ชั่น attachInterrupt() ซึ่งมีรูปแบบการใช้งานดังนี้
void attachInterrupt(int pin, void (*ISR)(void), int mode);
มีพารามิเตอร์อยู่ 3 ตัว คือ
และไม่มีการส่งค่ากลับ
ตัวอย่างโค้ดด้านล่างนี้ เป็นโค้ดที่กำหนดให้เมื่อกดสวิตซ์ IO0 บนบอร์ดแล้วจะแสดงคำว่า “Click !” บนหน้า Serial Monitor
ผลลัพธ์ที่ได้
บรรทัดที่ 1 สร้างฟังก์ชั่นที่ชื่อ click_fn
บรรทัดที่ 2 ส่งข้อความว่า “Click !”ไปที่ Serial Monitor
บรรทัดที่ 3 ใช้เครื่องหมาย } ระบุจุดสิ้นสุดคำสั่งในฟังก์ชั่น click_fn
บรรทัดที่ 4 ไม่นำมาวิเคราะห์
บรรทัดที่ 5 สร้างฟังก์ชั่น setup
บรรทัดที่ 6 ใช้ฟังก์ชั่นเริ่มต้นใช้งาน Serial ตั้งความเร็ว 9600
บรรทัดที่ 7 ไม่นำมาวิเคราะห์
บรรทัดที่ 8 ใช้ฟังก์ชั่นเริ่มใช้อินเตอร์รัพท์แบบภายนอกที่ขา 0 ในโหมด FALLING โดยเมื่อเกิดอินเตอร์รัพท์ขึ้นให้ไปเรียกฟังก์ชั่น click_fn
บรรทัดที่ 9 จบคำสั่งในฟังก์ชั่น setup
บรรทัดที่ 10 สร้างฟังก์ชั่น loop
บรรทัดที่ 11 จบคำสั่งในฟังก์ชั่น loop
อินพุต / เอาต์พุตแบบอนาล็อก คือการอ่านค่าแรงดันไฟฟ้า และการกำหนดให้ปล่อยแรงดันไฟฟ้า ได้ตามที่ต้องการ ในหัวข้อนี้จะรวมถึงการใช้งาน PWM ด้วย
ADC ย่อมาจาก Analog to Digital Converter ใช้ในการวัดแรงดันไฟฟ้า การใช้ ADC จะมีเรื่องของความเร็วในการวัด และความละเอียดในการวัด สำหรับ ESP32 สามารถใช้งาน ADC ได้ที่ความละเอียด 12 บิต หรือค่าที่ได้จะอยู่ในช่วง 0 – 4095 โดยค่าแรงดันที่วัดได้สูงสุดจะเรียกว่า แรงดันอ้างอิง สมมุติกำหนดให้แรงดันอ้างอิงเท่ากับ 3.3V หากวัดแรงดันได้ 3.3V จะอ่านค่าจาก ADC ได้ 4095 และหากวัดแรงดันได้ 1.62 จะอ่านค่าจาก ADC ได้ 2048 ทั้งนี้ค่าที่อ่านได้อาจจะไม่เที่ยงตรงบ้างเล็กน้อย ขึ้นอยู่กับปัจจัยหลาย ๆ อย่าง
ขาที่สามารถใช้งาน ADC ได้จะมีเฉพาะบางขาเท่านั้น สามารถดูได้จากรูป Pinout ในการอ้างอิงขา สามารถอ้างอิงตามหมายเลขขา GPIO ได้เลย หรืออ้างอิงตามช่อง ADC เช่น หากใช้ช่อง ADC0 ในโค้ดโปรแกรมจะต้องใส่ค่าพารามิเตอร์ของ ch เป็น A0 หรือเลือกใส่หมายเลขขา GPIO โดยใส่เป็น 36 เลยก็ได้
การอ่านค่า ADC จะใช้ฟังก์ชั่น analogRead() มีรูปแบบการใช้งานดังนี้
int analogRead(int ch);
มีพารามิเตอร์อยู่ตัวเดียว คือ
และมีการตอบกลับมาเป็นค่าที่อ่านได้ ซึ่งจะมีค่า 0 – 4095
สำหรับตัวอย่างการใช้งาน สามารถกดไปที่เมนู File > Examples > 01.Basics เลือก AnalogReadSerial
อัพโหลดโปรแกรมตัวอย่างลงบอร์ด NodeMCU-32S ได้เลย
เมื่ออัพโหลดเสร็จแล้ว ให้ต่อวงจรตามรูปด้านล่างนี้
เปิด Serial Monitor ขึ้นมา จากนั้นลองปรับตัวต้านทานปรับค่าได้แบบวอลุ่ม จะพบว่าตัวเลขที่แสดงเปลี่ยนไป
เพื่อให้เห็นภาพมากขึ้น กดปิดหน้าต่าง Serial Monitor แล้วกดไปที่เมนู Tool แล้วเลือก Serial Plotter
ค่าที่วัดได้แสดงออกมาเป็นกราฟ โดยค่าที่วัดได้จะเป็นแกน Y
จากตัวอย่าง AnalogReadSerial เราจะมาดูกันว่าโค้ดนี้สามารถทำงานได้อย่างไร โดยได้มีการตัดส่วนคอมเม้นและการเว้นบรรทัดออกแล้ว
บรรทัดที่ 1 สร้างฟังก์ชั่น setup
บรรทัดที่ 2 ใช้ฟังก์ชั่นเริ่มใช้การสื่อสารแบบ Serial ที่ความเร็ว 9600
บรรทัดที่ 3 จบคำสั่งในฟังก์ชั่น setup
บรรทัดที่ 4 สร้างฟังก์ชั่น loop
บรรทัดที่ 5 ใช้ฟังก์ชั่น analogRead() อ่านค่า ADC ที่ขา A0 หรือเทียบได้กับ GPIO36 แล้วนำค่าที่ได้ไปเก็บลงตัวแปร sensorValue
บรรทัดที่ 6 นำค่าในตัวแปร sensorValue มาแสดงผล
บรรทัดที่ 7 หน่วงเวลา 1 มิลิวินาที
บรรทัดที่ 8 จบคำสั่งในฟังก์ชั่น loop
การกำหนดค่าความละเอียดในการวัดค่า ADC – ใน ESP32 จะมีฟังก์ชั่นพิเศษที่ให้กำหนดค่าความละเอียดในการวัดได้ โดยใช้ฟังก์ชั่น analogReadResolution() ซึ่งมีรูปแบบการใช้งานดังนี้
void analogReadResolution(int bits);
มีค่าพารามิเตอร์ตัวเดียว คือ
และไม่มีการส่งค่ากลับ เมื่อกำหนดค่าความละเอียดของ ADC ใหม่ จะทำให้ค่าที่ได้จากฟังก์ชั่น analogRead() จะมีค่าสูงสุดน้อย หรือมากกว่าเดิม ซึ่งสามารถหาค่าสูงสุดได้จากสมการ 2bits – 1 สมมุติกำหนดให้ความละเอียดเป็น 10 บิต ค่าสูงสุดจะได้ 210 – 1 = 1023
ตัวอย่างนี้ มีการเพิ่มฟังก์ชั่น analogReadResolution() ลงไปในฟังก์ชั่น setup โดยตั้งให้ค่าความละเอียดเป็น 10 บิต
หลังจากอัพโหลด และปรับตัวต้านทานปรับค่าได้แบบวอลุ่มไปจนสุด พบว่าได้ค่าสูงสุดตามสมการคือ 1023
การแปลงค่าที่วัดได้เป็นแรงดันไฟฟ้า – สามารถแปลงได้โดยอาศัยความรู้คณิตศาสตร์เรื่องการเทียบบัญญัติไตรยางศ์ ซึ่งจะเป็นการนำค่าสูงสุด 2 ค่ามาเทียบกันแล้วนำค่าที่วัดได้มาคำนวณหาค่าเป็นแรงดัน ซึ่งสามารถพิจารณาได้ดังนี้
เมื่อค่าสูงสุดของคำสั่ง analogRead() คือ 4095 และ 4095 มีค่าเท่ากับ 3.3V เราจะนำค่าที่อ่านได้มาแปลงเป็นแรงดันได้จากหาว่าค่าที่ได้ 1 หน่วย จะได้แรงดันกี่โวล์ ซึ่งหาได้จาก 3.3V / 4095 = 0.00080586V จากนั้นจึงนำค่าที่ได้นี้ไปคูณกับค่าที่ได้จากฟังก์ชั่น analogRead() ได้เลย เรารู้ว่าแรงดันได้ครึ่งหนึ่งของ 3.3V คือ 1.65V เทียบได้กับค่าที่อ่านได้ 2047 ดังนั้นหากนำค่า 2047 ไปแทนฟังก์ชั่น analogRead() แรงดันที่คำนวณได้ควรจะเป็น 1.65V ด้วย เมื่อลองเอา 2047 ไปคูณกับ 0.00080586V ได้ 1.649V แสดงว่าสมการของเราถูกต้องแล้ว
จากตัวอย่าง AnalogReadSerial ในบรรทัดที่ 21 ได้มีการแก้ไขเพิ่มสมการแปลงค่าที่วัดได้เป็นแรงดัน
เมื่ออัพโหลดโปรแกรมและเปิด Serial Monitor ขึ้นมา พบว่ามีการแสดงค่าแรงดันที่วัดได้อย่างถูกต้อง
การวัดแรงดันที่สูงกว่า 3.3V – จำเป็นจะต้องใช้วงจรแบ่งแรงดัน (Voltage Dividers) เข้ามาช่วย โดยวงจรแบ่งแรงดันมีข้อจำกัดการวัดเช่นเดียวกัน โดยจะมีแรงดันสูงสุดที่สามารถวัดได้ และไม่สามารถใช้งานกับอุปกรณ์ที่ทำงานด้วยค่าความต้านทานเพื่อวัดแรงดันตกคร่อมได้ เนื่องจากอุปกรณ์ที่ใช้ค่าความต้านทานจะทำให้ค่าความต้านทานของวงจรเปลี่ยนแปลงไปและทำงานได้ไม่ตรงกับที่ออกแบบไว้
รูปแบบของวงจรแบ่งแรงดันมีดังนี้
จะเห็นได้ว่าวงจรประกอบไปด้วยตัวต้านทาน 2 ตัวต่ออนุกรมกัน ซึ่งสังเกตว่าแรงดันที่เข้า ADC (to ADC) คือแรงดันที่ตกคร่อม R2 ซึ่งแรงดันที่ตกคร่อม R2 สามารถหาได้จากสมการ
ทั้งนี้การเลือกใช้ค่าความต้านทานจะต้องคำนึงถึงกระแสไฟฟ้าที่ไหลผ่านด้วย ควรกำหนดค่าตั้งแต่ 1kΩ ขึ้นไป แต่ไม่ควรสูงถึงระดับ 1MΩ เนื่องจากค่าความต้านทานอินพุตของขา ADC ที่อยู่ในระดับ MΩ จะทำให้ค่าความต้านทานรวมวงจรผิดเพี้ยนไปมาก
สำหรับค่าความต้านทานของตัวต้านทาน 2 ตัว ที่นิยมใช้งานคือ R1 = 75kΩ และ R2 = 10kΩ ซึ่งเมื่อมีแรงดันไฟฟ้าเข้ามา 28V จะให้แรงดันเอาต์พุตประมาณ 3.3V ดังนั้นวงจรจึงสามารถวัดแรงดันได้สูงสุด 28V
หากใช้วงจรแบ่งแรงดันก่อนเข้าขา ADC แล้ว จะต้องเปลี่ยนสมการเพื่อให้สามารถคำนวณค่าแรงดันได้ถูกต้องด้วย โดยสามารถแก้ตัวเลข 3.3 ในสมการเป็นค่าแรงดันสูงสุดที่สามารถวัดได้ ๆ เลย
ตัวอย่างการวัดแรงดันที่สูงกว่า 3.3V ให้ต่อวงจรดังรูปด้านล่างนี้ ทั้งนี้สายที่ต่ออยู่กับแบตเตอรี่ 9V ในวงจรท่านสามารถเปลี่ยนเป็นเซ็นเซอร์ แหล่งจ่ายไฟ หรืออื่น ๆ ได้
จากโปรแกรมเดิมในหัวข้อ การแปลงค่าที่วัดได้เป็นแรงดันไฟฟ้า แก้ตัวเลข 3.3 ในบรรทัดที่ 21 เป็นเลข 28 จากนั้นอัพโหลดลงบอร์ดได้เลย
ตามหลักการแล้ว เมื่อเปิด Serial Monitor จะพบว่าสามารถอ่านค่าแรงดันได้ถูกต้อง
แต่เนื่องจากพบว่า ESP32 ยังมีบัคที่ตัวฮาร์ดแวร์ที่ไม่สามารถอ่านค่า ADC แบบลิเนียร์ได้ ทำให้ค่าที่อ่านได้ไม่ตรงกับความเป็นจริง หากผู้อ่านทดสอบแล้วพบว่าค่าไม่ตรงกับความเป็นจริง ให้อัพเดทโค้ดใหม่ เนื่องจากผู้พัฒนาได้ใช้วิธีการทางซอฟแวร์เพื่อทำให้ได้ค่าที่ตรง
PWM ย่อมาจาก Pulse Width Modulation ใช้สำหรับควบคุมอุปกรณ์แบบอนาล็อก โดยหลักการของ PWM คือสร้างความถี่ที่มีคาบเวลาเปิด – ปิดไม่เท่ากัน ซึ่งสามารถแสดงลักษณะสัญญาณได้ตามรูปด้านล่างนี้
คาบเวลาเปิด จะถูกเรียกว่า ดิวตี้ไซเคิล (Duty Cycle) ซึ่งค่านี้มักระบุเป็นร้อยละ หรือ % ทั้งนี้ในการใช้งานจริงจะสามารถควบคุมได้ตามจำนวนบิตที่ฮาร์ดแวร์รองรับ เช่น ควบคุมได้ความละเอียด 8 บิต จะหมายถึงควบคุมได้ค่า 0 – 255 หรือควบคุมได้สูงสุด 28 = 255
ใน ESP32 จะไม่รองรับ PWM ทางฮาร์ดแวร์โดยตรง โดยจะใช้ Timer ในการสร้างสัญญาณ PWM ขึ้นมาแทน ซึ่งมีจำนวนทั้งหมด 16 ตัว สามารถกำหนดความถี่ได้อิสระ และสามารถกำหนดค่าความละเอียดได้สูงสุด 16 บิต โดยไลบารี่ที่ใช้คือ LEDC
LEDC เป็นไลบารี่ที่ใช้สร้างความถี่สี่เหลี่ยมขึ้นมา โดยสามารถนำไปใช้สร้างสัญญาณ PWM รวมทั้งสร้างสัญญาณขับบัสเซอร์ได้ โดยพื้นฐานของ LEDC จะใช้ Timer ในการทำงาน และหากต้องการให้ขาใดเป็น OUTPUT สัญญาณ ก็จะต้องนำขานั้นไปผูกติดกับ Timer ตัวนั้น ๆ ซึ่งมีคำสั่งใช้งานดังนี้
void ledcSetup(byte channel, double freq, byte resolution_bits);
มีรายละเอียดของพารามิเตอร์แต่ละตัวดังนี้
และไม่มีการตอบกลับ
ต่อมาคือฟังก์ชั่น ledcAttachPin() ซึ่งใช้ผูก Timer เข้ากับขา GPIO มีรูปแบบการใช้งานดังนี้
void ledcAttachPin(int pin, byte channel);
มีรายละเอียดของพารามิเตอร์ดังนี้
และไม่มีค่าที่ตอบกลับ
นอกจากนี้ การกำหนดค่าดิวตี้ไซเคิลจะกำหนดที่ตัว Timer โดยตรง โดยใช้ฟังก์ชั่น ledcWrite() ซึ่งมีรายละเอียดการใช้งานดังนี้
void ledcWrite(byte channel, int duty);
มีรายละเอียดของพารามิเตอร์ดังนี้
และไม่มีค่าที่ตอบกลับ ค่าดิวตี้ไซเคิลที่สามารถตั้งได้จะขึ้นอยู่กับค่าพารามิเตอร์ resolution_bits ในฟังก์ชั่น ledcSetup() ซึ่งจะสามารถหาค่าที่กำหนดได้สูงสุดโดยใช้สูตร 2resolution_bits – 1 เช่น กำหนดไว้ที่ 13 บิต จะสามารถกำหนดได้สูงสุด 213 – 1 = 8191
ตัวอย่างการใช้งาน PWM สามารถดูได้จากโค้ดด้านล่างนี้ โดยผลที่ได้คือหลอด LED บนบอร์ด NodeMCU-32S สว่างมากขึ้นเรื่อย ๆ
บรรทัดที่ 1 ประกาศตัวแปร i แบบ int กำหนดค่าเป็น 0 ใช้เก็บค่าดิวตี้ไซเคิล
บรรทัดที่ 2 ไม่นำมาวิเคราะห์
บรรทัดที่ 3 สร้างฟังก์ชั่น setup
บรรทัดที่ 4 ใช้ฟังก์ชั่น ledcSetup() ตั้งค่า Timer เพื่อใช้สร้างสัญญาณ PWM โดยกำหนดใช้ Timer ช่องที่ 0 กำหนดความถี่ PWM เป็น 5kHz (5000) และกำหนดใช้ความละเอียด 13 บิต
บรรทัดที่ 5 ใช้ฟังก์ชั่น ledcAttachPin() กำหนดให้ขาที่ต่ออยู่กับหลอด LED บนบอร์ด NodeMCU-32S ใช้สัญญาณ PWM จาก Timer ช่องที่ 0
บรรทัดที่ 6 จบคำสั่งในฟังก์ชั่น setup
บรรทัดที่ 7 ไม่นำมาวิเคราะห์
บรรทัดที่ 8 สร้างฟังก์ชั่น loop
บรรทัดที่ 9 ใช้คำสั่ง ledcWrite() กำหนดค่าดิวตี้ไซเคิลลงใน Timer ช่องที่ 0 โดยใช้ค่าจากตัวแปร i
บรรทัดที่ 10 หน่วงเวลา 10 มิลิวินาที
บรรทัดที่ 11 ใช้ Ternary Operators เลือกค่าที่จะไปเซ็ตลงตัวแปร i ถ้าตัวแปร i น้อยกว่าหรือเท่ากับ 8191 ก็ให้นำค่าของ i + 100 ลงไปเซ็ต แต่ถ้าไม่ใช่ ให้เอา 0 ลงไปเซ็ต
บรรทัดที่ 12 จบคำสั่งในฟังก์ชั่น loop
DAC ย่อมาจาก Digital to Analog Converter ใช้กำหนดค่าแรงดันเอาต์พุตเพื่อนำไปควบคุมอุปกรณ์ที่ใช้แรงดันไฟฟ้าในการทำงาน ใน ESP32 มีให้ใช้งานจำนวน 2 ขา คือขา GPIO25 และ GPIO26 สามารถใช้งานได้ความละเอียด 8 บิต แรงดันเอาต์พุตสูงสุด 3.3V
ฟังก์ชั่นที่ใช้คือ dacWrite() โดยมีรูปแบบการใช้งานดังนี้
void dacWrite(int pin, int value);
มีรายละเอียดของพารามิเตอร์ดังนี้
และไม่มีค่าที่ตอบกลับ
การแปลงค่าแรงดันไฟฟ้าเป็น 0 – 255 – สามารถทำได้โดยใช้สูตร value = volt * 255 / 3.3
ข้อจำกัดกระแสไฟฟ้าที่สามารถจ่ายได้ – แรงดันที่ได้จากขา DAC มีกระแสไฟฟ้าไม่มากนัก หากต้องการใช้งานกระแสที่มากสามารถใช้ออปแอมป์ (Operational amplifier : Opamp) เข้ามาช่วยขยายกระแสได้ โดยใช้การจัดวงจรแบบบัฟเฟอร์ (Buffer) ตัวอย่างวงจรบัฟเฟอร์แสดงดังรูปด่านล่างนี้
ทั้งนี้ออปแอมป์ที่ใช้ควรคำนึงถึงแหล่งจ่ายเป็นสำคัญ อย่างเบอร์ LM324 LM358 สามารถใช้งานแบบแหล่งจ่ายไฟเดี่ยวได้ และต้องมีแรงดันไฟเลี้ยงสูงกว่าแรงดันอินพุต นั่นคือแรงดันไฟเลี้ยงของออปแอมป์ควรอยู่ที่ประมาณ 5 – 15V จึงจะสามารถให้แรงดันเอาต์พุตถึง 3.3V ได้
การใช้ DAC จ่ายแรงดันมากกว่า 3.3V – สามารถทำได้โดยใช้ออปแอมป์ช่วยขยายให้แรงดันสูงเท่าที่ต้องการ โดยใช้การจัดวงจรแบบวงจรขยายสัญญาณแบบไม่กลับเฟส (Non-Inverting Amplifier) ตัวอย่างของการใช้งานออปแอมป์ช่วยขยายแรงดันจาก 3.3V เป็น 5V แสดงดังรูปด้านล่างนี้
ด้วยข้อจำกัดของตัวต้านทานที่มีเฉพาะบางค่าเท่านั้น ทำให้แรงดันเอาต์พุตที่ได้เมื่อมีแรงดันเข้า 3.3V คือ 6.6V ทั้งนี้หากผู้อ่านต้องการแรงดันเอาต์พุตสูงสุดมากกว่านี้ สามารถคำนวณค่า R1 และ R2 ใหม่ได้ โดยใช้สูตร
ทั้งนี้ออปแอมป์ก็มีข้อจำกัดเรื่องแรงดันไฟฟ้าที่สามารถจ่ายได้สูงสุดซึ่งขึ้นอยู่กับแรงดันไฟเลี้ยงสูงสุดที่รับได้ โดยส่วนใหญ่แล้วออปแอมป์จะสามารถรองรับแรงดันไฟเลี้ยงได้สูงสุดประมาณ 30V ซึ่งแรงดันเอาต์พุตที่สามารถรองรับได้คือประมาณ 30V เช่นเดียวกัน
บัสเซอร์แบบพาสซีฟ จำเป็นต้องใช้ความถี่เข้าไปป้อน จึงจะสามารถส่งเสียงออกมาได้ การขับบัสเซอร์แบบพาสซีฟใน ESP32 จำเป็นต้องเรียกใช้ไลบารี่ LEDC เพื่อช่วยในการสร้างความถี่ออกไป ทั้งนี้ฟังก์ชั่นที่ใช้บางตัวจะเหมือนกับการใช้ PWM ท่านสามารถย้อนกลับไปอ่านรายละเอียดของแต่ละฟังก์ชั่นได้ในหัวข้อ การใช้งาน PWM
ในการขับบัสเซอร์แบบพาสซีฟ จะต้องใช้ Timer ในการสร้างความถี่ออกไปผ่านฟังก์ชั่นในไลบารี่ LEDC โดยฟังก์ชั่นที่ใช้มีดังนี้
void ledcWriteTone(byte channel, double freq);
โดยมีรายละเอียดของพารามิเตอร์ดังนี้
และไม่มีการตอบกลับ
ส่วนคำสั่งที่ใช้ควบคุมการส่งสัญญาณออกไป คือ
void ledcAttachPin(int pin, byte channel);
โดยมีรายละเอียดของพารามิเตอร์ดังนี้
และไม่มีค่าที่ตอบกลับมา
และหากต้องการยกเลิกการส่งสัญญาณเสียงออกไป สามารถใช้ฟังก์ชั่น ledcDetachPin() ได้ โดยมีรูปแบบการใช้งานดังนี้
void ledcDetachPin(uint8_t pin);
มีพารามิเตอร์ตัวเดียว คือ
ตัวอย่างต่อไปนี้ เป็นตัวอย่างของการขับบัสเซอร์แบบพาสซีฟ โดยเลือกความถี่ 2kHz และเลือกให้ขับสัญญาณออกไปที่ขา GPIO23
อัพโหลดโค้ดต่อไปนี้ลงบอร์ด NodeMCU-32S
จากนั้น ต่อวงจรดังรูปด้านล่างนี้
จากผลการทดลอง จะพบว่าบัสเซอร์มีการส่งเสียงออกมาสลับกับการหยุดส่งเสียงทุก ๆ ครึ่งวินาที ซึ่งจะสามารถอธิบายโค้ดได้ดังนี้
บรรทัดที่ 1 ประกาศตัวแปร buzzer_pin แบบ int กำหนดค่าเป็น 23 ใช้เก็บหมายเลขขาที่ต่อกับบัสเซอร์
บรรทัดที่ 2 ไม่นำมาวิเคราะห์
บรรทัดที่ 3 สร้างฟังก์ชั่น setup
บรรทัดที่ 4 ใช้ฟังก์ชั่น ledcWriteTone() ตั้งค่าใช้ Timer ช่องที่ 0 สร้างความถี่ออกมา 2kHz (2000Hz)
บรรทัดที่ 5 จบคำสั่งในฟังก์ชั่น setup
บรรทัดที่ 6 ไม่นำมาวิเคราะห์
บรรทัดที่ 7 สร้างฟังก์ชั่น loop
บรรทัดที่ 8 ใช้ฟังก์ชั่น ledcAttachPin() กำหนดให้ส่งสัญญาณเสียงไปที่ขาในตัวแปร buzzer_pin โดยใช้สัญญาณจาก Timer ช่องที่ 0
บรรทัดที่ 9 หน่วงเวลา 500 มิลิวินาที หรือครึ่งวินาที
บรรทัดที่ 10 ใช้ฟังก์ชั่น ledcDetachPin() ยกเลิกการส่งสัญญาณเสียงไปที่ขาในตัวแปร buzzer_pin
บรรทัดที่ 11 หน่วงเวลา 500 มิลิวินาที หรือครึ่งวินาที
บรรทัดที่ 12 จบคำสั่งในฟังก์ชั่น loop
การขับบัสเซอร์ – ในตัวอย่างได้เลือกใช้โมดูลบัสเซอร์ที่มีวงจรขับในตัว ทำให้สามารถใช้งานได้ง่าย หากต้องการนำไปใช้งานจริงจำเป็นจะต้องออกแบบวงจรขับบัสเซอร์เอง ซึ่งวงจรขับบัสเซอร์สามารถใช้งานทรานซิสเตอร์มาช่วยขับได้ โดยวงจรเป็นไปตามด้านล่างนี้
ในบทนี้ได้สอนเกี่ยวกับการใช้งานควบคุม GPIO ทั้งเป็นอินพุต และเอาต์พุต รวมไปถึงการควบคุมอุปกรณ์แบบอนาล็อกด้วย PWM ผ่านไลบารี่ LEDC ใช้ DAC ขับแรงดัน รวมไปถึงการใช้ฟังก์ชั่นขับบัสเซอร์แบบพาสซิฟด้วย
ในบทนี้รวม ๆ จะเรียกว่าการสื่อสารแบบขนาน หมายถึงสามารถรับ-ส่งข้อมูลได้ด้วยการควบคุมบิตเดียว แต่สำหรับในบทถัดไปจะมาเริ่มเรื่องการสื่อสารแบบอนุกรมเพื่อสื่อสารกับอุปกรณ์ต่าง ๆ กัน