ESP32 с TM1637 4-разрядным 7-сегментным LED-дисплеем (Arduino IDE)

Это руководство по подключению 4-разрядного 7-сегментного LED-дисплея TM1637 к ESP32, программируемому в Arduino IDE. Вы узнаете, как подключить дисплей к ESP32 и как выводить на него символы. В качестве примера мы покажем, как создать цифровые часы и дисплей температуры.

ESP32 с TM1637 4-разрядным 7-сегментным LED-дисплеем Arduino IDE

В этом руководстве мы рассмотрим следующие темы:

Знакомство с TM1637 4-разрядным 7-сегментным LED-дисплеем

TM1637 4-разрядный 7-сегментный LED-дисплей — это модуль дисплея, который объединяет четыре 7-сегментных цифры на одном дисплее, управляемом через драйвер TM1637. Конкретный модуль, который мы используем здесь, имеет четыре цифры, разделённые двоеточием между второй и третьей цифрами.

TM1637 4-разрядный 7-сегментный дисплей

Существуют аналогичные модули с точками между цифрами.

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

Примечание: Я попытался использовать свой 6-разрядный модуль дисплея, но, похоже, многие из этих дисплеев поставляются с дефектами по умолчанию. Мне не удалось заставить свой работать. Поэтому это руководство будет только о модуле с четырьмя цифрами и двоеточием посередине.

Где купить?

Вы можете проверить нашу страницу Maker Advisor Tools, чтобы сравнить цены на модуль TM1637 4-разрядного 7-сегментного дисплея в разных магазинах:

Вы можете использовать ссылки выше или перейти непосредственно на MakerAdvisor.com/tools, чтобы найти все детали для ваших проектов по лучшей цене!

Подключение TM1637 4-разрядного 7-сегментного дисплея к ESP32

TM1637 Display Module Pins CLK DIO VCC GND

Подключение дисплея к ESP32 довольно просто, так как требуется всего два цифровых пина: CLK и DI/O.

TM1637 Display

ESP32

CLK

Любой цифровой пин (например: GPIO 19)*

DIO

Любой цифровой пин (например: GPIO 18)*

VCC

VIN

GND

GND

* вы можете использовать любые другие подходящие GPIO. Проверьте руководство по распиновке ESP32:

Мы подключим пин CLK к GPIO 19, а пин DIO к GPIO 18, но вы можете использовать другую комбинацию пинов.

TM1637 Display - Подключение к ESP32

Установка библиотеки TM1637

Существует несколько библиотек для работы с дисплеем TM1637 на ESP32. Мы будем использовать библиотеку TM1637.h от avishorp (хотя она не обновлялась несколько лет, она всё ещё хорошо работает и очень проста в использовании).

Вы можете установить библиотеку через менеджер библиотек Arduino IDE. Найдите TM1637 и установите библиотеку от avishorp.

Установка библиотеки TM1637 в Arduino IDE

Тестирование дисплея TM1637 (базовые функции)

Следующий код предоставляется библиотекой для тестирования дисплея. Вы определите, правильно ли работает ваш дисплей, и увидите, как реализовать базовые функции для инициализации, управления дисплеем и записи символов.

/*
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete project details at https://RandomNerdTutorials.com/esp32-tm1637-4-digit-7-segment-display-arduino/
  Based on the TM1637Display library example: https://github.com/avishorp/TM1637/blob/master/examples/TM1637Test/TM1637Test.ino
*/
#include <Arduino.h>
#include <TM1637Display.h>

// Module connection pins (Digital Pins)
#define CLK 19
#define DIO 18

// The amount of time (in milliseconds) between tests
#define TEST_DELAY   2000

const uint8_t SEG_DONE[] = {
     SEG_B | SEG_C | SEG_D | SEG_E | SEG_G,           // d
     SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F,   // O
     SEG_C | SEG_E | SEG_G,                           // n
     SEG_A | SEG_D | SEG_E | SEG_F | SEG_G            // E
     };

TM1637Display display(CLK, DIO);

void setup()
{
}

