Вот решил сделать метеостанцию с передачей по воздуху значений температуры и влажности. Но на текущий момент застрял на выведении на дисплей (при нажатии кнопки) показаний температуры и влажности. Дело в том что мне нужно задержаться на 5 секунд когда на дисплее показана влажность, а функция delay() не работает в прерываниях. Думал использовать таймеры, но даже не понял могут ли они такое делать. Нужна ваша помощь. Если что то я полный нуб и изучаю программирование две недели, буду признателен на подробное объяснение . Код (Text): // Подключаем библиотеки: #include <LiquidCrystal.h> #include "DHT.h" #include <WolfCrystal.h> volatile int state = LOW; //Определяем датчик влажности и температуры #define DHTPIN 11 #define DHTTYPE DHT11 // Включаем дачик в 16 мгц режим ардуино DHT dht(DHTPIN, DHTTYPE); // обозначаем пины на которые подключён дисплей LiquidCrystal lcd(1, 3, 4, 5, 6, 7); // В конструкторе передаём указатель на ранее созданный // экземпляр LiquidCrystal: WolfCrystal WC(&lcd); // Описываем наши собственные символы в виде массивов битовых масок. enum { SYMBOL_HEIGHT = 8 }; byte simG[SYMBOL_HEIGHT] = { B00100, B10101, B01110, B00100, B01110, B10101, B00100, B00000, }; void setup() { pinMode(A0, OUTPUT); // устанавливаем 9 ногу как выход lcd.createChar(7, simG); //Влючаем пищалку на 0.2 сек digitalWrite(A0, HIGH); delay(200); analogWrite(A0, LOW); dht.begin(); // обозначаем строки и рядки дисплея: lcd.begin(16, 2); // Используем прерывание на кнопку attachInterrupt(0, vlag, RISING); } void loop() { // Ожидаем пару секунд перед измерениями. delay(2000); // читаем температуру с дачика в цельсиях float t = dht.readTemperature(); // Выводим надписи и температуру lcd.setCursor(0,0); lcd.print(WC.GS(" ТЕМПЕРАТУРА:") ); lcd.setCursor(5,1); lcd.print(t); lcd.print(" C "); } void vlag() { //выводим надписи и влажность lcd.clear(); float h = dht.readHumidity(); lcd.setCursor(3,0); lcd.print(WC.GS("ВЛА ")); lcd.setCursor(6,0); lcd.write(7); lcd.print(WC.GS("НОСТЬ: ")); lcd.setCursor(5,1); lcd.print(h); lcd.print(" %"); }
Я бы посоветовал вам пока не использовать прерывания, тем более что в данном случае это и не нужно. Заведите пару переменных типа unsigned long и отправляйте туда текущее время. Типа такого должно получится Код (C): ......//где-то перед Setup unsigned long temperatureDelay =0; unsigned long buttonCheck =0; //тут должен был быть Setup и т.д и т.п void loop() { // Ожидаем пару секунд перед измерениями. // delay(2000); if (millis()-temperatureDelay>=2000) { // читаем температуру с дачика в цельсиях float t = dht.readTemperature(); // Выводим надписи и температуру lcd.setCursor(0,0); lcd.print(WC.GS(" ТЕМПЕРАТУРА:") ); lcd.setCursor(5,1); lcd.print(t); lcd.print(" C "); temperatureDelay=millis(); } if (millis()-buttonCheck>=100) { buttonCheck = millis(); if (!digitalRead(2)) { //выводим надписи и влажность lcd.clear(); float h = dht.readHumidity(); lcd.setCursor(3,0); lcd.print(WC.GS("ВЛА ")); lcd.setCursor(6,0); lcd.write(7); lcd.print(WC.GS("НОСТЬ: ")); lcd.setCursor(5,1); lcd.print(h); lcd.print(" %"); delay(5000); } } }
Кстати в коде вы сделали опечатку и небольшую неточность. unsigned long нужно выводить перед функцией Setup, так как она потом будет недоступна нигде кроме Setup. С вашим вариантом нет долгих задержек и код работает быстрее. Подскажите пожалуйста как сделать так что бы при нажтии кнопки показывалась влажность, при следующем - температура и т.д. Планирую туда ещё и датчик атмосферного давления прилепить и что бы была всего 1 кнопка. То есть при каждом нажатии отображалась новая величина.
Упс, да. Спасибо поправил. Это был не готовый код а размышления на тему, но вы и так всё верно поняли). Возможно такое решение вам подойдёт http://wiki.amperka.ru/конспект-arduino:кнопочный-переключатель Ну и вообще, посмотрите разные штучки тут http://wiki.amperka.ru/мини-проекты-arduino-breadboard:оглавление Можно ещё сделать меню, об этом тут http://forum.amperka.ru/threads/Библиотека-для-создания-Меню-на-дисплеях.1815/ Да и вообще - посмотрите по форуму, много для себя найти сможете того, что можно было бы применить
У меня появилась идея но есть небольшие уточнения. Создать два своих цикла void в которых буду инициализировать вывод температуры и влажности В основном цикле написать условие в котором при нажатии кнопки будет идти переход с одного цикла на другой. Нормальная идея? Если да, скажите как синтаксически использовать названия циклов в условии. Например: Код (Text): if (knopka == HiGH) {переходим к циклу влажности}
void это не цикл, это функция которая ничего не возвращает. Аналог процедур в паскале, например. Когда мы пишем код функции, то перед её названием ставится тип того значения, которое она возвращает. Например Код (C): //функция вернёт площадь круга float circleArea(float radius) { return 3.14*radius*radius; } Вам же можно было бы завести переменную, в которой можно хранить текущее состояние, и потом проверять это состояние и выполнять соответствующую процедуру. Для случая двух состояний это будет предложенное вами решение Код (C): //где-то выше #define HUMID 0 #define TEMP 1 int state; //..... state = HUMID; //..... if (state == HUMID) showHumidity(); else showTemperature(); //..... //где-то далеко внизу void showHumidity() { } void showTemperature() { } Если состояний больше - например вам захочется выводить ещё и скорость ветра, то лучше воспользоваться конструкцией switch. Короче говоря рекомендую вам прочитать эту статью http://wiki.amperka.ru/программирование:конечный-автомат Ещё очень полезно было бы вообще прочитать для начала вот это http://wiki.amperka.ru/программирование:оглавление Для начала хватит, а дальше появятся другие вопросы)
По мере расширения функционала, появились проблемы. У меня есть дисплей на который выводятся показания с различных датчиков. Так вот мне нужно сделать два действия на одну кнопку, то есть при нажатии без задержки производится одно действие, а про нажатии с задержкой другое. Подскажите пожалуйста как это реализовать, а то неделю уже мучаюсь.
Для начала следует определиться со временем длинного и короткого нажатия и действием, если длительность нажатия оказалась между этими величинами: ничего, действие по короткому нажатию, какое-то третье действие. Есть два варианта. 1. Сделать одно действие при самом нажатии. Дождаться отпускания, периодически проверяя состояние кнопки. Если к моменту истечения времени длинного нажатия кнопка все еще нажата, выполнить второе действие, после чего вывесить флаг, что действие произошло, и сбросить его при отпускании кнопки. Это годится, если первое действие не влияет существенно на поведение прибора, например, включение подсветки. Примерно так: Код (Text): #define LONG_PRESS_TIME 3000 unsignrd long int buttonPressTime; int buttonState=0; // 0 - ждем нажатия, 1- ждем отпускания и времени длинного нажатия, 2 - ждем отпускания void loop() { int buttonPressed; ... // определение состояния кнопки тем или иным способом (прямое чтение с пина, прерывание) if (buttonPressed) { switch(state) { case 0: buttonState=1; buttonPressTime=millis(); // действия по короткому нажатию ... break; case 1: if (millis()-buttonPressTime>=LONG_PRESS_TIME) { buttonState=2; // действия по длинному нажатию ... } break; } } else { buttonState=0; } } 2. Засечь факт нажатия кнопки. Дождаться отпускания. Если время нажатия меньше короткого - выполнить одно действие. Ждать до истечения длинного действия или отпускания. Если время длинного нажатия произошло до отпускания, то выполнить второе действме. Примерно так: Код (Text): #define LONG_PRESS_TIME 3000 #define SHORT_PRESS_TIME 100 unsignrd long int buttonPressTime; int buttonState=0; // 0 - ждем нажатия, 1- ждем отпускания и времени длинного нажатия, 2 - ждем отпускания void loop() { int buttonPressed; ... // определение состояния кнопки тем или иным способом (прямое чтение с пина, прерывание) if (buttonPressed) { switch(state) { case 0: buttonState=1; buttonPressTime=millis(); break; case 1: if (millis()-buttonPressTime>=LONG_PRESS_TIME) { buttonState=2; // действия по длинному нажатию ... } break; } } else { buttonState=0; if (millis()-buttonPressTime<SHORT_PRESS_TIME) { // действия по короткому нажатию ... } else { if (buttonState==1) { // действия по нажатию длительностью между коротким и длинным ... } } } }