1

Тема: часы на gps модуле и семисегментных индикаторах

Основная статья - http://rcl-radio.ru/?p=131064

#define SEG_A  7
#define SEG_B  5
#define SEG_C  10
#define SEG_D  12
#define SEG_E  11
#define SEG_F  6
#define SEG_G  4
#define SEG_DP A4

#define LED_0  A1
#define LED_1  A0
#define LED_2  A2
#define LED_3  A3

#define time_offset   21600  // смещение от UTC 1 час = 3600
#define KORR_T  -2.7   // DS18B20 коррекция температуры

#include <TinyGPS++.h>      // https://github.com/mikalhart/TinyGPSPlus/archive/refs/heads/master.zip
#include <TimeLib.h>        // https://github.com/PaulStoffregen/Time/archive/master.zip
#include <OneWire.h>        // http://rcl-radio.ru/wp-content/uploads/2018/07/OneWire.zip             
 TinyGPSPlus gps;
 OneWire  ds(13); // Вход датчика 18b20

byte an,segm,a[4],i,dpp;
int br=1;
unsigned long times;
byte last_minute, Second, Minute, Hour, Day, Month;
int Year;
int timer;
bool w=1,w1;

void setup() {
  Serial.begin(9600);   
  cli();
  TCCR2A = 0;
  TCCR2B = 0;
  TCNT2 = 0;
  OCR2A = 155;
  TCCR2A |= (1 << WGM21);
  TCCR2B |= (1 << CS22) | (1 << CS21);
  TIMSK2 |= (1 << OCIE2A);
  sei();
  pinMode(SEG_A,OUTPUT);
  pinMode(SEG_B,OUTPUT);
  pinMode(SEG_C,OUTPUT);
  pinMode(SEG_D,OUTPUT);
  pinMode(SEG_E,OUTPUT);
  pinMode(SEG_F,OUTPUT);
  pinMode(SEG_G,OUTPUT);
  pinMode(SEG_DP,OUTPUT);
  pinMode(LED_0,OUTPUT);
  pinMode(LED_1,OUTPUT);
  pinMode(LED_2,OUTPUT);
  pinMode(LED_3,OUTPUT);
}

void loop() {
 
 while (Serial.available() > 0){ 
    if (gps.encode(Serial.read())){
      if (gps.time.isValid()){
        Minute = gps.time.minute();
        Second = gps.time.second();
        Hour   = gps.time.hour();
      }
      if (gps.date.isValid()){
        Day   = gps.date.day();
        Month = gps.date.month();
        Year  = gps.date.year();
      }}}
      
      if(last_minute != gps.time.minute()){
        last_minute = gps.time.minute();
        setTime(Hour, Minute, Second, Day, Month, Year);
        adjustTime(time_offset);
 }

if (millis() > 5000 && gps.charsProcessed() < 10){while(true);}

 if(Year==2000){
    a[0]=11;
    a[1]=11;
    a[2]=11;
    a[3]=11;
      }
 else{    
   timer=hour()*100+minute();
   if(Second>=55){timer = dsRead(0)*100; delay(200);}
  
    
    a[0]=timer/1000%10;
    a[1]=timer/100%10;
    a[2]=timer/10%10;
   if(Second>=55){a[3]=12;}else{a[3]=timer%10;}
 }
}


ISR(TIMER2_COMPA_vect){
   switch (i) {
    case 0: segm = 10; segment();an = 10;anod();delayMicroseconds(br);segm = a[0];segment();an = 0;ch(SEG_DP, 1);anod();break;
    case 1: segm = 10; segment();an = 10;anod();delayMicroseconds(br);segm = a[1];segment();an = 1;ch(SEG_DP, dpp);anod();break;
    case 2: segm = 10; segment();an = 10;anod();delayMicroseconds(br);segm = a[2];segment();an = 2;ch(SEG_DP, 1);anod();break;
    case 3: segm = 10; segment();an = 10;anod();delayMicroseconds(br);segm = a[3];segment();an = 3;ch(SEG_DP, 1);anod();break;
  }
  i++;if (i > 3) {i = 0;}
  if(millis()-times<500){dpp=1;}
  if(millis()-times>=500 || (Second>=55)){dpp=0;}
  if(millis()-times>1000){times=millis();}
  }

