#1 Re: Апаратні питання » Arduino Nano: проблема з пінами D11 та D12 » 2023-02-16 20:09:50

Honey пише:

Піни D11 та DIO замість провідника зєднайте резистором 200-300 Ом.

Дякую. Спрацювало.
А можна пояснити механізм "лікування" проблеми?

#2 Re: Апаратні питання » Arduino Nano: проблема з пінами D11 та D12 » 2023-02-16 09:40:36

Проєкт повністю з Інтернета, з недуже значним подальшим допилюванням додаткових функцій. Але проблема з блиманням екрану та виводом на нього незрозумілих символів є і в оригінальному коді.
Ось так виглядають код та схема підключення. На форумі проєкту питання про цю проблему піднімали, але жодної відповіді надано не було.

/*
  Скетч к проекту "Будильник - рассвет"
  Страница проекта (схемы, описания): https://alexgyver.ru/dawn-clock/
  Исходники на GitHub: https://github.com/AlexGyver/dawn-clock
  Нравится, как написан и закомментирован код? Поддержи автора! https://alexgyver.ru/support_alex/
  Автор: AlexGyver Technologies, 2018
  http://AlexGyver.ru/
*/
/*
   Клик в режиме часов -> установка будильника
   Клик в режиме установки будильника -> режим часов
   Удержание в режиме часов -> вкл/выкл будильник
   Удержание в режиме установки будильника -> установка времени
   Клик/удержание в режиме установки времени -> режим часов

   Режим часов: двоеточие моргает раз в секунду
   Установка будильника: цифры вместе с двоеточием моргают
   Установка часов: двоеточие горит, цифры моргают
*/

// *************************** НАСТРОЙКИ ***************************
#define DAWN_TIME 20      // продолжительность рассвета (в минутах)
#define ALARM_TIMEOUT 1600  // таймаут на автоотключение будильника, секунды
#define ALARM_BLINK 0     // 1 - мигать лампой при будильнике, 0 - не мигать
#define CLOCK_EFFECT 1    // эффект перелистывания часов: 0 - обычный, 1 - прокрутка, 2 - скрутка
#define BUZZ 0            // пищать пищалкой (1 вкл, 0 выкл)
#define BUZZ_FREQ 800     // частота писка (Гц)

#define DAWN_TYPE 1       // 1 - мосфет (DC диммер), 0 - симистор (AC диммер) СМОТРИ СХЕМЫ
#define DAWN_MIN 10       // начальная яркость лампы (0 - 255) (для сетевых матриц начало света примерно с 50)
#define DAWN_MAX 200      // максимальная яркость лампы (0 - 255)

#define MAX_BRIGHT 7      // яркость дисплея дневная (0 - 7)
#define MIN_BRIGHT 1      // яркость дисплея ночная (0 - 7)
#define	NIGHT_START 22	  // час перехода на ночную подсветку (MIN_BRIGHT)
#define NIGHT_END 6       // час перехода на дневную подсветку (MAX_BRIGHT)
#define LED_BRIGHT 50     // яркость светодиода индикатора (0 - 255)

#define ENCODER_TYPE 1    // тип энкодера (0 или 1). Типы энкодеров расписаны на странице проекта

// ************ ПИНЫ ************
#define CLKe 8        // энкодер
#define DTe 9         // энкодер
#define SWe 10        // энкодер

#define CLK 12        // дисплей
#define DIO 11        // дисплей

#define ZERO_PIN 2    // пин детектора нуля (Z-C) для диммера (если он используется)
#define DIM_PIN 3     // мосфет / DIM(PWM) пин диммера

#define BUZZ_PIN 7    // пищалка (по желанию)
#define LED_PIN 6	    // светодиод индикатор

// ***************** ОБЪЕКТЫ И ПЕРЕМЕННЫЕ *****************
#include "GyverTimer.h"
GTimer_ms halfsTimer(500);
GTimer_ms blinkTimer(800);
GTimer_ms timeoutTimer(15000);
GTimer_ms dutyTimer((long)DAWN_TIME * 60 * 1000 / (DAWN_MAX - DAWN_MIN));
GTimer_ms alarmTimeout((long)ALARM_TIMEOUT * 1000);

