การใช้ไฟหายใจ LED โดยใช้ไมโครคอนโทรลเลอร์ 51 ตัว

Jun 11, 2026 ฝากข้อความ

[การแนะนำ]


เทคโนโลยีไมโครคอนโทรลเลอร์เป็นเทคโนโลยีกระแสหลักที่ขาดไม่ได้ในระบบอัตโนมัติทางอุตสาหกรรมสมัยใหม่ อิเล็กทรอนิกส์ วิศวกรรมไฟฟ้า และ Internet of Things (IoT) เมื่อชีวิตของเราฉลาดมากขึ้นเรื่อยๆ เทคโนโลยีไมโครคอนโทรลเลอร์ก็แทรกซึมเข้ามาในชีวิตประจำวันของเราแทบทุกด้าน เช่น หม้อหุงข้าวอัจฉริยะ ลำโพงอัจฉริยะ และอื่นๆ อีกมากมาย


ด้วยเหตุนี้ บทความในซีรีส์ "การเรียนรู้ไมโครคอนโทรลเลอร์ 51 ตัว" จึงมุ่งหวังที่จะช่วยให้ผู้เริ่มต้นเริ่มต้นใช้งานเทคโนโลยีไมโครคอนโทรลเลอร์ได้ เราจะเริ่มต้นด้วยงานที่ง่ายที่สุด-การเปิดไฟ LED ดวงเดียว- และค่อยๆ ดำเนินการไปสู่การใช้งานโมดูลต่างๆ เช่น ปุ่มควบคุม จอแสดงผล LCD1602 เซ็นเซอร์อุณหภูมิ DS18B20 และ DS1302 และการสื่อสารระหว่างไมโครคอนโทรลเลอร์สองตัว นอกจากนี้ เรายังจะครอบคลุมถึงโปรโตคอลการสื่อสารด้วยฮาร์ดแวร์ เช่น UART, I²C และ SPI ด้วยการรวมแนวคิดเหล่านี้เข้ากับเทคนิคการเขียนโปรแกรม C เราจะใช้-โครงการวิศวกรรมระดับโลกจริงเพื่อแสดงวิธีการเขียนโปรแกรม ซึ่งจะทำให้คุณสามารถใช้พอยน์เตอร์และโครงสร้าง C ได้อย่างยืดหยุ่นเพื่อให้บรรลุการเขียนโปรแกรมแบบโมดูลาร์


ตอนนี้ กลับไปที่หัวข้อหลัก: การใช้ไมโครคอนโทรลเลอร์ 51 ตัวเพื่อควบคุม LED และสร้างเอฟเฟกต์แสงหายใจ

 

[ไฟหายใจทำงานอย่างไร]


ก่อนอื่น เรามาดูกันว่าเอฟเฟกต์แสงหายใจทำงานอย่างไร
แสงหายใจจะค่อยๆ สว่างขึ้น แล้วค่อยๆ ดับลง วนซ้ำในลักษณะคล้ายการหายใจ อย่างไรก็ตาม เนื่องจากพินของไมโครคอนโทรลเลอร์สามารถส่งออกเป็น 1 (เปิด) หรือ 0 (ปิด) เท่านั้น แล้วจะบรรลุผลการเปลี่ยนแปลงแบบค่อยเป็นค่อยไปได้อย่างไร
นี่เป็นเพราะความคงอยู่ของการมองเห็นในดวงตาของเรา เมื่อเรามองสิ่งใดสิ่งหนึ่ง ภาพที่เกิดจากดวงตาของเราคงอยู่นาน 0.04 วินาที (พบตัวเลขนี้ทางออนไลน์)
หากเราคำนวณตาม 0.04 วินาที นั่นจะเท่ากับ 40 ms ดังนั้นเมื่อเปิดและปิด LED เป็นเวลา 20 ms ในแต่ละดวง จะปรากฏต่อสายตามนุษย์ราวกับว่าเปิดอยู่ตลอดเวลา

图片

ไฟ LED กระพริบเป็นเวลา 20 ms และดับเป็นเวลา 20 ms มีผลเหมือนกับการเปิดตลอดเวลาหรือไม่?

 