void loop()
{
  int k;
  uint8_t data[] = { 0xff, 0xff, 0xff, 0xff };
  uint8_t blank[] = { 0x00, 0x00, 0x00, 0x00 };
  display.setBrightness(0x0f);

  // All segments on
  display.setSegments(data);
  delay(TEST_DELAY);

  display.showNumberDecEx(1230, 0b01000000);
  delay(10000);

  // Selectively set different digits
  data[0] = display.encodeDigit(7);
  data[1] = display.encodeDigit(6);
  data[2] = display.encodeDigit(5);
  data[3] = display.encodeDigit(9);
  display.setSegments(data);
  delay(TEST_DELAY);

  /*
  for(k = 3; k >= 0; k--) {
     display.setSegments(data, 1, k);
     delay(TEST_DELAY);
     }
  */

  display.clear();
  display.setSegments(data+2, 2, 2);
  delay(TEST_DELAY);

  display.clear();
  display.setSegments(data+2, 2, 1);
  delay(TEST_DELAY);

  display.clear();
  display.setSegments(data+1, 3, 1);
  delay(TEST_DELAY);

  // Show decimal numbers with/without leading zeros
  display.showNumberDec(0, false); // Expect: ___0
  delay(TEST_DELAY);
  display.showNumberDec(0, true);  // Expect: 0000
  delay(TEST_DELAY);
     display.showNumberDec(1, false); // Expect: ___1
     delay(TEST_DELAY);
  display.showNumberDec(1, true);  // Expect: 0001
  delay(TEST_DELAY);
  display.showNumberDec(301, false); // Expect: _301
  delay(TEST_DELAY);
  display.showNumberDec(301, true); // Expect: 0301
  delay(TEST_DELAY);
  display.clear();
  display.showNumberDec(14, false, 2, 1); // Expect: _14_
  delay(TEST_DELAY);
  display.clear();
  display.showNumberDec(4, true, 2, 2);  // Expect: 04__
  delay(TEST_DELAY);
  display.showNumberDec(-1, false);  // Expect: __-1
  delay(TEST_DELAY);
  display.showNumberDec(-12);        // Expect: _-12
  delay(TEST_DELAY);
  display.showNumberDec(-999);       // Expect: -999
  delay(TEST_DELAY);
  display.clear();
  display.showNumberDec(-5, false, 3, 0); // Expect: _-5_
  delay(TEST_DELAY);
  display.showNumberHexEx(0xf1af);        // Expect: f1Af
  delay(TEST_DELAY);
  display.showNumberHexEx(0x2c);          // Expect: __2C
  delay(TEST_DELAY);
  display.showNumberHexEx(0xd1, 0, true); // Expect: 00d1
  delay(TEST_DELAY);
  display.clear();
  display.showNumberHexEx(0xd1, 0, true, 2); // Expect: d1__
  delay(TEST_DELAY);


     // Run through all the dots
     for(k=0; k <= 4; k++) {
             display.showNumberDecEx(0, (0x80 >> k), true);
             delay(TEST_DELAY);
     }

  // Brightness Test
  for(k = 0; k < 4; k++)
     data[k] = 0xff;
  for(k = 0; k < 7; k++) {
    display.setBrightness(k);
    display.setSegments(data);
    delay(TEST_DELAY);
  }

  // On/Off test
  for(k = 0; k < 4; k++) {
    display.setBrightness(7, false);  // Turn off
    display.setSegments(data);
    delay(TEST_DELAY);
    display.setBrightness(7, true); // Turn on
    display.setSegments(data);
    delay(TEST_DELAY);
  }

  // Done!
  display.setSegments(SEG_DONE);

  while(1);
}

Посмотреть исходный код

Давайте рассмотрим некоторые из важных функций, используемых в этом примере.

Инициализация дисплея

Для инициализации дисплея вам нужно просто создать экземпляр TM1637Display с пинами, которые вы используете для подключения модуля к ESP32.

TM1637Display display(CLK, DIO);

Установка яркости дисплея

Для установки яркости дисплея вы можете использовать метод setBrightness() объекта display. Вы можете передать один или два аргумента в эту функцию.

void setBrightness(uint8_t brightness, bool on = true);

Первый — число от 0 (минимальная яркость) до 7 (максимальная яркость), а второй аргумент включает (true) или выключает (false) дисплей.

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

// Brightness Test
for(k = 0; k < 4; k++)
  data[k] = 0xff;
for(k = 0; k < 7; k++) {
  display.setBrightness(k);
  display.setSegments(data);
  delay(TEST_DELAY);
}

// On/Off test
for(k = 0; k < 4; k++) {
  display.setBrightness(7, false);  // Turn off
  display.setSegments(data);
  delay(TEST_DELAY);
  display.setBrightness(7, true); // Turn on
  display.setSegments(data);
  delay(TEST_DELAY);
}

Управление сегментами

Дисплей TM1637 поставляется с четырьмя 7-сегментными цифрами. Вы можете вручную управлять отдельными сегментами каждой цифры с помощью функции setSegments(), используя массив байтов.

