DIY годинник з синхронізацією через супутники!

Опубліковано 15.07.2025, 17:30 в категорії YouTube

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

Кран на фоні зірок

Мова йде про супутники системи GPS - Global Positioning System. Щоб визначити місцезнаходження, ваш телефон використовує трилатерацію, і, вимірюючи час проходження сигналу від супутників до нього, обчислює відстань до кожного супутника знаючи швидкість поширення радіохвиль, що дозволяє точно визначити своє місцезнаходження.

Трилатерація

Тому для GPS супутників надзвичайно важливо мати дуже точний годинник, адже навіть похибка в пару мілісекунд може суттєво вплинути на точність геолокації. Саме цим я і пропоную скористатись для того, щоб зробити крутий годинник, який завжди буде мати доступ до точного часу.

NEO-6M

В цьому нам допоможе ось такий ось GPS модуль, NEO-6M. Він має UART шину для підключення, та невеличку керамічну антенку. Знявши металевий екран з антени, можна побачити, що під ним майже нічого нічого немає:

Пасивна антена всередині

Це означає що дана антена - пасивного типу. Тут є лише пасивна узгоджувальна лінія, яка складається з резистора на 50 Ом, та якогось невідомого мені чотирьох вивідного SMD компонента. В антені активного типу під екраном знаходиться ціла купа всього, і band-pass фільтр, і підсилювачі, а також спеціальні лінії, щоб розділити корисний сигнал з антени, та постійний струм для живлення підсилювачів:

Активна антена всередині

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

Якщо подати на GPS модуль живлення, то він почне приймати сигнал з супутників, і відправляти по UART шині різного роду дані в форматі NMEA, що включають в себе наприклад координати, час та дату, швидкість, напрямок руху і так далі. Прийняти ці дані можна наприклад за допомогою мікроконтролера, або звичайного UART перетворювача, такого ж, який ми використовували щоб під'єднатись до роутера.

Можна виводити дані з модуля прямо в консоль, без всяких сторонніх програм, і наприклад через GREP фільтрувати необхідні дані:

cat /dev/ttyUSB0 | grep GPGSV

де:

  • /dev/ttyUSB0 - GPS модуль підключений через UART перетворювач
  • GPGSV - необхідне NMEA речення (NMEA sentence)

Тобто от настільки легко можна зараз додати GPS функціонал до будь якого ноутбука або комп'ютера.

Компоненти

Компоненти

Ітак, для створення годинника нам знадобиться:

  • вже раніше згаданий GPS модуль
  • символьний екранчик на 4 рядки по 20 символів
  • мікроконтролер STM32 Blue Pill (STM32F103C8T6)
  • якийсь корпус щоб все це сховати.

Ну і також купка інших дрібниць: транзистор 2N2222, резистор на 1 кОм, та слот під батарейку CR2032.

GPS модуль як я вже казав, буде виступати в ролі джерела точного часу. Дисплейчик потрібен для відображення часу та іншої інформації. В цілому можна використати будь який символьний, навіть 1602, але я вирішив взяти саме такий, щоб розмістити більше інформації. В якості мікроконтролера я взяв STM32 Blue Pill з декількох причин.

По перше в мене вже давно лежить така платка, тому хотілось її кудись приткнути. По друге, вона коштує майже стільки як і якась звичайна Arduino Nano, але на відміну від неї вже має вбудований Real Time Clock, RTC, тому відпадає необхідність використовувати якісь зовнішні модулі. Насправді GPS модуль теж має свій RTC, і в теорії можна використовувати його, але наскільки мені відомо, через певний час після втрати сигналу з супутників, він може відвалитись. Принаймні при втраті живлення - точно, там або розряджається наявний на платі акумулятор, або дані застарівають, або ще щось.

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

А щоб використовувати RTC на платі Blue Pill слід не підпаювати нічого до пінів С14 та С15, навіть звичайну гребінку, адже саме сюди підключається керамічний резонатор який тактує RTC, і зайві з'єднання будуть погано впливати на його точність. Ну і також нам треба надати мікроконтролеру резервне джерело живлення - батарейку типу CR2032, плюс якої необхідно підключити до контакту VB на платі.

