Часы на max7219 метеостанция V1

Дим M
Автор темы, Администратор
Администратор
Аватара
Дим M
Автор темы, Администратор
Администратор
Сообщения: 1611
Зарегистрирован: 5 апреля 2013
С нами: 11 лет

#1 Дим » 11 августа 2019, 13:36

phpBB [media]


Так как в предыдущей теме - Часы на max7219 + DS1307 + DS18B20 + BMP180 стало трудно разбираться что к чему, тему решил разделить на две, с разными версиями часов. Это будет первая версия. Что в ней реализовано:
1. Показ часов (что собственно от часов и требуется :grin: )
2. Каждые 10 минут или при нажатии на первую кнопку на часах или при нажатии кнопки на пульте будет запускаться бегущая строка с информацией о погоде дома, на улице и атмосферным давлением.
3. Двумя разными кнопками на ПДУ (какие именно определите для себя сами) прибавляем или убавляем яркость светодиодной матрицы.
4. При длительном нажатии на кнопку 2 переходим в режим установки времени. Сначала замигают часы - их циклично прибавляя, переводим кнопкой 1. ,
Коротко нажав на кнопку 2 теперь начинают мигать минуты, их так же циклично прибавляем кнопкой 1.
Если ещё раз коротко нажать на кнопку 2, мы устанавливаем секунды на :00 и автоматически выходим из режима установки времени.
Схема подключения
Часы на max7219 метеостанция V1.JPG
Часы на max7219 метеостанция V1
Часы на max7219 метеостанция V1.JPG (332.18 КБ) 8205 просмотров
Скетч

Код: Выделить всё

#include <Wire.h>
#include <Adafruit_BMP085.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Max72xxPanel.h>
#include <DallasTemperature.h>
#include "IRremote.h"
IRrecv irrecv(12);                            // указываем вывод, к которому подключен ИК приемник
decode_results results;
uint32_t Key1 = 0x2FD50AF;                    // Определяем код кнопки ПДУ OK
uint32_t Key2 = 0x2FD52AD;                    // Определяем код кнопки ПДУ лево
uint32_t Key3 = 0x2FDB24D;                    // Определяем код кнопки ПДУ право
#include <iarduino_RTC.h>                     // Подключаем библиотеку iarduino_RTC для работы с модулями реального времени.
iarduino_RTC time(RTC_DS1307);                // Объявляем объект time для работы с RTC модулем на базе чипа DS1307, используется аппаратная шина I2C
Adafruit_BMP085 bmp;
// ============================== кнопки
const uint8_t PIN_button_SET  = 4;            // указываем номер вывода arduino, к которому подключена кнопка SET
const uint8_t PIN_button_UP   = 3;            // указываем номер вывода arduino, к которому подключена кнопка UP
//const uint8_t PIN_button_DOWN = 5;            // указываем номер вывода arduino, к которому подключена кнопка DOWN
bool     button_state1      = false;          // статус кнопки 1
bool     button_state2      = false;          // статус кнопки 2
bool     button_long_state  = false;          // удержание кнопки (код выполнится один раз)
uint32_t ms_button         = 0;
uint32_t ms_auto_click     = 0;

uint8_t corrClock = 0;                        // корректировали время или нет
uint8_t updCnt = 0;
uint8_t dots = 0;
long dotTime = 0;
long clkTime = 0;

const uint8_t DS18B20 = 8;                    // Указываем, к какому выводу подключена DQ (уличн темп)

uint8_t wibor = 0;                            // После того как длительно нажали на кнопку SET можно будет нажимать коротко
uint8_t mig = 0;
uint8_t migSet = 0;
uint8_t migTime = 0;
long previousMillis = 0;
uint8_t val=0; 

uint8_t wait 
= 50;                            // скорость бегущей строки
uint8_t spacer = 2;
uint8_t width = 5 + spacer;                   // Регулируем расстояние между символами
uint8_t refresh=0;
const uint8_t  pinCS = 10;                    // Подключение пина CS
uint8_t numberOfHorizontalDisplays = 4;       // Количество светодиодных матриц по Горизонтали
uint8_t numberOfVerticalDisplays = 1;         // Количество светодиодных матриц по Вертикали
String weatherString;                         // бегущая строка
String clocks;                                // время