#include "GyverEncoder.h"
Encoder enc(CLKe, DTe, SWe);

#include "GyverTM1637.h"
GyverTM1637 disp(CLK, DIO);

#include "EEPROM.h"
#include <CyberLib.h> // шустрая библиотека для таймера

#include <Wire.h>
#include "RTClib.h"
RTC_DS3231 rtc;

boolean dotFlag, alarmFlag, minuteFlag, blinkFlag, newTimeFlag;
int8_t hrs = 21, mins = 55, secs;
int8_t alm_hrs, alm_mins;
int8_t dwn_hrs, dwn_mins;
byte mode;  // 0 - часы, 1 - уст. будильника, 2 - уст. времени

boolean dawn_start = false;
boolean alarm = false;
volatile int tic, duty;

void setup() {
  Serial.begin(9600);
  pinMode(DIM_PIN, OUTPUT);
  pinMode(LED_PIN, OUTPUT);

#if (DAWN_TYPE == 0)
  pinMode(ZERO_PIN, INPUT);
  attachInterrupt(0, detect_up, FALLING);
  StartTimer1(timer_interrupt, 40);        // время для одного разряда ШИМ
  StopTimer1();                            // остановить таймер
#endif

  enc.setType(ENCODER_TYPE);     // тип энкодера TYPE1 одношаговый, TYPE2 двухшаговый. Если ваш энкодер работает странно, смените тип
  disp.clear();

  rtc.begin();
  if (rtc.lostPower()) {
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }
  DateTime now = rtc.now();
  secs = now.second();
  mins = now.minute();
  hrs = now.hour();

  disp.displayClock(hrs, mins);
  alm_hrs = EEPROM.read(0);
  alm_mins = EEPROM.read(1);
  alarmFlag = EEPROM.read(2);
  alm_hrs = constrain(alm_hrs, 0, 23);
  alm_mins = constrain(alm_mins, 0, 59);
  calculateDawn();      // расчёт времени рассвета
  alarmFlag = constrain(alarmFlag, 0, 1);

  // установка яркости от времени суток
  if ( (hrs >= NIGHT_START && hrs <= 23)
       || (hrs >= 0 && hrs <= NIGHT_END) ) disp.brightness(MIN_BRIGHT);
  else disp.brightness(MAX_BRIGHT);
}

void loop() {
  encoderTick();  // отработка энкодера
  clockTick();    // считаем время
  alarmTick();    // обработка будильника
  settings();     // настройки
  dutyTick();     // управление лампой

  if (minuteFlag && mode == 0 && !alarm) {    // если новая минута и стоит режим часов и не орёт будильник
    minuteFlag = false;
    // выводим время
    if (CLOCK_EFFECT == 0) disp.displayClock(hrs, mins);
    else if (CLOCK_EFFECT == 1) disp.displayClockScroll(hrs, mins, 70);
    else disp.displayClockTwist(hrs, mins, 35);
  }
}

void calculateDawn() {
  // расчёт времени рассвета
  if (alm_mins > DAWN_TIME) {         // если минут во времени будильника больше продолжительности рассвета
    dwn_hrs = alm_hrs;                // час рассвета равен часу будильника
    dwn_mins = alm_mins - DAWN_TIME;  // минуты рассвета = минуты будильника - продолж. рассвета
  } else {                            // если минут во времени будильника меньше продолжительности рассвета
    dwn_hrs = alm_hrs - 1;            // значит рассвет будет часом раньше
    if (dwn_hrs < 0) dwn_hrs = 23;    // защита от совсем поехавших
    dwn_mins = 60 - (DAWN_TIME - alm_mins);   // находим минуту рассвета в новом часе
  }
}

void dutyTick() {
  if (dawn_start || alarm) {        // если рассвет или уже будильник
    if (DAWN_TYPE) {                // если мосфет
      analogWrite(DIM_PIN, duty);   // жарим ШИМ
    }
  }
}

