Доброго времени суток!!! Проблема с созданием меню для енкодера. Имеется Ардуино нано, шилд с 4мя реле, 2 датчика температуры 18b20, lcd 1602, енкодер. Задача сделать отдельную регулировку температуры для каждого реле. За ранее спасибо за помощь!!! P.S Ардуино взял в руки 2 недели назад Код (C++): include <LiquidCrystal.h> #include <EEPROM.h> #include <OneWire.h> #include <DallasTemperature.h> #define ONE_WIRE_BUS 4 // Указываем пин подключения data-вывода датчика температуры OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire); // используемые пины const int encPinA=7; // первый выход энкодера const int encPinB=6; // второй выход энкодера const int encBtn=5; // кнопка, встроенная в энкодер const int sensor=4; // температурный датчик const int relayPin=14; // реле_1 const int relayPin1=15; // реле_2 const int relayPin2=16; // реле_3 // переменные для хранения состояний пинов // (чтобы не производить ненужных считываний) boolean encA; boolean encB; // переменные для хранения информации о предыдущих состояниях // и движениях энкодера boolean prev11; // предыдущее состояние было 11 boolean clockwise1=true; // переход по часовой стрелке 1 (от 11) boolean clockwise2=false; // переход по часовой стрелке 2 (от 00) // температура const byte maxTemp=40; // максимальная температура const byte minTemp=10; // минимальная температура byte thTemp; // пороговая температура byte thTemp1; byte thTemp2; float curTemp; // температура в данный момент float curTemp1; const float hyst=0.2; // гистерезис // переменные для обработки состояния кнопки boolean encBtnPrev; // предыдущее состояние boolean encBtnCur; // текущее состояние int encBtnMinInterval=200; // минимальный интервал между нажатиями // нужно для фильтрации дребезга long int encBtnPrevMillis=0; // время предыдущего нажатия // переменные, задействованные во время регулировки температуры boolean edit=false; // включен режим редактирования температуры int blinkInterval=250; // интервал мигания во время редактирования boolean blinkState=true; // текущий этап мигания long int lastBlink=0; // время последнего перехода на следующий этап // время обновления температуры (и реакции дисплея и реле) int tempUpdateInterval=1000; // интервал long int lastTempUpdate=0; // время последнего обновления // символьный дисплей HD44780 16x2 // RS, EN, D4, D5, D6, D7 LiquidCrystal lcd(12,13,8,9,10,11); // обновление значения в EEPROM, если оно отличается void EEPROM_update(int addr, byte value){ byte lastValue = EEPROM.read(addr); if (lastValue!=value){ EEPROM.write(addr, value); } } // обновление информации на дисплее void lcdUpdate(){ lcd.clear(); lcd.setCursor(0,0); lcd.print("tVODA"); lcd.setCursor(5,0); lcd.print(float(curTemp),1); // отображение текущей температуры lcd.setCursor(10,0); lcd.print(float (curTemp1),1); if ((blinkState)||(!edit)){ // отображение целевой температуры // с учётом мигания lcd.setCursor(0,1); lcd.print("SetT>"); lcd.setCursor(5,1); lcd.print(thTemp); } sensors.requestTemperatures(); curTemp1 = float(sensors.getTempCByIndex(1)); delay(10); } // преобразования данных с аналогового датчика // по формуле из документации к датчику double Thermister (int RawADC) { double Temp; Temp = log (((10240000/RawADC) - 10000)); Temp = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * Temp * Temp)) * Temp); Temp = Temp - 273.15; // Convert Kelvin to Celcius return Temp; } void setup() { pinMode(encPinA, INPUT); digitalWrite(encPinA, LOW); pinMode(encPinB, LOW); digitalWrite(encPinB, LOW); pinMode(encBtn, INPUT); digitalWrite(encBtn, LOW); pinMode(relayPin, OUTPUT); pinMode(relayPin1, OUTPUT); pinMode(relayPin, OUTPUT); digitalWrite(relayPin,LOW); digitalWrite(relayPin1, HIGH); digitalWrite(relayPin2, HIGH); Serial.begin(9600); // целевая температура загружается из EEPROM, если она в заданных рамках thTemp = EEPROM.read(0); if ((thTemp>maxTemp)||(thTemp<minTemp)){ thTemp=20; EEPROM.write(0, thTemp); // если в EEPROM мусор, то делаем уборку } curTemp = float(sensors.getTempCByIndex(0)); // первое считывание // реальной температуры lcd.begin(16, 2); lcdUpdate(); } void loop(){ // считывание состояния выходов энкодера encA = digitalRead(encPinA); encB = digitalRead(encPinB); long int millisCur = millis(); // получаем текущее время // с момента запуска // если в состояние 11 пришли не из 11 // и 2 раза детектировалось движение // в одну и ту же сторону, то соответствующим // образом изменяем значение переменной if (edit){ if ((encA)&&(encB)&&(!prev11)){ if ((clockwise1)&&(clockwise2)){ if (thTemp<maxTemp){ thTemp++; } } if ((!clockwise1)&&(!clockwise2)){ if (thTemp>minTemp){ thTemp--; } } blinkState = true; lcdUpdate(); prev11 = true; } // детектирование направления первого перехода (от 11) else if ((!encA)&&(encB)&&(prev11)){ clockwise1 = true; prev11 = false; } else if ((encA)&&(!encB)&&(prev11)){ clockwise1 = false; prev11 = false; } // детектирование направления второго перехода (от 00) else if ((!encA)&&(encB)&&(!prev11)){ clockwise2 = false; } else if ((encA)&&(!encB)&&(!prev11)){ clockwise2 = true; } } // считывание нового состояния кнопки с сохранением старого encBtnPrev = encBtnCur; encBtnCur = digitalRead(encBtn); // если перход из 0 в 1, и предыдущий такой переход был достаточно давно // (защита от дребезга) if ( (encBtnCur)&&(!encBtnPrev)&& ((millisCur-encBtnPrevMillis)>=encBtnMinInterval) ){ // если был режим редактирования, то он выключается // и наоборот if (edit){ blinkState=true; EEPROM_update(0, thTemp); } else { blinkState=false; } lcdUpdate(); edit = !edit; encBtnPrevMillis=millisCur; } // мигание if ((millisCur-lastBlink)>=blinkInterval){ lastBlink=millisCur; if (edit){ lcdUpdate(); blinkState = !blinkState; } } // решение о включении, либо выключении обогревателя // с учётом гистерезиса if ((millisCur-lastTempUpdate)>=tempUpdateInterval){ curTemp = float(sensors.getTempCByIndex(0)); if (curTemp<=((float)thTemp+hyst)){ digitalWrite(relayPin, LOW); } else if (curTemp>=((float)thTemp-hyst)){ digitalWrite(relayPin, HIGH); } if (!edit) lcdUpdate(); lastTempUpdate=millisCur; } }
Творческий тупик) ни как не могу запилить что то типа меню или возможности установки температуры для ещё двух реле
Спасибо огромное! Все подробно описано, буду пробовать) P.S. Только про реализацию на енкодере не нашел ни чего.
С меню что то получилось. Теперь не могу реализовать запись температуры для каждого реле. Переменные для заданной(пороговой) температуры (th temp, th temp1 и 2). Код (C++): #include <LiquidCrystalRus.h> #include <TimerOne.h> #include <Button.h> #include <OneWire.h> #include <DallasTemperature.h> #include <EEPROM.h> #define ONE_WIRE_BUS 4 // Указываем пин подключения data-вывода датчика температуры OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire); LiquidCrystalRus lcd(12, 13, 8, 9, 10,11); Button encoderA (7, 4); // сигнал A Button encoderB (6, 4); // сигнал B Button encoderButton(5, 40); // кнопка long pos = 0; // пооложение энкодера int kn; uint8_t man_with_hat[8] = { 0b00111, 0b00101, 0b00111, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000 }; const int sensor=4; // температурный датчик const int relayPin=14; // реле_1 const int relayPin1=15; // реле_2 const int relayPin2=16; // реле_3 // температура const byte maxTemp=40; // максимальная температура const byte minTemp=10; // минимальная температура byte thTemp; // пороговая температура byte thTemp1;//пороговая температура2 byte thTemp2;//пороговая температура3 float curTemp; // температура в данный момент с первого датчика float curTemp1;// температура в данный момент со второго датчика const float hyst=0.2; // гистерезис // переменные для обработки состояния кнопки boolean encBtnPrev; // предыдущее состояние boolean encBtnCur; // текущее состояние int encBtnMinInterval=200; // минимальный интервал между нажатиями // нужно для фильтрации дребезга long int encBtnPrevMillis=0; // время предыдущего нажатия // переменные, задействованные во время регулировки температуры boolean edit=false; // включен режим редактирования температуры int blinkInterval=250; // интервал мигания во время редактирования boolean blinkState=true; // текущий этап мигания long int lastBlink=0; // время последнего перехода на следующий этап byte thermometer_glyphIndex = 2; byte celsiusSymbol_glyphIndex = 3; byte fan_glyphIndex = 0; // время обновления температуры (и реакции дисплея и реле) int tempUpdateInterval=1000; // интервал long int lastTempUpdate=0; // время последнего обновления // обновление значения в EEPROM, если оно отличается void EEPROM_update(int addr, byte value){ byte lastValue = EEPROM.read(addr); if (lastValue!=value){ EEPROM.write(addr, value); } } // преобразования данных с аналогового датчика // по формуле из документации к датчику double Thermister (int RawADC) { double Temp; Temp = log (((10240000/RawADC) - 10000)); Temp = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * Temp * Temp)) * Temp); Temp = Temp - 273.15; // Convert Kelvin to Celcius return Temp; } void setup() { pinMode(relayPin, OUTPUT); pinMode(relayPin1, OUTPUT); pinMode(relayPin, OUTPUT); digitalWrite(relayPin,HIGH); digitalWrite(relayPin1, HIGH); digitalWrite(relayPin2, HIGH); lcd.begin(16, 2); Timer1.initialize(250); // инициализация таймера 1, период 250 мкс Timer1.attachInterrupt(timerInterrupt, 250); // задаем обработчик прерываний kn = 0; // целевая температура загружается из EEPROM, если она в заданных рамках thTemp = EEPROM.read(0); if ((thTemp>maxTemp)||(thTemp<minTemp)){ thTemp=20; EEPROM.write(0, thTemp); // если в EEPROM мусор, то делаем уборку } curTemp = float(sensors.getTempCByIndex(0)); // первое считывание lcd.createChar(1, man_with_hat); // реальной температуры lcd.begin(16, 2); } void loop() { long int millisCur = millis(); // получаем текущее время // с момента запуска sensors.requestTemperatures(); lcd.setCursor(5,0); lcd.print("тВоды:"); lcd.print(float(sensors.getTempCByIndex(0)),1); lcd.print("\1"); lcd.setCursor(5,1); lcd.print("тДом::"); lcd.print(float(sensors.getTempCByIndex(1)),1); lcd.print("\1"); if(kn == 0){ if(pos <= 0){pos = 0;} if(pos >= 1){pos = 1;} if(encoderButton.flagClick == true && pos == 0){ encoderButton.flagClick = false; kn = 1; pos = 0; lcd.clear();} } if(kn == 1){ if(pos <= 0){pos = 0;} if(pos >= 3){pos = 3;} lcd.setCursor(0,0); lcd.print("НАСТ"); if(pos == 0){ lcd.setCursor(0,1); lcd.print("1РЛ");} if(pos == 1){ lcd.setCursor(0,1); lcd.print("2РЛ");} if(pos == 2){ lcd.setCursor(0,1); lcd.print("3РЛ");} if(pos == 3){ lcd.setCursor(0,1); lcd.print("ВЫХ"); if(encoderButton.flagClick == true && pos == 3){ encoderButton.flagClick = false; kn = 0; pos = 0; lcd.clear();} } } } // обработчик прерывания 250 мкс void timerInterrupt() { encoderA.filterAvarage(); // вызов метода фильтрации encoderB.filterAvarage(); // вызов метода фильтрации encoderButton.filterAvarage(); // вызов метода фильтрации // обработка сигналов энкодера if( encoderA.flagClick == true ) { encoderA.flagClick= false; if( encoderB.flagPress == true) { // против часовой стрелки pos--; } else { // по часовой стрелке pos++; } } }
ну это остается на совести читателя) Мне кажется, а я не работал с энкодерами и не знаю цели, что логика должна быть такой: нажали на энкодер - перевели программу в режим настройки температуры первого реле (Т1) и засекли таймер (таймер опционально). Крутим энкодер - настраиваем Т1 нажали на энкодер - сохраняем Т1 и переходим в режим настройки Т2 ... (аналогично для Т2, Т3 и почти Т4) нажали на энкодер - сохраняем Т4 и переходим в нормальный режим работы (опционально) Про таймер - любое движение с энкодером сбрасывает таймер, но если время (по вкусу) вышло, то сохраняется Ti и переходим в нормальный режим работы.
Совершенно с Вами согласен! Я не могу реализовать это в коде в виду недостатка опыта и знаний в работе с Ардуино. Был бы через мерно благодарен Вам за помощь в реализации на примере 1 реле. P.S. У меня уже как на экзамене. Запор знаний и понос мыслей)))
Ну я с энкодером не работал. Допустим где-то в коде есть bool EncPressed = тру когда кнопку нажали и отпустили. тогда Код (C++): int i=0; //номер используемого датчика float Ttmp; //временная переменная для хранения задаваемой температуры bool SetTemp=false; //флаг режима настройки .... Void encRotate()//процедура преобразования угла поворота в температуру { ... Ttmp = f(угла поворота) } void loop() { if (encPressed==true) || (SetTemp == true) { //если кнопка не нажата, то ничего не делаем //или //не делаем до тех пор в режиме настройки пока не нажмут кнопку. if (encPressed==true) { encPressed=false; SetTemp=true; //режим настройки температур. Этот флаг можно использовать далее в коде для остановки выполнения программы в других местах switch (i) case 0: T1=Ttmp; break; case 1: T2=Ttmp; break; case 2: T3=Ttmp; break; case 3: T4=Ttmp; i=-1;//т.к. далее все равно +1 будет SetTemp=false; //выкл блокировку кода break; i=i+1; } } } мне кажется первый иф лишний, но там можно вставить еще и таймера обработку код не проверял, не компилировал. Синтаксис свитч-кейз не проверял, i=i+1 должно быть вне свитча
Огромное спасибо, Вам! Теперь все понятно) на счет того, что не проверяли код ни чего страшного. Главное теперь мне понятно как именно все работает)