ฮ่าๆ มันแตกต่างแน่นอน เมื่อไฟสลับระหว่างเปิดและปิดทุกๆ 20 มิลลิวินาที เอฟเฟกต์ที่เราเห็นจะหรี่ลงกว่าการส่องสว่างอย่างต่อเนื่อง หากเราสมมติว่าความสว่างของแสงที่ส่องสว่างอย่างต่อเนื่องคือ 100% ความสว่างของแสงที่สลับระหว่างเปิดและปิดทุกๆ 20 มิลลิวินาทีจะเท่ากับ 50% ด้วยเหตุนี้เราจึงสามารถปรับความสว่างของ LED ได้

图片

 

ณ จุดนี้เราสามารถปรับความสว่างของ LED ได้ (โดยการตั้งค่าระยะเวลาของระดับสูงภายในรอบ 40ms) นี่คือหลักการเบื้องหลัง-วิธีการควบคุมความสว่างแบบ PWM (Pulse width Modulation) ที่เป็นที่รู้จัก และการตั้งค่าระยะเวลาของระดับสูงจะเทียบเท่ากับการปรับรอบการทำงาน (นั่นคือ ระยะเวลาของระดับสูงหารด้วยรอบทั้งหมด: 20/40=50%)


ปัจจัยที่สำคัญที่สุดคือรอบการทำงานนี้ ตัวอย่างเช่น หากช่วงเวลาคือ 20 ms โดยที่ LED สลับระหว่าง 10 ms เปิดและปิด 10 ms ความสว่างที่รับรู้จะยังคงอยู่ที่ 50% (กล่าวคือ รอบการทำงานคือ 10/20=50%)

ต่อไปเรามาดูวิธีการนำไปใช้ในโปรแกรมกัน

 

[การนำโปรแกรมไปใช้]


กำลังเปิดไฟ LED
ขั้นแรก เริ่มต้นด้วยการเปิดไฟ LED จากนั้นเราจะค่อยๆ ใช้เอฟเฟกต์แสงหายใจ ฮาร์ดแวร์ที่เราจะใช้มีดังนี้:

คณะกรรมการพัฒนา คณะกรรมการพัฒนาการฝึกอบรมไมโครคอนโทรลเลอร์ ZeroOne
รุ่นไมโครคอนโทรลเลอร์ STC89C52
อินเทอร์เฟซ LED ปักหมุด P4^4
图片

 

จากแผนผังเราจะเห็นว่า LED เชื่อมต่ออยู่กับขา P4^4 ของไมโครคอนโทรลเลอร์ เมื่อไมโครคอนโทรลเลอร์ส่งสัญญาณออกเป็น 1 ไฟ LED จะเปิดขึ้น เมื่อเอาต์พุตเป็น 0 ไฟ LED จะดับลง ดังนั้นโปรแกรมเปิดไฟ LED จึงค่อนข้างง่ายดังแสดงด้านล่าง:

info-299-230

 

 

โปรแกรมเปิด LED นั้นค่อนข้างง่าย ฉันแน่ใจว่าทุกคนรู้วิธีการทำเช่นนี้
 

การปรับความสว่าง LED


ต่อไปเราจะใช้ฟังก์ชันที่ช่วยให้สามารถปรับความสว่างได้ (เช่น ปรับรอบการทำงาน) ดังนี้

info-400-538


 

กำหนดตัวแปรคงที่ `duty_cycle` เพื่อจัดเก็บรอบการทำงาน เมื่อ `flag` เป็น 1 รอบการทำงานจะค่อยๆ เพิ่มขึ้นเป็น 255 จากนั้นตั้งค่า `flag` เป็น 0 และ `duty_cycle` จะค่อยๆ ลดลงจาก 255 เป็น 0 ทำซ้ำรอบนี้
ฮ่าๆ ถึงจุดนี้อาจจะคิดว่าไฟช่วยหายใจกำลังทำงานอยู่ แต่ก็ไม่ใช่ หากคุณไม่เชื่อฉันให้ลองใช้โค้ดด้านบนด้วยตัวเอง