#if (DAWN_TYPE == 0)  // если диммер
//----------------------ОБРАБОТЧИКИ ПРЕРЫВАНИЙ--------------------------
void timer_interrupt() {          // прерывания таймера срабатывают каждые 40 мкс
  if (duty > 0) {
    tic++;                        // счетчик
    if (tic > (255 - duty))       // если настало время включать ток
      digitalWrite(DIM_PIN, 1);   // врубить ток
  }
}

void detect_up() {    // обработка внешнего прерывания на пересекание нуля снизу
  if (duty > 0) {
    tic = 0;                                  // обнулить счетчик
    ResumeTimer1();                           // перезапустить таймер
    attachInterrupt(0, detect_down, RISING);  // перенастроить прерывание
  }
}

void detect_down() {      // обработка внешнего прерывания на пересекание нуля сверху
  if (duty > 0) {
    tic = 0;                                  // обнулить счетчик
    StopTimer1();                             // остановить таймер
    digitalWrite(DIM_PIN, 0);                 // вырубить ток
    attachInterrupt(0, detect_up, FALLING);   // перенастроить прерывание
  }
}
#endif

void settings() {
  // *********** РЕЖИМ УСТАНОВКИ БУДИЛЬНИКА **********
  if (mode == 1) {
    if (timeoutTimer.isReady()) mode = 0;   // если сработал таймаут, вернёмся в режим 0
    if (enc.isRight()) {
      alm_mins++;
      if (alm_mins > 59) {
        alm_mins = 0;
        alm_hrs++;
        if (alm_hrs > 23) alm_hrs = 0;
      }
    }
    if (enc.isLeft()) {
      alm_mins--;
      if (alm_mins < 0) {
        alm_mins = 59;
        alm_hrs--;
        if (alm_hrs < 0) alm_hrs = 23;
      }
    }
    if (enc.isRightH()) {
      alm_hrs++;
      if (alm_hrs > 23) alm_hrs = 0;
    }
    if (enc.isLeftH()) {
      alm_hrs--;
      if (alm_hrs < 0) alm_hrs = 23;
    }
    if (enc.isTurn() && !blinkFlag) {     // вывести свежие изменения при повороте
      disp.displayClock(alm_hrs, alm_mins);
      timeoutTimer.reset();               // сбросить таймаут
    }
    if (blinkTimer.isReady()) {
      if (blinkFlag) {
        blinkFlag = false;
        blinkTimer.setInterval(700);
        disp.point(1);
        disp.displayClock(alm_hrs, alm_mins);
      } else {
        blinkFlag = true;
        blinkTimer.setInterval(300);
        disp.point(0);
        disp.clear();
      }
    }
  }

  // *********** РЕЖИМ УСТАНОВКИ ВРЕМЕНИ **********
  if (mode == 2) {
    if (timeoutTimer.isReady()) mode = 0;   // если сработал таймаут, вернёмся в режим 0
    if (!newTimeFlag) newTimeFlag = true;   // флаг на изменение времени
    if (enc.isRight()) {
      mins++;
      if (mins > 59) {
        mins = 0;
        hrs++;
        if (hrs > 23) hrs = 0;
      }
    }
    if (enc.isLeft()) {
      mins--;
      if (mins < 0) {
        mins = 59;
        hrs--;
        if (hrs < 0) hrs = 23;
      }
    }
    if (enc.isRightH()) {
      hrs++;
      if (hrs > 23) hrs = 0;
    }
    if (enc.isLeftH()) {
      hrs--;
      if (hrs < 0) hrs = 23;
    }
    if (enc.isTurn() && !blinkFlag) { // вывести свежие изменения при повороте
      disp.displayClock(hrs, mins);
      timeoutTimer.reset();           // сбросить таймаут
    }
    if (blinkTimer.isReady()) {
      // прикол с перенастройкой таймера, чтобы цифры дольше горели
      disp.point(1);
      if (blinkFlag) {
        blinkFlag = false;
        blinkTimer.setInterval(700);
        disp.displayClock(hrs, mins);
      } else {
        blinkFlag = true;
        blinkTimer.setInterval(300);
        disp.clear();
      }
    }
  }
}

