В данной статье мы рассмотрим создание часов на основе микроконтроллера ESP32 и модуля часов реального времени DS3231. Информация о времени будет выводиться на экран OLED дисплея.
ESP32 – это больше чем обычный микроконтроллер. Он имеет встроенные чипы для Wi-Fi и Bluetooth связи, а также 39 контактов ввода/вывода (GPIO). Также он поддерживает множество протоколов связи: SPI, I2C, UART и т.д. Если вы только начинаете свое знакомство с модулем/микроконтроллером ESP32, то советуем прочитать руководство по началу работы с ним.
Необходимые компоненты
- Модуль ESP32 (купить на AliExpress).
- Модуль часов реального времени DS3231 (купить на AliExpress).
- Модуль OLED дисплея (SSD1306) 128×64 с 7-ю контактами (купить на AliExpress).
- Макетная плата.
- Соединительные провода.
Вместо модуля ESP32 в данном проекте можно также использовать плату NodeMCU ESP8266.
Что такое модуль DS3231
DS3231 – это модуль часов реального времени (Real Time Clock, RTC). Он используется для хранения информации о времени и дате во множестве электронных устройств во всем мире. В своем составе он имеет собственную батарейку, поэтому он сохраняет информацию о времени и дате даже когда питание основного устройства (в которое он входит) отключается или когда производится сброс устройства (микроконтроллера). То есть если мы один раз установим дату и время в модуле он будет хранить их постоянно, до тех пор пока не истощится его батарейка. В настоящее время существует несколько различных микросхем реального времени: DS1307, DS3231 и т.д.
Внешний вид модуля DS3231 показан на следующем рисунке.
Ранее на нашем сайте мы рассматривали применение модуля DS3231 в следующих проектах:
- часы на Arduino и 4-х разрядном семисегментном индикаторе;
- бесконтактный настенный термометр на Arduino с логгером данных;
- автоматический напоминатель приема лекарств на Arduino;
- автоматическая кормушка для животных на Arduino.
Примечание: в данном проекте вместо модуля DS3231 можно также использовать модуль DS1307, на нашем сайте мы рассматривали его подключение к плате Arduino.
Общие сведения об OLED дисплеях
Технология OLED (Organic Light emitting diode – органический светоизлучающий диод) в настоящее время является самой распространённой для создания различных дисплеев, которые используются в современных телевизорах, ноутбуках, смартфонах и т.д. Небольшие по размеру OLED дисплеи находят применение и в различных электронных проектах – по сравнению с обычными алфавитно-цифровыми ЖК дисплеями они обеспечивают более наглядное отображение информации.
Внешний вид модуля OLED дисплея с 7-ю контактами показан на следующем рисунке.
В нашем проекте мы будем использовать 7-контактый модуль OLED дисплея SSD1306 0.96”. Данный модуль поддерживает 3 режима связи с ним: 3-х проводный SPI, 4-х проводный SPI и IIC. Мы будем использовать интерфейс SPI с 4-мя проводами – он обеспечивает самую быструю передачу информации среди рассмотренных.
Назначение контактов данного дисплея приведено в следующей таблице.
Номер контакта | Название контакта | Альтернативное название контакта | Назначение контакта |
1 | Gnd | Ground | земля |
2 | Vdd | Vcc, 5V | напряжение питания (в диапазоне 3-5 В) |
3 | SCK | D0, SCL, CLK | контакт синхронизации (clock pin). Применяется в интерфейсах I2C и SPI |
4 | SDA | D1, MOSI | контакт данных. Применяется в интерфейсах I2C и SPI |
5 | RES | RST, RESET | контакт сброса модуля. Применяется в интерфейсе SPI |
6 | DC | A0 | контакт команд (Data Command pin). Применяется в интерфейсе SPI |
7 | CS | Chip Select (выбор чипа) | используется когда несколько устройств взаимодействуют по интерфейсу SPI |
В данном проекте для взаимодействия с OLED дисплеем мы будем использовать библиотеку Adafruit_SSD1306 – она проста в использовании и обеспечивает много возможностей по работе с графикой. Но если ваш проект имеет жесткие ограничения по используемой памяти/быстродействию, то рекомендуем использовать библиотеку U8g – она работает быстрее и использует значительно меньше памяти.
Ранее на нашем сайте мы рассматривали подключение OLED дисплея к платам Arduino и Raspberry Pi, а также к модулю ESP8266.
Схема проекта
Схема часов реального времени на ESP32 и модуле DS3231 представлена на следующем рисунке.
Микросхема модуля часов реального времени DS3231 использует для взаимодействия с другими устройствами протокол I2C по контактам SCL, SDA, Vcc и GND. Необходимо сделать следующие ее соединения с модулем ESP32:
- SCL of RTC -> SCL of ESP32 (Pin D22)
- SDA of RTC -> SDA of ESP32 (Pin D21)
- GND of RTC -> GND of ESP32
- Vcc of RTC -> Vcc of ESP32
В нашем проекте мы используем протокол SPI для взаимодействия между модулем ESP32 и OLED дисплеем. В схеме необходимо сделать следующие соединения между ними:
- CS (Chip select) pin of OLED -> PIN D5 модуля ESP32
- DC pin of OLED -> PIN D4 модуля ESP32
- RES pin of OLED -> PIN D2 модуля ESP32
- SDA pin of OLED -> PIN D23 (MOSI) модуля ESP32
- SCK pin of OLED -> PIN D18 (SCK) модуля ESP32
- Vdd of OLED -> Vcc модуля ESP32
- GND of OLED -> GND модуля ESP32
Внешний вид собранной на макетной плате конструкции проекта показан на следующем рисунке.
Объяснение программы для модуля ESP32
Полный код программы приведен в конце статьи, здесь же мы кратко рассмотрим его основные фрагменты.
Для данного проекта нам понадобится ряд библиотек, скачать которые можно по следующим ссылкам:
- Adafruit_SSD1306 : https://github.com/adafruit/Adafruit_SSD1306.
- SPI : https://github.com/PaulStoffregen/SPI.
- Adafruit_GFX : https://github.com/adafruit/Adafruit-GFX-Library.
- RTClib : https://github.com/adafruit/RTClib.
Далее в коде программы подключим эти библиотеки.
1 2 3 4 5 |
#include <SPI.h> // for OLED display #include <Wire.h> // for I2C with RTC module #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> // for display graphics #include "RTClib.h" //to show time |
Далее объявим все контакты модуля ESP32, к которым подключен OLED дисплей. Нет необходимости объявлять контакты для подключения модуля часов реального времени поскольку они уже объявлены в библиотеке WIRE.
1 2 3 4 5 6 |
#define OLED_MOSI 23 #define OLED_CLK 18 #define OLED_DC 4 #define OLED_CS 5 #define OLED_RESET 2 Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS); |
В функции setup мы будем вызывать функцию rtc.adjust(DateTime(__DATE__, __TIME__)), которая будет устанавливать дату и время на модуле часов реального времени, соответствующие дате и времени на нашем компьютере (с которого мы программируем модуль ESP32).
1 2 3 4 5 6 7 8 9 10 |
void setup() { Serial.begin(9600); if (! rtc.begin()) { Serial.println("Couldn't find RTC"); while (1); } rtc.adjust(DateTime(__DATE__, __TIME__)); |
Далее отобразим информацию на OLED дисплее.
1 2 3 4 5 6 7 8 9 10 |
display.begin(SSD1306_SWITCHCAPVCC); display.clearDisplay(); display.setTextColor(WHITE); //display.startscrollright(0x00, 0x0F); // You can uncomment this line to scroll your text on oled display.setTextSize(2); display.setCursor(0,5); display.print(" Clock "); //This will Display Clock on OLED for 3 seconds display.display(); delay(3000); } |
В функции loop мы будем сохранять значение времени в переменной now и отображать ее значение на экране OLED дисплея, используя также функции установки размера текста (setTextSize), установки позиции курсора (setCursor) и т.д. После установки необходимых параметров отображения информации мы будем выводить значение времени на экран дисплея с помощью функции display.println.
1 2 3 4 5 6 7 8 |
void loop() { DateTime now = rtc.now(); display.clearDisplay(); display.setTextSize(2); display.setCursor(75,0); display.println(now.second(), DEC); |
Исходный код программы (скетча)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
#include <SPI.h> #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #include "RTClib.h" RTC_DS3231 rtc; char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; #define OLED_MOSI 23 #define OLED_CLK 18 #define OLED_DC 4 #define OLED_CS 5 #define OLED_RESET 2 Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS); void setup() { Serial.begin(9600); if (! rtc.begin()) { Serial.println("Couldn't find RTC"); while (1); } rtc.adjust(DateTime(__DATE__, __TIME__)); display.begin(SSD1306_SWITCHCAPVCC); display.clearDisplay(); display.setTextColor(WHITE); //display.startscrollright(0x00, 0x0F); display.setTextSize(2); display.setCursor(0,5); display.print(" Clock "); display.display(); delay(3000); } void loop() { DateTime now = rtc.now(); display.clearDisplay(); display.setTextSize(2); display.setCursor(75,0); display.println(now.second(), DEC); display.setTextSize(2); display.setCursor(25,0); display.println(":"); display.setTextSize(2); display.setCursor(65,0); display.println(":"); display.setTextSize(2); display.setCursor(40,0); display.println(now.minute(), DEC); display.setTextSize(2); display.setCursor(0,0); display.println(now.hour(), DEC); display.setTextSize(1); display.setCursor(0,15); display.println(now.day(), DEC); display.print(daysOfTheWeek[now.dayOfTheWeek()]); display.setTextSize(1); display.setCursor(25,15); display.println("-"); display.setTextSize(1); display.setCursor(40,15); display.println(now.month(), DEC); display.setTextSize(1); display.setCursor(55,15); display.println("-"); display.setTextSize(1); display.setCursor(70,15); display.println(now.year(), DEC); display.display(); } |
Очередное поделие рукожопого программиста.
D:\Arduino\libraries\RTClib-master\src\RTC_DS1307.cpp: In member function 'void RTC_DS1307::writenvram(uint8_t, const uint8_t*, uint8_t)':
D:\Arduino\libraries\RTClib-master\src\RTC_DS1307.cpp:109:47: error: invalid conversion from 'const uint8_t* {aka const unsigned char*}' to 'uint8_t* {aka unsigned char*}' [-fpermissive]
i2c_dev->write(buf, size, true, &addrByte, 1);
^
In file included from D:\Arduino\libraries\RTClib-master\src\RTClib.h:25:0,
from D:\Arduino\libraries\RTClib-master\src\RTC_DS1307.cpp:1:
D:\Arduino\libraries\Adafruit_BusIO/Adafruit_I2CDevice.h:15:8: note: initializing argument 1 of 'bool Adafruit_I2CDevice::write(uint8_t*, size_t, bool, uint8_t*, size_t)'
bool write(uint8_t *buffer, size_t len, bool stop = true,
^
exit status 1
Ошибка компиляции для платы ESP32 Dev Module.
Ну зачем сразу так категорично ругать программиста? Все таки у статьи уже более 1000 просмотров и никто кроме вас не отписался об этой проблеме. Есть возможность попробовать проект на другом железе или хотя бы на другом компьютере?