Ардуино (Arduino). #28
Часы на RTC DS3231, с расширенными функциями v3
Продолжение проекта часов Часы на RTC DS3231, с расширенными функциями . После наработок в программе Универсальный таймер по управлению устройством с помощью всего трёх кнопок, пришёл к мнению, что такое управление необходимо внедрить в программу часов, созданных ранее.
Предыдущие проекты и основы этого
Описание
Предыдущий проект #21 Часы на RTC DS3231, с расширенными функциями подвергся сильнейшей переработке и поэтому решил под этот проект выделить отдельную страницу. Схема упростилась благодаря тому, что для управления используется всего три кнопки:
[MODE] - Настройка
[MINUS] - Убавить [-]
[PLUS] - Прибавить [+]
Переход по пунктам меню параметров настройки осуществляется по нажитаю на кнопку [MODE] . Во 2-м разряде индикатора выводится номер параметра. Далее каждый параметр может настраиваться кнопками [MINUS] и [PLUS] . Значение параметра отображается в 3-м и 4-м разрядах индикатора. Всего возможно настраивать 8 параметров:
Активность будильника 0|1
Установка часов будильника 0...23
Установка минут будильника 0...59
Настройка часов 0...23
Настройка минут 0...59
Яркость индикатора 0...7
Коэф. коррекции температуры для DS3231 +/-10° => 0...20.
Значение температуры вычисляется через отнимание 10, так:
–1° => установить 9 => 9-10 = -1°
+1° => установить 11 => 11-10 = +1°
Коэффициент коррекции давления +/-4.5 мм рт.ст. => 0..99.
Значение коррекции вычисляется через отнимание 50 и деление на 10, так:
+0.5 mm => установить 50 => 55-50 = 5 / 10 = +0.5 mm
-0.5 mm => установить 40 => 45-50 = -5 /10 = -0.5 mm
Индикация текущих значений при mode = 0 :
Время с DS3231
Температура с DS1820/DS3231
Давление с BMP280
Выход из меню настройки параметров осуществляется через выбор mode = 0 или автоматически через 16 секунд бездействия в меню настройки параметров.
Схема часов
Схема часов проще, чем в предыдущем проекте. Убрал лишние кнопки. Теперь осталось всего три кнопки для полного управления настройками часов. В остальном схема подобная предыдущим. Маленькая особенность: подключил управление индикатором к контактам 2 и 3 Ардуино.
Pic 1. Схема электрическая принципиальная для скетча #28
Перечень элементов
U1 – Arduino UNO R3 , Arduino Pro Mini , LGT8F328P , WAVGAT Nano или другое.
U2 – Модуль питания AC-DC на 5...6 В.
U3 – Модуль стабилизатора на +3,3 В, если нет на плате Arduino .
U4 – Модуль датчика абсолютного давления BMP280 .
DD1 – Датчик температуры семейства DS1820 .
RTC1 – Модуль реального времени DS3231 .
R1 – Резистор 4.7 кОм .
R2 – Резистор 10 кОм .
HL1 – Дисплей 4-х разрядный 7-и сегментный TM1637.
HL2 – Светодиод красный.
SA1 – Выключатель .
SB1...SB3 – Микрокнопка .
BA1 – Buzzer активный.
Скетч часов
Скетч часов претерпел сильные изменения, написаны новые функции вывода на индикатор. Постарался сделать всё более понятным и интуитивным. Главная особенность программы в том, что в неё заложена условная компиляция и автоматическое определение подключенных устройств (датчиков).
Условная компиляция позволяет легко перенастраивать скетч под любой используемый МК . Работоспособность программы проверена на следующих МК:
Arduino Uno R3 ;
Arduino Nano , Arduino Pro Mini ;
LGT8F328P * , WAVGAT Pro Mini * ;
WAVGAT Nano * .
Ниже на фото все проверенные платы Arduino , кроме Arduino Uno R3 .
Pic 2. Проверенные платы
Скетч написан так, что при наличии датчиков DS1820 и BMP280 , будут выводится значения с них, но если этих датчиков нет, или нет какого-то любого из них, то выводиться значения будут только с подключенных. Если не подключен внешний датчик семейства DS1820 , то температура будет выводиться со встроенного датчика температуры модуля реального времени. Проверка наличия подключенных датчиков осуществляется при включении. До включения можно подсоединять или отсоединять датчики, а после включения программа сама определит наличие датчиков и будет выводить их значения при индикации.
Весь код подробно закомментирован. Хочу лишь обратить внимание, что запись/чтение значения в/из EEPROM были проверены со всеми платами, кроме WAVGAT Nano * . Вначале запись в эту плату не удавалась, а потом не стал добавлять код для этой платы для работы с EEPROM .
Сам скетч и библиотеки можно скачать ниже в подразделе Приложение .
Показать скетч v3
/****************************************************************
2022-05-02 Mr.ALB v3.0 Создание управления часами
с помощью 3-х кнопок.
Часы на 4-х разрядном 7 сегментном индикаторе TM1637
и модуле реального времени DS3231 + датчик температуры
встроенный в DS3231 и датчик температуры внешний DS1820
+ датчик атмосферного давления BMP280
http://mralb.ru/sections/programming/arduino_28.php
Основа:
©2021-12...2022-04 Mr.ALB
Часы на RTC DS3231, с расширенными функциями
http://mralb.ru/sections/programming/arduino_21.php
Универсальный таймер
https://mralb.ru/sections/programming/arduino_24.php
ПОДКЛЮЧЕНИЕ:
Модуль RTC DS3231:
SCL - A5
SDA - A4
VCC - 5V
GND - GND
Кнопки управления подключить на пины и на GND
Датчик DS1820:
1 GND - GND
2 DQ - через 4.7кОм к VCC, и DQ к pin11
3 VCC - 5V
Датчик BMP280:
SCL - A5
SDA - A4
VCC - +3.3V
GND - GND
ИНДИКАТОР на TM1637:
CLK - D3
DIO - D2
VCC - 5V
GND - GND
Buzzer:
pin+ - D13
pin- - GND
HL2:
A - через R2 4.7k...10k к D10
K - GND
ИСТОРИЯ ИЗМЕНЕНИЙ:
2022-05-02 Mr.ALB v3.0 Использование условной компиляции.
Программа на WAVGAT Nano - китайской подделке
под Arduino Nano маркировка с МК стёрта,
но похоже на МК AVGA328 или LGT8F328
2022-05-10 Mr.ALB v3.1 Часы работают. Полное управление тремя
кнопками. Переходим к тестированию и отладке.
Потом будем добавлять сохранение параметров
в EEPROM.
2022-05-14 Mr.ALB Запись необходимых параметров в EEPROM
***** ОПИСАНИЕ *****
КНОПКИ:
[MODE] - Настройка
[MINUS] - Убавить [-]
[PLUS] - Прибавить [+]
При включении идёт тестирование подключения датчика температуры
DS1820.
Если датчик не подключен, то на индикаторе выводится 1 секунда
тип "3231" встроенного датчика температуры DS3231. И далее идёт
измерение температуры по встроенному датчику.
Если датчик температуры DS1820 подключен, то выводится
его тип "1820" 1 секунда.
Далее выводится разрешение датчика в 3-м и 4-м разрядах.
Все настройки осуществляются по нажитаю на кнопку MODE
Каждое нажатие - последовательный переход по параметрам.
Во 2-м разряде выводится номер параметра.
В 3-м и 4-м разрядах выводится значение параметра
mode=0 => Индикация текущих значений:
- Время DS3231
- Температура DS1820/DS3231
- Давление BMP280
Всего 8 пунктов меню MODE:
1 - Активность будильника 0|1
2 - Установка часов будильника
3 - Установка минут будильника
4 - Настройка часов
5 - Настройка минут
6 - Яркость индикатора 0...7
7 - Коэф. коррекции температуры DS3231 +/-10° =>0..20
Значение температуры вычисляется через
отнимание 10, так:
–1° => установить 9 => 9-10 = -1°
+1° => установить 11 => 11-10 = +1°
8 - Коэф. коррекции давления -5.0/+4.9 мм рт.ст. =>0..99
Значение коррекции вычисляется через
отнимание 50 и деление на 10, так:
+0.5 mm => 50 => 55-50 = 5 / 10 = +0.5 mm
-0.5 mm => 40 => 45-50 = -5 /10 = -0.5 mm
Выход через mode=0 или автоматически через 16 секунд
неактивности в меню MODE
Сигнал будильника только если он активен, при отключении
активности в mode=1 =>0 Сигнала не происходит
Остановить работающий сигнал можно нажав на любую кнопку
2022-05-14 Скетч использует 15662 байт WAVGAT Nano
Запись в EEPROM проверена на:
2022-05-14 Скетч использует 16054 байт LGT8F328P, WAVGAT Pro Mini
2022-05-14 Скетч использует 15752 байт Arduino Uno ATMega328P
2022-05-14 Скетч использует 15752 байт Arduino Nano ATMega328P Old bl.
Архив:
Библиотеки https://disk.yandex.ru/d/GAB2psiXtsH8cg
Скетч https://disk.yandex.ru/d/-gSYPX9HHsZs4w
*****************************************************************/
// Для индикатора 4-х разрядного 7 сегментного + дополнения
#include "TM1637_mralb.h" // Изменённая библиотека
#include < DS3231. h> // Для часов реального времени
#include < TimerOne . h> // Подключение библиотеки Таймер1
#include < OneWire . h> // OneWire для DS1820
#include < EEPROM . h> // Для EEPROM, запись яркости
#include < DallasTemperature . h> // Для DS1820
#include < Adafruit_BMP280. h> // для BMP280
#define MAXBEEP 30 // Сколько раз бикнет буззер
#define DEF_WAIT_BUTTON 26 // Подтверждение кнопки
#define DELAY_CLICK 21 // Время клика
#define DELAY_BT 350 // Пауза после нажатия кнопки
#define MAXMENU 8 // Последний номер в меню
/******************************************************
Включение режима отладки
Если нет надобности, то строку ниже закоментировать
*****************************************************/
//#define DEBUG
//#define DEBUG2
//#define SET_TIME // Установка времени по часам компа
/*****************************************************
Определение типа используемой платы
****************************************************/
#define MK 1 // Определяем тип микроконтроллера
; // 0 - Arduino Uno R3
; // 1 - Arduino Nano, Arduino Pro Mini
; // 2 - LGT8F328P, WAVGAT Pro Mini
; // 3 - WAVGAT Nano - Китайская подделка_
; // под Arduino Nano ATMega328
// Выбор микроконтроллера
#if (MK == 0)
#define ARDUINO_UNO // AVR ATMega328
#endif
#if (MK == 1)
#define AVR
#endif
#if (MK == 2)
#define LGT8F // Китайский аналог ATMega328,
#endif // WAVGAT Pro Mini AVGA328P
#if (MK == 3)
#define NANO_CH_WAVG // WAVGAT - Китайская подделка_
; // под Arduino Nano ATMega328
#endif
/******************
СОЕДИНЕНИЕ I/O
*****************/
// Кнопки
#define BT_MODE 4 // Кнопка [Mode]
#define BT_MINUS 5 // Кнопка [-]
#define BT_PLUS 6 // Кнопка [+]
#define PIN_ALARM_SET 10 // Индикатор установки будильника
#define BUZZER 13 // сигнал будильника на buzzer
/********************************
ИНДИКАТОР на TM1637
4-х разрядный 7 сигментный
*******************************/
#define CLK 3
#define DIO 2
// Символы на индикаторе
#define CELSIUM 12
#define DEGREE 16
#define PRESS 17
#define PUSTO 18
#define MINUS 19
TM1637 disp(CLK, DIO); // Создание объекта индикатора
byte bright = 2; // Яркость, от 1 до 7 2020-01-02
int8_t aDigDisp[4]; // Массив для цифр индикатора
// Структура разрядов дисплея
struct myDisp
{
byte high; // Разряды индикатора DID1, DIG2
byte low; // Разряды индикатора DIG3, DIG4
byte bright = 3; // Яркость 0...7
};
// Создание переменной типа
myDisp sdisp;
/*************************************
МОДУЛЬ реального времени на DS3231
************************************/
DS3231 dsClock; // Создание объекта часов
RTCDateTime dt; // Перемен. времени
RTCAlarmTime da; // Перем. будильника
#define SEC_2 2000000 // 2 секунды
byte kterm = 9; // Коэф. коррекции для DS3231
; // 0..10..20 => -10..0..+10
; // kterm - 10 = 9 - 10 = -1;
/****************************
ДАТЧИК температуры DS1820
****************************/
// Установка OneWire на Pin11, к которому подключен DS18B20
#define ONE_WIRE_BUS 11
OneWire oneWire(ONE_WIRE_BUS);
// Установка DallasTemperature для работы по OneWire
DallasTemperature sensors(& oneWire);
// Переменные для DS1820
int term;
byte addr[8];
byte resolution;
/***********************************************************
ДАТЧИК давления BMP280
Чтобы всё заработало необходимо
1. Сканером I2C найти адрес BMP280
или в библиотеке <Adafruit_BMP280.h>
1) Изменить адрес #define BMP280_ADDRESS (0x77)
на адрес #define BMP280_ADDRESS (0x76)
2) Закоментировать библиотеку #include <Adafruit_Sensor.h>
***********************************************************/
Adafruit_BMP280 bmp; // Создаём объект барометра
/*************************************************
мБар - мм рт. ст.
1013.2472 - 760 k=1.33322
1005.24788 - 754
*************************************************/
// Системный международный коэффициент
// для перевода Па в мм рт.ст.
const float kp = 133.322;
int press_now; // Переменная давления
byte kpress = 55; // Поправка давления при калибровке
; // укажите свою поправку_
; // для вашего BMP280
; // -5..+4.9 mm => 0..99
; // +0.5 mm => 55-50 = 5/10 = +0.5 mm
; // -0.5 mm => 45-50 = -5/10 = -0.5 mm
// Структура переменной флагов
struct myFlag
{
// Флаги индикатора
bool Br = false ; // Флаг для записи яркости
// Флаги будильника
bool setAlarm = false ;
bool alarm = false ;
// Разные флаги
bool Interrupt; // Флаг прерывания
bool bmp280 = false ; // Флаг наличия BMP280
bool ds1820 = false ; // Флаг наличия DS1820
bool uno; // Флаг единичного измерения
};
// Создание переменной типа myFlag
myFlag sflag;
// Структура переменной адресов
struct myAddress
{
int br = 3; // Адрес яркости 3
int kterm = br + 2; // Адрес поправки температуры 5
int kpress = kterm + 3; // Адрес поправки давления 8
};
// Создание переменной типа myAddress
myAddress addrEEPROM;
// Переменная для прерывания мигания точек
volatile boolean flag_point = true ;
// Разные переменные
byte digL, digH;
byte mode = 0; // Пункт меню 0 - вывод времени
unsigned long t1, dt1; // Переменные времени
/*********************
Настройка скетча
*********************/
void setup ()
{
#ifdef DEBUG
// Последовательный пор для отладки
Serial . begin (9600);
#endif
#ifdef DEBUG2
// Последовательный пор для отладки
Serial . begin (9600);
#endif
#ifdef NANO_CH_WAVG
// Bits of CLKPR
#define CLKOE1 6
#define CLKOE0 5
#define CLKOE 5
bool BIT;
CLKPR |= (1 << 7);
CLKPR &= ~ (1 << 1); // CLKPS0 установим в 0
#ifdef DEBUG
Serial . println (F(" Test - CLKPR: 0x03" ));
Serial . print (F("CLKPCE CLKPOEN1 CLKOEN0 - " ));
Serial . println (F("CLKPS3 CLKPS2 CLKPS1 CLKPS0" ));
Serial . print (F(" " ));
BIT = (CLKPR & (bit (CLKPCE)));
Serial . print (BIT); Serial . print (F(" " ));
BIT = (CLKPR & (bit (CLKOE1)));
Serial . print (BIT); Serial . print (F(" " ));
BIT = (CLKPR & (bit (CLKOE0)));
Serial . print (BIT); Serial . print (F(" " ));
Serial . print ("-" ); Serial . print (F(" " ));
BIT = (CLKPR & (bit (CLKPS3)));
Serial . print (BIT); Serial . print (F(" " ));
BIT = (CLKPR & (bit (CLKPS2)));
Serial . print (BIT); Serial . print (F(" " ));
BIT = (CLKPR & (bit (CLKPS1)));
Serial . print (BIT); Serial . print (F(" " ));
BIT = (CLKPR & (bit (CLKPS0)));
Serial . println (BIT);
Serial . println ();
Serial . println (F("End test" ));
#endif
#endif
pinMode (BT_MODE, INPUT_PULLUP ); // Кнопка Настройки
pinMode (BT_MINUS, INPUT_PULLUP ); // Кнопка убавить [-]
pinMode (BT_PLUS, INPUT_PULLUP ); // Кнопка прибавить [+]
pinMode (LED_BUILTIN , OUTPUT ); // Активный буззер будильника
digitalWrite (LED_BUILTIN , LOW ); // Выключим светодиод на pin13
pinMode (PIN_ALARM_SET, OUTPUT ); // Светодиод устав.будильника
#ifdef DEBUG
Serial . println ("disp.init()" );
#endif
delay (10);
disp. init (); // Инициализация индикатора
fnDisplayTest(); // Проверка всех сегментов
#if (MK== 0 || MK == 1 || MK == 2)
// Установка значений из EEPROM
// Считывание яркости из EEPROM
// Для AVR & LGT8F
byte br;
// Получим значение из EEPROM
EEPROM . get (addrEEPROM. br, br);
if
(
br >= 0 &&
br < 8 &&
br != bright
)
bright = br; // Установим яркость из EEPROM
#endif
disp. set(bright); // Установим яркость
// Инициализация прерывания на 500 мс
Timer1 . initialize (500000);
// Старт установки датчика DS1820
sensors. begin ();
// Установка в массив типа датчика 3231
fnDigDisp(32, 31);
#if (MK== 0 || MK == 1 || MK == 2)
// Считывание коррекции температуры из EEPROM
// Для AVR & LGT8F
byte kt;
// Получим значение из EEPROM
EEPROM . get (addrEEPROM. kterm, kt);
if
(
kt >= 0 &&
kt < 21 &&
kt != kterm
)
// Установим корр. темпер. из EEPROM
kterm = kt;
#endif
// Проверяем наличие DS1820
if (sensors. getAddress (addr, 0))
{
sflag. ds1820 = true ; // Подключен DS1820
/* Определяем устройство и его параметры */
// Считываем точность датчика
resolution = sensors. getResolution ();
if (resolution < 10) sensors. setResolution (10);
// Вывод на индикаторе типа датчика 1820
fnDigDisp(18, 20);
fnPrintDisp(); // Вывод на индикатор
delay (1000); // 1 сек
// Вывод разрешения/точности измерения
aDigDisp[0] = PUSTO; // Пусто
aDigDisp[1] = PUSTO;
aDigDisp[2] = resolution / 10;
aDigDisp[3] = resolution % 10;
} // End setup DS1820
#ifdef DEBUG
Serial . println ("End setup DS1820" );
#endif
fnPrintDisp(); // Вывод на индикатор
delay (1000); // 1 сек
#ifdef DEBUG
Serial . println ("bmp.begin()" );
#endif
// Проверим наличие датчика BMP280
if (bmp. begin ())
{
sflag. bmp280 = true ; // Подключен датчик BMP280
// Настройка режима работы датчика BMP280
/************************************************************
Первый параметр:
MODE_NORMAL – в данном режиме модуль циклически выходит
из режима сна через установленный интервал
времени. В активном состоянии он проводит
измерения, сохраняет их в своей памяти и
заново уходит в сон.
MODE_FORCED – в этом режиме датчик проводит измерения
при получении команды от Arduino, после
чего возвращается в состояние сна.
MODE_SLEEP – режим сна или пониженного энергопотребления.
MODE_SOFT_RESET_CODE – сброс на заводские настройки.
Второй и третий параметры отвечают за точность измерения
температуры и атмосферного давления соответственно.
Они могут принимать следующие значения:
SAMPLING_NONE - минимальная точность;
SAMPLING_X1 – точность АЦП 16 бит;
SAMPLING_X2 – точность АЦП 17 бит;
SAMPLING_X4 – точность АЦП 18 бит;
SAMPLING_X8 – точность АЦП 19 бит;
SAMPLING_X16 – точность АЦП 20 бит.
Четвёртый параметр отвечает за уровень фильтрации
измеренных данных.
Значения этого параметра могут быть следующие:
FILTER_OFF – фильтр выключен;
FILTER_X2 – минимальный уровень фильтрации;
FILTER_X4;
FILTER_X8;
FILTER_X16 – максимальный уровень фильтрации.
Пятый параметр функции setSampling(...) отвечает
за период перехода модуля в активное состояние
с целью выполнения измерений.
Параметр может принимать следующие значения:
STANDBY_MS_1 – модуль просыпается каждую миллисекунду;
STANDBY_MS_63 – модуль просыпается каждые 63 мс;
STANDBY_MS_125 – модуль просыпается каждых 125 мс;
STANDBY_MS_250 – модуль просыпается каждых 250 мс;
STANDBY_MS_500 – модуль просыпается каждых 500 мс;
STANDBY_MS_1000 – модуль просыпается каждую секунду;
STANDBY_MS_2000 – модуль просыпается каждые 2 секунды;
STANDBY_MS_4000 – модуль просыпается каждых 4 секунды;
Adafruit_BMP280::SAMPLING_X2
************************************************************/
bmp. setSampling
(
Adafruit_BMP280: : MODE_NORMAL, // Режим работы
Adafruit_BMP280: : SAMPLING_X1, // Точность температуры
Adafruit_BMP280: : SAMPLING_X4, // Точность давления
Adafruit_BMP280: : FILTER_X8, // Фильтрация
Adafruit_BMP280: : STANDBY_MS_500 // Интервал измерения
);
// Выводим на индикатор 280P
aDigDisp[0] = 2;
aDigDisp[1] = 8;
aDigDisp[2] = 0;
aDigDisp[3] = PRESS; // Символ P
fnPrintDisp(); // вывод на индикатор
delay (1000); // 1 сек
#if (MK== 0 || MK == 1 || MK == 2)
// Считывание коррекции давления из EEPROM
// Для AVR
byte kp;
// Получим значение из EEPROM
EEPROM . get (addrEEPROM. kpress, kp);
if
(
kp >= 0 &&
kp < 100 &&
kp != kpress
)
// Установим корр. темпер. из EEPROM
kpress = kp;
#endif
} // End check bmp280
#ifdef DEBUG
Serial . println ("dsClock.begin()" );
#endif
delay (100);
dsClock. begin (); // Старт часов
#ifdef DEBUG
Serial . println ("End setup()" );
#endif
#ifdef SET_TIME
// Установка DS3231 по времени компиляции, для настройки
dsClock. setDateTime(__DATE__ , __TIME__ );
#endif
// Запуска прерывания по Timer1 для мигания точек
Timer1 . attachInterrupt (blink );
sflag. Interrupt = true ;
t1 = millis ();
} // End setup
/**************************
*** Основная программа ***
**************************/
// Статусы кнопок
bool st_bt_minus,
st_bt_plus,
st_bt_mode;
void loop ()
{
// Читаем время из модуля DS3231
dt = dsClock. getDateTime();
// Читаем время будильника из модуля DS3231
da = dsClock. getAlarm1();
// Проверка состояния кнопки BT_MODE
/*******************************************************
Всего 8 пунктов меню:
0 - Индикация текущих значений:
- время
- температура
- давление
1 - Активность будильника 0|1
2 - Установка часов будильника
3 - Установка минут будильника
4 - Настройка часов
5 - Настройка минут
6 - Яркость индикатора 0...7
7 - Коэф. коррекции температуры DS3231 +/-10° =>0..20
-1° => 9-10 = -1°
+1° => 11-10 = +1°
8 - Коэф. коррекции давления +/-4.5мм рс.ст. =>0..99
+0.5 mm => 50 => 55-50 = 5 / 10 = +0.5 mm
-0.5 mm => 40 => 45-50 = -5 /10 = -0.5 mm
*******************************************************/
if (! digitalRead (BT_MODE))st_bt_mode = HIGH ;
if (st_bt_mode)
{
st_bt_mode = LOW ;
fnMenuMode(); // Меню выбора режима
delay (150);
}
// Текущее время работы программы в мс
t1 = millis ();
if (dt1 > t1) dt1 = t1; // Защита от переполнения t1
// Автоматической возвращение из меню параметров
// к индикации времени через 16 секунд бездействия
if ((t1 - dt1 > 16000) && mode != 0) mode = 0;
// Выбор установленных значений на индикатор
switch (mode)
{
case 1:
// Активность будильника 0|1
sdisp. low = sflag. setAlarm;
break ;
case 2:
// Настройка часов будильника
sdisp. low = da. hour ;
break ;
case 3:
// Настройка минут будильника
sdisp. low = da. minute ;
break ;
case 4:
// Настройка часов
sdisp. low = dt. hour ;
break ;
case 5:
// Настройка минут
sdisp. low = dt. minute ;
break ;
case 6:
// Настройка яркости
sdisp. low = bright;
break ;
case 7:
// Настройка коррекции term DS3231
sdisp. low = kterm;
break ;
case 8:
// Настройка коррекции term DS3231
sdisp. low = kpress;
}
/******************** setting *********************/
byte m; // Вспомогательная переменная
// Установка активности будильника
if (mode == 1)
{
sflag. setAlarm = fnSetParamMode(sflag. setAlarm, false , true );
sdisp. low = sflag. setAlarm;
digitalWrite (PIN_ALARM_SET, sflag. setAlarm);
}
// Установка часов будильника
if (mode == 2)
{
m = da. hour ;
da. hour = fnSetParamMode(da. hour , 0, 23);
sdisp. low = da. hour ;
// Запись значения в DS3231
if (m != da. hour )
{
// Запись значения в DS3231
fnSetAlarm();
}
}
// Установка минут будильника
if (mode == 3)
{
m = da. minute ;
da. minute = fnSetParamMode(da. minute , 0, 59);
sdisp. low = da. minute ;
if (m != da. minute )
{
// Запись значения в DS3231
fnSetAlarm();
}
}
// Установка часов
if (mode == 4)
{
m = dt. hour ;
dt. hour = fnSetParamMode(dt. hour , 0, 23);
sdisp. low = dt. hour ;
if (m != dt. hour ) // Если параметр изменён
fnSetTime(); // Запись значения в DS3231
}
// Установка минут
if (mode == 5)
{
m = dt. minute ;
dt. minute = fnSetParamMode(dt. minute , 0, 59);
sdisp. low = dt. minute ;
if (m != dt. minute )
{ // Если параметр изменён
dt. second = 0;
fnSetTime(); // Запись значения в DS3231
}
}
// Установка яркости индикатора
if (mode == 6)
{
m = bright;
bright = fnSetParamMode(bright, 0, 7);
sdisp. low = bright;
if (m != bright)
{
disp. set(bright); // Установка яркости
// Запись в EEPROM
EEPROM . put (addrEEPROM. br, bright);
}
}
// Установка коррекции температуры
if (mode == 7)
{
m = kterm;
kterm = fnSetParamMode(kterm, 0, 20);
sdisp. low = kterm;
if (m != kterm)
{
// Запись в EEPROM
EEPROM . put (addrEEPROM. kterm, kterm);
}
}
// Установка коррекции давления
if (mode == 8)
{
m = kpress;
kpress = fnSetParamMode(kpress, 0, 99);
sdisp. low = kpress;
if (m != kpress)
{
// Запись в EEPROM
EEPROM . put (addrEEPROM. kpress, kpress);
}
#ifdef DEBUG2
Serial . print ("kpress= " );
Serial . println (kpress);
#endif
}
/******************** end setting ****************/
if (mode != 0)
{ // Если настройка в меню
if (sflag. Interrupt)
{
Timer1 . detachInterrupt ();
sflag. Interrupt = false ;
}
disp. point (POINT_ON ); // Включить точки
sdisp. high = mode;
fnDigDisp(mode, sdisp. low);
}
else
{ // Вывод информации на индикатор
if (! sflag. Interrupt)
{
Timer1 . attachInterrupt (blink );
sflag. Interrupt = true ;
}
/*************************************************
Подготовка данных для вывода на индикатор
Вывод значений на индикатор по секундам
Время: 00..25 30..55
Температура: 26..27 56..57
Давление: 28..29 58..59
Если нет bmp280
Время: 00..27 30..57
Температура: 28..29 58..59
**************************************************/
if // Время
(
mode == 0 &&
(
( // Если подключен bmp280
dt. second >= 0 && dt. second < 26 ||
dt. second >= 30 && dt. second < 56
) && sflag. bmp280 ||
(
dt. second >= 0 && dt. second < 28 ||
dt. second >= 30 && dt. second < 58
) && ! sflag. bmp280
)
)
{
// Текущее время
sdisp. high = dt. hour ;
sdisp. low = dt. minute ;
fnDigDisp(sdisp. high, sdisp. low);
sflag. uno = true ;
}
// Температура
if
(
mode == 0 &&
(
(
dt. second >= 26 && dt. second < 28 ||
dt. second >= 56 && dt. second < 58
) && sflag. bmp280 ||
(
dt. second >= 28 && dt. second < 30 ||
dt. second >= 58 && dt. second < 60
) && ! sflag. bmp280
)
)
{
if (sflag. Interrupt)
{
Timer1 . detachInterrupt ();
sflag. Interrupt = false ;
}
disp. point (POINT_OFF ); // Выключить точки
if (sflag. ds1820)
{ // Если есть DS1820
// Обновление значения датчика DS1820
sensors. requestTemperatures ();
term = (int )round (sensors. getTempC (addr));
//term = -27; // симуляция температуры
}
else
{
// Если нет DS1820, то
// Читаем температуру из DS3231
term = (int )dsClock. readTemperature () + kterm - 10;
}
if (sflag. uno)
{
sflag. uno = false ;
// Значения в массив для индикатора
if (term > 0)
{
aDigDisp[0] = term / 10;
aDigDisp[1] = term % 10;
aDigDisp[2] = DEGREE;
aDigDisp[3] = CELSIUM;
}
else
{
aDigDisp[0] = MINUS;
aDigDisp[1] = abs (term) / 10;
aDigDisp[2] = abs (term) % 10;
aDigDisp[3] = DEGREE;
}
}
}
// Давление
if
(
mode == 0 && sflag. bmp280 &&
(
dt. second >= 28 && dt. second < 30 ||
dt. second >= 58 && dt. second < 60
)
)
{
if (sflag. Interrupt)
{
Timer1 . detachInterrupt ();
sflag. Interrupt = false ;
}
disp. point (POINT_OFF ); // Выключить точки
// Считываем давление и переводим в мм рт. ст.
// Поправка при калибровке byte kpress
// (укажите значение своей поправки)
// или в mode=8 установите значение
// 0..50..99 => -5..0..+4.9 mm
press_now =
(int )(bmp. readPressure() / kp + float ((kpress - 50) / 10));
#ifdef DEBUG2
Serial . print ("kpress= " );
Serial . println (float ((kpress - 45) / 10));
#endif
//press_now = 754; // Симуляция давления
uint16_t b = 0;
aDigDisp[0] = int (press_now / 100); // Сотни
b += aDigDisp[0] * 100; // суммируем сотни
aDigDisp[1] = (int )(press_now - b) / 10;// Десятки
b += aDigDisp[1] * 10; // сумма сотен и десятков
aDigDisp[2] = press_now - b ; // Единицы
aDigDisp[3] = PRESS; // Символ Р
}
}
fnPrintDisp(); // Вывод на индикатор
fnCheckAlarm(); // Проверка будильника
// Задержка 10 мс
t1 = micros ();
while (micros () - t1 < 10000);
} // End loop()
/*==============================================
*** Подпрограммы ***
==============================================*/
/***********************************************
Функция: Установка времени будильника в DS3231
************************************************/
void fnSetAlarm()
{
// Запись значения в DS3231
dsClock. setAlarm1
(
0,
da. hour ,
da. minute ,
0,
DS3231_MATCH_H_M_S
);
}
/*************************
Функция мигания точек
************************/
void blink ()
{
flag_point = ! flag_point;
disp. point (flag_point); // Мигание точки
}
/********************************************
Функция установки времени часов в DS3231
Секунды сбрасываем в 0
2022-01-04 Mr.ALB
*******************************************/
void fnSetTime()
{
dsClock. setDateTime
(
dt. year ,
dt. month ,
dt. day ,
dt. hour ,
dt. minute ,
dt. second
);
}
/*************************************************
Функция проверки всех сегментов
тест сегментов, поджигаем все на 1 сек
2022-01-02 Константин К.
2022-04-11 Mr.ALB переделка на вывод символов
************************************************/
void fnDisplayTest()
{
disp. point (POINT_ON ); // Включить точки
// Проверка символов индикатора
for (byte i = 0; i < 20; i++ )
{
disp. display (0, i);
disp. display (1, i);
disp. display (2, i);
disp. display (3, i);
delay (300);
}
disp. point (POINT_OFF ); // Выключить точки
disp. clearDisplay (); // Гашение экрана
delay (200); // 0.2 секунды
}
/**********************
Проверка будильника
2021-12-25 Mr.ALB
**********************/
void fnCheckAlarm()
{
if
(dsClock. isAlarm1() && sflag. setAlarm)
{
// Сработал будильник
// Заполняем массив значений временем
// т.к. должны всегда видеть время в
// момент срабатывания будильника
disp. point (POINT_ON ); // Включить точки
// Поднятие флага будильника
sflag. alarm = true ;
// Включаем сигнал
// Сигнал пульсирующий
// .5 секунды звук
// .5 секунды пауза
for (byte j = 0; j < MAXBEEP; j++ )
{
t1 = millis ();
while (millis () - t1 < 500)
{
// Звук .5 секунды
//digitalWrite(LED_BUILTIN, HIGH);
PORTB |= (1 << PB5); // Включаем
if
( // Если нажата любая кнопка
! digitalRead (BT_MINUS) ||
! digitalRead (BT_PLUS) ||
! digitalRead (BT_MODE)
)
break ;
}
t1 = millis ();
while (millis () - t1 < 500)
{ // Пауза .5 секунды
digitalWrite (LED_BUILTIN , LOW );
if
( // Если нажата любая кнопка
! digitalRead (BT_MINUS) ||
! digitalRead (BT_PLUS) ||
! digitalRead (BT_MODE)
)
break ;
}
if
( // Если нажата любая кнопка
! digitalRead (BT_MINUS) ||
! digitalRead (BT_PLUS) ||
! digitalRead (BT_MODE)
)
break ;
}
// Выключить звук
digitalWrite (LED_BUILTIN , LOW );
}
}
/**************************************
Функция звука нажатия кнопки
2022-04-12 Mr.ALB
2022-04-20 Mr.ALB v2.3
delay_ms - продолжительность звука
**************************************/
void fnClickButton(unsigned int delay_ms = DELAY_CLICK)
{
digitalWrite (BUZZER, HIGH ); // Звук
delay (DELAY_CLICK); // Задержка
digitalWrite (BUZZER, LOW ); // Откл. звук
}
/******************************************
Функция меню выбора режима
*****************************************/
void fnMenuMode()
{
delay (DELAY_BT);
// Было нажатие кнопку "mode"
// Переходим на следующий пункт
mode++ ;
fnClickButton();
if (mode > MAXMENU) mode = 0;
sdisp. high = mode;
// Установка автоматического выхода
// в режим индикации времени
if (mode != 0) dt1 = t1;
#ifdef DEBUG // Отладка
Serial . print ("mode= " );
Serial . println (mode);
#endif
}
/**********************************************
Массив значений на индикатор
dig_high - значение в старшем разряде
dig_low - значение в младшем разряде
2022-05-02 Mr.ALB
**********************************************/
void fnDigDisp(byte dig_high, byte dig_low)
{
aDigDisp[0] = dig_high / 10;
// Гашение незначащего нуля
if (aDigDisp[0] == 0) aDigDisp[0] = PUSTO;
aDigDisp[1] = dig_high % 10;
aDigDisp[2] = dig_low / 10;
aDigDisp[3] = dig_low % 10;
}
/*********************************************
Функция вывода на индикатор
********************************************/
void fnPrintDisp()
{
disp. display (0, aDigDisp[0]);
disp. display (1, aDigDisp[1]);
disp. display (2, aDigDisp[2]);
disp. display (3, aDigDisp[3]);
}
/***************************************************
Функция сканирования состояния кнопки
2022-04-14 Mr.ALB
but_pin - номер пина кнопки
but_wait - ожидание устойчивого состояния
***************************************************/
boolean fnScanButton
(byte buttonPin, byte buttonWait = DEF_WAIT_BUTTON)
{
boolean current;
byte count = 0;
for (byte i = 0; i < buttonWait; i++ )
{
// Опрос состояния кнопки
current = ! digitalRead (buttonPin);
if (current == LOW && count != 0) count-- ;
if (current == HIGH ) count++ ;
delay (2);
}
// Возвращаем истину, если подтверждений > 0
return ((count > 0) ? true : false );
}
/**************************************************
Функция: установка параметра в mode
2022-04-16 Mr.ALB v1
*************************************************/
byte fnSetParamMode
(
byte mode_param, // Устанавливаемый параметр (+/-)
byte mode_param_min, // Минимальное значение (+/-)
byte mode_param_max // Максимальное значение
)
{
if (fnScanButton(BT_PLUS))
{ // Нажата кнопка "Плюс"
if (mode_param != mode_param_max) mode_param++ ;
fnClickButton(21);
}
if (fnScanButton(BT_MINUS))
{ // Нажата кнопка "Минус"
if (mode_param != mode_param_min) mode_param-- ;
fnClickButton(21);
}
delay (21);
return mode_param;
}
Скрыть
Конструкция часов
Пока конструкции под этот вариант нет, но можно использовать, конструкцию первого варианта часов, только переделать узел кнопок и добавить светодиод HL2 и активный буззер для сигнала будильника.
Макетирование на плате WAVGAT Pro Mini . Долго она ждала своего часа . В итоге даже она заработала и получается, что можно использовать любую доступную плату Arduino вплоть до самых бюджетных вариантов.
Pic 3. Макет на WAVGAT Pro Mini
Приложение
Используемые библиотеки и программы:
В заключение можно сказать, что это, на данный момент, самая лучшая программа часов, в которой реализованы расширенные функции и, которая работает со всеми имеющимися у меня разновидностями Arduino и их клонами. Очень мне это нравится!
2022-05-12
Спасибо за внимание, Анатолий Беляев
Yoomoney .ru
2022-05-12 . Mr.ALB