В настоящее время во встраиваемой электронике (и не только) достаточно широкое применение находят часы на семисегментных дисплеях (индикаторах). Ранее на нашем сайте мы уже рассматривали подключение семисегментного дисплея к плате Arduino Uno, также у нас представлены проекты различных часов на основе Arduino:
- GPS часы;
- часы реального времени с будильником на основе Arduino;
- бинарные часы на светодиодах с использованием Arduino;
- умные часы (Smart Watch) на основе Arduino, OLED дисплея и смартфона.
В этой же статье мы рассмотрим создание часов на основе платы Arduino и четырех семисегментных дисплеях. Управление семисегментными дисплеями мы будем осуществлять с помощью технологии мультиплексирования.
Необходимые компоненты
- Плата Arduino UNO (купить на AliExpress).
- 4-х разрядный семисегментный дисплей (индикатор) (4-Digit 7 Segment Display) (купить на AliExpress).
- Микросхема 74HC595 (регистр сдвига) (купить на AliExpress).
- Модуль часов реального времени DS3231 (купить на AliExpress).
- Макетная плата.
- Соединительные провода.
Реклама: ООО «АЛИБАБА.КОМ (РУ)» ИНН: 7703380158
4-х разрядный семисегментный дисплей (4-Digit 7 Segment Display)
4-х разрядный семисегментный дисплей состоит из четырех семисегментных дисплеев, объединенных в единое устройство. Иногда говорят, что эти дисплеи “мультиплексированы вместе”, поэтому для управления ими можно использовать технологию мультиплексирования. Этот дисплей можно использовать для отображения цифр, а также некоторых букв. Дисплей можно использовать в обоих направлениях. 4 символа удобно использовать для изготовления электронных часов или счетчика от 0 до 9999.
На следующем рисунке показана внутренняя схема соединений 4-х разрядного семисегментного дисплея.
На нашем сайте есть достаточно подробные статьи про устройство семисегментных дисплеев и их программированию – они написаны для микроконтроллеров семейства AVR, но я думаю провести аналогию с Arduino вам будет не трудно:
- семисегментный светодиодный индикатор: описание, подключение к микроконтроллеру;
- перевод двоичного кода десятичного числа в код семисегментного индикатора. Программа вывода цифры на одноразрядный светодиодный индикатор;
- многоразрядный семисегментный индикатор: организация динамической индикации, алгоритм работы, программа индикации.
Также можно посмотреть статью о подключении семисегментного дисплея к микроконтроллеру AVR ATmega32.
Использование технологии мультиплексирования
Так каким образом мы можем на подобном 4-х символьном семисегментном дисплее отобразить, к примеру, число 1234? Это возможно сделать с использованием технологии мультиплексирования. Смысл этой технологии достаточно прост – в каждый момент времени мы отображаем только один символ (из 4-х возможных) на данном дисплее. Переключение между отображением всех 4-х символов происходит достаточно быстро – поэтому человеческий глаз воспринимает их непрерывно горящими.
Регистр сдвига 74HC595
Микросхема 74HC595 представляет собой 8-битовый регистр сдвига, работающий по принципу Serial IN – Parallel OUT (последовательный вход – параллельный выход). То есть данный регистр сдвига принимает входные данные последовательно и обеспечивает параллельный вывод этих данных на своих 8 контактах. С его помощью можно значительно уменьшить количество используемых контактов микроконтроллера (в нашем случае платы Arduino). Более подробно о подключении регистра сдвига 74HC595 к платы Arduino можно прочитать в этой статье.
Микросхема 74HC595 использует 3 контакта (Clock, Data & Latch) для подключения к микроконтроллеру и позволяет контролировать 8 своих выходных контактов. Контакт Clock используется для непрерывной подачи синхронизирующих импульсов, а контакт Data предназначен для подачи на него необходимых данных. Регистр сдвига 74HC595 работает по интерфейсу SPI, подробную информацию по использованию данного интерфейса в платах Arduino вы можете почерпнуть в этой статье. Назначение контактов микросхемы 74HC595 приведено на следующих двух рисунках.
Q0-Q7 – восемь параллельных выходов общего назначения. Данные выходы нужны для того, чтобы мы могли как-то воспользоваться пришедшими данными по SPI – подключить линейку светодиодов, либо сегменты какого-то индикатора, либо дешифратор и т.д.
VCC – напряжение питания.
GND – общий провод.
Q7′ – последовательный выход данных. По сути — это MISO.
DS – последовательный вход данных или MOSI.
MR – это master reset. Сбрасывает все выходы в 0. Для нормального функционирования регистра сдвига на нем должна быть логическая 1.
SH_CP – в нашем случае это будет chip select.
ST_CP – это контакт управления регистром хранения, в нашем случае это будет контакт синхронизации, на который необходимо подавать тактовые импульсы. Но Arduino будет делать для нас это автоматически при использовании соответствующей команды.
OE – задействования выхода. При отрицательном значении последовательный выход включен, при положительном – выключен.
Модуль часов реального времени DS3231
Внешний вид данного модуля представлен на следующем рисунке.
Модуль предназначен для хранения времени и даты даже когда общее питание схемы выключено – для этой цели в его состав входит элемент питания CR2032. В состав модуля DS3231 входит также датчик температуры, поэтому его можно использовать в различных встраиваемых устройствах, например, в цифровых часах с индикатором температуры и т.д. Модуль работает по интерфейсу I2C. На нашем сайте вы можете посмотреть следующие проекты с использованием данного модуля:
- автоматический напоминатель приема лекарств на Arduino;
- автоматическая кормушка для животных на Arduino;
- логгер данных (температуры, влажности) на SD карту и компьютер с помощью Arduino.
Назначение контактов (распиновка) модуля DS3231 приведена в следующей таблице.
Наименование контакта | Назначение контакта |
VCC | напряжение питания |
GND | общий провод (земля) |
SDA | контакт последовательной передачи данных (I2C) |
SCL | контакт синхронизации (тактирования) (I2C) |
SQW | выход прямоугольного сигнала (программируемый меандр) |
32K | выход меандра с частотой 32.768кГц |
Теперь перейдем непосредственно к схеме нашего проекта.
Схема проекта
Схема часов на Arduino и 4-х разрядном семисегментном индикаторе представлена на следующем рисунке.
DS3231 | Arduino Uno |
VCC | 5V |
GND | GND |
SDA | A4 |
SCL | A5 |
В следующей таблице представлены необходимые соединения между регистром сдвига 74HC595 и платой Arduino Uno.
Регистр сдвига 74HC595 | Arduino Uno |
11-SH_CP (SRCLK) | 6 |
12-ST_CP (RCLK) | 5 |
14-DS (Data) | 4 |
13-OE(Latch) | GND |
8-GND | GND |
10-MR(SRCLR) | +5V |
16-VCC | +5V |
В следующей таблице представлены необходимые соединения между регистром сдвига 74HC595, 4-х разрядным семисегментным дисплей и платой Arduino Uno.
4-х разрядный семисегментный дисплей | Регистр сдвига 74HC595 | Arduino Uno |
A | Q0 | — |
B | Q1 | — |
C | Q2 | — |
D | Q3 | — |
E | Q4 | — |
F | Q5 | — |
G | Q6 | — |
D1 | — | 10 |
D2 | — | 11 |
D3 | — | 12 |
D4 | — | 9 |
Внешний вид собранной конструкции проекта показан на следующем рисунке.
Объяснение программы для Arduino
Полный код программы и видео, демонстрирующее работу проекта, приведены в конце статьи. Здесь же мы рассмотрим основные фрагменты кода программы.
В программе мы должны считывать время (часы и минуты в 24-часовом формате) с модуля часов реального времени и конвертировать их в формат для отображения на 4-х символьном семисегментном дисплее.
Для подключения модуля часов реального времени DS3231 к плате Arduino используется шина I2C. Для работы с данным модулем (считывания даты, времени, температуры и т.д.) мы в программе будем использовать библиотеку <DS3231.h>. Скачайте ее по следующей ссылке — DS3231 RTC module Arduino Library. Поскольку мы используем интерфейс I2C нам в программе необходимо будет подключить и библиотеку <wire.h>.
В нашем проекте часы и минуты считываются с модуля часов реального времени и они потом объединяются вместе, например, 0930 – это будет 09:30 pm. Затем мы выделяем индивидуальные цифры из этого считанного числа. Далее эти индивидуальные цифры преобразуются в двоичный формат и передаются на регистр сдвига, а с него на семисегментный дисплей. Для отображения всех четырех символов мы используем технологию мультиплексирования – то есть в каждый момент времени мы отображаем только один символ, но переключение между символами происходит с высокой частотой, поэтому человеческий глаз этого не замечает.
Итак, первым делом в программе подключим необходимые библиотеки.
1 2 |
#include <Wire.h> #include<DS3231.h> |
Далее инициализируем контакты для управления семисегментным дисплеем с помощью технологии мультиплексирования.
1 2 3 4 |
#define latchPin 5 #define clockPin 6 #define dataPin 4 #define dot 2 |
Далее объявим необходимые переменные.
1 2 3 4 5 6 7 8 9 10 |
int h; //Variable declared for hour int m; //Variable declared for minute int thousands; int hundreds; int tens; int unit; bool h24; bool PM; |
Затем инициализируем объект RTC класса DS3231 – это упростит дальнейшую работу с модулем часов реального времени.
1 |
DS3231 RTC; |
Далее с помощью команды wire.begin() инициализируем связь по протоколу I2C, при этом объекту RTC (модулю часов реального времени) присвоится адрес по умолчанию поскольку у нас в схеме больше нет устройств, использующих шину I2C.
1 |
Wire.begin(); |
Зададим режимы работы используемых контактов – на ввод или вывод данных.
1 2 3 4 5 6 7 8 |
pinMode(9,OUTPUT); pinMode(10,OUTPUT); pinMode(11,OUTPUT); pinMode(12,OUTPUT); pinMode(latchPin, OUTPUT); pinMode(clockPin, OUTPUT); pinMode(dataPin, OUTPUT); pinMode(dot,OUTPUT); |
Затем в бесконечном цикле loop мы будем непрерывно считывать время (часы и минуты) с модуля часов реального времени (RTC) DS3231. При этом ‘h24’ будет обозначать 24-часовой формат переменной для хранения времени.
1 2 |
int h= RTC.getHour(h24, PM); int m = RTC.getMinute(); |
Затем часы и минуты упаковываются в одно число. Например, если число часов равно 10, а число минут равно 60, то результирующее число будет равно 10*100=1000+60 =1060.
1 |
int number = h*100+m; |
Затем из этого числа мы будем извлекать индивидуальные цифры. Например, в числе 1060: 1 – тысячи, 0 – сотни, 6 – десятки и 0 – последняя цифра (единицы). Для разделения этих цифр мы будем использовать оператор остатка от деления. К примеру, чтобы выделить число тысяч в нашем примере — 1060/1000=1.06%10=1. Все эти цифры мы будем хранить в отдельных переменных.
1 2 3 4 |
int thousands = number/1000%10; int hundreds = number/100%10; int tens = number/10%10; int unit = number%10; |
После этого с помощью операторов switch case каждую индивидуальную цифру мы конвертировать в соответствующий (двоичный) формат и передавать с помощью регистра сдвига на семисегментный дисплей. То есть мы каждую цифру преобразуем в такое двоичное число, чтобы при подаче его на семисегментный дисплей загоралась именно эта цифра. К примеру, цифра 1 преобразуется в формат 0000 0110 (число 6). После подачи его на семисегментный дисплей на нем высветится цифра 1 (0 for LOW, 1 for HIGH).
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 |
switch (t) { case 0: unit = 63; break; case 1: unit = 06; break; case 2: unit =91; break; case 3: unit=79; break; case 4: unit=102; break; case 5: unit = 109; break; case 6: unit =125; case 7: unit = 07; break; case 8: unit = 127; break; case 9: unit =103; break; } |
Затем индивидуальные цифры в двоичном формате передаются с помощью функции shiftout. Для реализации технологии мультиплексирования соответствующие контакты сначала устанавливаются в LOW, а потом в HIGH.
1 2 3 4 5 6 |
digitalWrite(9, LOW); digitalWrite(latchPin, LOW); shiftOut(dataPin, clockPin, MSBFIRST,thousands); digitalWrite(latchPin, HIGH); digitalWrite(9, HIGH); delay(5); |
Аналогично и для числа сотен, десятков и единиц.
Используемая частота синхронизации (frequency of the clock) будет влиять на качество работы технологии мультиплексирования. Если она будет низкой, то вы будете замечать мерцание при работе наших часов на семисегментных дисплеях.
На следующем рисунке показан пример работы проекта.
Исходный код программы (скетча)
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 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
//Four-Digit 7 Segments Multiplexing using Arduino: Display time in HH:MM //CIRCUIT DIGEST #include <Wire.h> //библиотека для связи по протоколу I2C #include <DS3231.h> // библиотека для работы с модулем часов реального времени #define latchPin 5 #define clockPin 6 #define dataPin 4 #define dot 2 DS3231 RTC; //объявляем объект RTC класса DS3231 int h; //переменная для хранения часов int m; //переменная для хранения минут int thousands; int hundreds; int tens; int unit; bool h24; bool PM; void setup () { Wire.begin(); pinMode(9,OUTPUT); pinMode(10,OUTPUT); pinMode(11,OUTPUT); pinMode(12,OUTPUT); pinMode(latchPin, OUTPUT); pinMode(clockPin, OUTPUT); pinMode(dataPin, OUTPUT); pinMode(dot,OUTPUT); } void loop () { digitalWrite(dot,HIGH); int h= RTC.getHour(h24, PM); //считываем значение часов int m = RTC.getMinute(); //считываем значение минут int number = h*100+m; //преобразуем часы и минуты в единое четырехзначное число int thousands = number/1000%10; //выделяем количество тысяч int hundreds = number/100%10; // выделяем количество сотен int tens = number/10%10; // выделяем количество десятков int unit = number%10; //выделяем количество единиц int t= unit; int u= tens; int v= hundreds; int w= thousands; //Converting the individual digits into corresponding number for passing it through the shift register so LEDs are turned ON or OFF in seven segment – преобразуем наши цифры в специальный двоичный формат чтобы отображать их на семисегментных дисплеях switch (t) { case 0: unit = 63; break; case 1: unit = 06; break; case 2: unit =91; break; case 3: unit=79; break; case 4: unit=102; break; case 5: unit = 109; break; case 6: unit =125; case 7: unit = 07; break; case 8: unit = 127; break; case 9: unit =103; break; } switch (u) { case 0: tens = 63; break; case 1: tens = 06; break; case 2: tens =91; break; case 3: tens=79; break; case 4: tens=102; break; case 5: tens= 109; break; case 6: tens =125; case 7: tens = 07; break; case 8: tens = 127; break; case 9: tens =103; break; } switch (v) { case 0: hundreds = 63; break; case 1: hundreds = 06; break; case 2: hundreds =91; break; case 3: hundreds=79; break; case 4: hundreds=102; break; case 5: hundreds = 109; break; case 6: hundreds =125; case 7: hundreds = 07; break; case 8: hundreds = 127; break; case 9: hundreds =103; break; } switch (w) { case 0: thousands = 63; break; case 1: thousands = 06; break; case 2: thousands =91; break; case 3: thousands=79; break; case 4: thousands=102; break; case 5: thousands = 109; break; case 6: thousands =125; case 7: thousands = 07; break; case 8: thousands= 127; break; case 9: thousands =103; break; } digitalWrite(9, LOW); digitalWrite(latchPin, LOW); shiftOut(dataPin, clockPin, MSBFIRST,thousands); // передаем количество тысяч digitalWrite(latchPin, HIGH); // устанавливаем на контакте latch HIGH чтобы сохранить переданный символ digitalWrite(9, HIGH); // Turinig on that thousands digit delay(5); // задержка для мультиплексирования digitalWrite(10, LOW); digitalWrite(latchPin, LOW); shiftOut(dataPin, clockPin, MSBFIRST,hundreds ); // передаем количество сотен digitalWrite(latchPin, HIGH); digitalWrite(10, HIGH); delay(5); digitalWrite(11, LOW); digitalWrite(latchPin, LOW); shiftOut(dataPin, clockPin, MSBFIRST,tens); // передаем количество десятков digitalWrite(latchPin, HIGH); digitalWrite(11, HIGH); delay(5); digitalWrite(12, LOW); digitalWrite(latchPin, LOW); shiftOut(dataPin, clockPin, MSBFIRST,unit); // передаем количество единиц digitalWrite(latchPin, HIGH); digitalWrite(12, HIGH); delay(5); } |
6 ответов к “Часы на Arduino и 4-х разрядном семисегментном индикаторе”
не совсем понял как устанавливается время на часах? все отображается корректно, вопросов нет, добавил строку break; во всех switch() в case 6, спасибо за подсказку, но время на модуле от балды, как начало отсчет с установки батарейки так его и ведет…
Добрый день. Время считывается из модуля часов реального времени. Соответственно, если у вас в этом модуле время установлено неправильное, то его нужно установить на правильное. Например, если бы мы работали с этим модулем с помощью библиотеки RTClib.h, то сделать это можно было бы с помощью команды rtc.adjust(DateTime(F(__DATE__), F(__TIME__))) (пример можно посмотреть в этой статье). Но поскольку в этом проекте мы используем библиотеку DS3231.h, то в ней время устанавливается с помощью функций setHour(hour), setMinute(minute) и setSecond(second). Пример их использования можно посмотреть здесь — https://github.com/NorthernWidget/DS3231/blob/master/examples/DS3231_set/DS3231_set.ino.
Цифра «6» не высвечивается в принципе!)))
Необходимо добавить строку break; во всех switch() в case 6:
Да, я думаю вы правы. Опечаточка в программе небольшая вышла ))
Собрал часы по вашему скетчу и схеме, часы не работают, приходят все единицы на диоды 7сегментника и так же на управляющие выводы(аноды) все единицы, в чем проблема?
У вас только с семисегментным индикатором проблема, а с модуля часов реального времени корректно считывается время? Вы проверяли?