void setSegments(const uint8_t segments[], uint8_t length = 4, uint8_t pos = 0);
  • segments: массив байтов, определяющий, какие сегменты включены для цифры. Каждый бит в байте соответствует одному LED-сегменту;

  • length: сколько цифр обновлять (от 0 до 4) — этот параметр необязательный;

  • pos: начальная позиция (0 — крайняя левая, 3 — крайняя правая) — по умолчанию 0. Этот параметр также необязательный.

7-сегментный дисплей

Как кодируются сегменты

Каждый сегмент соответствует биту в байте. Посмотрите на следующую таблицу:

Сегмент

Бит

A

0

B

1

C

2

D

3

E

4

F

5

G

6

Бит 1 включает сегмент, а бит 0 выключает его.

Например, чтобы включить сегменты A, B и C, вам понадобится байт вроде 0b0000111.

Байт начинается с G и заканчивается A. Например:

  • 0b0000110 включает сегменты C и B.

Отображение определённых цифр или символов

Чтобы отобразить определённое число, вам нужно использовать правильную комбинацию сегментов:

  • 0: a, b, c, d, e, f

  • 1: b, c

  • 2: a, b, g, e, d

  • 3: a, b, g, c, d

  • 4: f, g, b, c

  • 5: a, f, g, c, d

  • 6: a, f, g, e, d, c

  • 7: a, b, c

  • 8: a, b, c, d, e, f, g

  • 9: a, b, c, d, f, g

С этим вы также можете отображать другие символы, не только числа.

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

uint8_t segments[] = {
  0b0111111, // 0 — all segments except G
  0b0000110, // 1 — segments B and C
  0b1011011, // 2
  0b1001111  // 3
};

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

