• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Часы с кукушкой на esp 8266

vlad19950824@

New member
Добрый день, я написал скетч для esp 8266 ,часы с кукушкой.
Компоненты: esp8266, GC9A01 1,28 display, servo,mp3 Mini Player.
Работа часов такая, на дисплее отображается циферблат время часы запрашивают из интернета далее каждый час воспроизводится определённый трек для каждого часа и серво поворачивается на 90 градусов на врем проигрывания трека. Например 12 часов включается трек 12( часы кукукают 12 раз). Проблема в том что часы на esp8266 зависают в не определённый момент. Скетч компелируется без проблем вроде библиотеки тоже использовал актуальные. По питанию БП 5в 2а плюс на входе поставил конденсатор.
Программу писал через Arduino ide.

Помогите разобраться в чем проблема. Скетч есть :


#include <Wire.h>
#include "SPI.h"
#include <Adafruit_GFX.h>
#include <Adafruit_GC9A01A.h>
#include <ESP8266WiFi.h>
#include <WiFiUDP.h>
#include <NTPClient.h>
#include <DFRobotDFPlayerMini.h>
#include <Servo.h>
#include <math.h>
#include <SoftwareSerial.h>
#include <pgmspace.h>
#include <ESP8266WiFi.h>

// Параметры подключения Wi-Fi
const char* ssid = "xxxxxxxxxxxx";
const char* password = "xxxxxxxxxxxxx";

// NTP клиент для получения времени
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", 7200, 60000);

// Настройки дисплея GC9A01A
#define TFT_CS D8
#define TFT_RST D1
#define TFT_DC D2

Adafruit_GC9A01A tft = Adafruit_GC9A01A(TFT_CS, TFT_DC, TFT_RST);

// Настройки MP3 плеера
SoftwareSerial mySoftwareSerial(D4, D3); // RX, TX
DFRobotDFPlayerMini myDFPlayer;

// Настройки серво
Servo myServo;
#define SERVO_PIN D6

// Центр дисплея
#define CENTER_X 120
#define CENTER_Y 120

// Предыдущие координаты стрелок
int prevHourX = CENTER_X, prevHourY = CENTER_Y;
int prevMinuteX = CENTER_X, prevMinuteY = CENTER_Y;
int prevSecondX = CENTER_X, prevSecondY = CENTER_Y;

// Переменная для отслеживания времени
unsigned long targetTime = 0;

// Программенные строки
const char connectingToWiFi[] PROGMEM = "Connecting to WiFi...";
const char connectedToWiFi[] PROGMEM = "Connected to WiFi";
const char unableToBegin[] PROGMEM = "Unable to begin:";
const char recheckConnection[] PROGMEM = "1. Please recheck the connection!";
const char insertSDCard[] PROGMEM = "2. Please insert the SD card!";

void setup() {
Serial.begin(115200);

// Подключение к Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.println(FPSTR(connectingToWiFi));
}
Serial.println(FPSTR(connectedToWiFi));

// Настройка NTP клиента
timeClient.begin();

// Настройка дисплея
tft.begin();
tft.setRotation(0);
tft.fillScreen(GC9A01A_BLACK);

// Настройка MP3 плеера
mySoftwareSerial.begin(9600);
if (!myDFPlayer.begin(mySoftwareSerial)) {
Serial.println(FPSTR(unableToBegin));
Serial.println(FPSTR(recheckConnection));
Serial.println(FPSTR(insertSDCard));
while(true);
}
myDFPlayer.setTimeOut(500);
myDFPlayer.volume(29); // Установить уровень громкости от 0 до 30

// Настройка серво
myServo.attach(SERVO_PIN);
myServo.write(0); // Установка серво в начальное положение

// Рисование циферблата
drawClockFace();

// Установить начальное время для обновления
targetTime = millis() + 1000;
}

void loop() {
if (millis() >= targetTime) {
targetTime += 1000; // Обновить targetTime для следующей итерации

timeClient.update();
unsigned long epochTime = timeClient.getEpochTime();
struct tm *ptm = gmtime((time_t *)&epochTime);

int currentHour = ptm->tm_hour % 12;
int currentMinute = ptm->tm_min;
int currentSecond = ptm->tm_sec;

// Удаление старого времени и отображение нового времени
updateClock(currentHour, currentMinute, currentSecond);

// Проверка и воспроизведение трека каждый час
if (currentMinute == 0 && currentSecond == 0) {
playHourlyTrack(currentHour == 0 ? 12 : currentHour);
}
}
}

void drawClockFace() {
tft.fillScreen(GC9A01A_BLACK);

// Отметки часов
for (int i = 1; i <= 12; i++) {
float angle = (i - 3) * 30; // Каждый номер по 30 градусов
int radius = 105; // Радиус для обычных цифр

// Увеличиваем радиус для цифр
if (i == 2 || i == 3 || i == 4 || i == 5 || i == 6) {
radius = 110;
}
if (i == 3) {
radius = 114;
}

int x = CENTER_X + radius * cos(angle * M_PI / 180);
int y = CENTER_Y + radius * sin(angle * M_PI / 180);

// Определяем цвет цифры
if (i == 12 || i == 3 || i == 6 || i == 9) {
tft.setTextColor(GC9A01A_GREEN);
tft.setTextSize(2);
} else {
tft.setTextColor(GC9A01A_WHITE);
tft.setTextSize(2);
}

tft.setCursor(x - 10, y - 10); // Смещение для центрирования цифры
tft.print(i);
}

// Позиции точек
for (int i = 0; i < 12; i++) {
float startAngle = (i - 3) * 30; // Начальный угол
for (int j = 1; j <= 5; j++) {
float angle = startAngle + j * 6; // Угловое смещение для точек (6 градусов между точками)
int x = CENTER_X + 111 * cos(angle * M_PI / 180); // Уменьшенный радиус для точек
int y = CENTER_Y + 111 * sin(angle * M_PI / 180); // Уменьшенный радиус для точек
tft.drawPixel(x, y, GC9A01A_WHITE); // Рисуем точку как одиночный пиксель
}
}
}

