ARDUINO Стрелочные часы на Oled дисплее

sklecs

✩✩✩✩✩✩✩
4 Янв 2022
5
0
Представляю вашему вниманию стрелочные часы на Oled дисплее. Проект предназначен для практического изучения работы с дисплеем. Состоит он изArduino Nano и самого Oled дисплея.
Алгоритм работы: каждую секунду секундная стрелка движется и увеличивается количество секунд, когда секунд будет =60,тогда добавляется 1 минута, аналогично с часом.
В коде прокомментировал каждую строчку.
C++:
//Подключем библиотеки для работы с дисплеем
#include "Wire.h"
#include "Adafruit_GFX.h"
#include "Adafruit_SSD1306.h"

//Объявлем пины управления
#define OLED_MOSI 9
#define OLED_CLK 10
#define OLED_DC 11
#define OLED_CS 12
#define OLED_RESET 13

Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS); //Что это такое?Показываем пины библиотеке для работы?

int X=90; //Центр окружности и так же ось стрелочек
int Y=32; //Центр окружности и так же ось стрелочек

int Xs;   //Вторая точка секудной стрелки
int Ys;   //Вторая точка секудной стрелки
int Xm;   //Вторая точка минутной стрелки
int Ym;   //Вторая точка минутной стрелки
int Xh;   //Вторая точка часовой стрелки
int Yh;   //Вторая точка часовой стрелки

int second=0;       // Начальное значение секунды
int minutes=37;     // Начальное значание минуты
int hour=14;        // Начальное значение часов


void setup() {
display.begin(SSD1306_SWITCHCAPVCC); //Инициализируем дисплей
display.clearDisplay();              //Очищаем дисплей
display.setTextColor(WHITE);         //Установка цвета текста
display.setTextSize(1);              //Установка размера шрифта

display.drawCircle(X, Y, 31, WHITE); //Рисуем кружок (drawCircle(X,Y,Радиус,Цвет)
}


void loop() {

display.drawLine(X, Y, Xs, Ys, BLACK); //Стираем старую секундную стрелку
Xs = 90 + sin(2*PI*second/60)*27;      //Считаем координаты конца секундной стрелки. (Xs=[Координаты оси по Х] + sin(2*PI*[Значения секунды]/[Количество делений])*[Длина стрелки])
Ys = 32 - cos(2*PI*second/60)*27;      //Считаем координаты конца секундной стрелки. (Ys=[Координаты оси по Y] - cos(2*PI*[Значения секунды]/[Количество делений])*[Длина стрелки])
display.drawLine(X, Y, Xs, Ys, WHITE); //Рисуем новую секудную стрелку

display.drawLine(X, Y, Xm, Ym, BLACK); //Всё тоже самое что и с секундной
Xm = 90 + sin(2*PI*minutes/60)*29;     //Только поменял длину стрелки
Ym = 32 - cos(2*PI*minutes/60)*29;
display.drawLine(X, Y, Xm, Ym, WHITE);

display.drawLine(X, Y, Xh, Yh, BLACK); //Всё тоже самое что и с секундной и минутной
Xh = 90 + sin(2*PI*hour/12)*26;        //Только поменял длину стрелки
Yh = 32 - cos(2*PI*hour/12)*26;        //И количество делений
display.drawLine(X, Y, Xh, Yh, WHITE);

display.display();                     //Обновляем дисплей,чтобы стрелки показались
 
 

second++;                              //Добавляем 1 к переменной секунд
if (second==60) second=0, minutes++;   //Если переменная секунд=60,тогда обнуляем переменную секунд и добавляем 1 к минутам
if (minutes==60) minutes=0, hour++;    //Если переменная минут=60,тогда обнуляем переменную минут и добавляем 1 к часам

 display.fillRect(0, 0, 60, 8, BLACK); //Очищаем поле со временем {fillRect([Начальная точка по Х],[Начальная точка по Y],[Вторая точка по X],[Вторая точка по Y],[Цвет])}
 display.setCursor(0,0);               //Установка начала текста
 display.print(hour);                  //Пишем количество часов
 display.print(":");                   //Пишем две точки
 display.print(minutes);               //Пишем количество минут
 display.print(":");                   //Пишем две точки
 display.print(second);                //Пишем количество секунд
 delay(1000);                          //Делаем задержку которая равна 1секунде
    
}
Жду вашей критики или же предложений по доработке.
изображение_2022-01-04_153850.png
 