void encoderTick() {
  enc.tick();   // работаем с энкодером
  // *********** КЛИК ПО ЭНКОДЕРУ **********
  if (enc.isClick()) {        // клик по энкодеру
    minuteFlag = true;        // вывести минуты при следующем входе в режим 0
    mode++;                   // сменить режим
    if (mode > 1) {           // выход с режима установки будильника и часов
      mode = 0;
      calculateDawn();        // расчёт времени рассвета
      EEPROM.update(0, alm_hrs);
      EEPROM.update(1, alm_mins);

      // установка яркости от времени суток
      if ( (hrs >= NIGHT_START && hrs <= 23)
           || (hrs >= 0 && hrs <= NIGHT_END) ) disp.brightness(MIN_BRIGHT);
      else disp.brightness(MAX_BRIGHT);

      disp.displayClock(hrs, mins);
    }
    timeoutTimer.reset();     // сбросить таймаут
  }

  // *********** УДЕРЖАНИЕ ЭНКОДЕРА **********
  if (enc.isHolded()) {       // кнопка удержана
    minuteFlag = true;        // вывести минуты при следующем входе в режим 0
    if (dawn_start) {         // если удержана во время рассвета или будильника
      dawn_start = false;     // прекратить рассвет
      alarm = false;          // и будильник
      duty = 0;
      digitalWrite(DIM_PIN, 0);
      if (BUZZ) noTone(BUZZ_PIN);
      return;
    }
    if (mode == 0 && !dawn_start) {   // кнопка удержана в режиме часов и сейчас не рассвет
      disp.point(0);              // гасим кнопку
      alarmFlag = !alarmFlag;     // переключаем будильник
      if (alarmFlag) {
        disp.scrollByte(_empty, _o, _n, _empty, 70);
        analogWrite(LED_PIN, LED_BRIGHT);
      } else {
        disp.scrollByte(_empty, _o, _F, _F, 70);
        digitalWrite(LED_PIN, 0);
      }
      EEPROM.update(2, alarmFlag);
      delay(1000);
      disp.displayClockScroll(hrs, mins, 70);
    } else if (mode == 1) {   // кнопка удержана в режиме настройки будильника
      mode = 2;               // сменить режим
    } else if (mode == 2) {	  // кнопка удержана в режиме настройки часов
      mode = 0;               // сменить режим

      // установка яркости от времени суток
      if ( (hrs >= NIGHT_START && hrs <= 23)
           || (hrs >= 0 && hrs <= NIGHT_END) ) disp.brightness(MIN_BRIGHT);
      else disp.brightness(MAX_BRIGHT);

      disp.displayClock(hrs, mins);
    }
    timeoutTimer.reset();     // сбросить таймаут
  }
}

void alarmTick() {
  if (dawn_start && alarmFlag) {
    if (dutyTimer.isReady()) {    // поднимаем яркость по таймеру
      duty++;
      if (duty > DAWN_MAX) duty = DAWN_MAX;
    }
  }
  if (alarm) {                    // настало время будильника
    if (alarmTimeout.isReady()) { // таймаут будильника
      dawn_start = false;         // прекратить рассвет
      alarm = false;              // и будильник
      duty = 0;
      digitalWrite(DIM_PIN, 0);
      if (BUZZ) noTone(BUZZ_PIN);
    }
    if (blinkTimer.isReady()) {   // мигаем цифрами
      if (blinkFlag) {
        blinkFlag = false;
        blinkTimer.setInterval(700);
        disp.point(1);
        disp.displayClock(hrs, mins);
        if (ALARM_BLINK) duty = DAWN_MAX;     // мигаем светом
        if (BUZZ) tone(BUZZ_PIN, BUZZ_FREQ);  // пищим
      } else {
        blinkFlag = true;
        blinkTimer.setInterval(300);
        disp.point(0);
        disp.clear();
        if (ALARM_BLINK) duty = DAWN_MIN;
        if (BUZZ) noTone(BUZZ_PIN);
      }
    }
  }
}