void updateClock(int hour, int minute, int second) {
// Углы для стрелок
float hourAngle = (hour % 12 + minute / 60.0) * 30.0;
float minuteAngle = minute * 6.0;
float secondAngle = second * 6.0;

// Координаты стрелок
int hourX = CENTER_X + 50 * cos((hourAngle - 90) * M_PI / 180);
int hourY = CENTER_Y + 50 * sin((hourAngle - 90) * M_PI / 180);
int minuteX = CENTER_X + 69 * cos((minuteAngle - 90) * M_PI / 180);
int minuteY = CENTER_Y + 69 * sin((minuteAngle - 90) * M_PI / 180);
int secondX = CENTER_X + 80 * cos((secondAngle - 90) * M_PI / 180);
int secondY = CENTER_Y + 80 * sin((secondAngle - 90) * M_PI / 180);

// Удаление предыдущих стрелок
eraseLine(CENTER_X, CENTER_Y, prevHourX, prevHourY, GC9A01A_BLACK);
eraseLine(CENTER_X, CENTER_Y, prevMinuteX, prevMinuteY, GC9A01A_BLACK);
eraseLine(CENTER_X, CENTER_Y, prevSecondX, prevSecondY, GC9A01A_BLACK);

// Рисование новых стрелок
tft.drawLine(CENTER_X, CENTER_Y, hourX, hourY, GC9A01A_WHITE); // Часовая стрелка
tft.drawLine(CENTER_X, CENTER_Y, minuteX, minuteY, GC9A01A_WHITE); // Минутная стрелка
tft.drawLine(CENTER_X, CENTER_Y, secondX, secondY, GC9A01A_RED); // Секундная стрелка

// Сохранение текущих координат стрелок
prevHourX = hourX;
prevHourY = hourY;
prevMinuteX = minuteX;
prevMinuteY = minuteY;
prevSecondX = secondX;
prevSecondY = secondY;
}

void eraseLine(int x0, int y0, int x1, int y1, uint16_t color) {
tft.drawLine(x0, y0, x1, y1, color); // Стираем линию, рисуя её цветом фона
}

void playHourlyTrack(int hour) {
myDFPlayer.volume(28); // Понижаем громкость перед воспроизведением
delay(100); // Короткая задержка для стабилизации
myDFPlayer.play(hour); // Воспроизведение трека

int delayTime = 0;

switch (hour) {
case 1:
delayTime = 2500;
break;
case 2:
delayTime = 3500;
break;
case 3:
delayTime = 4500;
break;
case 4:
delayTime = 5500;
break;
case 5:
delayTime = 6500;
break;
case 6:
delayTime = 8500;
break;
case 7:
delayTime = 9500;
break;
case 8:
delayTime = 10500;
break;
case 9:
delayTime = 11500;
break;
case 10:
delayTime = 13500;
break;
case 11:
delayTime = 14500;
break;
case 12:
delayTime = 15500;
break;
}

myServo.write(90); // Выдвижение кукушки

unsigned long startTime = millis();
while (millis() - startTime < delayTime) {
// Ничего не делаем, чтобы ждать
yield(); // Вызов yield() для предотвращения watchdog перезагрузок
}

myServo.write(0); // Убираем кукушку
delay(100); // Короткая задержка для стабилизации
myDFPlayer.volume(29); // Возвращаем громкость
}
 

vlad19950824@

New member
Я думаю все таки проблема желательно в коде , так как делай такой-же проект только с lcdдисплеем там все работало. Может какие библиотеки конфликтуют?!
 

vlad19950824@

New member
Результат такой , я отключал серво , зависание все ещё есть , всетаки проблема лежит в коде ,но вот только где
 

nikolz

Well-known member
вместо этого
switch (hour) {
case 1:
delayTime = 2500;
break;
case 2:
delayTime = 3500;
break;
case 3:
delayTime = 4500;
break;
case 4:
delayTime = 5500;
break;
case 5:
delayTime = 6500;
break;
case 6:
delayTime = 8500;
break;
case 7:
delayTime = 9500;
break;
case 8:
delayTime = 10500;
break;
case 9:
delayTime = 11500;
break;
case 10:
delayTime = 13500;
break;
case 11:
delayTime = 14500;
break;
case 12:
delayTime = 15500;
break;
}
можно написать это
int T[]={0,2500,3500,4500,5500,6500,8500,9500,10500,11500,13500, 14500,15500};
....
delay_Tine=T[hour];
============
вместо этого:
targetTime += 1000; // Обновить targetTime для следующей итерации
так:
targetTime =millis() +1000; // Обновить targetTime для следующей итерации
 

nikolz

Well-known member
if (currentMinute == 0 && currentSecond == 0)
а вы уверены, что это условие будет всегда без пропусков?
 

vlad19950824@

New member
Спасибо за совет попробую исправить. Я не знаю , вроде и работает но виснет. Я всякие варианты пробую ( я новичок самоучка , так сказать методом тыка делаю)
 
Сверху Снизу