void segment() {
  switch (segm) {
            //  A          B             C              D             E            F            G
    case 0: ch(SEG_A, 0); ch(SEG_B, 0); ch(SEG_C, 0); ch(SEG_D, 0); ch(SEG_E, 0); ch(SEG_F, 0); ch(SEG_G, 1); break; // 0
    case 1: ch(SEG_A, 1); ch(SEG_B, 0); ch(SEG_C, 0); ch(SEG_D, 1); ch(SEG_E, 1); ch(SEG_F, 1); ch(SEG_G, 1); break; // 1
    case 2: ch(SEG_A, 0); ch(SEG_B, 0); ch(SEG_C, 1); ch(SEG_D, 0); ch(SEG_E, 0); ch(SEG_F, 1); ch(SEG_G, 0); break; // 2
    case 3: ch(SEG_A, 0); ch(SEG_B, 0); ch(SEG_C, 0); ch(SEG_D, 0); ch(SEG_E, 1); ch(SEG_F, 1); ch(SEG_G, 0); break; // 3
    case 4: ch(SEG_A, 1); ch(SEG_B, 0); ch(SEG_C, 0); ch(SEG_D, 1); ch(SEG_E, 1); ch(SEG_F, 0); ch(SEG_G, 0); break; // 4
    case 5: ch(SEG_A, 0); ch(SEG_B, 1); ch(SEG_C, 0); ch(SEG_D, 0); ch(SEG_E, 1); ch(SEG_F, 0); ch(SEG_G, 0); break; // 5
    case 6: ch(SEG_A, 0); ch(SEG_B, 1); ch(SEG_C, 0); ch(SEG_D, 0); ch(SEG_E, 0); ch(SEG_F, 0); ch(SEG_G, 0); break; // 6
    case 7: ch(SEG_A, 0); ch(SEG_B, 0); ch(SEG_C, 0); ch(SEG_D, 1); ch(SEG_E, 1); ch(SEG_F, 1); ch(SEG_G, 1); break; // 7
    case 8: ch(SEG_A, 0); ch(SEG_B, 0); ch(SEG_C, 0); ch(SEG_D, 0); ch(SEG_E, 0); ch(SEG_F, 0); ch(SEG_G, 0); break; // 8
    case 9: ch(SEG_A, 0); ch(SEG_B, 0); ch(SEG_C, 0); ch(SEG_D, 0); ch(SEG_E, 1); ch(SEG_F, 0); ch(SEG_G, 0); break; // 9
   case 11: ch(SEG_A, 1); ch(SEG_B, 1); ch(SEG_C, 1); ch(SEG_D, 1); ch(SEG_E, 1); ch(SEG_F, 1); ch(SEG_G, 0); break; // -
   case 10: ch(SEG_A, 1); ch(SEG_B, 1); ch(SEG_C, 1); ch(SEG_D, 1); ch(SEG_E, 1); ch(SEG_F, 1); ch(SEG_G, 1); break; // пусто
   case 12: ch(SEG_A, 0); ch(SEG_B, 1); ch(SEG_C, 1); ch(SEG_D, 0); ch(SEG_E, 0); ch(SEG_F, 0); ch(SEG_G, 1); break; // C
  }
}

void anod() {
  switch (an) {
    case 0: ch(LED_0, 0); ch(LED_1, 1); ch(LED_2, 1); ch(LED_3, 1); break;
    case 1: ch(LED_0, 1); ch(LED_1, 0); ch(LED_2, 1); ch(LED_3, 1); break;
    case 2: ch(LED_0, 1); ch(LED_1, 1); ch(LED_2, 0); ch(LED_3, 1); break;
    case 3: ch(LED_0, 1); ch(LED_1, 1); ch(LED_2, 1); ch(LED_3, 0); break;
   case 10: ch(LED_0, 1); ch(LED_1, 1); ch(LED_2, 1); ch(LED_3, 1); break;
  }
} 