แล้วปัญหาอยู่ที่ไหนกันแน่?


ปัญหาอยู่ที่การเรียกโดยตรงไปยังฟังก์ชันการตั้งค่าความสว่าง- `set_led_luminance()` ฟังก์ชันนี้ใช้เวลา 40 มิลลิวินาทีในการเสร็จสิ้นหนึ่งรอบ หมายความว่าไม่สามารถเปลี่ยนรอบการทำงานได้ในระหว่าง 40 มิลลิวินาทีเหล่านั้น ไม่เช่นนั้นการปรับความสว่างจะไม่ทำงาน เรามาดูฟังก์ชัน `breath_led` กันอีกครั้ง หลังจากการเรียก `set_led_luminance()` แต่ละครั้งเพื่อตั้งค่ารอบการทำงาน ระบบจะเปลี่ยนค่า `duty_cycle` ทันทีโดยไม่ต้องรอ 40 ms


ณ จุดนี้ เราจำเป็นต้องเพิ่มตัวจับเวลาซอฟต์แวร์เพื่ออัปเดตค่า `duty_cycle` หลังจากผ่านไป 40 ms โปรแกรมที่แก้ไขมีดังนี้:

info-495-656

 

 

หมายเหตุ: ระยะเวลาของตัวจับเวลาต้องมากกว่า 40 มิลลิวินาที (หมายความว่าค่าของ `s_breathCounter` ต้องมากกว่า 255) แต่ทางที่ดีควรตั้งค่าเป็นทวีคูณของรอบ ตัวอย่างเช่น หากวงจรของเราคือ 255 (เช่น 256 ค่าตั้งแต่ 0 ถึง 255) เราสามารถตั้งค่าให้เป็นสองเท่าของค่านั้นได้: 256 * 2 - 1=511 (เช่น 512 ค่าตั้งแต่ 0 ถึง 511)
เท่านี้คุณก็ทำได้แล้ว-แสงหายใจของเราเสร็จสมบูรณ์แล้ว! มันไม่ง่ายเหรอ? (* ̄︶ ̄)

 

ต่อไปคือส่วนโบนัสของวันนี้

แม้ว่าเราจะประสบความสำเร็จในการใช้เอฟเฟกต์แสงหายใจ แต่โค้ดยังไม่กระชับหรือสวยงามเพียงพอ-โดยจะใช้คำสั่ง if และ else มากมาย ลองดูว่าเราจัดรูปมันง่ายขึ้นอีกไหม

ก่อนอื่น มาทำให้ส่วนนี้ของฟังก์ชัน set_led_luminance() ง่ายขึ้น ดังแสดงในรูปด้านล่าง
 

图片

 

ก่อนที่เราจะทำให้มันง่ายขึ้น เรามาพูดถึงเคล็ดลับสั้นๆ เกี่ยวกับ C: ระดับบิต AND การดำเนินการกันก่อน

info-600-117

 

จากนี้ เรารู้ว่าไม่ว่าจะเป็น 1 หรือ 0 การดำเนินการในระดับบิต AND โดยที่ 0 จะให้ผลลัพธ์เป็น 0

ไม่ว่าจะเป็น 1 หรือ 0 การดำเนินการในระดับบิตและด้วย 1 จะให้ผลลัพธ์เป็นค่าดั้งเดิม

เพื่อความสะดวก เราใช้สัญลักษณ์เลขฐานสิบหก (นำหน้าด้วย "0x") ตัวอย่างเช่น 0xff สอดคล้องกับ 255 ในรูปทศนิยม ดังนั้น,

 

เมื่อตัวเลขที่น้อยกว่าหรือเท่ากับ 0xff ถูก ANDed ด้วย 0xff ผลลัพธ์จะเป็นตัวเลขนั้นเอง ดังที่แสดงด้านล่าง

info-534-63

 

 

จะเกิดอะไรขึ้นหากคุณดำเนินการระดับบิต AND ระหว่างตัวเลขที่มากกว่า 0xff ถึง 0xff

