Блок с датойБлок с временемБлок с возрастом сайта
Mr.ALB

    Анатолий Беляев (aka Mr.ALB). Персональный сайт

    Да пребудут с вами Силы СВЕТА!

     

    Ардуино (Arduino). #5

    Барометр на BMP280, BME280

    Продолжаю модернизацию скетча, размещённого на предыдущей странице #4 Тестируем BMP280. Подключаем графический экран Nokia 5110, на который будем выводить информацию о давлении, температуре и высоте.

    В процессе разработки и тестирования базовой программы, добавил пришедший из Китая датчик влажности DHT22. А из-за выявленной капризности дисплея Nokia5110, далее переделал программу для вывода информации на малюсенький дисплейчик типа OLED SSD1306 с разрешением 128*64. Мой вариант – как вывести полную информацию на русском языке улыбка.

    На странице ниже переделка программы для вывода информации на дисплей типа TFT ST7735 1.8 дюйма с разрешением 128*160 точек.

    Пришла посылка с датчиком BME280. Он позволяет измерять давление, высоту, температуру и влажность одновременно. В конце странице барометр на этом датчике.


    Варианты

     


    Использование дисплея Nokia 5110

    Для вывода большего количества информации удобно использовать графический дисплей.

    Графический экран Nokia 5110 имеет размеры 84 х 84 пикселя (точки). Размер самой платы экрана 43 х 45 мм. Подключение осуществляется через 8 контактов внизу экрана.

    Дисплей Nokia5110
    Pic 1. Дисплей Nokia5110

    Напряжение питания Nokia 5110 составляет 3.3В, как и у модуля BMP280.

    Для вывода информации на экран, используются библиотеки <Adafruit_GFX.h> и <Adafruit_PCD8544.h>.

    Все соединения модуля и экрана с Arduino указаны на схеме. Контакты Arduino можно использовать не обязательно такие как у меня, а любые свободные, при условии соответствующего изменения в скетче, однако, указанные контакты используют аппаратное подключение по SPI, что работает быстрее, чем программное подключение на других контактах.

    Схема для скетча #5
    Pic 2. Схема для скетча #5

    На монтажную панельку добавляем ещё одну кнопку SB2, с помощью которой будем управлять яркостью подсветки экрана.

    Реализация скетча #5
    Pic 3. Реализация скетча #5

    Вывод информации на экране осуществляется в три строки...

    Работа дисплея Nokia5110
    Pic 4. Работа дисплея Nokia5110

    Четвёртая строка внизу используется для вывода шага подсветки. Шаг подсветки равен 10%. После 100% яркости подсветки, нажатие кнопки SB2 переводит в отключение подсветки, т.е. яркость равна 0%. Изменение градации подсветки циклическое.

    Работа подсветки дисплея Nokia5110
    Pic 5. Работа подсветки дисплея Nokia5110

    После всех подключений модулей к плате Arduino, переходим к скетчу (программе).

    Скетч барометра на модуле BMP280 и
    экране Nokia 5110

    Особо трудных моментов при подключении дисплея нет. Используя библиотеки, делаем соответствующую настройку.

    Ниже скетч барометра, который можно скопировать и вставить в свой Arduino IDE, надеюсь все запятые на месте улыбка:

    /***************************************************************
     * 2018-05-24 Mr.ALB Тренировка в программировании Ардуино
     * 
     * Arduino  - BMP280 
     *  A5      - SCL
     *  A4      - SDA
     *  3.3V    - VCC
     *  GND     - GND
     *
      * Аппаратное подключение LCD
     * ARDUINO  - Nokia 5110 LCD 
     * PIN 10   - RST  Pin 1 
     * PIN 9    - CE   Pin 2  
     * PIN 8    - DC   Pin 3 
     * PIN 11   - DIN  Pin 4
     * PIN 13   - CLK  Pin 5
     * PIN 3.3V - VCC  Pin 6 
     * PIN 3    - BL   Pin 7
     * PIN GND  - GND  Pin 8
     *
     * 2018-05-26 v1.0 Вывод информации на Монитор порта
     * 2018-06-03 v1.1 Вывод информации на дисплей Nokia 5110
     * 2018-08-11 v1.2 Модернизация коррекции температуры
     * 2018-10-07 v1.3 Обновление по времени
     * 
    ***************************************************************/
    
    /* Подключение библиотек */
    #include <Wire.h>            // для I2C
    #include <Adafruit_BMP280.h> // для BMP280
    #include <Adafruit_GFX.h>    // для графики
    #include <Adafruit_PCD8544.h>// для Nokia 5110
    #include <Button.h>          // для кнопок
    
    // Создаём объект барометра
    Adafruit_BMP280 bme;
    
    // Создаём объект дисплея
    // Adafruit_PCD8544(int8_t CLK, int8_t DIN, int8_t DC, int8_t RST);
    Adafruit_PCD8544 lcdDisplay = Adafruit_PCD8544(13, 11, 8, 9, 10);
    
    #define BUTTON_SET_LEVEL 5 // Кнопка обнуления текущего давления
    #define BUTTON_LIGHT 4     // Кнопка подсветки дисплея
    #define LIGHT_PIN 3        // Вывод PWM для подсветки дисплея
    
    // Создание объектов для кнопкок
    Button buttonSetLevel(BUTTON_SET_LEVEL,18);
    Button buttonLight(BUTTON_LIGHT,18);
    
    /***************************************************************
     * мБар       - мм рт. ст.
     * 1013.2472  - 760 k=1.33322
     * 1005.24788 - 754
     * 
    ***************************************************************/
    
    // Нулевой уровень для давления 1005.24788 мБар => 754 мм рт.ст.
    double null_level = 1005.24788;
    
    // Коэффициент для перевода Па в мм рт.ст.
    double kp = 133.322;
    double press_now, press_last, press_tmp, altit;// Переменные давления
    double temp, temp_last;     // Переменные температуры
    double temp_correct = -2.94;// Коррекция температуры
    byte  xinf = 36;            // Позиция вывода значений
    
    int   level_light = 0;      // Уровень подсветки
    byte  count_level_light = 0;// Счётчик шагов подсветки
    
    unsigned long time_now, time_check;
    unsigned long time_delta = 27000;// Для обновления по времени
    boolean flagcheck = false;// Флаг для обновления по времени
    
    char vers[] = "v1.3";           // Версия программы
    char vers_date[] = "2018-10-07";// Дата создания
    
    /***************************************************************
     * Настроечная функция, выполняется один раз вначале
    ***************************************************************/
    void setup()
    {
     pinMode(LIGHT_PIN, OUTPUT);
    
    /* Установки дисплея */
     lcdDisplay.begin();        // Старт дисплея
    // Установить контраст фона экрана
    // Очень важный параметр!
     lcdDisplay.setContrast(45);// Установить от 40 до 60
     lcdDisplay.clearDisplay(); // Очистить экран
    
    /* Заставка на экране */
     lcdDisplay.setTextSize(2);// Крупный шрифт
     lcdDisplay.setTextColor(BLACK);
     lcdDisplay.setCursor(8,0);// (0,0)=> лево-верх
     lcdDisplay.print("BMP280");
     lcdDisplay.setTextSize(1);// Обычный шрифт
     lcdDisplay.setCursor(24,20);
     lcdDisplay.println("Mr.ALB");
     lcdDisplay.setCursor(30,28);
     lcdDisplay.println(vers);
     lcdDisplay.setCursor(12,36);
     lcdDisplay.print(vers_date);
     lcdDisplay.display();     // Вывод на экран
     delay(2000);              // Задержка на 2 сек
     lcdDisplay.clearDisplay();// Очистка экрана
    
     Serial.begin(9600);
     if(!bme.begin())
     {
       Serial.println("Не найден датчик BMP280, проверьте соединение!");
       lcdDisplay.setCursor(0,0);
       lcdDisplay.println("Not find...");
       lcdDisplay.println("BMP280 sensor!");
       lcdDisplay.println("Check contacts");
       lcdDisplay.println();
       lcdDisplay.println("Click Reset");
       lcdDisplay.display();
       while(1);// Остановка программы
     }
    }
    
    /***************************************************************
     * Функция loop() выполняется постоянно
    ***************************************************************/
    void loop()
    {
      time_now = millis();
      if(time_now - time_check > time_delta)// Проверка интервала времени
      {
        time_check = time_now;
        flagcheck = true;// Флаг на обновление
      }
    
      buttonSetLevel.scanState();// Считывание состояния кнопки SB1
      buttonLight.scanState();   // Считывание состояния кнопки SB2
    
     /* Было нажатие кнопки SB2 - подсветка экрана */
     if(buttonLight.flagClick == true)
     {
       buttonLight.flagClick = false;// Сброс признака клика
       count_level_light++;// Шаг яркости
       if(count_level_light > 10)
        {
          // Выключаем подсветку
          count_level_light=0;
          level_light=0;
          lcdDisplay.fillRect(0, 40, 83, 5,WHITE);
        }
       else
        {
          level_light = count_level_light*25;
          if(level_light == 250) level_light = 255;// Максимальная яркость
        }
    
       analogWrite(LIGHT_PIN, level_light); // Установка яркости
    
       /* 2018-10-07 Прогресс бар яркости подсветки */
       byte bar_step = 0;
       for(byte ip = 0; ip < count_level_light; ip++)
       {
          lcdDisplay.fillRect(bar_step+1, 40, 7, 5, BLACK);
          bar_step += 8;
       }
       lcdDisplay.display();// Выводим на дисплей
     }
    
     press_now = bme.readPressure()/kp;   // Считывание давления
     temp = bme.readTemperature();        // Считывание температуры
     if(temp_correct!=0) temp+=temp_correct;// Коррекция t° 2018-08-11
    
    /***************************************************************
     * Если давление изменилось больше чем на 0,2 мм рт.ст.
     * или нажата кнопка обнуления высоты...
     * или температура изменилась больше чем на 0,1°С
     ***************************************************************/
     if((press_now<(press_last-.2))||
         (press_now>(press_last+.2))||
         (temp<(temp_last-.1))||(temp>(temp_last+.1))||
          buttonSetLevel.flagClick == true||
          flagcheck == true
        )
     {
       flagcheck=false;// Сброс флага проверки по времени
    
       if(buttonSetLevel.flagClick == true)// Было нажатие кнопки SB1
       {
         buttonSetLevel.flagClick = false;// Сброс признака клика
        // Обнуляем значение высоты при текущем давлении
         null_level=press_now*kp/100;// В мБарах
       }
    
       altit = bme.readAltitude(null_level);// Считывание высоты
       Serial.print("Температура = ");
       Serial.print(temp);// Вывод скорректированной температуры
       Serial.println("°C");
    
       Serial.print("Давление = ");
       Serial.print(press_now);// В мм рт.ст.
       Serial.print(" мм рт.ст., ");
       Serial.print(press_now*kp/100);// Перевод Па в мБар
       Serial.println(" мБар");
    
       Serial.print("Приблизительная высота = ");
       Serial.print(altit);
       Serial.println(" м");
       Serial.println();
    
       /* Вывод на LCD */
       lcdDisplay.clearDisplay();// Очистить экран
    
       // Устанавливаем на дисплей температуру
       lcdDisplay.setCursor(0,0);
       lcdDisplay.print("Temp:");
       lcdDisplay.setCursor(xinf,0);
       if(temp > 0) lcdDisplay.print("+");
       lcdDisplay.print(temp);
       lcdDisplay.print("oC");
    
       // Устанавливаем на дисплей давление в мм рт.ст.
       lcdDisplay.setCursor(0,14);
       lcdDisplay.print("Press:");
       lcdDisplay.setCursor(xinf,14);
       lcdDisplay.print(press_now);
       lcdDisplay.print("mm");
    
       // Устанавливаем на дисплей высоту в м
       lcdDisplay.setCursor(0,26);
       lcdDisplay.print("Alt:");
       lcdDisplay.setCursor(xinf,26);
       lcdDisplay.print(altit);
       lcdDisplay.print(" m");
    
       // Вывод на дисплей новой информации
       lcdDisplay.display();
    
       /* Перезаписываем бывшие значения */
       press_last = press_now;
       temp_last = temp;
       delay(50);
     }
    }// Конец loop()
    

    Теперь в моей программе значение выводится ещё и на дисплей, и если оформить всю конструкцию в корпус с автономным питанием (батарея или аккумулятор), то будет небольшой электронный барометр-высотомер.

    Если необходимо уменьшить код, то вывод информации в последовательный порт можно удалить и оставить лишь вывод на дисплей.

    Для модернизации этого скетча можно предложить создать барограф, то есть на графический экран выводить кроме цифрового значения ещё и график изменения давления, к примеру, через час. По резкости изменения давления можно уже судить об изменении погоды. Ещё можно добавить свои пиктограммки: облако, солнышко, дождь, ветер и т.п.

    Возможно сделаю такую модернизацию программы и ниже на странице её размещу, если будет интерес продолжить это направление.

    Код закоментирован достаточно подробно и понятно.

    2018-06-10


    P.S. Попользовался таким дисплеем и обратил внимание, что он какой-то капризный. Всё время у него гуляет контакт на индикатор. Всё время плавает контрастность от совсем невидимого до чёрного даже фона. Может быть это мне такой попался экземпляр.

    P.P.S. Программу изменил и дополнил. Теперь у меня добавлен датчик влажности DHT22. На дисплей выводится температура и значение влажности и с него. А яркость подсветки дисплея выводится на чистый экран с дополнительным прогресс баром.

    Скетч можно скачать тут: sketch__5.zip

    Скетч обновлённой программы с датчиком влажности DHT22 тут: bmp280_nokia5110_dht22.zip

    Для проверки работоспособности вашего дисплея используйте этот скетч:

    Nokia_5110_test.zip

    Используемые библиотеки:

    Adafruit_BMP280_Library.zip
    Adafruit_PCD8544_Nokia_5110_LCD_library.zip
    Adafruit_GFX_Library_master.zip
    Button.zip

    2018-07-23
    2018-08-16

     


    Использование дисплея OLED SSD1306

    Из-за капризности дисплея Nokia5110, переделал программу для вывода информации на малюсенький графический дисплейчик типа OLED SSD1306 с разрешением 128*64 точки.


    Использование дисплея OLED SSD1306
    Pic 6. Использование дисплея OLED SSD1306

    При использовании библиотеки <iarduino_OLED_txt.h> можно установить шрифт SmallFontRus, который выводит на экран символы 6*8 пикселей, что позволяет вывести на экран 8 строк информации. Мелковато, конечно, лучше бы использовать, больший дисплей, что позволит вывести символы с разрешением 12*16 пикселей. При использовании OLED дисплея есть приятное преимущество – нет необходимости использования подсветки, в итоге используется лишь одна кнопка для обнуления высоты.

    Скетч обновлённой программы тут: OLED_128_32_bmp280.zip

    Используемая библиотека: iarduino_OLED_txt.zip

    2018-08-22

     


    Использование дисплея TFT ST7735 128*160 1.8 дюйма

    Это уже более качественный графический диспей. Позволяет выводить любые изображения в цвете.

    Получил посылку из Китая с новым цветным TFT ЖК-дисплеем. Контроллер обработки дисплея ST7735. Разрешение 128*160 точек размером 1.8 дюйма.

    Ниже представлена схема соединений. Контакты Ардуино выбраны для использования аппаратного подключения дисплея для быстроты обновления экрана.

    Схема для скетча #5 v3.2
    Pic 7. Схема для скетча #5 v3.2

    Предыдущий дисплейчик слишком маленький, а этот в самый раз, причём оказалось, что довольно недорогой для его размера и качества. При использовании библиотеки <Adafruit_ST7735.h> можно устанавливать шрифты разных размеров и использовать любые из 65 тысяч цветов в формате RGB565 – красный и синий по 5 бит, а зелёный 6 бит. Недостаток этой библиотеки – отсутствие русского шрифта.

    В скетче использую разный цвет при выводе значения влажности. До 30% – красный, от 30% до 60% – жёлтый, от 60% до 75% – зелёный, свыше 75% – синий. Так визуально легко ориентироваться на диапазон влажности.


    Использование дисплея TFT ST7735 128*160
    Pic 8. Использование дисплея TFT ST7735 128*160
    Использование дисплея TFT ST7735 128*160
    Pic 9. Использование дисплея TFT ST7735 128*160

    При использовании этого дисплея вернул кнопку подсветки, как с дисплеем Nikia5110. Этой кнопкой можно регулировать подсветку ЖК-дисплея, подавая ШИМ на вывод BL. По умолчанию поставил на 10% – для экономии энергии. При нажатии на кнопку прибавляется 10% яркости, после почти 100%(реальная 98%) яркость выключается (0%) и т.д. по кругу.

    Режим регулировки подсветки экрана
    Pic 10. Режим регулировки подсветки экрана

    Скетч обновлённой программы тут: TFT_128_160_bmp280.zip

    2018-09-04

    Модернизировал скетч под мобильный вариант. Теперь можно собрать конструкцию и получится карманный барометр-погодная станция. Через порт А0 (контакт 14) происходит измерение напряжения питания Li-Ion +3.7В батареи и выводится значение на экран в виде цифрового значения и пиктограммки. Li-Ion батарея питает DC-DC преобразователь выдающий +5В, которым запитывается Arduino с дисплеем и модулями. Скетч обновлённой программы тут: TFT_128_160_bmp280_v3.1.zip

    2018-09-06

    Ещё одна модернизация. Заметил, что не совсем хорошо, когда обновляются все надписи на экране, поэтому в новой версии обновляются только изменяющиеся значения. Дополнительно основные блоки выделены в функции. Ещё, если Arduino подключено к компьютеру, то значение напряжения питания батареи и её пиктограмка не выводятся. Скетч обновлённой программы тут: TFT_128_160_bmp280_v3.2.zip

     

    Барометр на Arduino Pro Mini и датчиках BMP280 и DHT22

    Схема этого варианта создана на базе Arduino Pro Mini, она включает в себя стабилизатор на +3.3В, подробнее про который можно посмотреть на странице Ардуино (Arduino). #7. В остальном схема подобна предыдущей.

    Схема для скетча #5 v3.3 на Arduino Pro Mini
    Pic 11. Схема для скетча #5 v3.3 на Arduino Pro Mini
    Вариант на Arduino Pro Mini
    Pic 12. Вариант на Arduino Pro Mini
    Вариант на Arduino Pro Mini
    Pic 13. Вариант на Arduino Pro Mini

    На фото видно использование самодельного модуля стабилизатора на 3.3В, для питания модуля барометра BMP280.


    Так дело пойдёт, то ещё немного и оформлю всю конструкцию в корпус как законченное устройство, пока же идёт тестирование работоспособности и удобства эксплуатации улыбка... если дело дойдёт до корпуса, то обязательно опубликую законченную конструкцию.

    2018-09-08

    Используемая библиотека: Adafruit_ST7735.zip

     

    Барометр на Arduino Pro Mini и датчике BME280

    Некоторые читатели просили сделать вариант на датчике BME280. Поэтому купил на Алиэкспрессе такой датчик и построил новый вариант барометра.

    Схема этого варианта создана на основе предыдущего. Вместо датчиков BMP280 и DHT22 применён датчик BME280, который позволяет измерять одновременно давление, высоту, температуру и влажность, что очень удобно для создания карманного варианта барометра.

    Для правильного управления цветом дисплеев TFT на контроллере ST7735, был создан вычислитель соответствия цветов кодировок RGB888 и RGB565 (Ардуино (Arduino). #9. Вычислитель RGB888 и RGB565), чем и воспользовался при программировании в этом варианте.

    Этот барометр построен, как и предыдущий, на Ардуино Про Мини, но можно использовать любую другую плату, без особой переделки схемы.

    У моего BME280 напряжение питания от 1.8 В до 5 В, поэтому отпадает необходимость в стабилизаторе на +3.3 В. Схема упрощается.

    Ниже на фото видны компоненты барометра: Адруино Про Мини, BME280, DC-DC преобразователь на +5 В, аккумулятор от сотового телефона Li-Ion +3.7 В, две кнопки.


    Вариант на Arduino Pro Mini и датчике BME280
    Pic 14. Вариант на Arduino Pro Mini и датчике BME280
    Вариант на Arduino Pro Mini и датчике BME280
    Pic 15. Вариант на Arduino Pro Mini и датчике BME280

    Ниже публикую скетч, его можно скопировать в ARDUINO IDE, но можно использовать уже готовый файл TFT_128x160_BME280.ino, см. ниже скетча.

    /******************************************************************
    * 2018-05-27 Mr.ALB Тренировка в программировании Ардуино
    * 
    * BMP280 I2C:
    * SCL - A5
    * SDA - A4
    * VCC - +3.3V
    * GND - GND
    *
    * 2018-07-17 v1.2 Добавлен датчик влажности DHT22: 
    * между контактом OUT и VCC подключить 10к
    * 
    * 2018-08-24 v3.0 Подключение дисплея TFT ST7735 128*160 1,8 дюйма   
    * 2018-09-05 v3.1 Автономная работа от батареии Li-Ion +3.7В 
    * 2018-09-08 v3.2 Перерисовка только меняющихся значений 
    * 2018-11-02 v3.2.1 Минимальная яркость = 1 
    * 2018-11-11 v3.2.2 Прогрессбар подсветки на главной странице
    * 
    * 2019-05-09 v3.3 Использование модуля BME280
    * BME280 I2C:
    * SCL - A5
    * SDA - A4
    * VCC - +5V
    * GND - GND
    * 
    * Аппаратное подключение TFT:
    * TFT ST7735        ARDUINO
    * Pin 1 RST -[R 1k]- PIN 10
    * Pin 2 CS  -[R 1k]- PIN 9
    * Pin 3 DC  -[R 1k]- PIN 8 
    * Pin 4 DIN -[R 1k]- PIN 11
    * Pin 5 CLK -[R 1k]- PIN 13
    * Pin 6 VCC -        PIN VCC +5V
    * Pin 7 BL  -        PIN 3 - для регулировки подсветки (ШИМ)
    * Pin 8 GND -        PIN GND
    * 
    * Контакты TFT 1-5 подключать через резисторы 1к...2к
    * 
    ******************************************************************/
    #include <Wire.h>             // Подключение библиотеки для I2C
    
    /* Графический дисплей TFT ST7735 1.8" */
    #include <Adafruit_GFX.h>     // Ядро графической библиотеки
    #include <Adafruit_ST7735.h>  // Библиотека для ST7735
    
    #define TFT_RST 10
    #define TFT_CS  9
    #define TFT_DC  8
    
    // Аппаратное подключение TFT 
    // Создаём объект tft
    Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
    
    #include <Adafruit_BME280.h>  // Подключение библиотеки BME280
    /* Чтобы всё заработало необходимо:
     *  1. Сканером I2C найти адрес BME280 и указать при инициализации
     *    или
     *  2. В библиотеке <Adafruit_BME280.h>:
     *      1) Изменить адрес #define BME280_ADDRESS (0x77)
     *          на адрес      #define BME280_ADDRESS (0x76)
     *      2) Закоментировать библиотеку #include <Adafruit_Sensor.h>
     */
    
    // Создаём объект барометра
    Adafruit_BME280 bme;
    /* мБар       - мм рт. ст.
     * 1013.2472  - 760 k=1.33322
     * 1005.24788 - 754
     */
     
    double null_level = 1005.24788; // Нулевой уровень для 754 мм рт.ст.
    float kp = 133.322;       // Коэффициент для перевода Па в мм рт.ст.
    
    // переменные давления
    float press_now, press_last, press_tmp, altit;
     
    // переменные температуры
    float temp, temp_last, temp_correct = -1;
    
    // переменные влажности 
    float humidity_now, humidity_last, humidity_correct = 0;
    
    #include <Button_2.h>      // Подключение библиотеки кнопок
    #define BUTTON_SET_LEVEL 6 // Кнопка обнуления текущего давления
    #define BUTTON_LIGHT 5     // Кнопка подсветки дисплея
    
    #define LIGHT_PIN 3   // Вывод PWM для подсветки дисплея
    #define VCC_PIN   A0  // Ввод VCC батареи питания, через резистор 1к
    
    // Создание объектов для кнопок
    Button_2 buttonSetLevel(BUTTON_SET_LEVEL,21);
    Button_2 buttonLight(BUTTON_LIGHT,21);
    
    uint8_t bxlz = 2 * 6;    // Позиция заставки
    uint8_t byinfo = 27;     // Позиция вывода информации по y
    uint8_t bxinfo = 10 * 6; // Позиция вывода информации по х
    
    // Уровень подсветки 0...10;
    uint8_t count_level_light = 1;
    // Значение подсветки 0...250;
    int level_light = count_level_light * 25;
    
    // Для обновления экрана по времени
    boolean flagcheck = false;
    // Для вывода надписей после установки яркости
    boolean flagSetLight = true;
    // Строка прогресс-бара подсветки
    uint8_t light_str = 15;
    
    // Для обновления экрана по времени
    unsigned long time_now, time_check, time_delta = 27000;
    
    char prog_title1[] = "BME280";    // Название программы
    char author[] = "Mr.ALB";         // Автор
    char vers[] = "v3.3";             // Версия программы
    char vers_date[] = "2019-05-09";  // Дата версии
    
    #define SCREEN_W 160              // Ширина экрана в рх
    #define SCREEN_H 128              // Высота экрана в рх
    uint8_t font_size = 1;            // Размер шрифта
    
    /***********************/
    /* Настройка программы */
    /***********************/
    void setup()
    {
      pinMode(LIGHT_PIN,OUTPUT);// Порт управления подсветкой экрана
      pinMode(VCC_PIN,INPUT);   // Порт для измерения батареи питания
      analogReference(DEFAULT); // Опорный источник - внутренний
    
      // Инициируем работу с дисплеем 1.8" TFT
      tft.initR(INITR_BLACKTAB);// initialize a ST7735S chip, black tab
      fnClrScreen();            // Очистить экран
      tft.setRotation(1);       // Поворот экрана: 
                                // 0 - 0°   книжный
                                // 1 - 90°  альбомный
                                // 2 - 180° книжный
                                // 3 - 270° альбомный
                                
      analogWrite(LIGHT_PIN,level_light);  // Установка яркости
    
      if(!bme.begin()) // Старт датчика давления
      {
          //Если ошибка запуска
          tft.setTextColor(ST7735_RED);
          
          tft.setTextSize(2);
          fnCenter(sizeof("Error!"),2,1,0);
          tft.print("Error!");
           
          tft.setTextSize(1);
          fnCenter(sizeof("Not find BME280 sensor!"),1,7,0);
          tft.print("Not find BME280 sensor!");
          fnCenter(sizeof("Check contacts"),1,9,4);
          tft.print("Check contacts");
    
          fnCenter(sizeof("Click Reset"),1,14,0);
          tft.setTextColor(ST7735_YELLOW);
          tft.print("Click Reset");
          while(1);
      }
      fnZastavka();   // Заставка
      fnPrintText();  // Вывод основного текста на экран
    }
    
    /***********************/
    /*  Рабочая программа  */
    /***********************/
    void loop()
    { 
      time_now=millis();         // Текущее время работы программы в мс
     
      // Проверка интервала времени
      if(time_now - time_check > time_delta)
      {
        time_check = time_now;
        flagcheck = true;
      }
      
      buttonSetLevel.scanState();// Считывание состояния кнопки уровня
      buttonLight.scanState(); // Считывание состояния кнопки подсветки
      
      if(buttonLight.flagClick == true) // Было нажатие кнопки подсветки
      {
        buttonLight.flagClick = false;  // Сброс признака клика
        count_level_light++;            // Шаг яркости
        if(count_level_light > 10)
        {
          count_level_light = 0;        // Выключаем подсветку
          level_light = 3;              // Минимальная яркость
          tft.fillRect(0, light_str * 8 + 2, 160, 3, ST7735_BLACK);
        }
        else
        {
          level_light=count_level_light * 25;
        }
        analogWrite(LIGHT_PIN,level_light); // Установка яркости
    
        /* Прогресс бар яркости подсветки */
        uint8_t bar_step = 0;
        uint8_t bar_step_const = 8 * 2;
        tft.setTextSize(1);
        for(uint8_t ip = 0; ip < count_level_light; ip++)
        {
          tft.fillRect
          (
            1 + bar_step,
            light_str * 8 + 2,
            bar_step_const - 2,
            3,
            ST7735_WHITE
          );
          bar_step += bar_step_const;
        } 
        flagSetLight = true;
      }
    
      // Измерение параметров
      press_now = bme.readPressure()/kp;  // Давление в мм рт. ст.
      temp = bme.readTemperature();       // Температура в °С
      humidity_now = bme.readHumidity();  // Влажность в %
      
      //Применение коррекции влажности
      if(humidity_correct != 0) humidity_now += humidity_correct; 
      
      //Применение коррекции температуры
      if(temp_correct != 0) temp += temp_correct;
    
      /* 
       * Если давление изменилось больше чем на 0,2 мм рт.ст.,
       * то выводим на дисплей...
       * или нажата кнопка обнуления высоты...
       * или температура изменилась больше чем на 0,1°С
      */
     if(
        (press_now < (press_last - .2)) ||
        (press_now > (press_last + .2)) ||
        (temp < (temp_last - .1)) || (temp > (temp_last + .1)) ||
        buttonSetLevel.flagClick == true ||
        flagcheck == true
       )    
      {
        flagcheck = false;  // Сброс флага проверки по времени
        
        if(flagSetLight)  // Если была настройка яркости
        {
          tft.fillRect(0, light_str * 8 + 2, 160, 3, ST7735_BLACK);
          flagSetLight=false;
        }
     
        // Было нажатие кнопки "Set Level 0 m"
        if(buttonSetLevel.flagClick == true)
        {
          buttonSetLevel.flagClick = false; // Сброс признака клика
          null_level=press_now * kp/100;    // Обнуляем значение высоты
        }
    
        altit = bme.readAltitude(null_level); // Высота в метрах
        
        tft.setTextColor(ST7735_YELLOW);
    
        // Вывод значения давления
        tft.fillRect(bxinfo, byinfo - 2, 6 * 12, 16, ST7735_BLACK);
        tft.setTextSize(2);
        tft.setCursor(10 * 6, byinfo - 2);
        tft.print(press_now);
    
        tft.setTextSize(1);
        
        // Вывод высоты
        tft.setTextColor(ST7735_WHITE);
        tft.fillRect(bxinfo, byinfo + 20, 6 * 7, 8, ST7735_BLACK);
        tft.setCursor(bxinfo, byinfo + 20);
        tft.print(altit);
        
        // Вывод значения температуры
        tft.setTextColor(ST7735_ORANGE);
        tft.fillRect(bxinfo, byinfo + 36, 6 * 6, 8, ST7735_BLACK);
        tft.setCursor(bxinfo, byinfo + 36);
        if(temp > 0) tft.print("+");
        tft.print(temp);
    
        /* Вывод влажности */
        /* Раскрашиваем значение в зависимости от % влажности */
        if(humidity_now < 30.0)                           // Сушь
            tft.setTextColor(ST7735_RED);
        if(humidity_now >= 30.0 &&  humidity_now < 60.0)  // Сухо
            tft.setTextColor(ST7735_YELLOW);
        if(humidity_now >= 60.0 &&  humidity_now < 75.0)  // Влажно
            tft.setTextColor(ST7735_GREEN);
        if(humidity_now >= 75.0)                          // Сыро
            tft.setTextColor(ST7735_BLUE);
     
        //Очистка места под значение
        tft.setTextColor(ST7735_BLUE);
        tft.fillRect(bxinfo, byinfo + 56, 6 * 12, 16, ST7735_BLACK);
        tft.setTextSize(2);
        tft.setCursor(bxinfo, byinfo + 56);
        tft.print(humidity_now);
    
        // Проверка напряжения питания
        int v = analogRead(VCC_PIN);
        float vcc = v * 5.0 / 1024; // Перевод бит в вольты
        
        // Вывод значения напряжения питания батареи
        if(vcc > 2.5) // Выводим, если запитываемся от батареи
        {
          uint8_t x_vcc = 20 * 6 + 3, y_vcc = 14;
          tft.fillRect(x_vcc, y_vcc, 6 * 6, 8, ST7735_BLACK);
          tft.setCursor(x_vcc, y_vcc);
          tft.setTextSize(1);
          if(vcc < 3.7)  tft.setTextColor(ST7735_YELLOW);
          if(vcc < 3.3)  tft.setTextColor(ST7735_RED);
          if(vcc >= 3.7) tft.setTextColor(ST7735_GREEN);
          tft.print("+");
          tft.print(vcc);
          tft.print("V");
          fnBattary(23 * 6, 3, vcc);//Вывод пиктограммки
        }
    
        // Перезаписываем бывшие значения
        temp_last = temp;
        press_last = press_now;
        humidity_last = humidity_now;
        delay(30);
      }
    }
    
    /* Функция - Вывод °С */
    void fnChrDegree(int16_t x, int16_t y, uint16_t color)
    {
      uint8_t radius = 2;
      tft.drawCircle(x += radius*2, y += radius*2 - 1, radius, color);
      tft.setCursor(x + 3, y);
      tft.setTextColor(color);
      tft.print("C");
    }
    
    /* Функция символа батарейки */
    void fnBattary(int16_t x, int16_t y, float vcc)
    {
      int16_t w = 19, h = 8;
    
      tft.drawRect(x, y, w, h, ST7735_WHITE);     // Контур батарейки
      tft.fillRect(x + w, y + 2, 2, 4, ST7735_WHITE); // Пимпочка
      
      // Вывод квадратиков наполнения 
      if(vcc < 3.3) fnPrintFillRect(x,y,1,ST7735_RED);
      if(vcc >= 3.3 && vcc < 3.5) fnPrintFillRect(x,y,1,ST7735_YELLOW);
      if(vcc >= 3.5 && vcc < 3.7) fnPrintFillRect(x,y,2,ST7735_YELLOW);
      if(vcc >= 3.7 && vcc < 3.9) fnPrintFillRect(x,y,3,ST7735_GREEN);
      if(vcc >= 3.9) fnPrintFillRect(x, y, 4, ST7735_GREEN);
    }
    
    /* Функция вывода квадратиков для символа батарейки */
    void fnPrintFillRect
          (
            int16_t x,
            int16_t y,
            uint8_t max_i,
            int16_t color
          )
    {
      tft.fillRect(x + 1, y + 1, 17, 6, ST7735_BLACK);
      for(uint8_t i = 0; i < max_i; i++)
      {
        tft.fillRect(x + 2 + i * 4, y + 2, 3, 4, color);
      }  
    }
    
    /* Функция - Заставка */
    void fnZastavka()
    {
      fnClrScreen(); // Очистить экран
      tft.setTextWrap(false);
    
      tft.setTextColor(ST7735_ORANGE);
      
      font_size = 3;
      tft.setTextSize(font_size);
      fnCenter(sizeof(prog_title1) - 1, font_size, 1, 0);
      tft.print(prog_title1);
      
      font_size = 2;
      tft.setTextSize(font_size);
      fnCenter(sizeof(author) - 1, font_size, 4, 0);
      tft.setTextColor(ST7735_DARKGREEN);
      tft.print(author);
      
      font_size = 1;
      tft.setTextSize(font_size);
      fnCenter(sizeof(vers) - 1, font_size, 11, 0);
      
      tft.setTextColor(ST7735_GRAY);
      tft.println(vers);
      
      fnCenter(sizeof(vers_date) - 1, font_size, 12, 2);
      tft.println(vers_date);
      
      delay(3000);
      fnClrScreen();              // Очистить экран
    }
    
    /* Функция - Вывод основных надписей на экран */
    void fnPrintText()
    {
      fnClrScreen();              // Очистить экран
      tft.setTextSize(1);
      tft.setCursor(8, 3);
      tft.setTextColor(ST7735_GREEN);
      tft.print("BME280 ");
      tft.println(vers);
     
      tft.setTextColor(ST7735_LIGHTGRAY);
      
      /* Вывод давления */
      tft.setCursor(0, byinfo);//24
      tft.print("Pressure:");
      tft.setCursor(bxinfo + 6 * 12, byinfo);
      tft.setTextSize(1);
      tft.print(" mm");           // Вывод размерности давления
    
      /* Вывод высоты */
      tft.setCursor(0, byinfo + 20);
      tft.print("Altitude:");
      tft.setCursor(bxinfo + 6 * 8, byinfo + 20);
      tft.print("m");             // Вывод размерности высоты
          
      /* Вывод температуры */
      tft.setCursor(0, byinfo + 36);
      tft.print("Temper. :");
     // Вывод размерности температуры
      fnChrDegree(bxinfo + 6 * 7, 60, ST7735_LIGHTGRAY);
    
      /* Вывод влажности */
      tft.setCursor(0, byinfo + 56);
      tft.print("Humidity:");
      tft.setTextSize(1);     
      tft.setCursor(bxinfo + 6 * 12, byinfo + 56);
      tft.print("%");  // Вывод размерности влажности
      
      //Разделитель давления и влажности
      tft.drawFastHLine(0, byinfo + 50, 160, ST7735_DARKGRAY);
    }
    
    /* Функция - центрирование строки */
    void fnCenter
          (
            uint8_t lenght,
            uint8_t fntsize,
            uint8_t row,
            uint8_t offset
          )
    {
      tft.setCursor
         (
           (SCREEN_W - lenght * fntsize * 6)/2 + fntsize * 6/2,
           fntsize * 8 * row + offset
         );
    }
    
    /* Функция - Cтирание экрана чёрным цветом,
     * т.е. закрасить чёрным
     */
    void fnClrScreen()
    {
      tft.fillScreen(ST7735_BLACK);
      tft.setCursor(0, 0);          // Курсор в начало экрана
    }
    

    Используемые библиотеки (обновлены):

    Скетч тут: TFT_128x160_BME280.zip

    Думаю, что это не конец улыбка, ещё мне хочется сделать функцию барографа – выводить график изменения параметров во времени. Пока только желание, как будет благоприятное время, то буду делать. И ещё, конечно, все эти модули поместить бы в корпус, тут уже инженерно-конструкторская задача, всё просчитать и разработать. В принципе, можно делать и без функции барографа, программу всегда можно дописать и запрограммировать уже в готовой конструкции. Время покажет, как всё сложится.

    2019-05-10


    . Mr.ALB
    Предыдущая страница Страница 6 Далее