float dsRead(byte x) {
  byte data[2], addr[8][8], kol = 0;
  while (ds.search(addr[kol])) {  // поиск датчиков, определение адреса и кол-ва датчиков
    kol++;
  } 
  ds.reset_search();  // Сброс поиска датчика
  ds.reset();         // Инициализация, выполняется сброс шины
  ds.select(addr[x]); // Обращение к датчику по адресу
  ds.write(0x44, 0);  // Измерение температуры с переносом данных в память
  ds.reset();         // Инициализация, выполняется сброс шины
  ds.select(addr[x]); // Обращение к датчику по адресу
  ds.write(0xBE);     // Обращение памяти
  for (byte i=0; i<9; i++) data[i]=ds.read();
  int raw=(data[1]<<8)|data[0];
  float value = (float)raw *0.0625 + KORR_T; return value; // Расчет температуры и вывод
}

void ch(int pin, int logic){digitalWrite(pin, logic);}  

2

Re: часы на gps модуле и семисегментных индикаторах

http://forum.rcl-radio.ru/uploads/images/2023/10/931a43e898b074d62d6f4bcd2539e4ad.png

http://forum.rcl-radio.ru/uploads/images/2023/10/627887eee152309f25c9e9ffd8b5bad8.png

http://forum.rcl-radio.ru/uploads/images/2023/10/38663f70853965458dbdc69871336cb6.png

3

Re: часы на gps модуле и семисегментных индикаторах

Интересно конечно, но может быть лучше индикаторы взять тм1637? Тогда эта конструкция имеет право на жизнь где нибудь в далёком колхозе. Интернета нет, а точное время есть.

4

Re: часы на gps модуле и семисегментных индикаторах

тм1637 - размер маленький

5

Re: часы на gps модуле и семисегментных индикаторах

Классная тема! Я сейчас тоже проникся такой идеей, а у Вас уже есть реализация.
Думаю что конструкция не только для далёкого колхоза. И для Москвы самое оно.
Началось с того что имеются китайские часы с большими светодиодными семисегментниками (LM8560 и дисплей Longtek 6250x), которые синхронизацию берут с сети 220v.). Они стали очень сильно убегать, уже на 20 мин вперёд. Полистал интернет, такая проблема с ними у многих. Бороться с ней слишком трудоёмко, отдельно дисплей вырезать и подключить к чему нибудь не получится. Сегодня разобрал, обнаружил две мизинчиковые алкалиновые батарейки (резерв при потере питания), они на минусах уже окислились. Выкинул, поставил вместо них аккумы. Время установил, понаблюдаю за точностью.
Но от идеи с синхронизацией от Glonass не отказался. Она мне нравится. Воткнул в розетку и не надо дрочиться время устанавливать и периодически проверять точность хода. Или работают, или нет.
Правда пришла  в голову мысль, что где нибудь в подвале они работать не будут. Тогда придётся задействовать резервную мелкосхему, какую нибудь DS3231, на время пропадания связи с Glonass. Это в общих чертах. Мелочи потом продумаем. Может вообще лучше большую часть времени работать на мелкосхеме, а с глонасс иногда сверяться.
И ещё хочу воткнуть в них Max7219.

6

Re: часы на gps модуле и семисегментных индикаторах

У меня нет сейчас модуля GPS, а без него написание кода не возможно.

7

Re: часы на gps модуле и семисегментных индикаторах

MAX7219

http://forum.rcl-radio.ru/uploads/images/2023/11/1b7c2f92967a4dfda5e7c8c4e72d3def.png

0.56-inch
http://forum.rcl-radio.ru/uploads/images/2023/11/0e79715870217f9ce1c4e2885a64b333.png

http://forum.rcl-radio.ru/uploads/images/2023/11/db3a522b20ea9781cb033d3d72fd710a.png


#define DIN 10
#define CLK 11
#define CS  12

#define RX      2
#define TX      3
#define time_offset   21600  // смещение от UTC 1 час = 3600
#define KORR_T  -4.0   // DS18B20 коррекция температуры

#include <TinyGPS++.h>      // https://github.com/mikalhart/TinyGPSPlus/archive/refs/heads/master.zip
#include <TimeLib.h>        // https://github.com/PaulStoffregen/Time/archive/master.zip
#include <SoftwareSerial.h>  
#include <OneWire.h>        // http://rcl-radio.ru/wp-content/uploads/2018/07/OneWire.zip                       
  TinyGPSPlus gps;
  SoftwareSerial SoftSerial(TX,RX);   
  OneWire  ds(5); // Вход датчика 18b20
  
  unsigned long times;
  byte last_minute, Second, Minute, Hour, Day, Month;
  int Year;
  int timer,temp;
  bool w=1;
  int min_old;
  int hh,mm,ss;

