Arduino
delay() o'rniga millis(): bloklamaydigan tugma bosish mantiqi
Uzun bosishni delay(3300) bilan yozish oson. Lekin shu uch soniya davomida qurilma butunlay o'lik bo'ladi: MQTT uziladi, GPS o'qilmaydi, hech qanday buyruq qabul qilinmaydi.
Sodda yechim va uning narxi
Push-start moduliga uzun signal berish kerak bo'lganda birinchi ko'ringan yechim shunday bo'ladi:
void pressLong(uint8_t pin) {
digitalWrite(pin, HIGH);
delay(3300); // ← muammo shu yerda
digitalWrite(pin, LOW);
}
Bu ishlaydi. Lekin delay() protsessorni to'liq to'xtatadi. Uch soniya davomida:
- MQTT kutubxonasi
loop()chaqirilmaydi — broker qurilmani o'lgan deb hisoblaydi - GSM moduldan kelayotgan ma'lumot buferga sig'may yo'qoladi
- GPS qatorlari o'qilmaydi, koordinata eskirdi
- Yangi buyruq kelsa, u qabul qilinmaydi
- Watchdog taymer ishga tushib, platani qayta yuklashi mumkin
Amaliy oqibat. Menda avtomobil o't oldirgandan keyin telefon "qurilma javob bermayapti" deb ko'rsatardi. Buyruq bajarilgan, lekin holat qaytmagan — chunki o'sha paytda MQTT uzilgan edi.
Asosiy g'oya
Kutish o'rniga vaqtni belgilab qo'yish kerak. Ya'ni: "hozir tugmani bosdim, uni 3300 millisekunddan keyin qo'yib yuboraman" deb yozib qo'yamiz va darhol boshqa ishlarga qaytamiz.
Har loop() aylanishida shunchaki tekshiramiz: vaqt keldimi? Kelgan bo'lsa — pinni tushiramiz.
Amalga oshirish
Uchta o'zgaruvchi yetarli: qaysi pin bosilgan, qachon bosilgan, qancha ushlanishi kerak.
struct Press {
uint8_t pin = 255; // 255 = bo'sh
uint32_t startMs = 0;
uint16_t holdMs = 0;
};
Press active;
bool pressBegin(uint8_t pin, uint16_t holdMs) {
if (active.pin != 255) return false; // band
active.pin = pin;
active.startMs = millis();
active.holdMs = holdMs;
digitalWrite(pin, HIGH);
return true;
}
void pressUpdate() {
if (active.pin == 255) return;
if (millis() - active.startMs >= active.holdMs) {
digitalWrite(active.pin, LOW);
active.pin = 255;
}
}
Endi asosiy tsikl toza va uzluksiz ishlaydi:
void loop() {
mqtt.loop(); // aloqa uzilmaydi
gpsRead(); // koordinata yangilanadi
sensorsUpdate(); // harorat o'qiladi
pressUpdate(); // tugma o'z vaqtida qo'yib yuboriladi
}
Nima uchun ayirma, taqqoslash emas
E'tibor bering, shart shunday yozilgan: millis() - startMs >= holdMs. Buni millis() >= startMs + holdMs deb yozish mumkindek tuyuladi, lekin bu xato.
millis() taxminan 49 kundan keyin nolga qaytadi. Agar qurilma o'sha paytda tugmani bosayotgan bo'lsa, ikkinchi variant abadiy kutishga tushadi. Birinchi variant esa to'g'ri ishlaydi, chunki belgilanmagan butun sonlar ayirmasi to'lib ketishni o'zi hisobga oladi.
Band holatni qaytarish
Funksiya false qaytarganda buyruq bajarilmagan bo'ladi. Buni foydalanuvchiga bildirish kerak, aks holda u tugmani qayta-qayta bosaveradi:
if (!pressBegin(PIN_START, T_LONG)) {
publishState("busy"); // telefon "kuting" deb ko'rsatadi
}
Bu bir vaqtda ikkita buyruq bajarilishining oldini oladi. Avtomobilda bu muhim — "qulfla" va "ochish" bir vaqtda ishga tushsa, modul noaniq holatga tushishi mumkin.
Xuddi shu naqsh boshqa joylarda
Bloklamaydigan yondashuv faqat tugmalar uchun emas. Men uni bir nechta joyda ishlataman:
| Vazifa | Bloklaydigan usul | Bloklamaydigan usul |
|---|---|---|
| Harorat o'qish | delay(750) | So'rov yuborib, keyin o'qish |
| Holat yuborish | Har tsiklda | 5 soniyada bir marta |
| Qayta ulanish | delay(5000) | Vaqt belgisi bilan |
| Svetodiod miltillashi | Ikki delay() | Interval tekshiruvi |
DS18B20 harorat datchigi yaxshi misol. U o'lchash uchun 750 millisekund vaqt talab qiladi. Kutish o'rniga: so'rov yuboriladi, vaqt belgilanadi, keyingi tsikllarda boshqa ishlar bajariladi va vaqt kelganda natija o'qiladi.
Qachon delay() joiz
Har doim ham uni tashlash shart emas. delay() quyidagi hollarda muammo tug'dirmaydi:
setup()ichida, hali hech narsa ishlamayotgan paytda- Juda qisqa pauzalarda — 1–5 millisekund
- Faqat bitta ish bajaradigan sodda qurilmalarda
Lekin tarmoqqa ulangan qurilmada asosiy tsikl ichida uzun delay() — bu deyarli har doim keyinchalik tushunarsiz xatolarga aylanadi.
Xulosa
State machine yondashuvi kodni biroz uzunroq qiladi, lekin qurilmani tirik saqlaydi. NBcaR da bu o'zgarishdan keyin MQTT uzilishlari butunlay to'xtadi va holat telefonda darhol yangilanadigan bo'ldi.
Qoida: asosiy tsikl hech qachon to'xtamasin. Kutish kerak bo'lsa — vaqtni belgilang, kutmang.