info-551-63

ผลลัพธ์จะเป็นเศษที่เหลือเมื่อหารตัวเลขนี้ด้วย (0xff + 1) (นั่นคือ ผลลัพธ์ยังคงอยู่ระหว่าง 0 ถึง 0xff)
ด้วยการดำเนินการระดับบิต AND นี้ โค้ดด้านบนจึงสามารถลดความซับซ้อนลงได้

info-550-64

 

 

ด้วยวิธีนี้ ค่าของ s_Counter จะอยู่ในช่วง 0x00 ถึง 0xff เสมอ
ในทำนองเดียวกัน ตัวจับเวลาของซอฟต์แวร์ในฟังก์ชัน Breath_led ด้านบนก็สามารถทำให้ง่ายขึ้นได้ดังนี้:

info-389-353

ในบรรทัดที่ 3 0x1ff คือ 511 ในรูปทศนิยม เงื่อนไขจะเป็นจริงเมื่อค่าของ s_breathCounter คือ (0x1ff+1) หรือ 512 เนื่องจาก 512 & 0x1ff=0. เครื่องหมายอัศเจรีย์ก่อนที่จะระบุว่าการดำเนินการเป็นระดับบิตเป็น NOT (ถ้าให้เจาะจงคือ จะตรงตามเงื่อนไขเมื่อค่าของ `s_breathCounter` เป็นผลคูณของ 512 ซึ่งช่วยลดความจำเป็นในการรีเซ็ต `s_breathCounter` ฉันหวังว่า คำอธิบายนี้ชัดเจน-โปรดคิดให้ละเอียด) หากตรงตามเงื่อนไข รอบการทำงานจะเริ่มเพิ่มขึ้นหรือลดลง


แต่ช่วงรอบการทำงาน 0 ถึง 255 ไม่ใช่เหรอ? เหตุใดบรรทัด 5 จึงกลายเป็น 0x1ff (511) ด้วย ไม่ต้องกังวล-ดูที่บรรทัด 8 เราจะลบ 0xff อีกครั้ง ดังนั้นช่วงรอบการทำงานจึงยังคงเป็น 0 ถึง 255


บรรทัดที่ 7–10 หมายถึง: เมื่อ `duty_cycle > (0xff)` เช่น 256–511 การลบ 0xff จะเท่ากับการเพิ่มจาก 1 เป็น 255 ดังนั้นความสว่างจะค่อยๆ เพิ่มขึ้น


เมื่อหน้าที่_รอบ<= 0xff, the duty_cycle increases from 0 to 255, while the set brightness is 255 - duty_cycle. This effectively decreases the brightness from 255 to 0, causing the light to gradually dim. This achieves the breathing light effect.


ฮ่าฮ่า คุณคิดว่าการทำให้ง่ายขึ้นของเราจบลงแล้วหรือยัง?

 

ไม่ ไม่ ไม่

จริงๆ แล้ว บรรทัดที่ 7 ถึง 10 สามารถทำให้ง่ายขึ้นได้อีก นี่คือจุดที่ฟังก์ชันค่าสัมบูรณ์มีประโยชน์

อะไร เหตุใดจึงต้องใช้ฟังก์ชันค่าสัมบูรณ์?

 

ดูที่บรรทัดที่ 10: 0xff - Duty_cycle เทียบเท่ากับ Duty_cycle - 0xff แล้วรับค่าสัมบูรณ์ เอาล่ะ นี่คือโค้ดแบบง่าย:

set_led_luminance(ABS(รอบการทำงาน - (0xff)));

 

 

ฟังก์ชันมาโครสำหรับการรับค่าสัมบูรณ์มีดังนี้

#define ABS(N) ((N) < 0 ? -(N) : (N))

 

สุดท้ายนี้ ฉันได้รวมโค้ดแบบง่ายทั้งหมดไว้ด้านล่างนี้

 

info-562-684

คุณคิดอย่างไร? มันไม่ง่ายเหรอ? (* ̄︶ ̄)

ส่งคำถาม

whatsapp

โทรศัพท์

อีเมล

สอบถาม