void setup(){
  Serial.begin(9600);
  SoftSerial.begin(9600);
  pinMode(DIN,OUTPUT);
  pinMode(CLK,OUTPUT);
  pinMode(CS,OUTPUT);
  delay(2);
  digitalWrite(CS,HIGH);digitalWrite(CLK,LOW);digitalWrite(DIN,LOW);
  WriteBit16(0x0F, 0);// тест выкл.
  WriteBit16(0x0C, 1);// вкл. индик.
  WriteBit16(0x0A, 2);// яркость
  WriteBit16(0x09, 0xFF);// дешифраторы вкл.
  WriteBit16(0x0B, 3);// кол-во разрядов
  Serial.println("LED_OK");
  }

void loop(){
while (SoftSerial.available() > 0){
    if (gps.encode(SoftSerial.read())){
      if (gps.time.isValid()){
        Minute = gps.time.minute();
        Second = gps.time.second();
        Hour   = gps.time.hour();
        Serial.println("UTC");
        Serial.print(Hour);Serial.print(":");
        Serial.print(Minute);Serial.print(":");
        Serial.println(Second);
      }
      if (gps.date.isValid()){
        Day   = gps.date.day();
        Month = gps.date.month();
        Year  = gps.date.year();
        Serial.print(Day);Serial.print("-");
        Serial.print(Month);Serial.print("-");
        Serial.println(Year);
      }}}
      
      if(last_minute != gps.time.minute()){ w=1;
        last_minute = gps.time.minute();
        setTime(Hour, Minute, Second, Day, Month, Year);
        adjustTime(time_offset);
        Serial.println("UTC+");
        Serial.print(hour());Serial.print(":");
        Serial.print(minute());Serial.print(":");
        Serial.println(second());
        Serial.print(day());Serial.print("-");
        Serial.print(month());Serial.print("-");
        Serial.println(year());
        Serial.println(week_day());
 }

if (millis() > 5000 && gps.charsProcessed() < 10){
    Serial.println("No GPS detected");
    while(true);}
  
  
    
  if(Year>=2023){
 if(millis()-times>=75000){
   temp = int(dsRead(0)*100);delay(200);
   Serial.print("TEMP = ");Serial.println(float(temp)/100.0,1);
   WriteBit16(1, temp/1000%10);
   WriteBit16(2, temp/100%10 + 0xF0);
   WriteBit16(3, temp/10%10);
   WriteBit16(4, 0x0F);
}
 if(millis()-times<75000){
   timer=hour()*100+minute();
   WriteBit16(1, timer/1000%10);
   WriteBit16(2, timer/100%10 + 0xF0);
   WriteBit16(3, timer/10%10);
   WriteBit16(4, timer%10);
   Serial.println("TIMER");
   Serial.print(hour()/10%10);Serial.print(hour()%10);Serial.print(":");
   Serial.print(minute()/10%10);Serial.print(minute()%10);Serial.print(":");
   Serial.print(second()/10%10);Serial.println(second()%10);
   delay(500);
   WriteBit16(1, timer/1000%10);
   WriteBit16(2, timer/100%10);
   WriteBit16(3, timer/10%10);
   WriteBit16(4, timer%10);
   delay(500);
 }
 if(millis()-times>80000){times=millis();}
 }
 else{
   WriteBit16(1, 10);
   WriteBit16(2, 10+0xF0);
   WriteBit16(3, 10);
   WriteBit16(4, 10);
   delay(500);
   WriteBit16(1, 10);
   WriteBit16(2, 10);
   WriteBit16(3, 10);
   WriteBit16(4, 10);
   delay(500);
  }
    
 }  // end loop

byte week_day(){
  byte a = f_div((14 - month()), 12);
  unsigned int y = year() - a;
  byte m = month() + 12 * a - 2;
  unsigned int y4 = f_div(y, 4);
  byte y100 = f_div(y, 100);
  byte y400 = f_div(y, 400);
  byte x = f_div(31 * m, 12);
  byte wd = (day() + y + y4 - y100 + y400 + x) % 7; 
  return wd;
} 

