View difference between Paste ID: 7S0w9mHW and 5403xZup
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
}