Часы с термометром, не всегда считываются нажатия на кнопки, помогите разобраться
- Войдите на сайт для отправки комментариев
Ср, 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)
А по-моему совсем не так. Где вы сохраняете результаты проверки нажатий в переменные?
Вы. похоже, вообще не понимаете, про что я вам гворю
Если закомментировать эти строки (обработака нажатия при опросе состояния кнопки):
065
minButton.setTickMode(AUTO);
// включаем автоопрос кнопок
066
hourButton.setTickMode(AUTO);
067
okButton.setTickMode(AUTO);
068
secButton.setTickMode(AUTO);
069
brButton.setTickMode(AUTO);
и разкомментировать эти (здесь кнопки опрашиваются и обрабатываются):
098
void
loop
(){
099
100
//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 не стоит копаться, но вы все равно упорно это делаете и других пытаетесь вовлечь.
Я ни кого не пытаюсь заставить копаться в библиотеках, хочу просто понять суть проблемы, чтобы снова не наступать на теже грабли. Информация для размышления получена буду ее пробовать на деле. Спасибо за подсказки и комментариии.
чтобы снова не наступать на теже грабли.
Так тебе объяснили как не наступать - не пользуйся софтом от Гивера. Чего непонятного-то?