unsigned int f_div(unsigned int x, unsigned int y){
  unsigned int result;
  result = (x - (x % y)) / y;
  return result;
}

void WriteBit16(byte reg, byte data){  
     digitalWrite(CLK,LOW); digitalWrite(CS,LOW);
     for(int i = 7; i >= 0; i--){
        if(((reg >> i) & 1) == 1){digitalWrite(DIN,HIGH);}else{digitalWrite(DIN,LOW);}
        digitalWrite(CLK,HIGH);digitalWrite(CLK,LOW);
        }
     for(int i = 7; i >= 0; i--){
        if(((data >> i) & 1) == 1){digitalWrite(DIN,HIGH);}else{digitalWrite(DIN,LOW);}
        digitalWrite(CLK,HIGH);digitalWrite(CLK,LOW);
        }
     digitalWrite(CS,HIGH);digitalWrite(CLK,LOW);digitalWrite(DIN,LOW);  
  }  

float dsRead(byte x) {
  byte data[2], addr[8][8], kol = 0;
  while (ds.search(addr[kol])) {  // поиск датчиков, определение адреса и кол-ва датчиков
    kol++;
  } 
  ds.reset_search();  // Сброс поиска датчика
  ds.reset();         // Инициализация, выполняется сброс шины
  ds.select(addr[x]); // Обращение к датчику по адресу
  ds.write(0x44, 0);  // Измерение температуры с переносом данных в память
  ds.reset();         // Инициализация, выполняется сброс шины
  ds.select(addr[x]); // Обращение к датчику по адресу
  ds.write(0xBE);     // Обращение памяти
  for (byte i=0; i<9; i++) data[i]=ds.read();
  int raw=(data[1]<<8)|data[0];
  float value = (float)raw *0.0625 + KORR_T; return value; // Расчет температуры и вывод
}  

8

Re: часы на gps модуле и семисегментных индикаторах

Ну вот почти часы выживальщика )). Теперь автономное питание прикрутить, и можно среди глухой тайги узнать точное время.

9

Re: часы на gps модуле и семисегментных индикаторах