poty

★★★★★★✩
19 Фев 2020
3,169
926
Если речь идёт о нано, то вычисление синусов, косинусов и вообще - работа с плавающей точкой, к.м.к. - это никуда не годится. Вполне реально хранить всего 15 целочисленных значений для вычисления всех необходимых координат.
И - да: не нужно приучать учащихся к delay!
Из неочевидного: когда стрелки находятся на одном угле изображение становится некрасивым.
 

sklecs

✩✩✩✩✩✩✩
4 Янв 2022
5
0
Если речь идёт о нано, то вычисление синусов, косинусов и вообще - работа с плавающей точкой, к.м.к. - это никуда не годится. Вполне реально хранить всего 15 целочисленных значений для вычисления всех необходимых координат.
Была попытка, определять 2 точку для стрелок в ручную и переключать по секундам с помощью Switch. Но я упёрся что это долго и не интересно. (Монотонная работа). По этому и было решено сделать через синус и косинус. Т.к. сам код не большой и затраты времени на его реализации минимальный.
Надеюсь я правильно понял вашу критику.
И - да: не нужно приучать учащихся к delay!
Согласен! Только что прочитал и понял что: delay сильно урезанная по сравнению с millis. Но своё применение может найти.
Из неочевидного: когда стрелки находятся на одном угле изображение становится некрасивым.
Была идея сделать на конце стрелку или сделать их не прямимы, а овальными. Так же как выше говорили можно настроить по длине и ширине.
 

Stamp

★✩✩✩✩✩✩
12 Янв 2021
61
33
Вот здесь чувак делал термометр для бани.
У него там стрелочный индикатор. Этот код можно использовать и для часов.
 

bort707

★★★★★★✩
21 Сен 2020
3,012
898
Была попытка, определять 2 точку для стрелок в ручную и переключать по секундам с помощью Switch. Но я упёрся что это долго и не интересно.
Не вручную, а просто посчитать заранее один раз в сетапе, потом положить 15 точек в массив и потом выбирать в цикле.
А switch - это да, некрасиво и неэффективно
 

poty

★★★★★★✩
19 Фев 2020
3,169
926
@Nikanor, можно, но, во-первых, не сделано, во вторых - не так-то это и легко. Разной длины стрелки сделаны (хотя я бы разницу между секундной и минутной стрелкой сделал побольше), но это не помогает, когда они совмещаются. Цвета здесь, насколько я понял, нет, только оттенки серого, не разгуляешься. Толщина на таких размерах будет смотреться грубовато, если только часть стрелки выделить. Нарисовать стрелку на конце стрелки - хорошая идея, но расчеты этой маленькой детали забьют всю память и производительность. Самый адекватный вариант, что я видел - рисовать на концах минутной и часовой стрелки черные (серые) точки и выводить стрелки начиная с секундной. Тогда при совмещении будет казаться, что на нижележащей стрелке как бы тень от верхней.
@bort707 правильно ответил, никаких switch не надо. Загнать 15 цифр в массив и выбирать их из него, вот и всё. Поведение координат x и y внутри одного квадранта инвертированно, а разница между квадрантами - лишь переключение направления изменения величины. Обычная тригонометрия. Я лишь говорил о заранее просчитанном массиве, а не расчетах в setup.
delay - лишь метод, сам по себе он не лучше и не хуже. Если этот код брать за основу, то добавлять обработку к нему, особенно критичных к времени выполнения элементов, типа общения по внешним интерфейсам, будет практически невозможно. А только и нужно, что использовать свойства loop и простые ветвления.
 
