millis вместо delay - помогите разобраться.
- Войдите на сайт для отправки комментариев
Добрый день.
Пытаюсь реализовать задержку в программе не через delay, а через millis. Чтобы нажатие на кнопки (в конце скетча) не зависили от паузы обновления дисплея.
Собственно в программе есть код, который должен повторяться 1 раз в секунду. В этом блоке кода происходит считывание температуры с температурного датчика, а также с модуля реального времени, и выводятся эти значения на экран Nokia 3110.
Далее следующий блок кода должен через 1 секунду после предыдущего блока очистить экран. Его я тоже хочу реализовать не через delay, а через millis.
Прилагаю скетч.
Проблема в том, что в момент удержания любой кнопки второй блок, который должен очищать экран - не работает. Данные на дисплее обновляются, но сам дисплей не очищается, в результате новые данные накладываются на предыдущие.
Подскажите что я делаю не так. Только начинаю осваивать Ардуино.
#include <Wire.h> #include "DS1307.h" // Библиотека для работы с часами точного времени #include <OneWire.h> // Библиотека для работы с шиной OneWire #include <DallasTemperature.h> // Библиотека для работы с сенсором температуры #include <Adafruit_GFX.h> #include <Adafruit_PCD8544.h> // pin 3 - Serial clock out (SCLK) // pin 2 - Serial data out (DIN) // pin 8 - Data/Command select (D/C) // pin 7 - LCD chip select (CS) // pin 6 - LCD reset (RST) Adafruit_PCD8544 display = Adafruit_PCD8544(3, 2, 8, 7, 6); // Пины, к которым подключен дисплей OneWire oneWire(10); DallasTemperature sensors(&oneWire); DeviceAddress tempDeviceAddress; //переменная для хранения адреса датчика float temp=0; //переменная для текущего значения температуры ///Объявим переменные для задания задержки unsigned long previousMillis = 0; // Переменная для считывания значения времени и температуры unsigned long interval = 1000; // интервал 1 секунда unsigned long currentMillisDisp; unsigned long currentMillis; unsigned long previousMillisDisp = 1000; int analog=0; // Переменная для работы с кнопками void setup() { Serial.begin(9600); //Инициализируем термодатчик и установим разрешающую способность 12 бит sensors.begin(); sensors.getAddress(tempDeviceAddress, 0); sensors.setResolution(12); display.begin(); // Инициализация дисплея display.clearDisplay(); // Очищаем дисплей display.display(); display.setContrast(50); // Устанавливаем контраст display.setTextColor(BLACK); // Устанавливаем цвет текста display.setTextSize(1); // Устанавливаем размер текста /* RTC.stop(); RTC.set(DS1307_SEC,10); //Секунды RTC.set(DS1307_MIN,47); //Минуты RTC.set(DS1307_HR,00); //Часы RTC.set(DS1307_DOW,6); //День недели RTC.set(DS1307_DATE,29); //Дата RTC.set(DS1307_MTH,3); //Месяц RTC.set(DS1307_YR,14); //Год RTC.start(); */ } void loop() { //Опрос датчика температуры и часов, вывод на дисплей //Вызывается 1 раз в секунду currentMillis = millis(); currentMillisDisp = millis(); if(currentMillis - previousMillis > interval) { previousMillis = currentMillis; display.setCursor(20, 2); // Устанавливаем курсор // Выводим время display.print(RTC.get(DS1307_HR,true)); display.print(':'); if (RTC.get(DS1307_MIN,false)<10) // Если значение минут меньше 10 { display.print('0')+display.print(RTC.get(DS1307_MIN,false)); } // Вывести ноль+минуты else display.print(RTC.get(DS1307_MIN,false)); // Иначе вывести просто минуты display.print(':'); if (RTC.get(DS1307_SEC,false)<10) // Если значение секунд меньше 10 { display.print('0')+display.print(RTC.get(DS1307_SEC,false)); } // Вывести ноль+секунды else display.print(RTC.get(DS1307_SEC,false)); // Иначе вывести просто секунды // Выводим дату display.setCursor(15, 12); // Устанавливаем курсор if (RTC.get(DS1307_DATE,false)<10) // Если значение даты меньше 10 { display.print('0')+display.print(RTC.get(DS1307_DATE,false)); } // Вывести ноль+дата else display.print(RTC.get(DS1307_DATE,false)); // Иначе вывести просто дату display.print('/'); if (RTC.get(DS1307_MTH,false)<10) // Если значение месяца меньше 10 { display.print('0')+display.print(RTC.get(DS1307_MTH,false)); } // Вывести ноль+месяц else display.print(RTC.get(DS1307_MTH,false)); // Иначе вывести просто месяц display.print('/'); display.print(RTC.get(DS1307_YR,true)); // Выводим год // Выводим день недели на дисплей ---------------------------------------------------------------------------- display.setCursor(20, 22); // Устанавливаем курсор switch (RTC.get(DS1307_DOW,false)) { case 1: display.print("MONDAY") ; break ; case 2: display.print("TUESDAY") ; break ; case 3: display.print("WEDNESDAY") ; break ; case 4: display.print("THURSDAY") ; break ; case 5: display.print("FRIDAY") ; break ; case 6: display.print("SATURDAY") ; break ; case 7: display.print("SUNDAY") ; break ; } //Запуск процедуры измерения температуры sensors.setWaitForConversion(false); sensors.requestTemperatures(); sensors.setWaitForConversion(true); //Считывание значения температуры sensors.getAddress(tempDeviceAddress, 0); temp=sensors.getTempC(tempDeviceAddress); display.setCursor(5, 32); // Устанавливаем курсор display.print("TEMP: "); display.print(temp); display.print(" C"); display.display(); } // Конец процедуры обновления экрана 1 раз в секунду if(currentMillis - previousMillis == interval) // Очистка экрана через секунду после вывода информации { //previousMillisDisp = currentMillisDisp; // Очищаем дисплей display.clearDisplay(); display.display(); Serial.println (previousMillisDisp); Serial.println (currentMillis); } analog=analogRead(14); //считываем сигнал с пина 14 //Serial.println (analog); if (analog >=690 && analog <=700) Serial.println ("Button 1 pressed"); if (analog >=925 && analog <=940) Serial.println ("Button 2 pressed"); if (analog >=825 && analog <=840) Serial.println ("Button 3 pressed"); }
Если честно, не хочу полнсостью вникать в твой код, ты уж не обижайся. Я как то "писал" часы без модуля часов (на форуме есть темка) и мне нужно было задержать выполнение кода ровно на пол секунды (в твоём случаи на секунду) но не замораживать программу а предоставить готовности выполнять другие действия при нажатии кнопок.
micros меняй на millis. micro -(у тебя interval) это количество твоих миллисекунд т.е. (1000)
и если нажимается кнопка, выпрыгиваем из цикла.
А вобще я бы посоветовал не чистить дисплей полностью. Чисть те области куда непосредственно будешь печатать без промежуточных команд. Тогда не будет мерцаний. Вот например
Ты постоянно сюда печатаешь одно и то же, зачем чистить.
Да и как тогромоздко всё. Вот нашёл у себя часы на ЖКИ от nokia 1100:
На сколько помню, нули сами печатаются (если понимаешь о чём я)
Выкину тогда ненужную часть кода, оставлю только сами блоки.
Понимаешь что ещё у тебя не так!? Ты чистиши дисплей, потом выполняешь какие то операции, потом чтото печатаешь, потом опять операции, потом опять печатаешь. Так он у тебя будет каждую секунду мерцать, это конечно не критично, но как то не эстетично, и глазу не очень приятно. Попробуй вставь функцию отчистки в 68 -ю строку(первоночального кода)
А теперь без проблемы отчистки дисплея ещё раз конкретно, что у тебя не получается?
Понимаешь что ещё у тебя не так!? Ты чистиши дисплей, потом выполняешь какие то операции, потом чтото печатаешь, потом опять операции, потом опять печатаешь. Так он у тебя будет каждую секунду мерцать, это конечно не критично, но как то не эстетично, и глазу не очень приятно. Попробуй вставь функцию отчистки в 68 -ю строку(первоночального кода)
А теперь без проблемы отчистки дисплея ещё раз конкретно, что у тебя не получается?
Попробовал перенести код - действительно получилось. И теперь при нажатии на кнопки всё нормально прорисовывается. Спасибо за помощь.
Да, дисплей моргает каждую секунду. Но я просто ещё не нашёл способ как сделать по другому, чтобы он не весь обновлялся, а только те цифры, которые меняются. Если есть ссылочка на это - дай пожалуйста.
Да, дисплей моргает каждую секунду. Но я просто ещё не нашёл способ как сделать по другому, чтобы он не весь обновлялся, а только те цифры, которые меняются. Если есть ссылочка на это - дай пожалуйста.
Если при работе с дисплеями чистить экран полностью, старайся делать отдельно вычисления, отдельно печать (всю сразу) и, как ты уже сделал, отчищать экран непосредственно перед печатью.
Или, будет лучше, отчищать только ту область, в которую печатаешь, как я тоже уже сказал.
например ты установил координаты для вывода значения температуры (значение уже расчитано), перед выводом ставь курсор в те же координаты и печатай или прямоугольник цвета фона(скажем "белый"), если библиотека позволяет или просто пробелы
Но периодически всёж надо чистить полностью. Например так:
Пробую очищать сейчас только те места экрана, в которых изменяется число. Например секунды. Через пробелы почему-то не получилось, делаю через пустые прямоугольники. Хотя есть ещё одна идея, надо попробовать. Хотелось бы вообще отказаться от полной очистки дисплея. Отпишусь как получится.
На сколько помню, нули сами печатаются (если понимаешь о чём я)
Может у тебя другая библиотека какая, то. У меня нули не печатаются, пришлось наворотить из одного примера, взятого из сети.
Попробуй вывети время так:
Сделал обновление только изменяемых параметров - часов, секунд, температуры и т.п. Т.е. если значени эти меняются, то обновляется именно то поле, где они меняются и на чистом всё переписывается.
Проблема теперь в том, что если нажать на кнопку и подержать её нажатой обновление экрана останавливается, все цифры замирают и обновление не возобновляется. Это что - сбивается отсчёт милисекунд пока я кнопку держу и цикл, который вызывался каждую секунду в это время не выполняется?
Навскидку поблема в строке 75. Попробуй записать её так:
Попробую. Но всё же интересно - если держать кнопку то цикл обновления не работает в это время?
Предпологаю потому, что ты запер условие в жёсткие рамки (если равно числу) не больше и не меньше, и я вобще удивляюсь как обновляется когда ты кнопку отпускаешь в чём я кстати сомневаюсь. На печать в порт уходит хоть небольшое но время и строго попасть в равенство до одной тысячной секунды это вряд ли. поэтому при следующей интерации условие ложное т.к. не менише, но больше а значит не равно, игнарируется и твой основной цикл остаётся
Я думал что независимо от процессов в основном цикле loop будет вызываться процедура обновления экрана. Ведь милисекунды продолжают отсчитываться. А получается что пока нажата кнопка весь основной цикл на этой кнопке и останавливается?
И когда я на кнопку нажимаю быстро, в порт выдается несолько надписей, а не одна.
А когда отпускаешь, что всё становится нормально, всмысле экран печатает нормально время?
А когда отпускаешь, что всё становится нормально, всмысле экран печатает нормально время?
Нет, после отпускания кнопки экран как застыл так и остается без изменений, ничего не обновляется. Видимо в цикле обновления переменная уже стала больше 1000 и условие не выполняется. Думаю замена равно на больше должно дать нужный эффект как ты сказал. Проверю - отпишусь.
Ну так а я о чём писал!? Внимательней читай ответы. После одного непопадания в условие, у тебя остаётся работать только та часть кода, что я написал в 14 посте. НО даже неисправные часы два раза в сутки показывают точное время, у тебя будет что то похожее, когда значение millis переполнится и сбросится, твои часы пойдут при достижении условия )))
Ну так а я о чём писал!? Внимательней читай ответы. После одного непопадания в условие, у тебя остаётся работать только та часть кода, что я написал в 14 посте. НО даже неисправные часы два раза в сутки показывают точное время, у тебя будет что то похожее, когда значение millis переполнится и сбросится, твои часы пойдут при достижении условия )))
Я прочитал внимательно, просто по другому представлял работу устройства.
В общем после замены условия с равно на >= всё нормально обновляется даже при зажатой кнопке.
Спасибо за помощь!