Как я ранее упоминал, я использовал среду разработки Arduino, версию использую 1.6.5 (последнее время они что-то изменили внутри всего этого безобразия, и добрая часть библиотек накрылась медным тазиком).
Ну а теперь сам код.
Весь я его сюда, конечно, пихать не буду, остановлюсь лишь на нескольких моментах.
Объяснять, как опрашивать датчики тоже не буду, см. выше, а если лень, то я хреново объясняю теорию.
_________________________________________________________________________________
void loop()
{
newBackLigth(map(analogRead(0), 0, 1023, 3, 255));
if (millis() > watchTime) showClock();
if (millis() > tempoMillis) tempo();
}
Это всё, что у меня есть в loop.
Задаю новую подсветку,
Если пришло время обновить часы, обновляем,
Аналогично с температурой
_________________________________________________________________________________
void newBackLigth(byte newBLnum)
{
int dif = nowBLnum - newBLnum;
if (abs(dif) > 25)
{
for (; nowBLnum != newBLnum; dif < 0 ? nowBLnum++ : nowBLnum--)
{
analogWrite(LEDpin, nowBLnum);
delay(5);
}
}
}
Этой функции мы скармливаем значение новой подсветки, считанное из нулевого аналогового порта, и конвертированное из диапазона от 0 до 1023 в диапазон от 3 (чтобы в полной темноте было видно) до 255.
Далее вычисляем разницу между текущей подсветкой и новой,
Смотрим на эту разницу по модулю, и если она больше 25, то
Постепенно наращиваем подсветку.
_________________________________________________________________________________
void showClock()
{
watchTime = millis() + 1000;
updateWatch();
if (mode == 0) bigWatch();
if (mode == 1 || mode == 2) smallWatch();
if (h == 0 && m == 0 && s < 2) showDate();
}
Тут я запоминаю, когда я должен в следующий раз сюда зайти,
Обновляю время,
Если 0 режим - чешем в функцию отрисовки больших часов,
Если 1, или 2, то рисуем маленькие часы (да-да-да, тут можно было юзать else),
Ну и если начался новый день, обновим дату, которую, к слову, мы уже показали в setup.
_________________________________________________________________________________
updateWatch ничего интересного из себя не представляет, она лишь загоняет в глобальные переменные количество часов минут и секунд. К слову, если считать время не удалось, то мы получим 165 вместо времени. Этим и воспользуемся тут. Но забудем воспользоваться этим в больших часах, и вспомним, когда будем пилить длиннопост.
void smallWatch()
{
lcd.setCursor(15, 3);
if (h == 165) lcd.print("ERROR");
else
{
if (h != hl)
{
hl = h;
if (h < 10) lcd.print("0");
lcd.print(h);
}
s % 2 == 0 ? lcd.print(" ") : lcd.print(":");
if (m != ml)
{
ml = m;
lcd.setCursor(18, 3);
if (m < 10) lcd.print("0");
lcd.print(m);
}
}
}
Тут всё просто. Выходим на исходную позицию,
Если 165, вместо часов, тупо пишем "ошибка", и валим оттуда,
Иначе смотрим поменялось ли количество часов, если нет, проходим мимо,
Если сменилось количество, запоминаем этот факт,
Смотрим нужно ли добавить "0" перед количеством часов, если нужно добавляем,
И пишем количество часов.
Потом проверяем количество секунд на чётность, и, если количество чётное,
пишем двоеточие, иначе, стираем его пробелом.
Делаем с количеством минут то же самое, что и с количеством часов чуть ранее.
Кстати, чтобы часы и минуты точно были написаны при включении я просто записал в переменные для сравнения 99. Попробуй, блин, не обнови!
_________________________________________________________________________________
void bigWatch()
{
if (h != hl)
{
hl = h;
numBuilder(h / 10, 0);
numBuilder(h % 10, 4);
}
if (m != ml)
{
ml = m;
numBuilder(m / 10, 10);
numBuilder(m % 10, 14);
}
if (s % 2 == 0)
{
lcd.setCursor(8, 0);
lcd.write(4);
lcd.setCursor(8, 2);
lcd.write(1);
}
else
{
lcd.setCursor(8, 0);
lcd.write(130);
lcd.setCursor(8, 2);
lcd.write(130);
}
lcd.setCursor(18, 2);
if (s < 10) lcd.print("0");
lcd.print(s);
}
Тут примерно то же самое, только теперь при несовпадении старых значений с новыми, мы запоминаем новые, и разбиваем их на десятки и единицы, после чего скармливаем с какой-то цифрой новой функции с именем numBuilder!
А ещё теперь смотрим на чётность секунд и рисуем большие точки, либо затираем их пустыми 130-ми символами. Да, так можно!
А ещё пишем количество секунд. Именно тут, в принципе, тоже надпись "ERROR" замутить, но не сейчас...
_________________________________________________________________________________
void numBuilder(byte num, byte pos)
{
if (num == 0) for (byte i = 0; i <= 8; i++)nowNumber[i] = number0[i];
if (num == 1) for (byte i = 0; i <= 8; i++)nowNumber[i] = number1[i];
if (num == 2) for (byte i = 0; i <= 8; i++)nowNumber[i] = number2[i];
if (num == 3) for (byte i = 0; i <= 8; i++)nowNumber[i] = number3[i];
if (num == 4) for (byte i = 0; i <= 8; i++)nowNumber[i] = number4[i];
if (num == 5) for (byte i = 0; i <= 8; i++)nowNumber[i] = number5[i];
if (num == 6) for (byte i = 0; i <= 8; i++)nowNumber[i] = number6[i];
if (num == 7) for (byte i = 0; i <= 8; i++)nowNumber[i] = number7[i];
if (num == 8) for (byte i = 0; i <= 8; i++)nowNumber[i] = number8[i];
if (num == 9) for (byte i = 0; i <= 8; i++)nowNumber[i] = number9[i];
for (byte i = 0; i <= 8; i++)
{
if (i == 0) lcd.setCursor(pos, 0);
if (i == 3) lcd.setCursor(pos, 1);
if (i == 6) lcd.setCursor(pos, 2);
lcd.write(nowNumber[i]);
}
}
А вот и моя радость! В общем, именно эта функция и рисует большие цифры!
Она получает значения цифры и позиции (откуда начинать рисовать самый верхний левый символ).
В зависимости от того, какую именно цифру мы хотим отобразить, выбираем соответствующий массив, и загоняем его в "буферный массив". Для каждой цифры я сделал массив с номерами символов в дисплее, из которых мы можем получить цифру. Размер цифры 3 на 3 символа, то есть 9, таким образом, девять номеров этих самых символов пойдут в массив, и в любом случае оттуда попадут прямо на дисплей!
_________________________________________________________________________________
В температурных экранах тот же принцип, по сути, запоминаем, когда можно залезть туда снова, в зависимости от режима, уходим в разные экраны.
Только несколько моментов:
- TempBigNum я перепишу, так как у меня появилась новая фитча, расскажу о ней позже.
- там же есть возможность работы с минусовой температурой, если она таковая, я рисую "минус", умножаю температуру на (-1) и спокойно отрисовываю.
- там же я отрисовал из доступных мне символов слово "ERROR":
_________________________________________________________________________________
Ну и по поводу влажности. Вот калькулятор абсолютной влажности.
Так как DHT11 возвращает только относительную влажность, необходимо иметь возможность высчитать абсолютную, чтобы не нагнать в гараж более влажный воздух по факту, когда относительно насыщенного пара он кажется суше. Всё просто, скармливаем функции 3 параметра: температуру, давление, влажность в %, она в ответку выплёвывает абсолютную влажность. Я очень долго бился над этой функцией, и я её доделал. К слову, она жрёт ОЧЕНЬ МНОГО памяти. Ну прям очень. Кстати, ей можно скармливать давление и в миллиметрах ртутного столба и в паскалях. Очень полезная фитча!
float CAH(float temperature, float pressure, float humidity)
{
// float A1 = (pressure * 133.322) / 100; // if pressure in mmHg
float A1 = pressure / 100; // if pressure in Pa
float A2 = 6.112 * exp((17.62 * temperature) / (243.12 + temperature));
float A3 = 1.0016 + (3.15 * pow(10, (-6))) * A1 - 0.074 / A1;
float A4 = A2 * A3;
float A5 = (humidity / 100) * A4;
float A6 = temperature + 273.15;
float A7 = A5 * 100 / (461.5 * A6) * 1000;
return A7;
}
_________________________________________________________________________________
Программа есть, скетч написан, адаптирован под использование БЕЗ i2c адаптера для LCD, проверени готов к заливке. Но... КУДА???
Развожу я платы в программе Sprint-Layout 6, всё нравится.
По сути ничего сложного нет. Размещаем отверстия, проводим дорожки, заканчиваем, смотрим фотовид, материмся на то, что некоторые элементы зазеркалили, переделываем 20 раз, рисуем обозначения, создаём макросы... Короче говоря, набиваем руку!
Далее идёт засверливание (по крайней мере у меня) на фрезерном станке с ЧПУ.
После чего МИР РАЗЛАМЫВАЕТСЯ НА ДВЕ ЧАСТИ!
Но не для меня. Я уже определился с выбором, и я использую фоторезист (не путать с фоторезистором!), кто-то использует ЛУТ.
В общем, ЛУТ расшифровывается, как лазерно-утюжная технология, когда дорожки зеркально печатаются на бумаге, с помощью утюга переносятся на текстолит, и травится.
У меня принтер струйный, поэтому фоторезист сам выбрал меня. А я и не против!
В общем, печатаем фотошаблон!