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");
}
Если честно, не хочу полнсостью вникать в твой код, ты уж не обижайся. Я как то "писал" часы без модуля часов (на форуме есть темка) и мне нужно было задержать выполнение кода ровно на пол секунды (в твоём случаи на секунду) но не замораживать программу а предоставить готовности выполнять другие действия при нажатии кнопок.
do{ if(set || digitalRead(but_set)==HIGH)break; //для утановок } while(micros() - previousMicros < micro);micros меняй на millis. micro -(у тебя interval) это количество твоих миллисекунд т.е. (1000)
и если нажимается кнопка, выпрыгиваем из цикла.
А вобще я бы посоветовал не чистить дисплей полностью. Чисть те области куда непосредственно будешь печатать без промежуточных команд. Тогда не будет мерцаний. Вот например
display.setCursor(5, 32); // Устанавливаем курсор display.print("TEMP: ");Ты постоянно сюда печатаешь одно и то же, зачем чистить.
Да и как тогромоздко всё. Вот нашёл у себя часы на ЖКИ от nokia 1100:
#include "nokia_1100_lib.h" #include <DS1307.h> DS1307 rtc(3, 4); //SDA, SCL void setup(){ LcdInit(); rtc.halt(false); /* rtc.setDOW(6); // Set Day-of-Week to SUNDAY rtc.setTime(3, 10, 0); // Set the time to 12:00:00 (24hr format) rtc.setDate(7, 12, 2013);*/ // Set the date to October 3th, 2010 // rtc.getTime(); // rtc.enableSQW(true); } void loop(){ LcdGotoXY(8, 0); LcdPrintF2("Time"); LcdGotoXY(8, 2); LcdPrintF(rtc.getDateStr()); LcdGotoXY(8, 4); LcdPrintF(rtc.getDOWStr()); LcdGotoXY(10, 6); LcdPrintln(rtc.getTimeStr()); delay(500); }На сколько помню, нули сами печатаются (если понимаешь о чём я)
Выкину тогда ненужную часть кода, оставлю только сами блоки.
#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); // Устанавливаем размер текста } void loop() { //Опрос датчика температуры и часов, вывод на дисплей //Вызывается 1 раз в секунду currentMillis = millis(); currentMillisDisp = millis(); if(currentMillis - previousMillis > interval) { previousMillis = currentMillis; } // Конец процедуры обновления экрана 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"); }Понимаешь что ещё у тебя не так!? Ты чистиши дисплей, потом выполняешь какие то операции, потом чтото печатаешь, потом опять операции, потом опять печатаешь. Так он у тебя будет каждую секунду мерцать, это конечно не критично, но как то не эстетично, и глазу не очень приятно. Попробуй вставь функцию отчистки в 68 -ю строку(первоночального кода)
А теперь без проблемы отчистки дисплея ещё раз конкретно, что у тебя не получается?
Понимаешь что ещё у тебя не так!? Ты чистиши дисплей, потом выполняешь какие то операции, потом чтото печатаешь, потом опять операции, потом опять печатаешь. Так он у тебя будет каждую секунду мерцать, это конечно не критично, но как то не эстетично, и глазу не очень приятно. Попробуй вставь функцию отчистки в 68 -ю строку(первоночального кода)
А теперь без проблемы отчистки дисплея ещё раз конкретно, что у тебя не получается?
Попробовал перенести код - действительно получилось. И теперь при нажатии на кнопки всё нормально прорисовывается. Спасибо за помощь.
Да, дисплей моргает каждую секунду. Но я просто ещё не нашёл способ как сделать по другому, чтобы он не весь обновлялся, а только те цифры, которые меняются. Если есть ссылочка на это - дай пожалуйста.
Да, дисплей моргает каждую секунду. Но я просто ещё не нашёл способ как сделать по другому, чтобы он не весь обновлялся, а только те цифры, которые меняются. Если есть ссылочка на это - дай пожалуйста.
Если при работе с дисплеями чистить экран полностью, старайся делать отдельно вычисления, отдельно печать (всю сразу) и, как ты уже сделал, отчищать экран непосредственно перед печатью.
Или, будет лучше, отчищать только ту область, в которую печатаешь, как я тоже уже сказал.
например ты установил координаты для вывода значения температуры (значение уже расчитано), перед выводом ставь курсор в те же координаты и печатай или прямоугольник цвета фона(скажем "белый"), если библиотека позволяет или просто пробелы
..................... //задаёшь координаты display.print(" "); //4 пробела, отчистка области ..................... //задаёшь те же координаты display.print(temp);Но периодически всёж надо чистить полностью. Например так:
Пробую очищать сейчас только те места экрана, в которых изменяется число. Например секунды. Через пробелы почему-то не получилось, делаю через пустые прямоугольники. Хотя есть ещё одна идея, надо попробовать. Хотелось бы вообще отказаться от полной очистки дисплея. Отпишусь как получится.
На сколько помню, нули сами печатаются (если понимаешь о чём я)
Может у тебя другая библиотека какая, то. У меня нули не печатаются, пришлось наворотить из одного примера, взятого из сети.
Попробуй вывети время так:
Сделал обновление только изменяемых параметров - часов, секунд, температуры и т.п. Т.е. если значени эти меняются, то обновляется именно то поле, где они меняются и на чистом всё переписывается.
Проблема теперь в том, что если нажать на кнопку и подержать её нажатой обновление экрана останавливается, все цифры замирают и обновление не возобновляется. Это что - сбивается отсчёт милисекунд пока я кнопку держу и цикл, который вызывался каждую секунду в это время не выполняется?
#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 currentMillis; int MIN = 61; int HOUR = 26; int DATE = 35; int TEMP0 = 3000; int analog=0; // Переменная для работы с кнопками int x_time = 20; int y_time = 0; int x_date = 15; int y_date = 12; 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(); if(currentMillis - previousMillis == interval) { previousMillis = currentMillis; //display.clearDisplay(); //display.display(); // Выводим время if (RTC.get(DS1307_HR,true) != HOUR) { HOUR = RTC.get(DS1307_HR,true); display.fillRect(x_time, y_time, 11, 7, WHITE); // x, y, w, h, color // Стираем предыдущие значения белым прямоугольником display.display(); display.setCursor(x_time, y_time); // Устанавливаем курсор display.print(RTC.get(DS1307_HR,true)); } display.setCursor(x_time+11, y_time); // Устанавливаем курсор display.print(':'); if (RTC.get(DS1307_MIN,false) != MIN) { MIN = (RTC.get(DS1307_MIN,false)); if (RTC.get(DS1307_MIN,false)<10) { display.fillRect(x_time+16, y_time, 11, 7, WHITE); // x, y, w, h, color // Стираем предыдущие значения белым прямоугольником display.display(); display.setCursor(x_time+16, y_time); // Устанавливаем курсор display.print('0')+display.print(RTC.get(DS1307_MIN,false)); // Если значение минут меньше 10 - вывести ноль+минуты display.display(); } else { display.fillRect(x_time+16, y_time, 11, 7, WHITE); // x, y, w, h, color // Стираем предыдущие значения белым прямоугольником display.display(); display.setCursor(x_time+16, y_time); // Устанавливаем курсор display.print(RTC.get(DS1307_MIN,false)); // Если значение минут меньше 10 - вывести ноль+минуты display.display(); } } display.setCursor(x_time+27, y_time); // Устанавливаем курсор display.print(':'); if (RTC.get(DS1307_SEC,false)<10) { display.fillRect(x_time+32, y_time, 11, 7, WHITE); // x, y, w, h, color // Стираем предыдущие значения белым прямоугольником display.display(); display.setCursor(x_time+32, y_time); // Устанавливаем курсор display.print('0')+display.print(RTC.get(DS1307_SEC,false)); // Если значение секунд меньше 10 - вывести ноль+секунды display.display(); } else { display.fillRect(x_time+32, y_time, 11, 7, WHITE); // x, y, w, h, color // Стираем предыдущие значения белым прямоугольником display.display(); display.setCursor(x_time+32, y_time); // Устанавливаем курсор display.print(RTC.get(DS1307_SEC,false)); // Иначе вывести просто секунды display.display(); } // Выводим дату if (RTC.get(DS1307_DATE,false) != DATE) { DATE = RTC.get(DS1307_DATE,false); if (RTC.get(DS1307_DATE,false)<10) { display.fillRect(x_date, y_date, 11, 7, WHITE); // x, y, w, h, color // Стираем предыдущие значения белым прямоугольником display.display(); display.setCursor(x_date, y_date); // Устанавливаем курсор display.print('0')+display.print(RTC.get(DS1307_DATE,false)); // Если значение даты меньше 10 - вывести ноль+дата display.display(); } else { display.fillRect(x_date, y_date, 11, 7, WHITE); // x, y, w, h, color // Стираем предыдущие значения белым прямоугольником display.display(); display.setCursor(x_date, y_date); // Устанавливаем курсор display.print(RTC.get(DS1307_DATE,false)); // Иначе вывести просто дату display.display(); } display.setCursor(x_date+11, y_date); // Устанавливаем курсор display.print('/'); if (RTC.get(DS1307_MTH,false)<10) display.print('0')+display.print(RTC.get(DS1307_MTH,false)); // Если значение месяца меньше 10 - вывести ноль+месяц else display.print(RTC.get(DS1307_MTH,false)); // Иначе вывести просто месяц display.print('/'); display.print(RTC.get(DS1307_YR,true)); // Выводим год display.display(); // Выводим день недели на дисплей ---------------------------------------------------------------------------- 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"); display.display(); break ; } } //Запуск процедуры измерения температуры sensors.setWaitForConversion(false); sensors.requestTemperatures(); sensors.setWaitForConversion(true); //Считывание значения температуры sensors.getAddress(tempDeviceAddress, 0); temp=sensors.getTempC(tempDeviceAddress); if (temp != TEMP0) { sensors.getAddress(tempDeviceAddress, 0); TEMP0=sensors.getTempC(tempDeviceAddress); display.setCursor(5, 32); // Устанавливаем курсор display.print("TEMP: "); display.fillRect(41, 32, 29, 7, WHITE); // x, y, w, h, color // Стираем предыдущие значения белым прямоугольником display.print(temp); display.print(" C"); display.display(); } } // Конец процедуры обновления экрана 1 раз в секунду 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"); }Навскидку поблема в строке 75. Попробуй записать её так:
Попробую. Но всё же интересно - если держать кнопку то цикл обновления не работает в это время?
Предпологаю потому, что ты запер условие в жёсткие рамки (если равно числу) не больше и не меньше, и я вобще удивляюсь как обновляется когда ты кнопку отпускаешь в чём я кстати сомневаюсь. На печать в порт уходит хоть небольшое но время и строго попасть в равенство до одной тысячной секунды это вряд ли. поэтому при следующей интерации условие ложное т.к. не менише, но больше а значит не равно, игнарируется и твой основной цикл остаётся
void loop() { //Опрос датчика температуры и часов, вывод на дисплей //Вызывается 1 раз в секунду currentMillis = millis(); 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"); }Я думал что независимо от процессов в основном цикле loop будет вызываться процедура обновления экрана. Ведь милисекунды продолжают отсчитываться. А получается что пока нажата кнопка весь основной цикл на этой кнопке и останавливается?
И когда я на кнопку нажимаю быстро, в порт выдается несолько надписей, а не одна.
А когда отпускаешь, что всё становится нормально, всмысле экран печатает нормально время?
А когда отпускаешь, что всё становится нормально, всмысле экран печатает нормально время?
Нет, после отпускания кнопки экран как застыл так и остается без изменений, ничего не обновляется. Видимо в цикле обновления переменная уже стала больше 1000 и условие не выполняется. Думаю замена равно на больше должно дать нужный эффект как ты сказал. Проверю - отпишусь.
Ну так а я о чём писал!? Внимательней читай ответы. После одного непопадания в условие, у тебя остаётся работать только та часть кода, что я написал в 14 посте. НО даже неисправные часы два раза в сутки показывают точное время, у тебя будет что то похожее, когда значение millis переполнится и сбросится, твои часы пойдут при достижении условия )))
Ну так а я о чём писал!? Внимательней читай ответы. После одного непопадания в условие, у тебя остаётся работать только та часть кода, что я написал в 14 посте. НО даже неисправные часы два раза в сутки показывают точное время, у тебя будет что то похожее, когда значение millis переполнится и сбросится, твои часы пойдут при достижении условия )))
Я прочитал внимательно, просто по другому представлял работу устройства.
В общем после замены условия с равно на >= всё нормально обновляется даже при зажатой кнопке.
Спасибо за помощь!