Max72xxPanel matrix = Max72xxPanel(pinCS, numberOfHorizontalDisplays, numberOfVerticalDisplays);
OneWire oneWire(DS18B20);                   
DallasTemperature sensors
(&oneWire);
byte brightness = 0;                         // Яркость матрицы от 0 до 15
// ===================================================================================================================================
void setup(void) {
  Serial.begin( 9600 );                       // Инициируем передачу данных в монитор последовательного порта
  irrecv.enableIRIn();                        // запускаем прием ИК приемника
  if (!bmp.begin())                           //для температуры улицы
  {
    while (1) {}
  } 
  time
.begin();                               // Инициируем работу с модулем.
  //time.settime(0,27,21,03,01,18,3);         // Записываем время в модуль: 0 сек, 27 мин, 21 час, 3, января, 2018 года, среда. time.settime(0,27,21,03,01,18,3);
  matrix.setIntensity(brightness);            // Яркость матрицы от 0 до 15
  matrix.setRotation(matrix.getRotation()+2); // 1 - 90  2 - 180   3 - 270 угол поворота
                                   // начальные координаты матриц 8*8
  matrix.setRotation(0, 1);        // 1 матрица
  matrix.setRotation(1, 1);        // 2 матрица
  matrix.setRotation(2, 1);        // 3 матрица
  matrix.setRotation(3, 1);        // 4 матрица                                  
  pinMode(PIN_button_SET, INPUT_PULLUP);      // кнопки
  pinMode(PIN_button_UP, INPUT_PULLUP);
//  pinMode(PIN_button_DOWN, INPUT_PULLUP);
//   digitalWrite(PIN_button_SET ,HIGH);
}
// =======================================================================
void loop(void) 
{   
  if
(updCnt<=0) 
  
{                                                               // каждые 10 циклов получаем данные времени и погоды
    updCnt = 1;
    getWeatherData();
    clkTime = millis();
  }
//  if((millis()-clkTime > 600000 && dots && mig == 0) || (mig == 3))// Через 10 минут/600000 мили/сек и не переводим часы (mig == 0) (или нажата кнопа UP) запускаем бегущую строку
  if(((time.minutes == 9 || time.minutes == 19 || time.minutes == 29 || time.minutes == 39 || time.minutes == 49 || time.minutes == 59) && time.seconds == 59 && mig == 0) || (mig == 3)) 
  
{                                                               // каждые (9,19,29,39,49,59) минут и 59 секунд и не переводим часы (mig == 0)(или нажата кнопа UP) запускаем бегущую строку
    //ScrollText(utf8rus("sampawno.ru!"));                        // текст строки
    ScrollText(utf8rus(weatherString));                           // текст температуры и давления
    updCnt--;
    clkTime = millis();
    mig = 0;                                                      // переменная mig не 3, для кнопки вызова бегущей строки, что бы не циклило её
  }
  DisplayTime();
  time.blinktime(migSet);                                         // мигаем устанавливаемым параметром (migSet больше 0) при установке времени
  if(millis()-dotTime > 500) 
  
{
    dotTime = millis();
    dots = !dots;
  }
  Func_buttons_control();
  if ( irrecv.decode( &results )) 
  
{                              // если данные с ПДУ пришли  
    if (results.value == Key1)                                     // если нажата кнопка 1
      {mig = 3;}                                                   // запускаем бегущую строку
      
    if 
(results.value == Key2)                                     // если нажата кнопка 2
      {brightness --;}                                             // убавляем переменную яркости матрицы
      if (brightness == 255) brightness = 15;                      // если вылезли за границы присваеваем 15 
      {matrix.setIntensity(brightness);}                           // устанавливаем яркость матрицы     
      
    if 
(results.value == Key3)                                      // если нажата кнопка 3
      {brightness ++;}                                             // прибавляем переменную яркости матрицы
      if (brightness > 15) brightness = 0;                         // если вылезли за границы присваеваем 0
      {matrix.setIntensity(brightness);}                           // устанавливаем яркость матрицы   
      
    irrecv
.resume();   // принимаем следующую команду
  }
}
void Func_buttons_control()
{
   uint32_t ms    = millis();
   bool pin_state1 = digitalRead(PIN_button_SET); // кнопка SET
   bool pin_state2 = digitalRead(PIN_button_UP);  // 2 кнопка
//=========================================================================== кнопка SET
// Фиксируем нажатие кнопки  SET
  if( pin_state1  == LOW && !button_state1 && ( ms - ms_button ) > 50 ){
      button_state1     = true;
      button_long_state = false;
      ms_button         = ms;
      if(wibor == 1)
        switch (mig) 
        
{
          case 1:         // кнопка SET выбор мин
            migSet = 2;
            mig = 2;
            break;
          case 2:         // кнопка SET сброс сек на 00
            migSet = 0;                                   // НЕмигают минуты и часы
            mig = 0;
            time.settime(0, -1, -1);                      // Сбросит секунды на 0, а часы, минуты и дату, оставит без изменений.
            wibor = 0;
            break;
        }  
  
}
// После 2000 мс нажатия кнопки SET единоразово выполним код
  if( pin_state1  == LOW && !button_long_state && ( ms - ms_button ) > 2000 ) // кнопка SET выбор час
  {
    migSet = 3;
    mig = 1;  
    wibor 
= 1;                                     // длительно нажали
  }
// Фиксируем отпускание кнопки SET 
   if( pin_state1 == HIGH && button_state1 && ( ms - ms_button ) > 50  ){
      button_state1     = false;   
      ms_button         
= ms;
      Serial.println("No Press 2"); //действие после отпуска длительного нажатия
   }   
  
//===========================================  Кнопка UP (Установка часов)
  if(mig == 1 && pin_state2  == LOW && !button_state2 && ( ms - ms_button ) > 50 )
  { 
    button_state2     
= true;
    ms_button         = ms;
    migSet = 0;
    time.Hours ++;                            // прибавляем единицу к часам
    if (time.Hours > 23) time.Hours = 0;      // если вылезли за границы присваеваем 0
    time.settime(-1, -1, time.Hours);         // установит часы, а секунды, минуты и дату, оставит без изменений.
  }
  if(mig == 1 && pin_state2  == LOW && ( ms - ms_button ) > 1000 && ( ms - ms_auto_click )>300 ) // После 1000 мс нажатия кнопки каждые 400 мс фиксируем событие нажатия  
  {
    ms_auto_click     = ms;
    migSet = 0;
    time.Hours ++;                            // прибавляем единицу к часам
    if (time.Hours > 23) time.Hours = 0;      // если вылезли за границы присваеваем 0
    time.settime(-1, -1, time.Hours);         // установит часы, а секунды, минуты и дату, оставит без изменений.
  }
  //===========================================  Кнопка UP (Установка минут)
  if(mig == 2 && pin_state2  == LOW && !button_state2 && ( ms - ms_button ) > 50 )
  { 
    button_state2     
= true;
    ms_button         = ms;
    migSet = 0;
    time.minutes ++;                          // прибавляем единицу к минутам
    if (time.minutes > 59) time.minutes = 0;  // если вылезли за границы присваеваем 0
    time.settime(-1, time.minutes, -1);       // установит минуты, а секунды, часы и дату, оставит без изменений.
  }
  if(mig == 2 && pin_state2  == LOW && ( ms - ms_button ) > 1000 && ( ms - ms_auto_click )>300 ) // После 1000 мс нажатия кнопки каждые 400 мс фиксируем событие нажатия  
  {
    ms_auto_click     = ms;
    migSet = 0;
    time.minutes ++;                          // прибавляем единицу к минутам
    if (time.minutes > 59) time.minutes = 0;  // если вылезли за границы присваеваем 0
    time.settime(-1, time.minutes, -1);       // установит минуты, а секунды, часы и дату, оставит без изменений.
  }
  //===========================================  Кнопка UP (Установка минут) вызов бегущей строки  
  if(mig == 0 && pin_state2  == LOW && !button_state2 && ( ms - ms_button ) > 50 )
  { 
    mig 
= 3;
  } 
//==============================================================================  Кнопка UP ( Фиксируем отпускание кнопки установки часов/минут  )
  if(pin_state2 == HIGH && button_state2 && ( ms - ms_button ) > 50  )
  {
    button_state2     = false;   
    ms_button         
= ms;
    if(mig == 1){migSet = 3;}
    if(mig == 2){migSet = 2;}
  }
}
void DisplayTime()
{
  sensors.requestTemperatures();             // Считываем показания температуры 
  clocks = String(time.gettime("His"))+" ";  // Время
  if(time.Hours == 23 && time.minutes == 30 && time.seconds == 45 && corrClock == 0){ // Действия внутри оператора if, будут выполняться если время 23:30:45 и не переводили часы (corrClock == 0)
  time.settime(5, -1, -1);                  // Корректируем - устанавливаем время. Так как у меня убегали на 40 сек. Часы (-1) не трогаем, минуты (-1) не трогаем, а сек ставим 5. Было 23:30:45 стало 23:30:05 - на 40 сек меньше.
  corrClock = 1;                             // перевели время (что бы в 23:30:45 опять не перевелись часы)
}
if(
time.Hours==23 && time.minutes==59 && time.seconds==00){ //в  23:59:00...
 corrClock = 0;                                             // обнуляем переменную corrClock, что перевели время, что бы на следующие сутки в 23:30:45 опять перевелись часы   
}
 
  matrix
.fillScreen(LOW);
  int y = (matrix.height() - 8) / 2;         // Центрируем текст по Вертикали
  // if(clocks[5] & 1){matrix.drawChar(14, y-1, (String(":"))[0], HIGH, LOW, 1);} //каждую четную секунду печатаем двоеточие по центру (чтобы мигало)
//  else{matrix.drawChar(14, y, (String(" "))[0], HIGH, LOW, 1);}               //каждую НЕЧЕТНУЮ секунду НЕ ПЕЧАТАЕМ двоеточие по центру (чтобы мигало)
  if(clocks[5] & 1){matrix.drawChar(14, -1, (String(":"))[0], HIGH, LOW, 1);}    //каждую четную секунду печатаем двоеточие по центру (чтобы бегало)
  else{matrix.drawChar(14, -2, (String(":"))[0], HIGH, LOW, 1);}                //каждую НЕЧЕТНУЮ секунду печатаем двоеточие ВЫШЕ на 1 (чтобы бегало)
  
  int xh 
= 2;
  int xm = 19;
  matrix.drawChar(xh, y, clocks[0], HIGH, LOW, 1);
  matrix.drawChar(xh+6, y, clocks[1], HIGH, LOW, 1);
  matrix.drawChar(xm, y, clocks[2], HIGH, LOW, 1);
  matrix.drawChar(xm+6, y, clocks[3], HIGH, LOW, 1); 
  matrix
.write();                                     // Вывод на дисплей
}
void ScrollText (String text)
{
    for ( int i = 0 ; i < width * text.length() + matrix.width() - 1 - spacer; i++ ) {
    if (refresh==1) i=0;
    refresh=0;
    matrix.fillScreen(LOW);
    int letter = i / width;
    int x = (matrix.width() - 1) - i % width;
    int y = (matrix.height() - 8) / 2;  // Центрируем текст по Вертикали
    while ( x + width - spacer >= 0 && letter >= 0 ) 
    
{
      if ( letter < text.length() ) 
      
{
        matrix.drawChar(x, y, text[letter], HIGH, LOW, 1);
      }
      letter--;
      x -= width;
    }
    matrix.write();                    // Вывод на дисплей
    delay(wait);
  }
}
//float tempOffset = 1.5;               //поправка уличного датчика
float tempOffset = 1.0;               //поправка уличного датчика
void getWeatherData()
{
  weatherString = " t.д: " + String(bmp.readTemperature(),1)+" ";
  weatherString += " ул: " + String(sensors.getTempCByIndex(0) - tempOffset, 1)+" ";
  weatherString += " дв: " + String(bmp.readSealevelPressure()/133.3) + " мм ";       //131.42 поправка реального(из инета)
}
String utf8rus(String source)
{
  int i,k;
  String target;
  unsigned char n;
  char m[2] = { '0', '\0' };
  k = source.length(); i = 0;
  while (< k) {
    n = source[i]; i++;
    if (>= 0xC0) {
      switch (n) {
        case 0xD0: {
          n = source[i]; i++;
          if (== 0x81) { n = 0xA8; break; }
          if (>= 0x90 && n <= 0xBF) n = n + 0x30-1;
          break;
        }
        case 0xD1: {
          n = source[i]; i++;
          if (== 0x91) { n = 0xB8; break; }
          if (>= 0x80 && n <= 0x8F) n = n + 0x70-1;
          break;
        }
      }
    }
    m[0] = n; target = target + String(m);
  }
return target;
}
Я маленько изменил шрифт (увеличил размер). Это с лёгкостью можно сделать при помощи программы Image generate v2.004. Рисуем нужный нам символ и выделив код (не весь), как показано на рисунке ниже,

