Энкодер + 1-wire
- Войдите на сайт для отправки комментариев
Чт, 21/04/2016 - 17:42
Уважаемы коллеги!
Есть проблема. Три дня назад купил ардуину (что само по себе проблема - кончилось свободное время). Начал осваивать. Прицепил температурный датчик 1-wire (1DS18B20), экранчик, кнопочки, светодиодики. Все работает. Начал цеплять энкодер. Появилась проблема.
Код:
#include <LiquidCrystal.h> #include <OneWire.h> LiquidCrystal lcd(12, 11, 5, 4, 3, 2); // описываем экранчег enum { LCD_WIDTH = 16, LCD_HEIGHT = 2 }; // размеры экрана enum { ENC_PIN1 = 7, ENC_PIN2 = 10 }; // куда прицеплен энкодер OneWire ds(6); // DS18B20 on pin 6 (a 4.7K resistor is necessary) int ledPin = 8; // сетодиод int btnPin = 13; // кнопка int val=0; // для кнопки int enc_counter = 0; // счетчик щелчков энкодера void setup() { pinMode(ledPin, OUTPUT); // это выход - светодиод pinMode(btnPin, INPUT); // а это вход - кнопка // описываем подключение энкодера pinMode(ENC_PIN1, INPUT); pinMode(ENC_PIN2, INPUT); // запускаем экран lcd.begin(LCD_WIDTH, LCD_HEIGHT); // запускаем ком-порт Serial.begin(9600); } /* Функция декодирования кода Грея, взятая с Википедии. * Принимает число в коде Грея, возвращает обычное его представление. */ unsigned graydecode(unsigned gray) { unsigned bin; for (bin = 0; gray; gray >>= 1) bin ^= gray; return bin; } void loop() { // НАЧАЛО МЕГАЦИКЛА /* НАЧАЛО 1-WIRE // для 1-wire датчика byte i; byte present = 0; byte data[12]; byte addr[8]; if ( !ds.search(addr)) { // Serial.print("No more addresses.\n"); ds.reset_search(); // delay(250); return; } if ( OneWire::crc8( addr, 7) != addr[7]) { Serial.print("CRC is not valid!\n"); return; } if ( addr[0] != 0x28) { Serial.print("Device is not a DS18B20 family device.\n"); return; } ds.reset(); ds.select(addr); ds.write(0x44,1); // запускаем конвертацию // delay(1000); // скорее всего достаточно 750ms // we might do a ds.depower() here, but the reset will take care of it. present = ds.reset(); ds.select(addr); ds.write(0xBE); // считываем ОЗУ датчика for ( i = 0; i < 9; i++) { // обрабатываем 9 байт data[i] = ds.read(); } // высчитываем температуру :) int HighByte, LowByte, TReading; float celsius; LowByte = data[0]; HighByte = data[1]; TReading = (HighByte << 8) + LowByte; celsius = TReading/16.0; lcd.setCursor(0, 0); lcd.print("T = "); lcd.print(celsius); lcd.print(" "); // простейший термостат if(celsius > 27 ) // температура выше 27 { digitalWrite(ledPin, HIGH); } // зажигаем светодиод else // температура ниже { digitalWrite(ledPin, LOW); } // гасим светодиод КОНЕЦ 1-WIRE */ /* НАЧАЛО ОБРАБОТКИ ЭНКОДЕРА */ // Обрабатываем энкодер static uint8_t previous_code = 0; // предыдущий считанный код /* gray_code - считанное с энкодера значение * code - декодированное значение */ uint8_t gray_code = digitalRead(ENC_PIN1) | (digitalRead(ENC_PIN2) << 1), code = graydecode(gray_code); /* Если считался нуль, значит был произведён щелчок ручкой энкодера */ if (code == 0) { /* Если переход к нулю был из состояния 3 - ручка вращалась * по часовой стрелке, если из 1 - против. */ if (previous_code == 3) { enc_counter++; } else if (previous_code == 1) { enc_counter--; } } /* Сохраняем код и ждём 1 мс - вполне достаточно опрашивать энкодер * не более 1000 раз в секунду. */ previous_code = code; delay(1); /* КОНЕЦ ОБРАБОТКИ ЭНКОДЕРА */ // Выводим на экран lcd.setCursor(0, 1); lcd.print(enc_counter); lcd.write(" "); // Сброс счетчика энкодера val = digitalRead(btnPin); // узнаём состояние кнопки if(val==HIGH) // кнопка нажата { lcd.clear(); enc_counter = 0; } // КОНЕЦ МЕГАЦИКЛА }
В общем, как только раскоментирую кусок кода от "НАЧАЛО 1-WIRE" до "КОНЕЦ 1-WIRE", то начинает работать градусник, но перестает работать энкодер. :(
Куда бечь?
концевик посадить на другие пины (например А2, А3)
концевик посадить на другие пины (например А2, А3)
Что-то не сильно помогло. Ввод стал более ощутим ( на цифовых входах на 8-10 оборотов счетчик менялся на 1-2, теперь надо сделать 3-4 оборота энкодера, чтобы изметить счетчик на 1-2).
Замечено, что реакция на обороты энкодера более заметна при неизменной температуре. Как только начинают передаваться данные о температуре, так не реагирует на энкодер. Т.е. надо функцию опроса датчика температуры запускать раз в 5-10 сек., чаще не чему. Вопрос - как это сделать? Насколько я понял, delay() приостанавливает всю программу?
Думаю вам надо покурить "блинк без делай", должно помочь.
Думаю вам надо покурить "блинк без делай", должно помочь.
Должно. Но помогает только 1 цикл в первые 10 сек. Мистика какая-то.
Снял захватывающий боевик о работе скетча - https://youtu.be/UgmeN3wiuB4
Ткните носом, где я ошибся?
вычитание двух беззнаковых длинных и сравнение со знаковым интервалом .. а так, в целом все работает как вы задумали. :)
сделайте интервал тоже беззнаковым и будет вам щастье.
Я бы на вашем месте, всеж таки вынес строчки определения статических переменных из loop() .. некомильфо.
Да и вывод на дисплей тоже бы загнал в everyMillis() также как съем температуры .. не шустро он отрисовывает вообще-то. На каждый символ ставит задержку в 4-5мсек. Вполне можно отрисовывать раз в 100мсек. (каждую 0.1сек) для отображения - вполне достаточно. Зато энкодер будет работать пошустрей.
Спасибо! Заработало!! :)
Осталось разобраться с длинным-коротким нажатием кнопки для задания уставки... :)
Я бы на вашем месте, всеж таки вынес строчки определения статических переменных из loop() .. некомильфо.
С какого перепугу? По всем ресурсам - одинаково, а вот по возможности случайного изменения - в loop они локализованы, а снаружи - меняй, кто хочет.
После истории с define, думал, что Вы уже не сможете меня удивить своей безграмотностью, но я Вас явно недооценивал :)))
Мне надоело уже ваше загубленное в молодости ЧСВ, поэтому стараюсь не комментировать ваши перлы. В частности этот тоже. Ещё один Клапауций.. :)
Продолжаем разговор. Допилил скетч до задания уставки. Начал ломать голову над мигающим тестом. Начал с мигающего курсора. Файл примера из библиотеки LiquidCrystal работает на "УРА". Поэксперементировал с положением курсора - тоже работает. В моем скетче куда бы не написал
lcd.setCursor(x,y);
lcd.blink();
Этого самого блинка и не происходит. Только рябь проходит по строке, где блинк.
Куда копать?
Там в классе есть метод отправки команды дисплею, попробуйте его так: lcd.command(9);
Там в классе есть метод отправки команды дисплею, попробуйте его так: lcd.command(9);
Что-то не получается...
Так?
На экране просто все пропадает и все. После отпускания кнопки не появляется.. :(