void clockTick() {
  if (halfsTimer.isReady()) {
    if (newTimeFlag) {
      newTimeFlag = false;
      secs = 0;
      rtc.adjust(DateTime(2014, 1, 21, hrs, mins, 0)); // установка нового времени в RTC
    }
    dotFlag = !dotFlag;
    if (mode == 0) disp.point(dotFlag);                 // выкл/выкл точки
    if (mode == 0) disp.displayClock(hrs, mins);        // костыль, без него подлагивает дисплей
    if (alarmFlag) {
      if (dotFlag) analogWrite(LED_PIN, LED_BRIGHT);    // мигаем светодиодом что стоит аларм
      else digitalWrite(LED_PIN, 0);
    }

    if (dotFlag) {          // каждую секунду пересчёт времени
      DateTime now = rtc.now();
      secs = now.second();
      mins = now.minute();
      hrs = now.hour();
      if (!secs) minuteFlag = true;

      if (!mins && !secs) {      // каждый час
        // меняем яркость
        if (hrs == NIGHT_START) disp.brightness(MIN_BRIGHT);
        if (hrs == NIGHT_END) disp.brightness(MAX_BRIGHT);
      }

      // после пересчёта часов проверяем будильник!
      if (dotFlag) {
        if (dwn_hrs == hrs && dwn_mins == mins && alarmFlag && !dawn_start) {
          duty = DAWN_MIN;
          dawn_start = true;
        }
        if (alm_hrs == hrs && alm_mins == mins && alarmFlag && dawn_start && !alarm) {
          alarm = true;
          alarmTimeout.reset();
        }
      }
    }
  }
}

scheme1.jpeg

#3 Re: Апаратні питання » Arduino Nano: проблема з пінами D11 та D12 » 2023-02-14 00:10:10

Тільки починаю освоювати Ардуіно та програмування її, тому про "діагональну ітерацію" не зрозумів нічого.
Увагу звернув на дроти. А як правильно? Коротко та прямо? У мене поки що все зібрано на макетній платі, тому усі дроти йдуть дугою від піна до піна.

До речі, схема пропрацювала певний час, і проблема з екраном повернулася навіть на 4 і 5 пінах. Екран починає блимати і показувати випадкові символи, змінюючи яскравість. Закономірність не помітив.

#4 Апаратні питання » Arduino Nano: проблема з пінами D11 та D12 » 2023-02-08 23:01:21

Tim_M
відповідей: 9

На базі Arduino Nano (була в наявності) зібрав схему. З периферії таймер, екнодер, екран і мосфет для світлодіода. Все працювало, і виникла необхідність зробити ще одну таку саму. Повністю комплект периферії і ще одну Nano замовив тут. Зібрав схему. Вона повністю працювала, окрім того моменту, що екран час від часу показував дивні речі: або вимикався, або блимав з частотою 1 Гц, або показував випадкові цифри.
Оскільки обидві схеми були зібрані на макетних платах, просто поміняв Arduino місцями. Проблема на новій платі залишилась: екран показував дивні речі.
Про проблему написав в службу підтримки, і плату поміняли, хоча при діагностиці проблему не виявили.
Коли ж вдома я вставив цю (вже третю) плату в зібрану схему, то я був здивований - екран знов показує що завгодно.
Оскільки були ще вільні пара пінов (3 і 4), переключив екран на них. Проблема зникла.

Питання: що може бути не так, що в двох платах саме на D11 і D12 екран веде себе не правильно?

#5 Re: Різне » Вопрос по работе магазина arduino.ua » 2023-02-08 22:48:26

Замовляв вперше. А через тиждень вдруге. Затягує!
Дякую за якісний та швидкий сервіс, консультацію, і навіть оперативну заміну проблемного компонента.

P.S. Проблема виявилась цікавою, опишу в тематичному розділі.

Підвал форуму