SHOW:
|
|
- or go back to the newest paste.
1 | /* | |
2 | ВНИМАНИЕ! ПУТЬ К ПАПКЕ СО СКЕТЧЕМ НЕ ДОЛЖЕН СОДЕРЖАТЬ РУССКИХ СИМВОЛОВ | |
3 | ВО ИЗБЕЖАНИЕ ПРОБЛЕМ ПОЛОЖИТЕ ПАПКУ В КОРЕНЬ ДИСКА С | |
4 | ||
5 | Внимание! При первом запуске initial_calibration должен быть равен 1 (строка №17) | |
6 | При подключении и открытии монитора порта будет запущен процесс калибровки. | |
7 | Вам нужно при помощи вольтметра измерить напряжение на пинах 5V и GND, | |
8 | затем отправить его в монитор В МИЛЛИВОЛЬТАХ, т.е. если на вольтметре 4.56 | |
9 | то отправить примерно 4560. После этого изменить initial_calibration на 0 | |
10 | и заново прошить Arduino. | |
11 | Если хотите пропустить процесс калибровки, то введите то же самое напряжение, | |
12 | что было показано вам при калибровке (real VCC). И снова прошейте код. | |
13 | */ | |
14 | /* | |
15 | ------------------------ЛОГИКА РАБОТЫ-------------------------- | |
16 | Дверь закрыта, нажато СНАРУЖИ - проснуться, ждать ввод пароля | |
17 | Дверь закрыта, нажато ВНУТРИ - открыть | |
18 | Дверь открыта, нажато СНАРУЖИ - закрыть | |
19 | Дверь открыта, нажато ВНУТРИ - закрыть | |
20 | Дверь открыта, нажат КОНЦЕВИК - закрыть | |
21 | ||
22 | Просыпаться каждые несколько секунд, следить за СОБЫТИЕМ | |
23 | Каждые несколько минут следить за напряжением акума | |
24 | Если акум разряжен: | |
25 | - открыть дверь (опционально) | |
26 | - запретить дальнейшее открытие и закрытие | |
27 | - при нажатии на кнопки мигать красным светодиодом | |
28 | - перестать следить за СОБЫТИЕМ | |
29 | ||
30 | //-----------------------ПАРОЛЬ------------------------ | |
31 | Когда система не спит, нажать кнопку смены пароля (скрытая кнопка). Попадаем в режим смены пароля: | |
32 | - Вводим пароль из цифр (МАКСИМУМ 10 ЦИФР!!!) | |
33 | - При нажатии * пароль записывается в память и система выходит из смены пароля | |
34 | - При нажатии # пароль сбрасывается (можно вводить заново) | |
35 | - Если ничего не нажимать 10 секунд, автоматически выйдем из режима смены пароля, пароль останется старый | |
36 | ||
37 | Когда система не спит (проснулись по кнопки или сон отключен), нажать * для входа в режим ввода пароля | |
38 | Если система спит и периодически просыпается проверять СОБЫТИЕ, то нажимаем * и удерживаем, пока не загорится красный светодиод | |
39 | Режим ввода пароля: | |
40 | - Обработка пароля сделана таким образом, что правильный пароль засчитывается только при наборе | |
41 | правильной последовательности цифр, то есть если пароль 345, то вводить можно любые числа до тех пор, | |
42 | пока не появится последовательность 345, т.е. 30984570345 откроет замок, так как оканчивается на 345 | |
43 | - Если пароль введён верно, дверь откроется | |
44 | - Если ничего не нажимать, через 10 секунд система вернётся в обычный (дежурный) режим | |
45 | //-----------------------ПАРОЛЬ------------------------ | |
46 | */ | |
47 | ||
48 | //-------------------------------НАСТРОЙКИ----------------------------------- | |
49 | #define lock_type 0 // 0 - сервопривод, 1 - щеколда, 2 - привод автомобильный | |
50 | ||
51 | #define tail_button 1 // 1 - используется концевик на закрытие, 0 - не используется | |
52 | #define sleep_time 10000 // время на ввод пароля после просыпания (если не начать вводить - уснёт) | |
53 | ||
54 | #define sleep_enable 0 // спящий режим с кнопкой проснуться (0 - выключить, 1 - включить) | |
55 | #define wake_button 0 // 1 - просыпаться только по наружной кнопке, 0 - просыпаться периодически и проверять СОБЫТИЕ | |
56 | boolean battery_monitor = 1; // измерение заряда акума (защита от переразряда) | |
57 | #define bat_low 3000 // напряжение акума в МИЛЛИВОЛЬТАХ, при котором сработает защита | |
58 | boolean open_bat_low = 1; // 1 - открыть дверь, если акум разряжен | |
59 | ||
60 | #define vol_calibration 0 // калибровка вольтметра (если работа от АКБ) 1 - включить, 0 - выключить | |
61 | ||
62 | //--------------СЕРВО-------------- | |
63 | #define servoMin 0 // угол сервы для положения "замок открыт", подбирается экспериментально | |
64 | #define servoMax 170 // угол сервы для положения "замок закрыт", подбирается экспериментально | |
65 | ||
66 | //--------------ЩЕКОЛДА-------------- | |
67 | boolean latch_inverse = 0; // 0 - если у вас реле высокого уровня или МОСФЕТ, 1 - если у вас реле низкого уровня | |
68 | int latch_time = 1000; // время (в миллисекундах), которое ток будет подаваться на защёлку для открытия | |
69 | ||
70 | //--------------ПРИВОД-------------- | |
71 | #define gear_inv 0 // инвертировать привод (1 или 0) | |
72 | ||
73 | //-------------------------------НАСТРОЙКИ----------------------------------- | |
74 | ||
75 | // автоматический выбор close_button: 0 - если используем захлопывающуюся щеколду, 1 если серво или привод замка | |
76 | #if lock_type == 1 | |
77 | #define close_button 0 | |
78 | #else | |
79 | #define close_button 1 | |
80 | #endif | |
81 | ||
82 | //---АВТОМАТИЧСЕКИЕ НАСТРОЙКИ В ЗАВИСИМОСТИ ОТ ТИПА ЗАМКА----- | |
83 | #if lock_type == 0 | |
84 | //-----------------СЕРВО---------------- | |
85 | #include <Servo.h> // используем библиотеку для работы с сервоприводом | |
86 | #define servo_pin A3 // серво на A3 | |
87 | Servo servo; // объявляем переменную servo типа Servo | |
88 | //-----------------СЕРВО---------------- | |
89 | #elif lock_type == 1 | |
90 | //-----------------ЩЕКОЛДА---------------- | |
91 | #define latch_pin A3 | |
92 | //-----------------ЩЕКОЛДА---------------- | |
93 | #elif lock_type == 2 | |
94 | //-----------------ПРИВОД---------------- | |
95 | #define relay1 A2 // пин реле 1 подключен к А2 | |
96 | #define relay2 A3 // пин реле 2 подключен к А3 | |
97 | #define gear_delay 400 // время (в мс), которое ток подаётся на привод (время открытия/закрытия) | |
98 | //-----------------ПРИВОД---------------- | |
99 | #endif | |
100 | //---АВТОМАТИЧСЕКИЕ НАСТРОЙКИ В ЗАВИСИМОСТИ ОТ ТИПА ЗАМКА----- | |
101 | ||
102 | //----------------------БИБЛИОТЕКИ------------------------ | |
103 | #include <EEPROMex.h> // библиотека для работы со внутренней памятью ардуино | |
104 | #include <LowPower.h> // библиотека сна | |
105 | #include "Keypad.h" //библиотека клавиатуры | |
106 | //----------------------БИБЛИОТЕКИ------------------------ | |
107 | ||
108 | //----------------------КЛАВИАТУРА------------------------ | |
109 | unsigned long pass_timer; | |
110 | char key; | |
111 | String str_pass = ""; | |
112 | byte pass_lenght, j; | |
113 | unsigned long int_pass; // 10 знаков моксимум!! | |
114 | char keys[4][3] = { | |
115 | {'1', '2', '3'}, | |
116 | {'4', '5', '6'}, | |
117 | {'7', '8', '9'}, | |
118 | {'*', '0', '#'} | |
119 | }; | |
120 | byte rowPins[] = {12, 11, 10, 9}; // Подключены строки (4 пина) | |
121 | byte colPins[] = {8, 7, 6}; // подключены столбцы (4 пина) | |
122 | Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, 4, 3 ); //иниициализировать клавиатуру | |
123 | //----------------------КЛАВИАТУРА------------------------ | |
124 | ||
125 | #define LEDgrn A0 // красный светодиод на А0 | |
126 | #define LEDred A1 // зелёный светодиод на А1 | |
127 | #define set_pass_btn 4 // кнопка смены пароля на 4 пин | |
128 | #define tail_pin 5 // кнопка концевика | |
129 | float my_vcc_const = 1.1; // начальное значение константы вольтметра | |
130 | ||
131 | boolean set_pass_btn_flag; // флажок кнопки смены пароля | |
132 | boolean batteryOK = true; // дверь можно закрыть, если акум заряжен | |
133 | boolean set_access_flag; // флажок режима смены пароля/ключа | |
134 | volatile boolean door_state; // состояние двери (1 - открыто, 0 - закрыто) | |
135 | volatile unsigned long awake_timer, auto_awake_timer, last_press; | |
136 | volatile boolean inside_btn_flag, close_flag, sleep_flag; | |
137 | volatile byte sleep_count; | |
138 | boolean wake_event = false, wait_for_event = true, wakeUP_procedure_flag = false; | |
139 | ||
140 | void setup() { | |
141 | Serial.begin(9600); // открыть порт для отладки | |
142 | if (vol_calibration) calibration(); // калибровка, если разрешена | |
143 | my_vcc_const = EEPROM.readFloat(1000); | |
144 | ||
145 | // ПАРОЛЬ | |
146 | int_pass = EEPROM.readLong(0); // вспоминаем пароль из памяти | |
147 | str_pass = String(int_pass, DEC); // переводим в строчный тип | |
148 | pass_lenght = str_pass.length(); // получиаем длину пароля | |
149 | // ПАРОЛЬ | |
150 | ||
151 | // подтянуть все кнопки | |
152 | pinMode(2, INPUT_PULLUP); | |
153 | pinMode(3, INPUT_PULLUP); | |
154 | pinMode(set_pass_btn, INPUT_PULLUP); | |
155 | pinMode(tail_pin, INPUT_PULLUP); | |
156 | ||
157 | pinMode(LEDred, OUTPUT); | |
158 | pinMode(LEDgrn, OUTPUT); | |
159 | digitalWrite(LEDred, 0); | |
160 | digitalWrite(LEDgrn, 0); | |
161 | ||
162 | // прерывания: 2 пин на внутреннюю кнопку | |
163 | attachInterrupt(0, inside_btn, FALLING); | |
164 | // 3 пин на внешнюю кнопку | |
165 | attachInterrupt(1, outside_btn, FALLING); | |
166 | ||
167 | //---АВТОМАТИЧСЕКИЕ НАСТРОЙКИ В ЗАВИСИМОСТИ ОТ ТИПА ЗАМКА----- | |
168 | #if lock_type == 1 // если щеколда | |
169 | pinMode(latch_pin, OUTPUT); | |
170 | digitalWrite(latch_pin, latch_inverse); | |
171 | #elif lock_type == 2 // если привод (2 реле) | |
172 | pinMode(relay1, OUTPUT); | |
173 | pinMode(relay2, OUTPUT); | |
174 | digitalWrite(relay1, 1); | |
175 | digitalWrite(relay2, 1); | |
176 | #endif | |
177 | //---АВТОМАТИЧСЕКИЕ НАСТРОЙКИ В ЗАВИСИМОСТИ ОТ ТИПА ЗАМКА----- | |
178 | close_door(); | |
179 | } | |
180 | ||
181 | // набор команд для открытия двери | |
182 | void open_door() { | |
183 | if (batteryOK) { // если акум заряжен | |
184 | digitalWrite(LEDgrn, 1); // зелёный свет | |
185 | digitalWrite(LEDred, 0); | |
186 | last_press = millis(); | |
187 | //--------ОТКРЫТЬ--------- | |
188 | #if lock_type == 0 | |
189 | servo.attach(servo_pin); // привязываем привод к порту | |
190 | servo.write(servoMin); // поворачиваем серву | |
191 | delay(500); // ждём поворот | |
192 | servo.detach(); // отвязываем привод | |
193 | #elif lock_type == 1 // если щеколда | |
194 | digitalWrite(latch_pin, !latch_inverse); // подать ток на защёлку | |
195 | delay(latch_time); // подождать | |
196 | digitalWrite(latch_pin, latch_inverse); // прекратить подачу тока | |
197 | #elif lock_type == 2 // если привод замка | |
198 | if (gear_inv) { // перещёлкнуть реле, подождать, все дела | |
199 | digitalWrite(relay1, 0); | |
200 | delay(gear_delay); | |
201 | digitalWrite(relay1, 1); | |
202 | } else { | |
203 | digitalWrite(relay2, 0); | |
204 | delay(gear_delay); | |
205 | digitalWrite(relay2, 1); | |
206 | } | |
207 | #endif | |
208 | //--------ОТКРЫТЬ--------- | |
209 | if (!close_button) { | |
210 | door_state = 0; // считать дверь закрытой (сама захлопнется) | |
211 | digitalWrite(LEDred, 0); // выключить свет | |
212 | digitalWrite(LEDgrn, 0); | |
213 | } | |
214 | else door_state = 1; // считать дверь открытой | |
215 | } else { // если акум разряжен | |
216 | for (int i = 0; i < 3; i++) { // мигать красным светодиодом | |
217 | digitalWrite(LEDred, 1); | |
218 | delay(500); | |
219 | digitalWrite(LEDred, 0); | |
220 | delay(500); | |
221 | } | |
222 | } | |
223 | if (sleep_enable) sleep_mode(); | |
224 | } | |
225 | ||
226 | // набор команд для закрытия двери | |
227 | void close_door() { | |
228 | if (batteryOK) { // если акум заряжен | |
229 | digitalWrite(LEDred, 1); // зелёный свет | |
230 | last_press = millis(); | |
231 | //--------ЗАКРЫТЬ--------- | |
232 | #if lock_type == 0 // если серво | |
233 | servo.attach(servo_pin); // привязываем привод к порту | |
234 | servo.write(servoMax); // поворачиваем серву | |
235 | delay(500); // ждём поворот | |
236 | servo.detach(); // отвязываем привод | |
237 | #elif lock_type == 1 // если щеколда | |
238 | // ничего не делать, щеколда же =) | |
239 | #elif lock_type == 2 // если привод замка | |
240 | if (gear_inv) { // перещёлкнуть реле, подождать, все дела | |
241 | digitalWrite(relay2, 0); | |
242 | delay(gear_delay); | |
243 | digitalWrite(relay2, 1); | |
244 | } else { | |
245 | digitalWrite(relay1, 0); | |
246 | delay(gear_delay); | |
247 | digitalWrite(relay1, 1); | |
248 | } | |
249 | #endif | |
250 | //--------ЗАКРЫТЬ--------- | |
251 | door_state = 0; | |
252 | delay(500); | |
253 | digitalWrite(LEDred, 0); // выключить свет | |
254 | digitalWrite(LEDgrn, 0); | |
255 | } else { // если акум разряжен | |
256 | for (int i = 0; i < 3; i++) { // мигать красным светодиодом | |
257 | digitalWrite(LEDred, 1); | |
258 | delay(500); | |
259 | digitalWrite(LEDred, 0); | |
260 | delay(500); | |
261 | } | |
262 | } | |
263 | if (sleep_enable) sleep_mode(); | |
264 | } | |
265 | ||
266 | void passChange() { | |
267 | digitalWrite(LEDred, 0); // | |
268 | digitalWrite(LEDgrn, 0); // зеленый свет | |
269 | delay(70); | |
270 | digitalWrite(LEDgrn, 1); // зеленый свет | |
271 | ||
272 | str_pass = ""; | |
273 | pass_timer = millis(); // сброс таймера ввода пароля | |
274 | while (1) { // бесконечный цикл | |
275 | key = keypad.getKey(); // обработка нажатия | |
276 | if (key != NO_KEY) { // если была нажата | |
277 | pass_timer = millis(); // сбросить таймер | |
278 | if (key == '*') { // если нажата * | |
279 | int_pass = str_pass.toInt(); // перевести в число | |
280 | EEPROM.writeLong(0, int_pass); // записать в память | |
281 | pass_lenght = str_pass.length(); // получиаем длину пароля | |
282 | Serial.println(str_pass); | |
283 | break; // выйти из цикла | |
284 | } | |
285 | else if (key == '#') { // если нажата # | |
286 | str_pass = ""; // начать ввод сначала | |
287 | } | |
288 | else { // если * не нажата | |
289 | str_pass += key; // прибавить нажатую цифру к паролю | |
290 | } | |
291 | } | |
292 | // если нажата кнопка смены пароля, просто выйти из режима смены пароля | |
293 | if (!digitalRead(set_pass_btn) && !set_pass_btn_flag) { | |
294 | str_pass = String(int_pass, DEC); | |
295 | awake_timer = millis(); | |
296 | set_pass_btn_flag = 1; | |
297 | break; | |
298 | } | |
299 | if (millis() - pass_timer > 10000) { // если сработал таймер | |
300 | str_pass = String(int_pass, DEC); // сбросить ввод и выйти из цикла | |
301 | break; | |
302 | } | |
303 | } | |
304 | digitalWrite(LEDgrn, 0); // погасить зеленый свет | |
305 | } | |
306 | ||
307 | void wakeUP_procedure() { | |
308 | ||
309 | } | |
310 | void sleep_procedure() { | |
311 | ||
312 | } | |
313 | ||
314 | void event() { | |
315 | key = keypad.getKey(); // обработка нажатия | |
316 | if (key == '*') { // если была нажата * | |
317 | pass_timer = millis(); // сбросить таймер | |
318 | digitalWrite(LEDgrn, 0); | |
319 | digitalWrite(LEDred, 1); | |
320 | j = 0; | |
321 | while (1) { // бесконечный цикл ввода пароля | |
322 | key = keypad.getKey(); // обработка нажатия | |
323 | if (key != NO_KEY) { // если была нажата | |
324 | pass_timer = millis(); // сбросить таймер | |
325 | if (key == str_pass[j]) { // если новая введённая цифра совпала с цифрой пароля | |
326 | j++; // прибавить счётчик | |
327 | } else { // если нет | |
328 | j = 0; // начать с начала | |
329 | } | |
330 | if (j == pass_lenght) { // если были введены все правильные цифры пароля | |
331 | digitalWrite(LEDred, 0); // вырубить красный | |
332 | digitalWrite(LEDgrn, 1); // включить зелёный | |
333 | open_door(); // открыть дверь | |
334 | break; // выйти из цикла | |
335 | } | |
336 | if (key == '#') { // если нажата # | |
337 | digitalWrite(LEDred, 0); // вырубить красный | |
338 | break; // выйти из цикла | |
339 | } | |
340 | } | |
341 | if (millis() - pass_timer > 10000) { // если сработал таймер | |
342 | break; // выйти из цикла | |
343 | } | |
344 | } | |
345 | } | |
346 | } | |
347 | ||
348 | // отработка прерывания нажатия изнутри | |
349 | void inside_btn() { | |
350 | if (millis() - last_press > 500) { // таймер повторного открытия (побеждает глюк с приводом!) | |
351 | auto_awake_timer = millis(); // сбросить таймер | |
352 | if (!door_state) // если дверь ЗАКРЫТА | |
353 | inside_btn_flag = 1; // флажок на открытие | |
354 | else // если дверь ОТКРЫТА | |
355 | close_flag = 1; // флажок на закрытие | |
356 | sleep_count = 0; // обнулить таймер вольтметра | |
357 | } | |
358 | } | |
359 | ||
360 | // отработка прерывания нажатия снаружи | |
361 | void outside_btn() { | |
362 | if (millis() - last_press > 500) { // таймер повторного открытия (побеждает глюк с приводом!) | |
363 | auto_awake_timer = millis(); | |
364 | if (door_state) { // если дверь ОТКРЫТА | |
365 | close_flag = 1; // флажок на закрытие | |
366 | } else { // если нет | |
367 | // проснуться и обнулить таймер | |
368 | digitalWrite(LEDred, 1); | |
369 | digitalWrite(LEDgrn, 1); | |
370 | wakeUP_procedure_flag = true; // выполнить 1 раз когда проснулся | |
371 | awake_timer = millis(); | |
372 | sleep_flag = 1; | |
373 | } | |
374 | sleep_count = 0; // обнулить таймер вольтметра | |
375 | } | |
376 | } | |
377 | ||
378 | void loop() { | |
379 | ||
380 | event(); | |
381 | ||
382 | // ---- ВЫПОЛНИТЬ КАК ПРОСНЁМСЯ ----- | |
383 | if (wakeUP_procedure_flag) { | |
384 | wakeUP_procedure(); | |
385 | wakeUP_procedure_flag = false; | |
386 | } | |
387 | // ---- ВЫПОЛНИТЬ КАК ПРОСНЁМСЯ ----- | |
388 | ||
389 | if (set_access_flag) { | |
390 | passChange(); | |
391 | set_access_flag = 0; | |
392 | } | |
393 | ||
394 | // если дверь была открыта и нажат концевик (кнопка закрыть) | |
395 | if (close_flag) { | |
396 | close_flag = 0; | |
397 | close_door(); // закрыть дверь | |
398 | } | |
399 | ||
400 | // если дверь закрыта и нажата кнопка открытия изнутри | |
401 | if (inside_btn_flag && !door_state) { | |
402 | inside_btn_flag = 0; | |
403 | open_door(); // команда для открытия двери | |
404 | } | |
405 | ||
406 | // отработка нажатия кнопки смены пароля | |
407 | if (!digitalRead(set_pass_btn) && !set_pass_btn_flag) { | |
408 | awake_timer = millis(); | |
409 | set_pass_btn_flag = 1; | |
410 | } | |
411 | if (digitalRead(set_pass_btn) && set_pass_btn_flag) { | |
412 | set_pass_btn_flag = 0; | |
413 | set_access_flag = 1; | |
414 | } | |
415 | // отработка нажатия кнопки смены пароля | |
416 | ||
417 | // если разрешён сон и прошло больше времени, чем по таймеру | |
418 | if (millis() - awake_timer > sleep_time && !set_access_flag) { | |
419 | if (!door_state) { // если дверь закрыта, выключить светодиоды | |
420 | digitalWrite(LEDred, 0); | |
421 | digitalWrite(LEDgrn, 0); | |
422 | sleep_flag = 0; | |
423 | } | |
424 | if (sleep_enable) { | |
425 | sleep_mode(); | |
426 | if (wake_button) awake_timer = millis(); | |
427 | } | |
428 | } | |
429 | if (!digitalRead(tail_pin) && door_state) { | |
430 | close_door(); | |
431 | } | |
432 | } | |
433 | ||
434 | ||
435 | // режим сна (зависит от того, измеряем мы напряжение акума или нет) | |
436 | void sleep_mode() { | |
437 | sleep_procedure(); | |
438 | if (!batteryOK) digitalWrite(LEDgrn, 0); | |
439 | delay(50); | |
440 | if (tail_button && door_state && close_button) { | |
441 | LowPower.powerDown(SLEEP_500MS, ADC_OFF, BOD_OFF); // спать 500 мс. mode POWER_OFF, АЦП выкл | |
442 | awake_timer = millis() + sleep_time; // КОСТЫЛЬ БЛЯ | |
443 | if (!digitalRead(tail_pin)) { | |
444 | close_door(); | |
445 | } | |
446 | } else { | |
447 | if (sleep_enable && wake_button && !battery_monitor) // если ничего не надо | |
448 | LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); // спать. mode POWER_OFF, АЦП выкл | |
449 | if (sleep_enable && wake_button && battery_monitor) { // если просто исзеряем акб | |
450 | LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF); // спать 8 сек. mode POWER_OFF, АЦП выкл | |
451 | awake_timer = millis() + sleep_time; // КОСТЫЛЬ БЛЯ | |
452 | battery_m(); | |
453 | } | |
454 | if (sleep_enable && !wake_button) { // если ловим событие + акб измеряем | |
455 | LowPower.powerDown(SLEEP_4S, ADC_OFF, BOD_OFF); // спать 4 сек. mode POWER_OFF, АЦП выкл | |
456 | awake_timer = millis() + sleep_time; // КОСТЫЛЬ БЛЯ | |
457 | delay(50); | |
458 | Serial.println("awake"); | |
459 | event_m(); | |
460 | if (battery_monitor) battery_m(); // если хотим ещё акб измерять, измеряем | |
461 | } | |
462 | } | |
463 | } | |
464 | void battery_m() { | |
465 | sleep_count++; | |
466 | if (sleep_count > 75) { // если прошло ~5 минут | |
467 | sleep_count = 0; // сбросить счётчик | |
468 | if (readVcc() < bat_low) { // если акум разряжен | |
469 | wait_for_event = false; // перестать ждать СОБЫТИЕ | |
470 | battery_monitor = false; // перестать мониторить АКБ | |
471 | //if (open_bat_low) open_door(); // открыть дверь (и уснуть) | |
472 | batteryOK = false; // запретить закрытие и открытие двери | |
473 | } | |
474 | } | |
475 | } | |
476 | void event_m() { | |
477 | if (wake_event) { | |
478 | // проснуться и обнулить таймер | |
479 | digitalWrite(LEDred, 1); | |
480 | digitalWrite(LEDgrn, 1); | |
481 | wake_event = false; | |
482 | wakeUP_procedure_flag = true; // выполнить 1 раз когда проснулся | |
483 | awake_timer = millis(); | |
484 | sleep_count = 0; // обнулить таймер вольтметра | |
485 | } | |
486 | } | |
487 | ||
488 | void calibration() { | |
489 | //--------калибровка---------- | |
490 | my_vcc_const = 1.1; // начальаня константа калибровки | |
491 | Serial.print("Real VCC is: "); Serial.println(readVcc()); // общаемся с пользователем | |
492 | Serial.println("Write your VCC (in millivolts)"); | |
493 | while (Serial.available() == 0); int Vcc = Serial.parseInt(); // напряжение от пользователя | |
494 | float real_const = (float)1.1 * Vcc / readVcc(); // расчёт константы | |
495 | Serial.print("New voltage constant: "); Serial.println(real_const, 3); | |
496 | EEPROM.writeFloat(1000, real_const); // запись в EEPROM | |
497 | while (1); // уйти в бесконечный цикл | |
498 | //------конец калибровки------- | |
499 | } | |
500 | ||
501 | long readVcc() { //функция чтения внутреннего опорного напряжения, универсальная (для всех ардуин) | |
502 | #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) | |
503 | ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); | |
504 | #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) | |
505 | ADMUX = _BV(MUX5) | _BV(MUX0); | |
506 | #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) | |
507 | ADMUX = _BV(MUX3) | _BV(MUX2); | |
508 | #else | |
509 | ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); | |
510 | #endif | |
511 | delay(2); // Wait for Vref to settle | |
512 | ADCSRA |= _BV(ADSC); // Start conversion | |
513 | while (bit_is_set(ADCSRA, ADSC)); // measuring | |
514 | uint8_t low = ADCL; // must read ADCL first - it then locks ADCH | |
515 | uint8_t high = ADCH; // unlocks both | |
516 | long result = (high << 8) | low; | |
517 | ||
518 | result = my_vcc_const * 1023 * 1000 / result; // расчёт реального VCC | |
519 | return result; // возвращает VCC | |
520 | } |