/*
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete project details at https://RandomNerdTutorials.com/esp32-tm1637-4-digit-7-segment-display-arduino/
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include <Arduino.h>
#include <TM1637Display.h>

#define CLK 19
#define DIO 18
TM1637Display display(CLK, DIO);

void setup() {
  display.setBrightness(7);

  // Custom segments (one byte per digit)
  uint8_t segments[] = {
    0b0111111, // 0 — all segments except G
    0b0000110, // 1 — segments B and C
    0b1011011, // 2
    0b1001111  // 3
  };

  display.setSegments(segments);
}

void loop() {

}

Посмотреть исходный код

Отображение десятичного числа

Для отображения десятичного числа вы можете использовать функцию showNumberDec() объекта display.

void showNumberDec(int num, bool leading_zero = false, uint8_t length = 4, uint8_t pos = 0);

Эта функция принимает следующие параметры:

  • num: отображаемое число

  • leading_zero: когда true, отображаются ведущие нули. В противном случае ненужные цифры остаются пустыми.

  • length: количество отображаемых цифр. Пользователь должен убедиться, что отображаемое число помещается в запрашиваемое количество цифр (например, если нужно отобразить две цифры, число должно быть от 0 до 99)

  • pos: позиция старшей цифры (0 — крайняя левая, 3 — крайняя правая)

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

display.showNumberDec(0, false); // Expect: ___0
delay(TEST_DELAY);
display.showNumberDec(0, true);  // Expect: 0000
delay(TEST_DELAY);
display.showNumberDec(1, false); // Expect: ___1
delay(TEST_DELAY);
display.showNumberDec(1, true);  // Expect: 0001
delay(TEST_DELAY);
display.showNumberDec(301, false); // Expect: _301
delay(TEST_DELAY);
display.showNumberDec(301, true); // Expect: 0301
delay(TEST_DELAY);
display.clear();
display.showNumberDec(14, false, 2, 1); // Expect: _14_
delay(TEST_DELAY);
display.clear();
display.showNumberDec(4, true, 2, 2);  // Expect: 04__
delay(TEST_DELAY);
display.showNumberDec(-1, false);  // Expect: __-1
delay(TEST_DELAY);
display.showNumberDec(-12);        // Expect: _-12
delay(TEST_DELAY);
display.showNumberDec(-999);       // Expect: -999
delay(TEST_DELAY);
display.clear();
display.showNumberDec(-5, false, 3, 0); // Expect: _-5_
delay(TEST_DELAY);

Отображение десятичного числа с двоеточием/точкой

Существует ещё одна функция, которая позволяет отображать десятичное число и управлять тем, включено ли двоеточие или точка (в зависимости от дисплея). Это функция showNumberDecEx(). Вот принимаемые параметры:

void showNumberDecEx(uint16_t num, uint8_t dots = 0, bool leading_zero = false, uint8_t length = 4, uint8_t pos = 0);

Она аналогична предыдущей функции showNumberDec(), но второй аргумент позволяет включать или выключать двоеточие/точку.

  • num: отображаемое число

  • dots: включение точки/двоеточия — смотрите ниже, как это работает

  • leading_zero: когда true, отображаются ведущие нули. В противном случае ненужные цифры остаются пустыми.

  • length: количество отображаемых цифр. Пользователь должен убедиться, что отображаемое число помещается в запрашиваемое количество цифр (например, если нужно отобразить две цифры, число должно быть от 0 до 99)

  • pos: позиция старшей цифры (0 — крайняя левая, 3 — крайняя правая)

Управление двоеточием/точкой

Второй аргумент функции showNumberDecEx() — это битовая маска, где каждый бит соответствует точке между цифрами (или знаку двоеточия, в зависимости от реализации каждого модуля).

Например, для дисплеев с точками между каждой цифрой:

  • 0.000 > (0b10000000)

  • 00.00 > (0b01000000)

  • 000.0 > (0b00100000)

  • 0.0.0.0 > (0b11100000)

В нашем случае это дисплей только с двоеточием. Поэтому для отображения двоеточия мы можем передать следующее двоичное значение в качестве второго аргумента:

  • 00:00 > (0b01000000)

Наконец, вот пример для дисплеев с точками и двоеточием:

  • 0.0:0.0 > (0b11100000)

Например, чтобы отобразить 12:30, вы бы вызвали:

display.showNumberDecEx(1230, 0b01000000);

В коде функция используется здесь:

// Run through all the dots
for(k=0; k <= 4; k++) {
  display.showNumberDecEx(0, (0x80 >> k), true);
  delay(TEST_DELAY);
}

Демонстрация

Загрузите код на плату. На дисплее будет отображаться серия цифр, символов и сегментов для тестирования функций библиотеки.

ESP32 с TM1637 дисплеем - тестирование ESP32 с TM1637 дисплеем - демонстрация тестирования ESP32 с TM1637 дисплеем - демонстрация тестирования 2

Если пример не работает, перепроверьте подключение и источник питания.


Практические примеры с дисплеем TM1637

Теперь, когда вы знаете базовые функции управления дисплеем, мы покажем вам два практических примера, которые вы можете протестировать с дисплеем TM1637 и ESP32:

Эти два проекта требуют только ESP32 и дисплей. Дополнительное оборудование не нужно, так как вся информация будет запрашиваться из интернета с помощью :doc:`Wi-Fi возможностей ESP32 <../esp32-useful-wi-fi-functions-arduino/index>`_.

Цифровые часы ESP32 с дисплеем TM1637 (с настройкой часового пояса и DST)

Компоновка 4-разрядного 7-сегментного дисплея TM1637 с двоеточием между вторым и третьим символами идеально подходит для создания цифровых часов, с часами на одной стороне двоеточия и минутами на другой.

ESP32 TM1637 цифровые интернет-часы

Мы получим время для вашего часового пояса, используя NTP (network time protocol) с учётом перехода на летнее время.

Чтобы узнать больше о получении времени с ESP32 для вашего часового пояса с учётом перехода на летнее время (если это актуально), вы можете прочитать следующее подробное руководство:

Обзор проекта

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

  • Инициализация дисплея;

  • Инициализация Wi-Fi и подключение ESP32 к вашей локальной сети, чтобы он мог получать данные из интернета;

  • Инициализация времени для указанного часового пояса (учитывает переход на летнее время);

  • Отображение времени на дисплее (мигание двоеточия между цифрами каждую секунду).

Код – Цифровые часы TM1637

Вы можете загрузить следующий код на вашу плату ESP32. Вам нужно:

  • Вставить ваш SSID и пароль;

  • Вставить строку вашего часового пояса. Список можно найти на GitHub nayarsystems.

/*
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete project details at https://RandomNerdTutorials.com/esp32-tm1637-4-digit-7-segment-display-arduino/
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include <WiFi.h>
#include "time.h"
#include <TM1637Display.h>

// Replace with your network credentials
const char* ssid     = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

// TM1637 pins
#define CLK 19
#define DIO 18

TM1637Display display(CLK, DIO);

// Timezone (Lisbon / Portugal)
// Change if needed - See list of timezones strings: https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
const char* TZ_INFO = "WET0WEST,M3.5.0/1,M10.5.0";

// Init Wifi
void initWiFi() {
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }
}

// Initialize Time with the specified timezone
void initTime() {
  configTime(0, 0, "pool.ntp.org");
  setenv("TZ", TZ_INFO, 1);
  tzset();
}

// display the time on the screen
void displayTime() {

  // blinking colon
  static bool colon = false;
  colon = !colon;

  // get the current time
  struct tm timeinfo;
  if (!getLocalTime(&timeinfo)) {
    return;
  }

  int hours   = timeinfo.tm_hour;   // get hours (0–23)
  int minutes = timeinfo.tm_min;    // get minutes (0–59)

  // move hours to the left two digits
  int hourPart = hours * 100;

  // combine hours and minutes into HHMM
  int value = hourPart + minutes;

  // control the colon (for blinking colon)
  uint8_t colonMask;
  if (colon == true) {
    colonMask = 0b01000000;   // turn colon ON
  } else {
    colonMask = 0;            // turn colon OFF
  }

  display.showNumberDecEx(
    value,
    colonMask,   // blink colon
    true         // leading zeros
  );
}

void setup() {
  Serial.begin(115200);

  display.setBrightness(7);
  display.clear();

  initWiFi();
  initTime();
}

void loop() {
  displayTime();
  delay(1000);
}

Посмотреть исходный код

Как работает код?

Давайте быстро рассмотрим код, чтобы понять, как он работает.

Подключение библиотек

Начните с подключения необходимых библиотек.

#include <WiFi.h>
#include "time.h"
#include <TM1637Display.h>

Сетевые учётные данные

Вставьте ваши сетевые учётные данные в следующие строки.

// Replace with your network credentials
const char* ssid     = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

Инициализация дисплея

Установите пины TM1637 и создайте экземпляр дисплея с именем display.

// TM1637 pins
#define CLK 19
#define DIO 18

TM1637Display display(CLK, DIO);

Часовой пояс

Вставьте строку вашего часового пояса в следующую строку. Вы можете найти список строк часовых поясов здесь. В моём случае мой часовой пояс — Лиссабон/Португалия, поэтому это будет выглядеть так:

const char* TZ_INFO = "WET0WEST,M3.5.0/1,M10.5.0";

Инициализация Wi-Fi

Следующая функция инициализирует Wi-Fi и подключает ESP32 к вашей локальной сети. Она будет вызвана позже в setup().

// Init Wifi
void initWiFi() {
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }
}

Вы можете узнать больше о Wi-Fi функциях ESP32 в следующем руководстве:

Инициализация времени

Функция initTime() инициализирует NTP-время и настраивает его на ваш часовой пояс — обратите внимание на функции setenv() и tzset().

// Initialize Time with the specified timezone
void initTime() {
  configTime(0, 0, "pool.ntp.org");
  setenv("TZ", TZ_INFO, 1);
  tzset();
}

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

Функция displayTime() будет отображать дату и время на экране.

void displayTime() {

У нас есть булева переменная colon, которая определяет, отображается ли двоеточие или нет (для создания эффекта мигания).

// blinking colon
static bool colon = false;
colon = !colon;

Мы получаем текущее время и сохраняем его в структуре timeinfo.

// get the current time
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
  return;
}

Затем мы можем получить часы и минуты следующим образом:

int hours   = timeinfo.tm_hour;   // get hours (0–23)
int minutes = timeinfo.tm_min;    // get minutes (0–59)

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

Мы можем сделать это, умножив часы на 100 и затем добавив минуты.

// move hours to the left two digits
int hourPart = hours * 100;

// combine hours and minutes into HHMM
int value = hourPart + minutes;

Например, представьте, что час — 12, а минуты — 30. Мы хотим получить 12:30. Поэтому нам нужно получить число 1230 и отобразить двоеточие посередине.

12*100+30 даст желаемое 1230. Это число сохраняется в переменной value.

Наконец, мы настраиваем битовую маску для отображения двоеточия в зависимости от того, пора ли его показывать.

// control the colon (for blinking colon)
uint8_t colonMask;
if (colon == true) {
  colonMask = 0b01000000;   // turn colon ON
} else {
  colonMask = 0;            // turn colon OFF
}

Мы можем использовать showNumberDecEx() для отображения времени на экране. Передайте в качестве аргумента значение, битовую маску для двоеточия и наличие ведущих нулей.

display.showNumberDecEx(
  value,
  colonMask,   // blink colon
  true         // leading zeros
);

Теперь, когда все основные функции объявлены, легко настроить наш код.

setup()

В setup() инициализируйте Serial Monitor, установите яркость дисплея, инициализируйте Wi-Fi и время.

void setup() {
  Serial.begin(115200);

  display.setBrightness(7);
  display.clear();

  initWiFi();
  initTime();
}

loop()

Наконец, в loop() вам нужно просто вызвать функцию displayTime() для отображения времени на 4-разрядном 7-сегментном дисплее.

void loop() {
  displayTime();
  delay(1000);
}

Демонстрация

После ввода ваших сетевых учётных данных и информации о часовом поясе вы можете загрузить код на ESP32.

Он должен начать отображать текущее время для вашего часового пояса.

ESP32 TM1637 цифровые интернет-часы

Двоеточие должно мигать каждую секунду, имитируя старые цифровые часы.


Отображение температуры на ESP32 (TM1637) из Weather API

В этом проекте мы будем отображать текущую температуру для вашего города на дисплее. Мы получим температуру из Weather API.

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

Пример прогноза погоды

Мы получим температуру для вашего местоположения и отобразим её на 7-сегментном дисплее.

Получение API-ключа

  1. Перейдите на сайт Weather API: weatherapi.com/

  2. Зарегистрируйтесь для создания аккаунта.

  3. После подтверждения аккаунта войдите в него.

  4. На вашей панели управления на weatherapi.com/my/ вы найдёте ваш API-ключ (несмотря на то, что указано, что пробная версия закончится, вы можете продолжать использовать ваш API-ключ бесплатно).

Weather API Key

Скопируйте API-ключ в безопасное место, потому что он понадобится вам позже.

Чтобы получить информацию о погоде в выбранном вами местоположении, введите следующий URL в веб-браузер, но вставьте ваше местоположение и API-ключ в нужные места:

https://api.weatherapi.com/v1/current.json?q=YOUR_LOCATION+&key=YOUR_API_KEY'

Например, в моём случае:

https://api.weatherapi.com/v1/current.json?q=Oporto+&key=d1578a064b07453c917164350240106'

Скопируйте ваш URL и вставьте его в браузер, и API вернёт информацию, соответствующую вашей местной погоде. Например:

{
  "location": {
    "name": "Oporto",
    "region": "Porto",
    "country": "Portugal",
    "lat": 41.15,
    "lon": -8.62,
    "tz_id": "Europe/Lisbon",
    "localtime_epoch": 1719843562,
    "localtime": "2024-07-01 15:19"
  },
  "current": {
    "last_updated_epoch": 1719843300,
    "last_updated": "2024-07-01 15:15",
    "temp_c": 22.3,
    "temp_f": 72.1,
    "is_day": 1,
    "condition": {
      "text": "Sunny",
      "icon": "//cdn.weatherapi.com/weather/64x64/day/113.png",
      "code": 1000
    },
    "wind_mph": 10.5,
    "wind_kph": 16.9,
    "wind_degree": 310,
    "wind_dir": "NW",
    "pressure_mb": 1021,
    "pressure_in": 30.15,
    "precip_mm": 0,
    "precip_in": 0,
    "humidity": 69,
    "cloud": 0,
    "feelslike_c": 24.7,
    "feelslike_f": 76.4,
    "windchill_c": 21.9,
    "windchill_f": 71.5,
    "heatindex_c": 24.6,
    "heatindex_f": 76.2,
    "dewpoint_c": 15,
    "dewpoint_f": 58.9,
    "vis_km": 10,
    "vis_miles": 6,
    "uv": 6,
    "gust_mph": 15.4,
    "gust_kph": 24.7
  }
}

Из этого JSON мы можем легко получить температуру для вашего местоположения, как в Цельсиях, так и в Фаренгейтах: temp_c и temp_f.

Установка библиотек

Для этого примера вам нужно установить библиотеку ArduinoJSON от bblanchon.

Установка библиотеки ArduinoJSON в Arduino IDE

Код – Дисплей температуры TM1637

Вы можете загрузить следующий код на вашу плату. Вам нужно:

  • вставить ваш SSID и пароль;

  • вставить ваш API-ключ WeatherAPI;

  • вставить город, для которого вы хотите получить температуру.

/*
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete project details at https://RandomNerdTutorials.com/esp32-tm1637-4-digit-7-segment-display-arduino/
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <TM1637Display.h>

// Wi-Fi credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

const char* api_key = "REPLACE_WITH_YOUR_WeatherAPI_API_Key";
const char* location = "Oporto";  // "q" Parameter documentation for location: https://www.weatherapi.com/docs/#intro-request

// Request URL
String url = "https://api.weatherapi.com/v1/current.json?q=" + String(location) + "&key=" + String(api_key);

// TM1637 pins
#define CLK 19
#define DIO 18

TM1637Display display(CLK, DIO);

// Create the °C Symbol
const uint8_t Celsius[] = {
  SEG_A | SEG_B | SEG_F | SEG_G,  // Circle
  SEG_A | SEG_D | SEG_E | SEG_F   // C
};

// Create the °F Symbol
const uint8_t Fahrenheit[] = {
  SEG_A | SEG_B | SEG_F | SEG_G,  // Circle
  SEG_F | SEG_E | SEG_A | SEG_G   // F
};

// Global variables for temperatures and timers
float currentTempC = 9999;  // Initial error value
float currentTempF = 9999;  // Initial error value
unsigned long lastFetchTime = 0;
const unsigned long fetchInterval = 3600000UL;  // 1 hour in milliseconds

// Init Wifi
void initWiFi() {
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }
  Serial.println("Connection successful");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}

bool updateTemperatures() {
  HTTPClient http;
  http.begin(url);

  int httpCode = http.GET();

  if (httpCode == HTTP_CODE_OK) {  // Check for 200 specifically
    String payload = http.getString();
    Serial.print(payload);

    // Parse JSON
    StaticJsonDocument<1024> doc; // Adjust size if needed based on response
    DeserializationError error = deserializeJson(doc, payload);

    if (error) {
      Serial.print("JSON parsing failed: ");
      Serial.println(error.c_str());
      http.end();
      return false;
    }

    // Get both temperatures
    currentTempC = doc["current"]["temp_c"];
    currentTempF = doc["current"]["temp_f"];
    http.end();
    return true;
  } else {
    Serial.print("Error during request: ");
    Serial.println(httpCode);
    http.end();
    return false;
  }
}

void setup() {
  Serial.begin(115200);
  delay(1000); // Give time for Serial to initialize

  // Connect to Wi-Fi
  initWiFi();

  display.setBrightness(7);  // Set the display brightness (0-7)

  // Initial fetch
  if (updateTemperatures()) {
    lastFetchTime = millis();
  }
}

void loop() {
  // Check if it's time to fetch new data
  if (millis() - lastFetchTime >= fetchInterval) {
    if (updateTemperatures()) {
      lastFetchTime = millis();
    } else {
      // If failed, try again next loop
      Serial.println("Fetch failed, keeping old values.");
    }
  }

  // Show Celsius
  Serial.print("Temperature in Celsius: ");
  Serial.println(currentTempC, 2);

  int roundedTempC = round(currentTempC);
  display.showNumberDec(roundedTempC, false, 2, 0);
  display.setSegments(Celsius, 2, 2);

  delay(5000);

  // Show Fahrenheit
  Serial.print("Temperature in Fahrenheit: ");
  Serial.println(currentTempF, 2);

  int roundedTempF = round(currentTempF);
  display.showNumberDec(roundedTempF, false, 2, 0);
  display.setSegments(Fahrenheit, 2, 2);

  delay(5000);
}

Посмотреть исходный код

Как работает код?

Давайте быстро рассмотрим основные части кода для этого руководства.

Подключение библиотек

Мы начинаем с подключения необходимых библиотек.

#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <TM1637Display.h>

Сетевые учётные данные

Вставьте ваши сетевые учётные данные в следующие строки.

// Replace with your network credentials
const char* ssid     = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

Weather API

Вставьте ваш ключ WeatherAPI и местоположение, для которого вы хотите получить данные.

const char* api_key = "REPLACE_WITH_YOUR_API_KEY";
const char* location = "REPLACE_WITH_YOUR_LOCATION";

Это URL запроса, который вернёт данные о погоде.

String url = "https://api.weatherapi.com/v1/current.json?q=" + String(location) + "&key=" + String(api_key);

Дисплей TM1637

Установите пины, управляющие дисплеем, и создайте экземпляр дисплея с именем display.

// TM1637 pins
#define CLK 19
#define DIO 18

TM1637Display display(CLK, DIO);

Создайте массив с необходимыми сегментами для создания символов градусов Цельсия и Фаренгейта.

// Create the °C Symbol
const uint8_t Celsius[] = {
  SEG_A | SEG_B | SEG_F | SEG_G,  // Circle
  SEG_A | SEG_D | SEG_E | SEG_F   // C
};

// Create the °F Symbol
const uint8_t Fahrenheit[] = {
  SEG_A | SEG_B | SEG_F | SEG_G,  // Circle
  SEG_F | SEG_E | SEG_A | SEG_G   // F
};

SEG_A, SEG_B и так далее — это ссылки на их конкретные байты (они определены в .h файле библиотеки).

Глобальные переменные

Создайте глобальные переменные для хранения температуры в Цельсиях и Фаренгейтах.

float currentTempC = 9999;  // Initial error value
float currentTempF = 9999;  // Initial error value

И вспомогательные переменные для подсчёта времени, чтобы делать запрос к API каждый час.

unsigned long lastFetchTime = 0;
const unsigned long fetchInterval = 3600000UL;  // 1 hour in milliseconds

Инициализация Wi-Fi

Функция initWiFi() инициализирует Wi-Fi и подключится к вашей сети с использованием введённых учётных данных.

// Init Wifi
void initWiFi() {
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }
  Serial.println("Connection successful");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}

Получение/обновление температуры

Функция updateTemperatures() делает запрос к URL WeatherAPI.

Запрос возвращает множество данных о погоде, как мы видели ранее. Мы выводим все данные в Serial Monitor.

bool updateTemperatures() {
HTTPClient http;
http.begin(url);

int httpCode = http.GET();

if (httpCode == HTTP_CODE_OK) {  // Check for 200 specifically
  String payload = http.getString();
  Serial.print(payload);

Затем мы сохраняем только те данные, которые нас интересуют. В данном случае — температуру в Цельсиях и Фаренгейтах. Мы сохраняем их в переменных currentTempC и currentTempF.

currentTempC = doc["current"]["temp_c"];
currentTempF = doc["current"]["temp_f"];

Если всё прошло хорошо с запросом, функция возвращает true. В противном случае — false.

setup()

В setup() мы инициализируем Serial Monitor, подключаемся к Wi-Fi и устанавливаем яркость дисплея.

void setup() {
  Serial.begin(115200);
  delay(1000); // Give time for Serial to initialize

  // Connect to Wi-Fi
  initWiFi();

  display.setBrightness(7);  // Set the display brightness (0-7)

Затем мы делаем наш первый запрос к API для получения текущих температур при первом запуске кода. С этого момента мы также начинаем отсчёт времени, чтобы проверить позже в loop(), пора ли делать ещё один запрос.

// Initial fetch
if (updateTemperatures()) {
  lastFetchTime = millis();
}

loop()

В loop() мы постоянно проверяем, когда пора получить новые значения.

// Check if it's time to fetch new data
if (millis() - lastFetchTime >= fetchInterval) {
  if (updateTemperatures()) {
    lastFetchTime = millis();
  } else {
    // If failed, try again next loop
    Serial.println("Fetch failed, keeping old values.");
  }
}

Затем на дисплее мы чередуем отображение температуры в Цельсиях и Фаренгейтах каждые пять секунд.

// Show Celsius
Serial.print("Temperature in Celsius: ");
Serial.println(currentTempC, 2);

int roundedTempC = round(currentTempC);
display.showNumberDec(roundedTempC, false, 2, 0);
display.setSegments(Celsius, 2, 2);

delay(5000);

// Show Fahrenheit
Serial.print("Temperature in Fahrenheit: ");
Serial.println(currentTempF, 2);

int roundedTempF = round(currentTempF);
display.showNumberDec(roundedTempF, false, 2, 0);
display.setSegments(Fahrenheit, 2, 2);

delay(5000);

Поскольку значения температуры приходят как переменные float, нам нужно преобразовать их в целые числа. Для этого мы используем функцию round() для округления числа. Например:

int roundedTempC = round(currentTempC);

Затем мы просто вызываем функцию showNumberDec() для отображения значений.

display.showNumberDec(roundedTempC, false, 2, 0);

Затем вызываем функцию setSegments() для отображения единиц измерения градусов Цельсия и Фаренгейта.

display.setSegments(Celsius, 2, 2);

Демонстрация

Загрузите код на вашу плату ESP32. Не забудьте вставить ваш SSID и пароль в код, а также API-ключ и ваше местоположение.

Вы должны получить сообщение об успехе в Serial Monitor.

Получение температуры из API - ESP32 - Serial Monitor

И температура в градусах Цельсия и Фаренгейта будет поочерёдно отображаться на дисплее.

ESP32 с дисплеем TM1637 - отображение температуры в Цельсиях ESP32 с дисплеем TM1637 - отображение температуры в Фаренгейтах

Заключение

Это было исчерпывающее руководство по подключению 4-разрядного 7-сегментного дисплея TM1637 к ESP32. Он может быть весьма полезен для отображения температуры, времени или другой информации.

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

Мы надеемся, что это руководство оказалось полезным. У нас есть руководства для других дисплеев, которые могут быть полезны:

Чтобы узнать больше об ESP32, обязательно ознакомьтесь с нашими ресурсами:


Источник: Random Nerd Tutorials – Rui Santos & Sara Santos https://randomnerdtutorials.com/esp32-tm1637-4-digit-7-segment-display-arduino/