До речі все раніше перераховане, а саме мікроконтролер, дисплей, GPS модуль, та корпус, можна купити в магазині arduino.ua. Я саме там все і купив, окрім мікроконтролера який в мене вже був. Я був дуже здивований, коли дізнався, що власник цього магазину дивиться мій канал, і навіть надав мені промокод на знижку, тому найменше що я можу зробити - розповісти вам про такий чудовий магазин! Я вже не перший раз замовляю там різні штуки, і це дуже круто, що не треба за всім цим бігти на наприклад Аліекспрес. Тож якщо вам треба щось зі сфери мікроконтролерів або одноплатних комп'ютерів - раджу завітати на Arduino.ua.

Схема

Щож, спочатку поговоримо про схему годинника.

Схема

GPS модуль підключається до першої UART шини мікроконтролера, тобто пінів PA9 та PA10. Достатньо всього лише підключити Tx GPS модуля до PA10, так як нам треба лише приймати дані, але щоб Rx не висів в повітрі, можна і його підключити. Живлення модуля підключається до 3.3В.

Дисплей працює в 4х бітному режимі, і підключається до пінів від РА0 до РА5. Звісно вільних пінів у нас вдосталь, тому можна було б і 8ми бітний режим використати, але особисто я не бачу в цьому сенсу, так як ми все одно впираємось в інерційність рідкокристалічного дисплея, тому швидкостей 4х бітного режима достатньо з головою. Катод підсвітки підключається до землі через транзистор 2N2222, і керується за допомогою мікроконтролера через пін РА6.

Також не забуваємо додати змінний резистор для налаштування контрастності дисплея. Ну і не забуваємо про батарейку для RTC. На цьому все, ніяких кнопок чи чогось такого - не потрібно.

Годинник зібраний на бредборді

Я зібрав все на бредборді для тестів, це значно спрощує відладку та написання коду.

Код

А стосовно коду - я писав його в PlatformIO. Він дозоляє легко використовувати STM32 з фреймворком Arduino. Як я вже неодноразово казав - я не вважаю себе програмістом, тому подужати Arduino для мене набагато легше ніж чистий STM32.

В проєкті використовується купка бібліотек. Більшість з них, а саме бібліотеки для роботи з GPS модулем, з часом, та LCD дисплейчиком - PlatformIO завантажить автоматично:

  • TinyGPS++
  • STM32RTC
  • Timezone
  • TimeLib -LiquidCrystal

А одну бібліотеку довелось модифікувати, тому вона вже лежить в директорії lib в репозиторії проєкту. Це бібліотека BigNums2x2, яка використовується для відображення великих цифр на символьних дисплейчиках.

Цифри відображені за допомогою BigNums

Вона використовує 8 кастомних символів дисплея для того щоб формувати з 4х комірок гарні та великі цифри. Саме тому я й обрав такий дисплей, адже він дозволить виводити великий цифрами час, ну і на додачу ще дату та кількість супутників які приймає GPS модуль. Хоча якщо потрібен лише час, то вистачить і звичайного 16-ти символьного дисплея на 2 рядки.

І от схоже автори бібліотеки не передбачували що хтось буде використовувати дисплей з 4ма рядками, тому захардкодили вивід тексту на перший рядок, а так як я хотів малювати час по центру, довелось підправити тут нуль на одинцю.

Ну і також ще довелось прибрати ось цей ось блок коду, так як він заважав нормально малювати розділові символи між цифрами:

  // clears the spaces between digits, prob not needed if you're good about using lcd.clear
  for (i = 0; i < numdigits; i++) {
    if (i == 0 && startcol == 0);
    else {
      int col = (startcol - 1) + 3*i;
      for (int row = 0; row < 2; row++){
        lcd.setCursor(col, row);
        lcd.write(32);
      }
    }
  }

Timezone

Цілим відкриттям для мене до речі стала бібліотека Timezone, яка дозволяє задати коли починається літній та зимовий час, та автоматично конвертувати UTC в потрібний часовий пояс.

Тобто в RTC зберігається не локальний час, а UTC, який як раз і повертають супутники, і ця бібліотека дивиться на дату, та виходячи з неї конвертує його в необхідний часовий пояс - UTC+2 або UTC+3. Дуже зручно, і тому годинник взагалі не потребує ніяких кнопок та налаштувань.

Насправді я немало часу витратив на те шоб зрозуміти як все це скомпонувати, бо наприклад бібліотека для роботи з GPS модулем повертає повний рік, наприклад 2025. TimeLib, яка знадобилась для бібліотеки Timezone, як виявляється очікує рік в форматі оффсету від 1970 року, тобто наприклад не 2025, а 55. Ну а STM32 очікує та повертає рік в форматі оффсету від 2000 року. Тому місцями в коді можна побачити ці дивні перетворення.