Точно, часы выживальщика.
Приёмник GPS в глухой тайге будет работать наверное гораздо лучше чем в Москве.
Не думал что можно столкнуться с плохим приёмом спутников с сигналом GPS.
Дома смартфон показывает нормально местоположение даже когда в сортире сидишь.
Значит GPS модуль должен прекрасно работать.
Ну и конечно он должен уметь работать с Глонасс. 
Абы какой модуль, типа кривота,  покупать не хотелось. Вспомнил про одну интересную контору iarduino.ru .
У них на сайте есть объёмный набор различных библиотек для ардуино собственной разработки.
Однажды воспользовался библиотекой iarduino_OLED_txt . Это вывод на OLED дисплей текстовой информации включая русские буквы. Прекрасная работа ПО. Легко разобраться как использовать. Всё наглядно и понятно. К тому же маленький размер кода.
До неё перепробовал кучу других библиотек, но везде была какая то засада, особенно в части русских букв.
С ней правда наткнулся на косячок, нормально работала с Arduino UNO, а с ESP32 клинила компиляция. Обратился по E-mail в эту контору, описал проблему. Думал что не помогут ни хрена. А вот и нет. Прислали исправленную библиотеку.
Попробовал, всё нормально компилируется и с ESP32.
Я был очень рад  что не пришлось ставить крест на любимой библиотеке.
Получается что с этой конторой можно иметь дело.
Многие железки у них тоже собственного ппроизводства.
Полез к ним на сайт посмотреть модули GPS.
Выбрал GPS/GLONASS модуль (Trema-модуль) на ATGM336H.
Для него есть две библиотеки в коллекции на сайте, iarduino_GPS_NMEA и arduino_GPS_ATGM336.
В использовании библиотек легко разобраться. Качество кода надеюсь будет нормальным.
Пришёл этот модуль. Батарейка с ним не поставляется.
Подключаю к Nano через SoftSerial. И вообще ничего.
Затыкается на строке инициализации работы с GPS модулем по указанной шине UART, в моём случае программном UART.
Подключаю к UNO. Всё тоже самое.
Подключаю к компьютеру через USB-TTL. Устанавливаю программу от uBlox U-Center. Тоже ничего.
Обращаю внимание что светодиод PPS не моргает. Этот светодиод моргает раз в секунду когда модуль обнаруживает и видит спутники.
Т.е. пока не моргает - ничего работать не будет, спутники не обнаружены.
Какого х. он не моргает?
Брак что ли ? Странно, покупал в хорошей конторе.
Пишу в контору, прикладываю видео.
Получаю ответ,
Модуль не будет работать в помещении. Можно даже программу не загружать. До тех пор пока модуль не замигает светодиодом, он никаких координат не даст. Модуль должен быть на открытом пространстве. Если в модуле нет батарейки, он будет дольше искать спутники. НО главное пока не моргает светодиод, значит он не нашел спутники.
Лезу в инет с вопросом обнаружения спутников. И да, это действительно гемор.
Обнаруживать спутники лучше на улице, на крайняк приёмник должен лежать на подоконнике. Желательно что бы окна выходили на юг.
Но почему тогда смартфон так прекрасно определяет местоположение?
Оказывается он ориентируется не только по GPS, а также по сотовым вышкам оператора связи.
Запитываю приемник от 18650 и иду с ним на улицу. Ставлю на торпеду в машине, жду некоторое время  - результата ноль. Не моргает. Покатался на машине по району, и опять ничего не изменилось, не моргает.
Модуль мне всё таки поменяли. Сказали что даже проверяли прежде чем мне передать.
Но результаты те же. Никак не ловит спутники.
Остаётся попробовать с батарейкой.
Батарейка нужна CR-1220. Оказывается такая на каждом углу не продаётся. В ашане вроде есть, 5 шт. 500 с небольшим руб. Чего то крутовато. Да и с SoftSerial затык тоже не нравится.
Решаю купить ещё один модуль, на котором вставлена батарейка.
В amperkot.ru нахожу GY-GPSV3-NEO ー миниатюрный GPS приемник с поддержкой GLONASS построен на модуле uBlox NEO-M8N. Батарейка на плате уже установлена.
Покупаю. Питание 2.7-3.6v.
Дома конечно ничего не ловит, на застекленном балконе, окна на восток, тоже ничего.
Запитываю от двух пальчиковых, иду на улицу.
Кладу в машине на торпеду.
Во дворе опять ничего. Прокатился на машине по делам. Смотрю синий светодиод заморгал. Ура, хоть какой то результат есть.
Дома подключаю к компьютеру, смотрю программой U-Center.
Работает. Хрен его знает что там с координатами, мне они как то не нужны. Но время, дату показывает. Хотя светодиод PPS не моргает.
Остаётся только купить батарейку для первого модуля на ATGM336.
Купил.
Поставил, и на улицу. Во дворе - ничего не получается.
На следующий день пошёл на работу. Первый модуль взял с собой. Вышел покурить. Модуль держу в руке. Пока курил - заморгал светодиод. Ну наконец-то! Дождался.
Пришёл в кабинет, свтодиод моргать перестал.
Положил на подоконник, окна на запад. Прошло немного времени и светодиод заморгал. Ну и прекрасно.
К компу с  U-Center его. Всё работает.
Остаётся вопрос с косячным SoftSerial. Надо пробовать с hard UART.
На Nano и UNO по одному hard UART. Очень неудобно, Монитор в Arduino перестаёт работать.
Беру ESP32. У него несколько hard UART. Леплю конструкцию на нём.
Serial0 - для Arduino IDE монитор, а Serial2 к приёмнику GPS.
Всё прекрасно работает. Дату и время выдаёт.
Дописал вывод на малюсенький OLED монитор через I2C. Всё прекрасно.
Через hard UART всё работает как и задумывалось. Библиотеки от iarduino.ru, как мне и хотелось.
А с косячным SoftSerial - вопрос пока висит, да и нет особой нужды с ним заморачиваться.
Вот так мне пришлось помучаться с модулями GPS.
Много букв написал, но думаю кому то будет интересно почитать.
Короче, батарейка на плате обязательна, и в Москве не везде нормально ловятся спутники.
Большие индикаторы заказал на али. Скоро придут.