выделив код.png
выделив код
выделив код.png (21.13 КБ) 8205 просмотров



заменяем его в файле glcdfont.c библиотеки Adafruit-GFX


заменяем его в файле glcdfont.c библиотеки Adafruit-GFX.png
заменяем его в файле glcdfont.c библиотеки Adafruit-GFX
заменяем его в файле glcdfont.c библиотеки Adafruit-GFX.png (21.24 КБ) 8205 просмотров


Все библиотеки с уже изменённым файлом glcdfont.c будут приложены в конце статьи.

Что нам потребовалось:
Arduino Nano
Светодиодная матрица max7219
RTC модуль часов DS1307
Модуль датчика температуры DS18B20 (для показаний температуры улицы)
Датчик атмосферного давления BMP280 (для показаний давления и температуры в помещении)
ИК приёмник. Читаем Как определить код кнопок ИК пульта

библиотеки.zip
библиотеки
(497.77 КБ) 907 скачиваний
[center]i love you [s]mxIni[/s] Mysql[/center]


Алексей
Аватара
Алексей
Сообщения: 1
Зарегистрирован: 23 января 2020
С нами: 4 года 2 месяца

Загрузка скетча

#2 Алексей » 23 января 2020, 18:56

Спасибо. Заработало. Была проблема с библиотекой #include <OneWire.h>