Також в коді є блок змінних, які можна налаштувати під себе:

// ============ User Settings =============
const uint8_t dim_start_hour = 22; // The hour when the nighttime begins (backlights dimms)
const uint8_t dim_end_hour = 6; // The hour when the nighttime ends  (backlights brighten)
const uint8_t day_dim = 255; // Daytime backlight brightness   (0 - minimum, 255 - maximum)
const uint8_t night_dim = 20; // Nighttime backlight brightness (0 - minimum, 255 - maximum)
const uint8_t min_sats_to_calibrate_time = 6; // Minimum number of satellites for time calibration
// ========================================

Тут можна задати коли вмикається та вимикається нічна підсвітка, наскільки підсвітка буде яскравою вночі та вдень, ну і також обрати мінімальну кількість супутників, необхідних для синхронізації часу. В теорії час можна отримати і від одного супутника, але чим більше супутників бачить модуль, тим впевненіше можна сказати що сигнал якісний та надійний. Репозиторій з кодом проєкту доступний за посиланням. Достатньо просто клонувати або завантажити його, і відкрити як проєкт в PlatformIO.

Далі натискаємо галочку Build, або натискаємо комбінацію клавіш Ctrl + Alt + B, та проєкт почне компілюватись, завантажуючи все необхідне.

Прошиваємо мікроконтролер

Тепер можна прошити мікроконтролер. Я зробив це за допомогою ось такого ST Link програматора:

ST Link V2

Саме він вказаний в файлі platformio.ini як спосіб програмування:

upload_protocol = stlink

Якщо ви будете використовувати щось інше - змініть upload_protocol на потрібний.

Також ще варто зазначити що плати BluePill бувають на різних чіпах. Наприклад в мене на платі стоїть stm32f103c6, тому я вказав саме його:

STM32F103C6T6

board = bluepill_f103c6

Але в репозиторії буде вказаний інший, а саме stm32f103c8, так як він більш поширений, має більше пам'яті, і саме його ви може знайти в магазині arduino.ua:

board = bluepill_f103c8

Тож тримайте це в голові, і замініть за потреби, якщо у вас як і в мене C6.

Підключаємо програматор до мікроконтролера, та натискаємо стрілочку Upload або комбінацію клавіш Ctrl + Alt + U. Мікроконтролер прошитий.

Годинник на бредборді

Збираємо годинник

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

Віконце під дисплей

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

Перемички

Далі я спаяв все за схемою, використовуючи макетну плату, але трішки навиворіт. Вона тут здебільшого лише фіксує елементи, а з'єднання я робив дротиками напряму. Для контрасту дисплея я спочатку вирішив використати резистивний дільник замість змінного резистора, але так як потрібних резисторів в мене не було, я вирішив збільшити опір дільника в 10 разів. Нічого гарного з цієї ідеї не вийшло, тим паче я ще й не раз сплутав їх місцями, та переполюсовав живлення дисплею, тому я вирішив повернутись до змінного резистору.

Для живлення годинника я вирішив використати ось роз'єм під штекер 5.5 на 2.5, для якого довелось просвердлити 8ми міліметровий отвір в корпусі годинника. Також я просвердлив отвір під фідер антени. Ну і під саморізи щоб кріпити задню кришку.

Спаяний годинник

Тепер коли годинник зібраний, саме час поговорити, як він працює. При першому включенні, так як RTC не налаштований, годинник почне шукати GPS супутники, щоб взяти з них час. На це може піти немало часу, так як модуль повинен завантажити там всякі альманахи, ефемериди, PRN коди, і так далі, і все це використовуючи ту хіленьку пасивну антену.

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

Точність синхронізації до речі прям дуже гарна, годинник секунда в секунду йде з часом з інтернету:

Точність синхронізації

А як тільки похибка зросте до 5 секунд, при наявності сигналу з супутників, наявність яких до речі можна побачити на дисплеї, годинник автоматично синхронізується. Я вирішив зробити саме 5 секунд, щоб не мучити RTC частим перезаписуванням, та і на мою думку це не дуже велика похибка, але якщо що, то на 63-му рядку коду це можна змінити.

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

Звісно корпус міг би бути краще, але мене і так все влаштовує.

А на цьому в мене все! Про всяк випадок дублюю посилання на репозиторій проєкту.

Post Scriptum

Це текстова версія відео з мого YouTube каналу. Відео можна переглянути за ось цим посиланням.