เคล็ดลับที่ฉันได้เรียนรู้เกี่ยวกับการใช้นาฬิกาเรียลไทม์ DS3231 เพื่อขัดจังหวะ Arduino
คุณต้องการระบุเวลาที่แม่นยำเมื่อ Arduino จะรันส่วนโค้ดพิเศษในแบบร่าง โดยไม่ต้องใช้ตัวจับเวลาและตัวนับในฮาร์ดแวร์ Arduino คุณมีทักษะและประสบการณ์ในการเขียนโค้ดด้วย Arduino IDE และต้องการหลีกเลี่ยงการใช้คำสั่งโค้ด เช่น delay()
คุณต้องการเชื่อมต่อโมดูลนาฬิกาเรียลไทม์ DS3231 ที่แม่นยำมากเป็นแหล่งของการขัดจังหวะภายนอกแทน อาจเป็นสิ่งสำคัญสำหรับคุณที่ DS3231 สามารถใช้แบตเตอรี่เพื่อรักษาเวลาที่แม่นยำ แม้ว่า Arduino จะสูญเสียพลังงานชั่วคราวก็ตาม
สุดท้ายนี้ คุณต้องการเรียนรู้วิธีใช้ไลบรารี DS3231.h โดย Andrew Wickert ที่อ้างถึงในข้อมูลอ้างอิงออนไลน์ของ Arduino: https://www.arduino.cc/reference/en/libraries/ds3231/ มันมีเทคนิคบางอย่างที่สามารถพิสูจน์ได้ว่าคุ้มค่ากับความพยายามที่จะเชี่ยวชาญ คุณสามารถนำเข้าไลบรารีนี้ไปยัง Arduino IDE ของคุณได้โดยใช้ Library Manager (เครื่องมือ > จัดการไลบรารี...)
ไปทีละขั้นตอน บทช่วยสอนนี้สาธิตขั้นตอนต่อไปนี้:
หากคุณต้องการให้รหัสพิเศษทำงานมากกว่าหนึ่งครั้ง ตามช่วงเวลาที่คุณระบุ รหัสของคุณสามารถดำเนินการขั้นตอนที่ 3 อีกครั้งและตั้งค่าการเตือนใหม่ได้ ตัวอย่างภาพร่างที่มาพร้อมกับบทช่วยสอนนี้จะขัดจังหวะ Arduino ซ้ำๆ ทุกๆ 10 วินาที
บทช่วยสอนนี้ดึงมาจากการอ้างอิง "อย่างเป็นทางการ" รวมถึง:
attachInterrupt()
: https://www.arduino.cc/reference/en/ language/functions/external-interrupts/attachinterrupt/ รหัสพิเศษในตัวอย่างนี้ไม่สำคัญ: จะพิมพ์เฉพาะเวลาปัจจุบันจาก DS3231 เท่านั้น ตัวอย่างในชีวิตจริงอาจทำสิ่งที่มีประโยชน์ เช่น รดน้ำต้นไม้ หรือบันทึกการวัดอุณหภูมิ ไม่ว่างานจะเป็นเช่นไร รหัสควรจะอยู่ในบล็อกพิเศษของตัวเองเพื่อให้ทำงานเฉพาะเมื่อสัญญาณเตือน DS3231 ขัดจังหวะ Arduino
ฉันเชื่อว่าเป็นวิธีปฏิบัติที่ดีที่จะแบ่งโค้ดออกเป็นฟังก์ชันสั้นๆ โดยแต่ละฟังก์ชันจะจัดการงานเดียวหรือชุดงานที่เกี่ยวข้องเพียงชุดเดียว ชื่อของฟังก์ชันสามารถเป็นอะไรก็ได้ ทำไมไม่ทำให้มันอธิบายว่าฟังก์ชั่นทำอะไร? นี่คือส่วนหนึ่งของฟังก์ชันของฉันที่รันโค้ดพิเศษในตัวอย่างนี้
void runTheSpecialCode() {
// get the current time
// using the DateTime and RTClib classes
// defined in DS3231.h
DateTime dt = RTClib::now();
// print the current time
Serial.print(dt.hour()); Serial.print(":");
if (dt.minute() < 10) Serial.print("0");
Serial.print(dt.minute()); Serial.print(":");
if (dt.second() < 10) Serial.print("0");
Serial.println(dt.second());
// There will be more to do here, as you will see.
// This is enough, for now, to illustrate the idea:
// put special code in its own, special function
}
คุณจะเดินสายไฟระหว่างพินห้าคู่ แต่ละคู่ทำหน้าที่ด้านไฟฟ้าเพียงอย่างเดียว และจับคู่พินบน Arduino กับพินที่สอดคล้องกันบน DS3231 ค่อยๆ เชื่อมต่อแต่ละคู่ จากนั้นตรวจสอบปลายทั้งสองเพื่อให้แน่ใจว่าแต่ละสายไปในที่ที่ควรจะเป็น ตารางแสดงรายการคู่ตามลำดับที่แนบจากซ้ายไปขวาบน DS3231 จาก Arduino Uno
วัตถุประสงค์ | DS3231 พิน | พิน Arduino |
---|---|---|
เตือน | ตร.ว | 3* |
เอสซีแอล | เอสซีแอล | เอสซีแอล** |
สดีเอ | สดีเอ | สดีเอ** |
กำลังไฟ 5 โวลต์ | วีซีซี | 5V |
พื้น | จีเอ็นดี | จีเอ็นดี |
อย่างที่ฉันบอกไป ใช้เวลาสร้างความสัมพันธ์เหล่านี้ ช้าและแน่นอนมักเป็นวิธีที่เร็วที่สุดในการทำสิ่งที่ถูกต้องให้เสร็จสิ้น
เราจะพูดคุยกับโมดูล DS3231 โดยใช้ "วัตถุ" DS3231 ซึ่งเป็นกล่องเครื่องมือซอฟต์แวร์ประเภทหนึ่งที่มีชื่ออยู่ ไลบรารี DS3231 กำหนดฟังก์ชันต่างๆ มากมาย ซึ่งถือเป็นเครื่องมือภายในกล่อง เมื่อเราต้องการใช้ฟังก์ชัน เราจะเขียนชื่อของกล่องเครื่องมือ ตามด้วยจุด ตามด้วยชื่อของเครื่องมือ ตัวอย่างร่างจะสร้างตัวแปร "นาฬิกา" เพื่อจุดประสงค์นี้ จากนั้นร่างจะสามารถเข้าถึงเครื่องมือในกล่อง "นาฬิกา" เครื่องมือทั้งหมดได้รับการประกาศไว้ในไฟล์ DS3231.h ตามที่กล่าวไว้ข้างต้น
#include <DS3231.h>
DS3231 clock;
Serial.println(clock.getMinute()); // the current minute, 0..59
เราจะใช้เครื่องมือในวัตถุ "นาฬิกา" เพื่อตั้งปลุก แต่ก่อนอื่นเราต้องคำนวณเวลาปลุกก่อน
ขั้นตอนนี้ถือว่าคุณได้ตั้งเวลาจริงบน DS3231 ไว้ก่อนหน้านี้ ภาพร่างตัวอย่างประกอบด้วยโค้ดที่คุณสามารถใช้เพื่อตั้งเวลาบนนาฬิกาได้ ในกรณีที่คุณต้องการ เพียงลบตัวคั่นความคิดเห็น /* และ */ ที่ล้อมรอบออก
ตัวอย่างแบบร่างในบทช่วยสอนนี้จะคำนวณเวลาปลุกในอนาคตโดยการเพิ่มช่วงเวลาเป็นจำนวนวินาทีเข้ากับเวลาปัจจุบัน ตัวอย่างนี้เพิ่มอีกสิบวินาที นาทีจะเพิ่มเป็น 60 วินาที หนึ่งชั่วโมงจะบวกกับ 3,600 วินาที หนึ่งวัน 86,400 วินาที และอื่นๆ.
ไลบรารี DS3231 มี "เคล็ดลับ" ที่ซ่อนอยู่ซึ่งทำให้ง่ายต่อการเพิ่มเวลาเป็นจำนวนวินาที คุณจะไม่พบเคล็ดลับนี้ในรายการฟังก์ชันที่มีอยู่ในหน้า README ของไลบรารี DS3231 เมื่อดูจากไฟล์ DS3231.h ก็ไม่ชัดเจนนักเช่นกัน รายละเอียดบางส่วนรออยู่ในไฟล์โค้ด DS3231.cpp ต่อไปนี้เป็นขั้นตอนในการคำนวณ
now()
ซึ่งจำเป็นต้องเข้าถึงด้วยวิธีพิเศษสามารถรวมขั้นตอนที่ 4 และ 5 เข้าด้วยกันได้
const Uint32_t interval = 10; // number of seconds to add
DateTime currentTime; // default declaration
currentTime = RTClib::now(); // RTClib is defined in DS3231.h
uint32_t currentSeconds = currentTime.unixtime(); // express the date in seconds
DateTime alarmTime(currentSeconds + interval); // add 10 seconds and create a new date
แม้ว่าอ็อบเจ็กต์ alarmTime จะถูกสร้างขึ้นตามจำนวนวินาที แต่ก็มีเครื่องมือในกล่องเครื่องมือเพื่อแสดงปี เดือน วัน ชั่วโมง นาที และวินาที เราตั้งเวลาปลุกบน DS3231 ตามที่อธิบายไว้ถัดไป โดยใช้อ็อบเจ็กต์ alarmTime เป็นแหล่งที่มาของค่าที่เราต้องการ
ตัวอย่างเช่น สมมติว่าเวลาปัจจุบันที่โมดูล DS3231 รายงานคือ 7 วินาทีผ่านเวลา 10:42 น. ของเช้าวันพุธที่ 27 ตุลาคม 2021 เวลาปลุกที่คำนวณข้างต้นจะเป็น 10:42:17 น. ของวันเดียวกันนั้น หรือสิบวินาทีต่อมา
DS3231 มีสัญญาณเตือนให้เลือก 2 แบบ ได้แก่ สัญญาณเตือน #1 (A1) และสัญญาณเตือน #2 (A2) นาฬิกาปลุกทั้งสองแบบสามารถระบุวันและเวลาได้ โดยลงไปได้ถึงหนึ่งนาที ข้อแตกต่างคือสามารถระบุ A1 เพิ่มเติมได้จนถึงระดับวินาที นาฬิกาปลุกแต่ละตัวมีคู่ฟังก์ชันของตัวเองในไลบรารี DS3231 สำหรับตั้งเวลาปลุกและอ่านเวลานั้น ฟังก์ชันทั้งหมดเข้าถึงได้ผ่านวัตถุ DS3231 ตัวอย่างเช่นอันที่เราตั้งชื่อว่า "นาฬิกา":
clock.setA1Time(), clock.getA1Time(), clock.setA2Time() และ clock.getA2Time()
ฟังก์ชัน setA1Time() รับพารามิเตอร์แปดตัว ดังที่แสดงไว้ในใบเสนอราคานี้จากไฟล์ DS3231.h:
void setA1Time(byte A1Day, byte A1Hour, byte A1Minute, byte A1Second, byte AlarmBits, bool A1Dy, bool A1h12, bool A1PM);
การอ่านไฟล์ส่วนหัว DS3231.h อย่างละเอียดสามารถอธิบายพารามิเตอร์ได้ สิ่งต่อไปนี้คือความพยายามของฉันที่จะอธิบายสิ่งเหล่านี้ให้ตัวเองฟังอีกครั้งด้วยคำพูดของฉันเอง หากผู้อ่านพบความแตกต่างระหว่างเวอร์ชันของฉันกับไฟล์ส่วนหัว ให้ถือว่าส่วนหัวนั้นถูกต้อง
พารามิเตอร์ห้าตัวแรกเป็นประเภท "ไบต์" เว็บไซต์ cppreference กำหนดประเภทไบต์ด้วยวิธีนี้ https://en.cppreference.com/w/cpp/types/byte:
std::byte เป็นประเภทที่แตกต่างที่ใช้แนวคิดของไบต์ตามที่ระบุไว้ในคำจำกัดความภาษา C ++
เช่นเดียวกับถ่านและถ่านที่ไม่ได้ลงนาม สามารถใช้เพื่อเข้าถึงหน่วยความจำดิบที่ถูกครอบครองโดยอ็อบเจ็กต์อื่น (การแสดงอ็อบเจ็กต์) แต่ไม่เหมือนกับประเภทเหล่านั้น มันไม่ใช่ประเภทอักขระและไม่ใช่ประเภทเลขคณิต ไบต์เป็นเพียงชุดของบิต และตัวดำเนินการเดียวที่กำหนดไว้สำหรับไบต์นั้นคือตัวดำเนินการระดับบิต
เราสามารถปล่อยให้ตัวเองนึกถึงตัวแปรประเภทไบต์สำหรับวันและเวลาราวกับว่าตัวแปรเหล่านั้นเป็นจำนวนเต็มที่ไม่ได้ลงนามในสถานการณ์เฉพาะนี้ สามารถเก็บค่าจำนวนเต็มระหว่าง 0 ถึง 255 ข้อควรระวัง: ผู้เขียนโค้ดต้องหลีกเลี่ยงค่าที่ไร้สาระ ตัวอย่างเช่น ค่า 102 ไม่สมเหตุสมผลสำหรับพารามิเตอร์ใดๆ เหล่านี้ เป็นหน้าที่ของคุณในฐานะนักเขียนโค้ดในการจัดหาคุณค่าที่สมเหตุสมผล
มาต่อกันที่ alarmTime ที่สร้างในขั้นตอนก่อนหน้า: วันที่ 27 ของเดือน เวลา 17 วินาที ผ่าน 10:42 น. ในตอนเช้า รายการด้านล่างแสดงวิธีที่คุณสามารถใส่ค่าเหล่านั้นลงในฟังก์ชันได้ ฉันแสดงรายการพารามิเตอร์แต่ละตัวในบรรทัดของตัวเอง เพื่อให้มนุษย์สามารถอ่านได้ง่ายขึ้น และเพื่อให้มีพื้นที่สำหรับแสดงความคิดเห็น ตัวอย่างที่นี่ไม่สมบูรณ์ มันแสดงให้เห็นเฉพาะค่าประเภทไบต์สำหรับวันที่และเวลา ฟังก์ชันนี้ต้องการพารามิเตอร์เพิ่มเติมตามที่อธิบายไว้ด้านล่าง และจะไม่ทำงานในรูปแบบที่แสดงไว้ที่นี่
อย่างไรก็ตาม โปรดสังเกตว่าตัวแปร "นาฬิกา" และ "alarmTime" เป็นวัตถุ กล่าวคือ เป็นกล่องเครื่องมือซอฟต์แวร์ อย่างที่คุณเห็น เราใช้เครื่องมือจากภายในกล่องเครื่องมือที่เกี่ยวข้องเพื่อเข้าถึงข้อมูลที่ออบเจ็กต์มีอยู่
clock.setA1Time(
alarmTime.day(), // the day of the month: 27
alarmTime.hour(), // the hour of the day: 10
alarmTime.minute(), // the minute of the hour: 42
alarmTime.second(), // the second of the minute: 17
// ... the remaining parameters are explained below
);
พารามิเตอร์ชนิดไบต์ถัดไปที่ชื่อว่า AlarmBits เป็นเพียงชุดของบิตเท่านั้น บิตมีชื่อตามที่กำหนดไว้ในเอกสารข้อมูล DS3231 (ในหน้า 11)
บิต 7 | บิต 6 | บิต 5 | บิต 4 | บิต 3 | บิต 2 | บิต 1 | บิต 0 |
---|---|---|---|---|---|---|---|
- | - | - | DyDt | A1M4 | A1M3 | A1M2 | A1M1 |
บิตเมื่อรวมกันจะทำให้เกิด "หน้ากาก" หรือรูปแบบ ซึ่งจะบอก DS3231 ว่าควรส่งสัญญาณเตือนภัยเมื่อใดและบ่อยเพียงใด ตารางในหน้า 12 ของแผ่นข้อมูลให้ความหมายสำหรับคอลเลกชันต่างๆ ของบิต จากตารางนั้น ตัวอย่างแบบร่างในบทช่วยสอนนี้ใช้คอลเลกชันของบิตต่อไปนี้:
- | - | - | DyDt | A1M4 | A1M3 | A1M2 | A1M1 |
---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 |
การจัดเรียงบิตนี้สามารถแสดงอย่างชัดเจนในโค้ด: 0x00001110
โดยจะสั่งให้ DS3231 ส่งสัญญาณแจ้งเตือนเมื่อใดก็ตามที่ "วินาทีตรงกัน" นั่นคือเมื่อค่า "วินาที" ของการตั้งค่าสัญญาณเตือนตรงกับค่า "วินาที" ของเวลาปัจจุบัน
พารามิเตอร์สามตัวสุดท้ายของฟังก์ชัน setA1Time()
คือค่าบูลีนหรือค่าจริง/เท็จ พวกเขาแจ้งข้อมูลเพิ่มเติมแก่ DS3231 เกี่ยวกับวิธีประเมินการตั้งค่าสัญญาณเตือน ส่วนของโค้ดต่อไปนี้แสดงการเรียก setA1Time() ที่เสร็จสมบูรณ์ โดยดำเนินการต่อตามตัวอย่างที่เริ่มต้นด้านบน:
clock.setA1Time(
alarmTime.day(), // the day of the month: 27
alarmTime.hour(), // the hour of the day: 10
alarmTime.minute(), // the minute of the hour: 42
alarmTime.second(), // the second of the minute: 17
0x00001110, // AlarmBits = signal when the seconds match
false, // A1Dy false = A1Day means the date in the month;
// true = A1Day means the day of the week
false, // A1h12 false = A1Hour in range 0..23;
// true = A1Hour in range 1..12 AM or PM
false // A1PM false = A1Hour is a.m.;
// true = A1Hour is p.m.
);
ในภาพร่างตัวอย่าง ซึ่งเราตั้งค่าให้ปลุกขัดจังหวะทุกๆ 10 วินาที เฉพาะพารามิเตอร์ A1Second และ AlarmBits เท่านั้นที่สำคัญ อย่างไรก็ตาม เราจำเป็นต้องระบุทั้งหมดเมื่อเราเรียกใช้ฟังก์ชันไปที่ setA1Time()
ค่าที่ถูกต้องนั้นไม่ยากไปกว่าการระบุค่าขยะ เราอาจดูแลพวกเขาด้วย
ฟังก์ชัน setA2Time()
ทำงานคล้ายกัน แต่ไม่มีพารามิเตอร์เป็นเวลาวินาที ใช้เวลาสักครู่เพื่อตรวจทานบรรทัดที่ 119 ถึง 145 ของไฟล์ DS3231.h ในไลบรารีและหน้า 11-12 ในแผ่นข้อมูล นั่งอดทนกับข้อมูลอ้างอิงเหล่านี้จนกว่าคุณจะพบข้อมูลที่จำเป็นในการตั้งเวลาปลุก
หลังจากตั้งเวลาแล้ว ร่างจะต้องดำเนินการเพิ่มเติมเพื่อเปิดใช้งานการเตือนใน DS3231 ฉันแนะนำให้ผู้อ่านปฏิบัติตามลำดับสามขั้นตอนอย่างสม่ำเสมอ แม้ว่าบางขั้นตอนอาจดูเหมือนจำเป็นน้อยลงในบางครั้งด้วยเหตุผลบางประการก็ตาม หากรหัสของคุณต้องผิดพลาด ก็ปล่อยให้มันผิดพลาดอย่างแน่นอน
สำหรับสัญญาณเตือน A1 คำแนะนำในไลบรารี DS3231 จะเป็นดังนี้:
turnOffAlarm(1); // clear the A1 enable bit in register 0Eh
checkIfAlarm(1); // clear the A1 alarm flag bit in register 0Fh
turnOnAlarm(1); // set the A1 enable bit in register 0Eh
สำหรับสัญญาณเตือน A2 เพียงเปลี่ยนพารามิเตอร์เป็น 2 ตัวอย่างเช่น: checkIfAlarm(2); // clear A2 flag bit in register 0Fh
ปัญหาที่อธิบายใน repo นี้โดย @flowmeter เน้นว่าต้องล้างแฟล็กสัญญาณเตือนทั้งสองรายการก่อนที่ DS3231 จะสามารถส่งสัญญาณสัญญาณเตือนได้ เพื่อให้แน่ใจ ให้ลองเรียก checkIfAlarm() สองครั้ง หนึ่งครั้งสำหรับการเตือนแต่ละครั้ง แม้ว่าคุณจะใช้การเตือนเพียงอันเดียวก็ตาม :
checkIfAlarm(1);
checkIfAlarm(2);
เหตุใดผู้เขียนโค้ดจึงเลือกที่จะ "ตรวจสอบ" สัญญาณเตือนที่พวกเขาเชื่อว่าไม่ได้ส่งสัญญาณในปัจจุบัน เหตุผลก็คือฟังก์ชัน checkIfAlarm()
มีผลข้างเคียงที่ไม่ชัดเจน มันจะล้างบิตการตั้งค่าสถานะการเตือน เราใช้ฟังก์ชัน checkIfAlarm()
เนื่องจากเป็นฟังก์ชันเดียวในไลบรารี DS3231 ที่ดำเนินการที่จำเป็น
ลองคิดดูสิ ด้วยเหตุผลที่จะอธิบายด้านล่าง ฮาร์ดแวร์การตรวจจับการขัดจังหวะของ Arduino ต้องการให้แรงดันไฟฟ้าบนพิน SQW ของ DS3231 สูงก่อนที่จะเกิดสัญญาณเตือน เหตุการณ์การเตือนเปลี่ยนแปลงสองสิ่งภายใน DS3231:
พิน SQW จะยังคงต่ำตราบใดที่บิตแฟล็กสัญญาณเตือน ตัวใดตัวหนึ่ง ยังคงตั้งค่าอยู่ ตราบใดที่บิตแฟล็กสัญญาณเตือนภายใน DS3231 เก็บพิน SQW ไว้ต่ำ Arduino จะไม่สามารถตรวจจับสัญญาณเตือนได้อีกต่อไป ต้องล้างบิตแฟล็กสัญญาณเตือนทั้งคู่เพื่อให้ DS3231 คืนค่าแรงดันไฟฟ้าสูงบนพินสัญญาณเตือน SQW โปรดดูการอภิปรายเกี่ยวกับบิต 1 และ 0 ใน "การลงทะเบียนสถานะ (0Fh)" บนหน้าที่ 14 ของเอกสารข้อมูล DS3231
สัญญาณเตือนแต่ละตัวจะมีบิตแฟล็กสัญญาณเตือนของตัวเองอยู่ภายใน DS3231 บิตแฟล็กสัญญาณเตือนตัวใดตัวหนึ่งสามารถเก็บพิน SQW LOW ได้ DS3231 จะไม่ล้างบิตแฟล็กสัญญาณเตือนด้วยความคิดริเริ่มของตัวเอง เป็นหน้าที่ของผู้เขียนโค้ดในการล้างบิตแฟล็กสัญญาณเตือนหลังจากที่สัญญาณเตือนเกิดขึ้น
ลูปหลักของคุณไม่จำเป็นต้องวัดเวลา จำเป็นต้องตรวจสอบแฟล็กเพื่อดูว่ามีสัญญาณเตือนเกิดขึ้นหรือไม่ ในตัวอย่างนี้ แฟล็กนี้เป็นตัวแปรบูลีนชื่อ "alarmEventFlag":
if (alarmEventFlag == true) {
// run the special code
}
โดยส่วนใหญ่ แฟล็กจะเป็น false และการวนซ้ำจะข้ามโค้ดพิเศษ ร่างนี้ตั้งธงอย่างไร? สามขั้นตอน:
bool alarmEventFlag = false;
void rtcISR() {alarmEventFlag = true;}
attachInterrupt()
ที่ได้รับจาก Arduino IDE จะนำฟังก์ชันทั้งหมดมารวมกัน ตัวอย่างต่อไปนี้บอกให้ฮาร์ดแวร์ Arduino รันฟังก์ชัน rtcISR()
ทันทีทุกครั้งที่ตรวจพบสัญญาณ "FALLING" บนพินดิจิทัลที่กำหนดattachInterrupt(digitalPinToInterrupt(dataPin), rtcISR, FALLING);
ด้วยเหตุผลลึกซึ้งและลึกลับ ให้ใช้ฟังก์ชันพิเศษ digitalPinToInterrupt()
เสมอ เมื่อระบุหมายเลขพินสำหรับการขัดจังหวะ ฉันปล่อยให้มันเป็นแบบฝึกหัดสำหรับผู้อ่านที่จะค้นพบว่าทำไมเราถึงต้องการฟังก์ชันนั้น
สัญญาณ FALLING คืออะไร? หมายถึงการเปลี่ยนแปลงแรงดันไฟฟ้าเป็น LOW จาก HIGH ตามที่ตรวจพบโดยพินดิจิทัลของ Arduino การเปลี่ยนแปลงแรงดันไฟฟ้ามาจากไหน? มันเริ่มต้นที่พินสัญญาณเตือนของโมดูล DS3231 พินนั้นมีป้ายกำกับว่า SQW และปล่อยแรงดันไฟฟ้าสูง ใกล้กับระดับการจ่าย VCC (เช่น 5 โวลต์บน Uno) โดยส่วนใหญ่ สัญญาณเตือนทำให้ DS3231 เปลี่ยนแรงดันไฟฟ้าบนพิน SQW เป็น LOW Arduino ตรวจจับแรงดันไฟฟ้าที่มาจากพิน SQW และสังเกตเห็นการเปลี่ยนแปลง เราบอกให้ Arduino สังเกตว่า FALLING เนื่องจากเหตุการณ์นั้นเกิดขึ้นเพียงครั้งเดียวต่อการเตือนแต่ละครั้ง ในขณะที่ระดับ LOW สามารถคงอยู่และทำให้ Arduino สับสนจนทำให้เกิดการขัดจังหวะหลายครั้ง
พินใดที่สามารถตรวจจับการเปลี่ยนแปลงแรงดันไฟฟ้าที่ลดลงได้ สำหรับ Unos คุณสามารถเลือกพิน 2 หรือ 3 ได้ สำหรับ Leonardo อาจเป็นพิน 0, 1 หรือ 7 ใดก็ได้ (ใช่ ฉันรู้ Leonardo สัมผัสได้ถึงการขัดจังหวะบนพิน 2 และ 3 เช่นกัน อย่างไรก็ตาม สิ่งเหล่านี้คือ พิน I2C ของ Leonardo ซึ่งหมายความว่าโมดูล DS3231 จะใช้พวกมัน ฉันเริ่มต้นด้วยพิน 7 สำหรับการขัดจังหวะบน Leonardo) ภาพร่างตัวอย่างกำหนดตัวแปร dataPin และเตรียมค่าเริ่มต้นเป็น 3 สำหรับการรันบน Uno ด้วยวิธีนี้:
int dataPin = 3;
รหัสพิเศษสามารถตั้งเวลาปลุกใหม่ได้เช่นกัน หากคุณต้องการทำซ้ำ เริ่มต้นด้วยการคำนวณเวลาปลุกใหม่ ตามที่อธิบายไว้ในขั้นตอนที่ 3 และทำตามขั้นตอนต่อจากนั้น
ฉันคาดหวังว่าภาพร่างตัวอย่างจะสร้างเอาต์พุตคล้ายกับภาพประกอบด้านล่าง เมื่อรันบน Arduino Uno ที่เชื่อมต่อกับโมดูล DS3231 อย่างถูกต้อง ตามที่ฉันอธิบายไว้ในบทช่วยสอนนี้ อย่าแปลกใจถ้าเวลาที่แสดงแตกต่างออกไป คุณควรทำงานตามเวลาของคุณเองอยู่แล้ว