Изменено:

Старик Похабыч

★★★★★★★
14 Авг 2019
4,227
1,292
Москва
Я как то делал что то типа компаса. Нужно было вращать одну ось для совмещения с направлением. Что бы не рисовать стрелки рисовал диск и окружность разного диаметра, так что бы диск умещался внутрь окружности. Если вспомнить часы, то где то были такие стрелки.
Вот для примера:
1641369584890.png
 
  • Лойс +1
Реакции: sklecs

bort707

★★★★★★✩
21 Сен 2020
3,012
898
Оформлений может быть много. Я как-то вот такой секундомер делал
Screenshot_20220105-114929_1.jpg
 

sklecs

✩✩✩✩✩✩✩
4 Янв 2022
5
0
Вот здесь чувак делал термометр для бани.
У него там стрелочный индикатор. Этот код можно использовать и для часов.
Вариант не плохой, но есть некоторые НО...
1)У меня дисплей исключительно белый
2)Размер окружности часов и так максимальное. Если сделаю больше будет вылезать за границы.
3)Дисплей всего 128х64.
@Nikanor,
@bort707 правильно ответил, никаких switch не надо. Загнать 15 цифр в массив и выбирать их из него, вот и всё.
Делать массив я не вижу смысла... Потому что, если использовать sin/cos есть возможность быстро масштабировать сами часы,если я захочу повесить такие часы на стену.
@Nikanor,
delay - лишь метод, сам по себе он не лучше и не хуже. Если этот код брать за основу, то добавлять обработку к нему, особенно критичных к времени выполнения элементов, типа общения по внешним интерфейсам, будет практически невозможно. А только и нужно, что использовать свойства loop и простые ветвления.
delay я использую исключительно потому что у меня нет модуля реального времени. Был бы модуль, понятное дело я б использовал его.
Я как то делал что то типа компаса. Нужно было вращать одну ось для совмещения с направлением. Что бы не рисовать стрелки рисовал диск и окружность разного диаметра, так что бы диск умещался внутрь окружности. Если вспомнить часы, то где то были такие стрелки.
Вот для примера:
Посмотреть вложение 33122
Как по мне лучший путь решения этой проблемы.
Оформлений может быть много. Я как-то вот такой секундомер делал
Посмотреть вложение 33123
Можно использовать твой принцип с секундой, но не использовать оттенок серого, а увеличить/уменьшить размер.
Но всё упирается в размер дисплея, у тебя он большего разрешения .
 

Stamp

★✩✩✩✩✩✩
12 Янв 2021
61
33
@sklecs, Написано много и красиво.
На самом деле всё упирается в мозг.
Дисплей всего 128х64
Масштаб можно сделать любой.
delay я использую исключительно потому что у меня нет модуля реального времени
Даже на сраной ардуине можно построить довольно точные часы.
 

poty

★★★★★★✩
19 Фев 2020
3,169
926
Делать массив я не вижу смысла... Потому что, если использовать sin/cos есть возможность быстро масштабировать сами часы,если я захочу повесить такие часы на стену.
По-моему, Вы не очень понимаете, что должно помещаться в массив. Для масштабирования часов достаточно записать туда соответствующие размеру координаты. Вам всё равно нужно это масштабировать в sin и cos.
По поводу float: команда у Вас одна, но в коде Atmega таких команд нет, то есть вычисления производятся опосредованно, с помощью встроенной подпрограммы, что занимает память и, самое главное, - время. Чтобы хоть как-то оценить - посмотрите сюда.
Если Вы подключите какой-то источник времени, хотя бы распространённый здесь, по I2C, то получите проблемы. Я уже не говорю про всякие таймеры, энкодеры и проч.
Аналогичные рассуждения - с delay. Ничто не мешает этот код сделать на millis сразу.