Arduino
Сержант
Сержант
Аватара
Arduino
Сержант
Сержант
Сообщения: 64
Зарегистрирован: 19 апреля 2017
С нами: 6 лет 11 месяцев

#3 Arduino » 24 января 2020, 16:44

Алексей писал(а):Была проблема с библиотекой #include <OneWire.h>
А она тут и не нужна вроде )

Дим M
Автор темы, Администратор
Администратор
Аватара
Дим M
Автор темы, Администратор
Администратор
Сообщения: 1611
Зарегистрирован: 5 апреля 2013
С нами: 11 лет

#4 Дим » 8 декабря 2020, 23:20

Если кому то не нравится что показывается "лишний ноль", такое бывает в 01, 02 ... 09 часов. То можно его убрать, для этого добавляем условие:

Этот код добавить ...

Код: Выделить всё

  if(time.Hours == 1 || time.Hours == 2 || time.Hours == 3 || time.Hours == 4 || time.Hours == 5 || time.Hours == 6 || time.Hours == 7 || time.Hours == 8 || time.Hours == 9){ //если время 01 или 02 ... 09 часов то первый ноль не показываем
  matrix.drawChar(xh, y, clocks[0], LOW, LOW, 1); //   то первый ноль не показываем
  

... перед этим:

Код: Выделить всё

  matrix.drawChar(xh+6, y, clocks[1], HIGH, LOW, 1);
  matrix.drawChar(xm, y, clocks[2], HIGH, LOW, 1);
  matrix.drawChar(xm+6, y, clocks[3], HIGH, LOW, 1); 
  matrix
.write();                                     // Вывод на дисплей     
[center]i love you [s]mxIni[/s] Mysql[/center]

didm
Аватара
didm

SamPawno Часы на max7219 метеостанция V1 - Программирование - SamPawno

#5 didm » 5 февраля 2022, 13:15

А как сделать не 10 а 1 минуту бегущей строки?

Arduino
Сержант
Сержант
Аватара
Arduino
Сержант
Сержант
Сообщения: 64
Зарегистрирован: 19 апреля 2017
С нами: 6 лет 11 месяцев

#6 Arduino » 5 февраля 2022, 13:45

Измени в коде Через 10 минут/600000 мили/сек на нужное тебе время

valera1950
Аватара
valera1950
Сообщения: 3
Зарегистрирован: 30 ноября 2021
С нами: 2 года 4 месяца

#7 valera1950 » 14 марта 2024, 16:46

Сделал попытку вставить код, чтобы убрать " лишний ноль' все скомпилировалось, но убираются не только незначащие нули, но и значащие цифры, те десятки часов не высвечиваются ни при каком раскладе . Может кто пробывал вставить этот код в программу? У меня все сделано по рекомендации автора
этой вставки. Опыт работы с Ардуино у меня незначительный.

Код: Выделить всё

 if(time.Hours == || time.Hours == || time.Hours == || time.Hours == || time.Hours == || time.Hours == || time.Hours == || time.Hours == || 
  
time.Hours == 9){                                                                                                         //если время 01 или 02 ... 09 часов то первый ноль не показываем
  
matrix.drawChar(xhyclocks[0], LOWLOW1); //   то первый ноль не показываем
  

valera1950
Аватара
valera1950
Сообщения: 3
Зарегистрирован: 30 ноября 2021
С нами: 2 года 4 месяца

#8 valera1950 » 17 марта 2024, 17:59

Повторил попытку вставить код, чтобы убрать " лишний ноль' , но уже с оператором If...else,теперь все заработало

Код: Выделить всё

 if(time.Hours == || time.Hours == || time.Hours == || time.Hours == || time.Hours == || time.Hours == || time.Hours == || time.Hours == || time.Hours == 9)
 {                                                                                
//если время 01 или 02 ... 09 часов то первый ноль не показываем
    
matrix.drawChar(xhyclocks[0],LOW LOW1); //   то первый ноль не показываем
 

 else
 {
  
matrix.drawChar(xhyclocks[0], HIGHLOW1);
 } 

valera1950
Аватара
valera1950
Сообщения: 3
Зарегистрирован: 30 ноября 2021
С нами: 2 года 4 месяца

#9 valera1950 » 6 апреля 2024, 12:58

Еще одно предложение по вставке кода убрать " лишний ноль". Сначала не обратил внимание, а потм ночью посмотрел время то понял, в строку

Код: Выделить всё

if( time.Hours == 1 || time.Hours == 2 || time.Hours == 3 || time.Hours == 4 || time.Hours == 5 || time.Hours == 6 || time.Hours == 7 || time.Hours == 8 ||  time.Hours == 9

  Нужно добавить (time.Hours == 0...), т.к при времени 0 часов,чтобы  незначащий 0 десятки часов не высвечивался. Код получиться такой:

Код: Выделить всё

if(time.Hours ==|| time.Hours == 1 || time.Hours == 2 || time.Hours == 3 || time.Hours == 4 || time.Hours == 5 || time.Hours == 6 || time.Hours == 7 || time.Hours == 8 || time.Hours == 9)     //если время 00 или 01 ... 09 часов 
 {                                                                                
    matrix
.drawChar(xh, y, clocks[0],LOW , LOW, 1); //   то первый ноль не показываем
 } 
 else
 
{
  matrix.drawChar(xh, y, clocks[0], HIGH, LOW, 1);
 }

Тема поднималась пользователем Дим 6 апреля 2024, 12:58.


  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Программирование»

Кто сейчас на форуме (по активности за 5 минут)

Сейчас этот раздел просматривают: 3 гостя