Часы с термометром, не всегда считываются нажатия на кнопки, помогите разобраться
- Войдите на сайт для отправки комментариев
Ср, 26/12/2018 - 13:44
Пишу программу часов на дисплее TM1637, RTC DC1307 и DHT11. В общем ситуация следующая: не обрабатываются (как понял не фиксируются) на кнопки. Иногда срабатывают, иногда нет, помогите пожалуйста разобраться почему. С ардуино знаком около 2х месяцев, потому прошу не пинать сильно.
Вот скетч:
#include <Wire.h> // подключаем библиотеку для работы с I2C
#include "stDHT.h" // подключаем библиотеку для работы с датчиком DHT
#include "iarduino_RTC.h" // подключаем библиотеку для работы с DS1307
#include "GyverTM1637.h" // подключаем библиотеку для работы с дисплеем TM1637
#include "GyverButton.h" // подключаем библиотеку для работы с кнопками
#define EEPROM_ADDR 0x50 //Адрес EEPROM на DS1307
#define start_addr 0xFF //Адрес по которому пишем значения
#define sensorPin 4
#define DIO_Pin 5
#define CLK_Pin 6
#define alLedPin 3
#define buzPin 7
#define brButPin 8
#define secButPin 9
#define okButPin 10
#define hourButPin 11
#define minButPin 12
#define dispPrintDelay 1000
#define sensReadDelay 2000
#define alarmTime 300000
int8_t timeMins;
int8_t timeHours;
int8_t timeSeconds;
int8_t alarmMins = 0;
int8_t alarmHours = 0;
boolean potFlag;
boolean noPotFlag = false;
boolean alarmOn = false;
boolean alarmSound = true;
boolean alarmStart = false;
uint8_t oldTimeSec = 0;
uint8_t oldTimeMin = 0;
uint8_t menuLevel = 1;
uint8_t DHT_Temp;
uint8_t DHT_Hum;
uint8_t bright = 1;
volatile uint8_t backTime = 0;
unsigned long curMillisTime = 0; //
unsigned long curMillisSensor = 0; //
unsigned long curMillisAlarm = 0; //
DHT sensor(DHT11); // объявляем переменную для работы с датчиком DHT11
iarduino_RTC RTClock(RTC_DS1307); // объявляем переменную для работы с DS1307
GyverTM1637 disp(CLK_Pin, DIO_Pin); // объявляем переменную для работы с TM1637
GButton minButton(minButPin); // объявляем переменную для работы с кнопками
GButton hourButton(hourButPin); // объявляем переменную для работы с кнопками
GButton okButton(okButPin); // объявляем переменную для работы с кнопками
GButton secButton(secButPin); // объявляем переменную для работы с кнопками
GButton brButton(brButPin); // объявляем переменную для работы с кнопками
//============ блок программы SETUP ====================
void setup(){
Serial.begin(9600); // открываем последовательный порт на скорости 9600 бод
RTClock.begin();
//okButton.setTimeout(1000);
//secButton.setTimeout(1000);
brButton.setTimeout(1000); // время длительного нажатия на кнопку
minButton.setTickMode(AUTO); // включаем автоопрос кнопок
hourButton.setTickMode(AUTO);
okButton.setTickMode(AUTO);
secButton.setTickMode(AUTO);
brButton.setTickMode(AUTO);
minButton.setDebounce(50);
hourButton.setDebounce(50);
okButton.setDebounce(50);
secButton.setDebounce(50);
brButton.setDebounce(50);
disp.clear();
disp.brightness(bright); // яркость, 0 - 7 (минимум - максимум)
byte welcome_banner[] = {_H, _E, _L, _L, _O}; // текст приветствия
disp.runningString(welcome_banner, sizeof(welcome_banner), 200); // 200 это время в миллисекундах!
delay(1000); // выполняем задержку
Wire.beginTransmission(0x68); // включаем выход SQW
Wire.write(0x07); //
Wire.write(0x10); // меандр 1 Гц
Wire.endTransmission(); //
readAlarmTime(); // считываем время будильника из EEPROM
delay(50);
attachInterrupt(0, blink, CHANGE); //включаем 0 прерывание по 2-ой ноге (по изменению состояния)
RTClock.gettime();
}// end setup
//************ основной цикл программы *************
void loop(){
//okButton.tick();
//minButton.tick();
//hourButton.tick();
//secButton.tick();
//brButton.tick();
//============ считываем время и др. раз в секунду ==============
if ((millis() - curMillisTime) > dispPrintDelay){
curMillisTime = millis();
curMillisAlarm = millis();
timeHours = RTClock.Hours;
timeMins = RTClock.minutes;
//RTClock.gettime();
Serial.println(RTClock.gettime("d-m-Y, H:i:s, D")); // выводим время
Serial.println((String) "DHT11: " + DHT_Temp + " *C - " + DHT_Hum + " %");
printOnDisp();
if ((alarmHours == timeHours) && (alarmMins == timeMins) && alarmOn && !alarmStart){ //включаем будильник, если пришло время
alarmSound = true;
alarmStart = true;
curMillisAlarm = millis();
}//end if
}//end if
//============ считываем показания DHT11 раз в 2 секунды ==============
if ((millis() - curMillisSensor) > sensReadDelay){
curMillisSensor = millis();
DHT_Temp = sensor.readTemperature(sensorPin);
DHT_Hum = sensor.readHumidity(sensorPin);
}//end if
//============ вызываем функцию будильника, если флаг звука будильника "true" ==================
if (alarmSound) alarm();
//============ выключаем будильник, если он звонит более alarmTime ==============
if ((millis() - curMillisAlarm) > alarmTime){ //время по умолчанию 5 минут
alarmSound = false;
alarmStart = false;
}//end if
//============ выключаем звук будильника нажатием на кнопку ==============
if (secButton.isClick() && alarmStart) alarmSound = false;
//============ переключение режимов отображения ==============
if (okButton.isClick()){
menuLevel ++;
if (menuLevel > 3) menuLevel = 1;
//delay(50);
}//end if
//============ устанавливаем флаг точек ==============
if (menuLevel >=2) noPotFlag = true;
else noPotFlag = false;
//okButton.tick();
//minButton.tick();
//============ устанавливаем минуты ==============
if (okButton.isHold() && minButton.isClick()){
backTime = 0;
menuLevel = 1;
timeMins ++;
if (timeMins > 59) timeMins = 0;
RTClock.settime(-1, timeMins, -1, -1, -1, -1, -1); // устанавливаем только минуты, секунды не трогаем
//delay(50);
}//end if
//okButton.tick();
//hourButton.tick();
//============ устанавливаем часы ==============
if (okButton.isHold() && hourButton.isClick()){
backTime = 0;
menuLevel = 1;
timeHours ++;
if (timeHours > 23) timeHours = 0;
RTClock.settime(-1, -1, timeHours, -1, -1, -1, -1); // устанавливаем только часы, секунды и минуты не трогаем
//delay(50);
}//end if
//secButton.tick();
//============ выводим на экран секунды =================
if (secButton.isClick()&& !alarmStart){
menuLevel = 5; // выводим на экран секунды
printOnDisp();
//delay(50);
}//end if
//okButton.tick();
//============ сбрасываем секунды в 0 =================
if ((menuLevel == 4) && okButton.isClick()){
RTClock.settime(0, -1, -1, -1, -1, -1, -1);
//delay(50);
}//end if
//brButton.tick();
//============ изменяем яркость =================
if (brButton.isClick()){
bright ++;
if (bright > 7) bright = 1;
disp.brightness(bright);
//delay(50);
}//end if
//brButton.tick();
//============ вкл/выкл будильника =================
if (brButton.isHolded()){
alarmOn != alarmOn;
digitalWrite(alLedPin,alarmOn);
}//end if
//secButton.tick();
//============ выводим время будильника =================
if (secButton.isHold() && !(menuLevel == 4)){
backTime = 0;
menuLevel = 4;
printOnDisp();
}//end if
//hourButton.tick();
//============ устанавливаем время будильника (часы) =================
if ((menuLevel == 4) && hourButton.isClick()){
alarmHours ++;
if (alarmHours > 23) timeHours = 0;
backTime = 0;
}// end if
//minButton.tick();
//============ устанавливаем время будильника (минуты) =================
if ((menuLevel == 4) && minButton.isClick()){
alarmMins ++;
if (alarmMins > 59) timeMins = 0;
backTime = 0;
}//end if
//okButton.tick();
//============ сохраняем время будильника =================
if ((menuLevel == 4) && okButton.isClick()){
//saveAlarmTime();
backTime = 0;
alarmStart = false;
}//end if
//delay(10);
}//end loop
//********* основной цикл программы окончен ***************
//++++++++++++++++++++++++ функции ++++++++++++++++++++++++
//------------------ выводим на дисплей -------------------
void printOnDisp(){
switch (menuLevel){
case 1: //если уровень меню 1 - выводим время
//noPotFlag = false;
//disp.displayClockScroll(RTClock.Hours, RTClock.minutes, 50);
disp.displayClock(RTClock.Hours, RTClock.minutes);
if (backTime > 20) {
backTime = 0;
menuLevel = 2;
}//end if
break;
case 2: //если уровень меню 2 - выводим температуру
//noPotFlag = true;
disp.displayByte(_empty, _empty, _degree, _C);
disp.display(0, DHT_Temp / 10);
disp.display(1, DHT_Temp % 10);
if (backTime > 10) {
backTime = 0;
menuLevel = 3;
}//end if
break;
case 3: //если уровень меню 3 - выводим влажность
//noPotFlag = true;
disp.displayByte(_empty, _empty, _degree, _b);
disp.display(0, DHT_Hum / 10);
disp.display(1, DHT_Hum % 10);
if (backTime > 10) {
backTime = 0;
menuLevel = 1;
}//end if
break;
case 4: //если уровень меню 4 - выводим время будильника
//noPotFlag = true;
disp.displayClock(alarmHours, alarmMins);
if (backTime > 20) {
backTime = 0;
menuLevel = 1;
}//end if
break;
case 5: //если уровень меню 5 - выводим секунды
//noPotFlag = true;
//disp.clear();
disp.displayByte(_empty, _empty, RTClock.seconds / 10, RTClock.seconds % 10);
//disp.display(3, RTClock.seconds % 10);
if (backTime > 70) {
backTime = 0;
menuLevel = 1;
}//end if
break;
}//end switch
}//end printOnDisp
//------------ сохраняем время будильника -------------
void saveAlarmTime(){
Wire.beginTransmission(EEPROM_ADDR);
Wire.write((int)(start_addr >> 8));
Wire.write((int)(start_addr & 0xFF));
Wire.write(alarmHours);
delay(5);
Wire.endTransmission();
delay(10);
Wire.beginTransmission(EEPROM_ADDR);
Wire.write((int)((start_addr+1) >> 8));
Wire.write((int)((start_addr+1) & 0xFF));
Wire.write(alarmMins);
delay(5);
Wire.endTransmission();
delay(10); //Datasheet описана задержка записи в 5мс
}//end saveAlarmTime()
//------------ считываем время будильника -------------
void readAlarmTime(){
Wire.beginTransmission(EEPROM_ADDR);
Wire.write((int)(start_addr >> 8));
Wire.write((int)(start_addr & 0xFF));
Wire.endTransmission();
Wire.requestFrom(EEPROM_ADDR,1);
alarmHours = Wire.read();
Wire.write((int)((start_addr + 1) >> 8));
Wire.write((int)((start_addr + 1) & 0xFF));
Wire.endTransmission();
Wire.requestFrom(EEPROM_ADDR,1);
alarmMins = Wire.read();
}//end readAlarmTime()
//------------ будильник -------------
void alarm(){
for(int i=0;i<200;i++){
digitalWrite(buzPin,HIGH);
delay(1);
digitalWrite(buzPin,LOW);
delay(1);
}//end for
}
//------------ мигаем точками -------------
//------------ (или не мигаем) ------------
void blink() {
digitalWrite(13, !digitalRead(13));
backTime ++;
if (backTime > 100) backTime = 0;
if (!noPotFlag){
potFlag = !potFlag;
disp.point(potFlag); // вкл/выкл точки
}//end if
else disp.point(false); // выкл точки
}//end blink
Вы библиотеки у Гивера взяли и попытались на них построить серьезный проект - это почти БЕЗВЫИГРЫШНАЯ лотерея. В его библиотеках столько косяков. что проще (и правильнее) свою собственную написать. чем выловить все его баги.
На первое время что могу посоветовать - посмотрите в библиотеке кнопок, не стирает ли она статус кнопки при обращении с методу isClick() - вполне возможно, что этот метод можно использовать только один раз за цикл ЛУП
Чет мне подсказывает, что код нихрена не самописный. Поэтому и кнопы жматься не желают.
Так код гиверовский.
Обратили бы Вы лучше к автору. У него и сайт свой есть и ютуб, и вконтакте. Он там вроде отвечает.
Ковыряться в какашках этого специалиста тут мало желающих найдётся.
Ясно, спасибо! Короче, как я понял дело скорее всего в библиотеке. А состояние кнопок после опроса сбрасывается точно - это в библиотеке прописано. Попробую другую или вручную обработку напишу.
А если знаете. что сбрасывается, так зачем по мнгоу раз опрашиваете? Спросите один раз, присвойте переменной и уже везде эту переменную проверяйте. В чём проблема-то? Или код не Ваш?
А состояние кнопок после опроса сбрасывается точно - это в библиотеке прописано.
ну тогда у вас, к примеру, строчки 144, 157, 169 и 188 одновременно работать не будут
Или код не Ваш?
А есть сомнения?
Код писал я, ну некоторые моменты подглянул. По идее, как у автора описано, при установке в авто считывания кнопок, они должны опрашиваться каждый раз когда считываешь их состояние. Я даже перед каждым сравнением ставил принудительное считывание и становилось лучше, но не намного. Все равно большинство нажатий пропускалось и снопки срабатывали с задержшкой. Я вот думаю, может из-за вызова функций их состояние сбрасывается? Например мигание точками, вызывается по прерыванию со 2 ой ноги. Сначала, когда были только часы и термометр и переключение было между режимами только одной кнопкой, все работало нормально. Потом по мере добавления функций кнопки перестали нормально реагировать.
Вы не поняли. Если ставить принудительное считывание перед сравнением - должно стать еще хуже. Так делать нельзя. Кнопку можно считывать ОДИН РАЗ ЗА ЦИКЛ - понимаете?
В начале лупа, до всех сравнений - считайте по одному разу статус всех кнопок и присвойте результаты переменным. И больше к кнопкам нигде в программе не обращайтесь
У меня так и было изначально сделано (в коде строке закомментированы после loop), но как раз после этого я и включил авто считывание кнопок при обращениии к функциям, потому что начались пропуски нажатий.
У меня так и было изначально сделано (в коде строке закомментированы после loop)
А по-моему совсем не так. Где вы сохраняете результаты проверки нажатий в переменные?
Вы. похоже, вообще не понимаете, про что я вам гворю
Если закомментировать эти строки (обработака нажатия при опросе состояния кнопки):
065minButton.setTickMode(AUTO);// включаем автоопрос кнопок066hourButton.setTickMode(AUTO);067okButton.setTickMode(AUTO);068secButton.setTickMode(AUTO);069brButton.setTickMode(AUTO);и разкомментировать эти (здесь кнопки опрашиваются и обрабатываются):
098voidloop(){099100//okButton.tick();101//minButton.tick();102//hourButton.tick();103//secButton.tick();104//brButton.tick();то, насколько правильно я понял, так и должно получиться. Рузультаты нажатий хранятся в переменных библиотеки.
Судя по бибилиотеке, как раз функция tick и обрабатывает все, а остальные только возвращают ложь или правда, в зависимости от запроса.
Когда код был короткий, то все работало нормально, ну и кнопок было меньше.
Хотя могу предположить в чем может быть дело: при опросе состояния это состояние сбрасывается (у автора так в описании) и, сюдя по всему, про переменные состояния вы были правы, нужно дополнительно к встроенным в библиотеку ввести еще переменные состояния кнопок. Т.е., если я вызвал опрос одной из кнопок при проверке одного из условий, к примеру
if(okButton.isClick()), то если условие не выполнится, состояние кнопки все-равно будет сброшено в 0. И, если произойдет опрос далее по кодуif((menuLevel == 4) && okButton.isClick()), то уже это условие не выполнится никогда, т.к. состояние кнопки будет всегда 0. Для этого я и попробовал включить автоопрос кнопок, чтобы tick вызывался при считывании состояния. Хотя и это не помогло.Сам пример из библиотеки работает нормально, но там только выводит в порт нажатия.
Странный Вы человек. Вроде бы уже написали, что в библиотеках от Gyver не стоит копаться, но вы все равно упорно это делаете и других пытаетесь вовлечь.
Я ни кого не пытаюсь заставить копаться в библиотеках, хочу просто понять суть проблемы, чтобы снова не наступать на теже грабли. Информация для размышления получена буду ее пробовать на деле. Спасибо за подсказки и комментариии.
чтобы снова не наступать на теже грабли.
Так тебе объяснили как не наступать - не пользуйся софтом от Гивера. Чего непонятного-то?