Здравствуйте. Только начал осваивать ардуино уно и уже возникли вопросы. Пытаюсь избавиться от функции "delay()" в коде так как нужно чтобы ардуино не "зависала" на время обработки этих delay. Решил попробовать на простейшем скетче, который попеременно выводит два экрана дисплея 1602 с I2C. На первом экране температура (1 строка) и влажность (2 строка) с DHT11, потом задержка 5 сек, потом второй экран со временем (1 строка) и датой (2 строка) с DS3231, потом опять задержка и цикл повторяется по новой. Скетч ниже, от delay во втором экране я ушел - сделал через while и millis Код (C++): #include <Time.h> #include <DS1307RTC.h> #include <LiquidCrystal_I2C.h> LiquidCrystal_I2C lcd(63,16,2); // Устанавливаем дисплей #include <DHT.h> #define DHTPIN 2 // what pin we're connected to #define DHTTYPE DHT11 // DHT 11 DHT dht(DHTPIN, DHTTYPE); byte degree[8] = // кодируем символ градуса { B00111, B00101, B00111, B00000, B00000, B00000, B00000, }; byte l [8] = // кодируем символ л { B00111, B01001, B01001, B01001, B01001, B01001, B10001, }; byte g [8] = // кодируем символ л { B10101, B10101, B10101, B01110, B10101, B10101, B10101, }; byte mz [8] = // кодируем символ л { B10000, B10000, B11110, B10001, B10001, B10001, B11110, }; byte p [8] = // кодируем символ п { B11111, B10001, B10001, B10001, B10001, B10001, B10001, }; byte y [8] = // кодируем символ у { B10001, B10001, B10001, B11111, B00001, B00001, B11110, }; byte i=0; unsigned long previousMillis = 0; const long interval =5000; void setup() { setSyncProvider(RTC.get); //Устанавливаем время в формате: //Часы, минуты, секунды, день, месяц, год //setTime(14,29,0,30,7,2016); //Применяем: //RTC.set(now()); dht.begin(); lcd.init(); lcd.backlight();// Включаем подсветку дисплея lcd.createChar(1, degree); // Создаем символ градус под номером 1 lcd.createChar(2, l); // Создаем символ л под номером 2 lcd.createChar(3, g); // Создаем символ ж под номером 3 lcd.createChar(4, mz); // Создаем символ ь под номером 4 lcd.createChar(5, p); // Создаем символ ж под номером 5 lcd.createChar(6, y); // Создаем символ ь под номером 6 } void loop() { int h = dht.readHumidity(); int t = dht.readTemperature(); lcd.clear(); lcd.setCursor(0, 0); lcd.print("TEM\5EPAT\6PA: "); lcd.print(t); lcd.print("\1"); lcd.setCursor(0, 1); lcd.print("B\2A\3HOCT\4: "); lcd.print(h); lcd.print("%"); delay(5000); lcd.clear(); i=0; //обновляем показания часов через цикл каждую секунду while(i<=1){ digitalClockDisplay(); //вызываем функцию, которая числа меньше 10 выводит с нулем впереди unsigned long currentMillis = millis(); if(currentMillis - previousMillis >= interval){ previousMillis = currentMillis; i++; } } } void digitalClockDisplay(){ // digital clock display of the time lcd.setCursor(4, 0); printDigits(hour()); lcd.print(":"); printDigits(minute()); lcd.print(":"); printDigits(second()); lcd.setCursor(3, 1); printDigits(day()); lcd.print("."); printDigits(month()); lcd.print("."); lcd.print(year()); } void printDigits(int digits){ // utility function for digital clock display: prints preceding colon and leading 0 if(digits < 10) lcd.print('0'); lcd.print(digits); } При попытке заменить delay(5000) на такой же цикл while и millis как у времени (даже с другими переменными начального времени и интервала) начинается какая-то ахинея: то первый экран вообще не показывается, то идет наложение двух экранов друг на друга, причем второй экран поверх первого. И вообще так и не понял как эта функция millis работает. Почему, например, при таком коде Код (C++): while(i<=1){ digitalClockDisplay(); //вызываем функцию, которая числа меньше 10 выводит с нулем впереди unsigned long currentMillis = millis(); if(currentMillis - previousMillis >= interval){ previousMillis = currentMillis; i++; } Экран со временем отображается 5 сек и данные обновляются каждую секунду (то есть виден ход секунд), а при коде Код (C++): while(i<=1){ unsigned long currentMillis = millis(); if(currentMillis - previousMillis >= interval){ previousMillis = currentMillis; digitalClockDisplay(); //вызываем функцию, которая числа меньше 10 выводит с нулем впереди i++; } хода секунд не видно - время обновляется просто каждые 5 секунд (если поставить условие while(i<=1) другим, например, while(i<=3) для удобства наблюдения) Вобщем вопросы на которые не могу найти ответа: 1. Как избавиться от delay на первом экране (с температурой и влажностью)? 2. Почему время в цикле while обновляется каждую секунду несмотря на то, что цикл считает до одного и время интервала для millis стоит 5 секунд? 3. Конструкция вида while --- millis вообще лучше чем delay? В плане не тормозит ли она программу, например, если в программе будет еще модуль подсчета количества импульсов на дискретном входе (от счетчиков воды), при том что входы это не входы прерываний.
На первый взгляд проблема в том, что вы просто заменяете delay() циклом который выжидает некоторое время, что то же самое. Функция проверки интервала не должна останавливать программу, а должна встраиваться в нее ожидая своего времени.
В том то и проблема что если убираю while то millis перестает работать - на секунду выводит экран с временем и датой а потом опять переходит на температуру. Хотя интервал задан в 5000 мс. Не могу понять почему так и как сделать правильно
Если надо вот это, то навскидку - примерно так: Код (C++): #define SCREEN_SHOW_TIME 5000 // сколько мс показывать один экран enum {SCREEN_ONE, SCREEN_TWO, DUMMY_SCREEN}; int8_t whichScreen; // переменная, которая держит в себе номер экрана unsigned long lastScreenChangeCheck; // сюда будем складывать millis // функция показа определённого экрана void showScreen(byte whichScreen) { switch(whichScreen) { case SCREEN_ONE: // Показываем первый экран break; case SCREEN_TWO: // показываем второй экран break; } } void setup() { lastScreenChangeCheck = 0; whichScreen = SCREEN_ONE; // при старте сразу показываем первый экран showScreen(whichScreen); } void loop() { unsigned long curTime = millis(); if(curTime - lastScreenChangeCheck > SCREEN_SHOW_TIME) { // настало время показать новый экран lastScreenChangeCheck = curTime; whichScreen++; // прибавляем номер экрана // если зашли за последний - переваливаемся на первый if(whichScreen == DUMMY_SCREEN) whichScreen = SCREEN_ONE; // рисуем новый экран showScreen(whichScreen); } // если надо рисовать в каждом вызове loop, // то просто раскомментируем // showScreen(whichScreen); // тогда первый вызов showScreen (выше) можно убрать. } Код расширяем, достаточно перед DUMMY_SCREEN поставить ещё идентификатор, и в функцию showScreen дописать вывод нужной информации на экран, когда показывается экран с новым идентификатором. Разбирайтесь
Попробовал код - работает. Вот только если функцию digitalClockDisplay(); вставить перед break, то часы показываются 5 секунд как и должно, но хода секунд нету. Если я вставлю свою старую конструкцию в "экран" Код (C++): //обновляем показания часов через цикл каждую секунду while(i<=1){ digitalClockDisplay(); //вызываем функцию, которая числа меньше 10 выводит с нулем впереди unsigned long currentMillis = millis(); if(currentMillis - previousMillis >= interval){ previousMillis = currentMillis; i++; } это позволит ардуино работать в режиме многопоточности (имея ввиду что она фоном должна еще считать импульсы от счетчиков)? Или в данном случае применение while равноценно delay?
Я жевал что-то подобное. Посмотри в конце темы ссылки. Сылка на другой форум http://arduino.ru/forum/programmirovanie/klass-protsessy-i-programma-blink-bottom