Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Manufacturing Technology >> Производственный процесс

7-сегментный массив часов

Компоненты и расходные материалы

SparkFun Arduino Pro Mini 328 - 5 В / 16 МГц
× 1
Часы реального времени (RTC)
Купите "Модуль часов реального времени DS1302 для Arduino" и распаяйте разъем микросхемы и кристалл.
× 1
Батарея и держатель CR1220
Искать "5 шт., черный корпус CR1220 CR1225 Держатель гнезда аккумуляторной батареи кнопочного типа BS-1220-1"
× 1
Конденсатор 0,1 мкФ 1206 SMD
× 1
Конденсатор 10 мкФ 1206 SMD Ceramic
× 1
Тактильный переключатель, срабатывающий сверху
вариант 12 мм с верхними частями кнопок
× 4
Модуль понижающего преобразователя Mini DC-DC 3A
× 1
0,28 дюйма, 4-значный 7-сегментный дисплей с общим катодом
× 36
MAX7219 DIP IC
× 18
Зуммер
× 1
Заголовок компьютера
Вам нужны как мужские, так и женские заголовки - обычно они бывают полосами по 40, так что вы получите 8 полосок мужских обработанные штифты и 8 полос обработанных головок с внутренней резьбой
× 1
розетка постоянного тока
Искать "Гнездо гнезда блока питания 12 В постоянного тока, разъем для монтажа на панель 5.5 x 2.ODZ2"
× 1

Необходимые инструменты и машины

Паяльник (общий)
3D-принтер (общий)

Приложения и онлайн-сервисы

IDE Arduino

Об этом проекте

Просматривая сайт Hackaday.io, я наткнулся на красивые часы, сделанные Frugha на 7-сегментных дисплеях. Я действительно хотел построить это, но версия Frugha довольно большая из-за того, что в ней используются 7-сегментные дисплеи с диагональю 0,56 дюйма. В моем дизайне используются 7-сегментные дисплеи с диагональю 0,28 дюйма, что делает ее только четвертью размера.

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

Видео

Экран конфигурации

Часы управляются четырьмя кнопками. Кнопка ВЫБОР (самая верхняя) отображает экран конфигурации. Текущий выбор будет мигать. Повторное нажатие кнопки SELECT будет переключать различные разделы конфигурации (время, дату, будильник, настройку, яркость, формат даты и часы).

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

Когда параметр мигает, кнопки ВВЕРХ и ВНИЗ (две нижние кнопки) изменяют его.

Экран даты

При нажатии кнопки ENTER (вторая сверху вниз) при отображении часов на пять секунд отображается экран даты.

Раздел «Формат даты» на экране конфигурации позволяет вам установить формат даты (ДД-ММ или ММ-ДД) и используемый шрифт.

Соображения по дизайну

Проще говоря, в моей версии используются 4-значные дисплеи, а не одноразрядные дисплеи, которые использовались в исходной версии. Поскольку 0,28-дюймовые дисплеи маленькие, мне пришлось разместить микросхемы MAX7219 на отдельной плате. Чтобы упростить разводку, для подключения плат используются обработанные штыревые и розеточные разъемы,

Файлы Eagle были включены, если вы хотите, чтобы платы производились на коммерческой основе или делали то же самое, что и я, и делали их сами. При изготовлении я использовал метод тонера.

Доски колонн

Необходимо сделать шесть колонных досок, на которых будут размещены все дисплеи. При пайке мужских разъемов станка начните со среднего набора и двигайтесь к внешнему краю. Используйте спичку или что-то подобное, чтобы поднять гнездо так, чтобы можно было легко припаять контакты. Используйте небольшой паяльник с острым наконечником и припоем 0,5 мм.

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

Материнская плата MAX7219

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

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

Плата MPU

Плата микропроцессора содержит все остальные компоненты. Четыре кнопки и два конденсатора SMD установлены на задней части платы, а все остальные компоненты установлены на передней части платы. Чтобы сохранить низкий профиль, контактный разъем FTDI, который обычно припаян к Arduino Pro Mini, теперь припаян непосредственно к печатной плате. Два провода идут от контактов DTR и VCC прямо к плате.

Обоснование

Были включены файлы STL для передней и задней части. Оба были напечатаны с использованием высоты слоя 0,2 и полей. На передней панели также включены опоры, которые касаются только рабочей пластины.

Материнская плата MAX7219 с модулями на стойках вставляется спереди. Если вы обнаружите, что он немного болтается, используйте один или два слоя малярной ленты в качестве упаковки.

Плата MPU приклеена к задней части горячим клеем.

Программное обеспечение

Программное обеспечение требует, чтобы библиотека MD_MAX72XX была установлена ​​в вашей Arduino IDE. Я предоставил свой скетч Hardware_Test_V1 для тестирования. Он загорится на каждом сегменте, чтобы вы могли проверить на предмет коротких замыканий или обрыва проводки. Как только дисплей заработает, загрузите скетч Clock_V4.

Код

  • Clock_V4.ino
  • Digits.h
  • Tunes.h
  • Button.h
  • Button.cpp
  • Hardware_Test_V1.zip
Clock_V4.ino C / C ++
 / * --------------------------------------------- ------ * Часы с 7-сегментным массивом * * На основе часов Фруга (https://hackaday.io/project/169632-7-segment-display-array-clock) * * Изменения Джона Брэднэма (jbrad2089 @ gmail.com) * - Аппаратное обеспечение изменено для использования 7-сегментных дисплеев 0,28 дюйма * - Порядок цифр и сегментов устройства MAX7219 был изменен на простую * сложную маршрутизацию платы PCB. * - Аппаратное обеспечение использует Arduino Mini Pro, DS1302 RTC и 4 кнопки * - Добавлена ​​функция будильника с возможностью выбора будильника * - Добавлена ​​настройка яркости * - Добавлен экран настройки для установки времени, даты, будильника, музыки и яркости * - Добавлен экран даты (отображается в течение двух секунд при нажатии кнопки ENTER * Обновить 2020 -06-16 * - Добавлена ​​опция формата даты на экране конфигурации * - Увеличено время ожидания экрана даты с 2 до 5 секунд * - Добавлен конфигурируемый выбор шрифта для отображения даты * -------------- ------------------------------------ * / #include  #include  # включить  # include  #include  #include "button.h" #include "Tunes.h" #include "Digits.h" #define HARDWARE_TYPE MD_MAX72XX ::GENERIC_HW # define MAX_DEVICES 18 # define LED_CLK 13 / / или SCK (WHI) #define LED_DATA 11 // или MOSI (BRN) #define LED_CS 10 // или SS (YEL) #define SPEAKER 2 # define SW_UP 3 # define SW_DOWN 4 # define RTC_CLK 5 #define RTC_IO 6 #define SW_ENTER 7 # define RTC_CE 8 #defin SW_SELECT 9DS1302RTC rtc (RTC_CE, RTC_IO, RTC_CLK); // аппаратный интерфейс SPI MD_MAX72XX mx =MD_MAX72XX (HARDWARE_TYPE, LED_CS, MAX_DEVICES_ins); // произвольно LED_CLK, LED_CS, MAX_DEVICES); // Обработка EEPROM # определить EEPROM_ADDRESS 0 # определить EEPROM_MAGIC 0x0BAD0DADtypedef struct {uint32_t magic; bool alarm; uint8_t минут; uint8_t часов; bool format12hr; uint8_t яркость; uint8_t tune; bool formatDmy; bool squareFont;} EEPROM_DATA; EEPROM_DATA EepromData; // Текущие настройки EEPROMvoid clockButtonPressed (void); void enterButtonPressed (void); void downButtonPressed (void); void upButtonPressed (void); Button * clockButton; Button * enterButton; Button * downButton; Button * upButton; // Режимы работыbool =inSubM ложь; #define SETUP_FLASH_RATE 200; без знака длиной setupTimeout; BOOL setupDisplayState =ложь; перечисление ClockButtonModesEnum {ЧАСЫ, TIME_SET, DATE_SET, ALARM_SET, TUNE_SET, BRIGHT_SET, FORMAT_SET}; ClockButtonModesEnum clockMode =ЧАСЫ; перечисление TimeSetMenuEnum {TIME_HOUR, TIME_MIN, TIME_FORMAT}; TimeSetMenuEnum timeSetMode =TIME_HOUR; перечисление DateSetMenuEnum {DATE_YEAR, DATE_MONTH, DATE_DAY}; DateSetMenuEnum dateSetMode =DATE_YEAR; перечисление AlarmSetMenuEnum {ALARM_HOUR, ALARM_MIN, ALARM_STATE}; AlarmSetMenuEnum alarmSetMode =ALARM_HOUR; перечисление FormatSetMenuEnum {DAY_MONTH, FONT_STYLE}; FormatSetMenuEnum formatSetMode =DAY_MONTH; INT lastSeconds =-1; bool alarmRinging =false; // истина, когда тревога включенаbool alarmCancelled =false; // тревога отменена пользователемbool musicPlaying =false; // истина, если воспроизводится песня clockColon =false; // показать / скрыть двоеточиеint8_t dom [] ={31,28,31,30,31,30,31,31,30,31,30,31}; tmElements_t newTime; // Используется для сохранения нового timevoid setup () {Serial.begin (115200); // Eprom readEepromData (); // Инициализируем кнопки clockButton =new Button (SW_SELECT); enterButton =новая кнопка (SW_ENTER); downButton =новая кнопка (SW_DOWN); downButton-> Повторить (downButtonPressed); upButton =новая кнопка (SW_UP); upButton-> Повторить (upButtonPressed); // Инициализируем звук pinMode (SPEAKER, OUTPUT); mx.begin (); mx.control (MD_MAX72XX ::ИНТЕНСИВНОСТЬ, EepromData.brightness); //0..MAX_INTENSITY mx.update (MD_MAX72XX ::OFF); // Без автоматического обновления setSyncProvider (rtc.get); // функция для получения времени от RTC if (timeStatus ()! =timeSet) {Serial.println ("RTC Sync Bad"); newTime.Year =CalendarYrToTm (2020); newTime.Month =5; newTime.Day =30; newTime.Hour =14; newTime.Minute =53; newTime.Second =0; time_t t =makeTime (новое время); setTime (t); rtc.set (t); if (rtc.set (t)! =0) {Serial.println ("Установить время не удалось"); }} newTime.Year =CalendarYrToTm (год ()); newTime.Month =месяц (); newTime.Day =день (); newTime.Hour =час (); newTime.Minute =минута (); newTime.Second =второй (); Serial.println ("Время:" + String (newTime.Hour) + ":" + String (newTime.Minute) + ":" + String (newTime.Second)); Serial.println ("Дата:" + String (newTime.Day) + "/" + String (newTime.Month) + "/" + String (tmYearToCalendar (newTime.Year))); clockMode =ЧАСЫ; showTime (истина);} недействительный цикл () {testButtons (); если (clockMode ==ЧАСЫ) {showTime (ложь); if (EepromData.alarm &&EepromData.hours ==час () &&EepromData.minutes ==минута ()) {if (! alarmCancelled) {alarmRinging =true; playSong (мелодии [EepromData.tune]); }} else {alarmCancelled =false; alarmRinging =false; }} еще {showSetup (ложь); } delay (100);} // ----------------------------------------- ---------------------- // Проверяем, были ли нажаты какие-либо кнопкиvoid testButtons () {// Однократное нажатие кнопок if (clockButton-> Pressed ()) { clockButtonPressed (); } если (enterButton-> Pressed ()) {enterButtonPressed (); } // Не нужно проверять результат нажатия, так как обработчик кнопки вызовет свою функцию повтора upButton-> Pressed (); downButton-> Pressed ();} // ---------------------------------------- ----------------------- // Обработка ЧАСОВ bttonvoid clockButtonPressed () {if (cancelAlarm ()) return; inSubMenu =false; clockMode =(clockMode ==FORMAT_SET)? ЧАСЫ:(ClockButtonModesEnum) ((int) clockMode + 1); if (clockMode ==CLOCK) {Serial.println ("Время сохранения:" + String (newTime.Hour) + ":" + String (newTime.Minute)); Serial.println ("От:" + строка (час ()) + ":" + строка (минута ())); if (newTime.Year! =CalendarYrToTm (year ()) || newTime.Month! =month () || newTime.Day! =day () || newTime.Hour! =час () || newTime.Minute! =минута ()) {// Обновление времени Serial.println ("Обновление RTC"); newTime.Second =второй (); time_t t =makeTime (новое время); setTime (t); rtc.set (t); if (rtc.set (t)! =0) {Serial.println ("Установить время не удалось"); }} writeEepromData (); showTime (правда); } else {если (clockMode ==TIME_SET) {newTime.Year =CalendarYrToTm (год ()); newTime.Month =месяц (); newTime.Day =день (); newTime.Hour =час (); newTime.Minute =минута (); newTime.Second =второй (); Serial.println ("Время загрузки:" + строка (час ()) + ":" + строка (минута ())); } showSetup (true); }} // ---------------------------------------------- ----------------- // Обработка ENTER bttonvoid enterButtonPressed () {if (cancelAlarm ()) return; если (clockMode! =ЧАСЫ) {если (! inSubMenu) {timeSetMode =TIME_HOUR; dateSetMode =DATE_YEAR; alarmSetMode =ALARM_HOUR; formatSetMode =DAY_MONTH; inSubMenu =true; } else {переключатель (clockMode) {case TIME_SET:timeSetMode =(timeSetMode ==TIME_FORMAT)? ВРЕМЯ_ЧАС:(TimeSetMenuEnum) ((int) timeSetMode + 1); ломать; case DATE_SET:dateSetMode =(dateSetMode ==DATE_DAY)? ДАТА_ГОД:(DateSetMenuEnum) ((int) dateSetMode + 1); ломать; case ALARM_SET:alarmSetMode =(alarmSetMode ==ALARM_STATE)? ALARM_HOUR:(AlarmSetMenuEnum) ((int) alarmSetMode + 1); ломать; case FORMAT_SET:formatSetMode =(formatSetMode ==FONT_STYLE)? ДЕНЬ_МЕСЯЦ:(FormatSetMenuEnum) ((int) formatSetMode + 1); ломать; }} showSetup (true); } else {showDate (день (), месяц (), год ()); задержка (5000); }} // ---------------------------------------------- ----------------- // Обработка DOWN bttonvoid downButtonPressed () {if (cancelAlarm ()) return; переключатель (clockMode) {case TIME_SET:if (inSubMenu) {switch (timeSetMode) {case TIME_HOUR:newTime.Hour =(newTime.Hour + 24-1)% 24; ломать; case TIME_MIN:newTime.Minute =(newTime.Minute + 60-1)% 60; ломать; case TIME_FORMAT:EepromData.format12hr =! EepromData.format12hr; ломать; } showSetup (true); } ломать; case DATE_SET:if (inSubMenu) {switch (dateSetMode) {case DATE_YEAR:newTime.Year =((newTime.Year - 30 + 100) - 1)% 100 + 30; ломать; case DATE_MONTH:newTime.Month =((newTime.Month - 1 + 12) - 1)% 12 + 1; ломать; case DATE_DAY:uint8_t md =daysInMonth (newTime.Year, newTime.Month); newTime.Day =((newTime.Day - 1 + md) - 1)% md + 1; ломать; } showSetup (true); } ломать; case ALARM_SET:if (inSubMenu) {переключатель (alarmSetMode) {case ALARM_HOUR:EepromData.hours =(EepromData.hours + 24-1)% 24; ломать; case ALARM_MIN:EepromData.minutes =(EepromData.minutes + 60-1)% 60; ломать; case ALARM_STATE:EepromData.alarm =! EepromData.alarm; ломать; } showSetup (true); } ломать; case TUNE_SET:EepromData.tune =(EepromData.tune + NUM_OF_MELODIES - 1)% NUM_OF_MELODIES; showSetup (правда); ломать; case BRIGHT_SET:EepromData.brightness =(EepromData.brightness + MAX_INTENSITY - 1)% MAX_INTENSITY; mx.control (MD_MAX72XX ::ИНТЕНСИВНОСТЬ, EepromData.brightness); //0..MAX_INTENSITY showSetup (true); ломать; case FORMAT_SET:if (inSubMenu) {switch (formatSetMode) {case DAY_MONTH:EepromData.formatDmy =! EepromData.formatDmy; ломать; case FONT_STYLE:EepromData.squareFont =! EepromData.squareFont; ломать; }} showSetup (true); ломать; }} // ---------------------------------------------- ----------------- // Обработка UP bttonvoid upButtonPressed () {if (cancelAlarm ()) return; переключатель (clockMode) {case TIME_SET:if (inSubMenu) {switch (timeSetMode) {case TIME_HOUR:newTime.Hour =(newTime.Hour + 1)% 24; ломать; case TIME_MIN:newTime.Minute =(newTime.Minute + 1)% 60; ломать; case TIME_FORMAT:EepromData.format12hr =! EepromData.format12hr; ломать; } showSetup (true); } ломать; case DATE_SET:if (inSubMenu) {switch (dateSetMode) {case DATE_YEAR:newTime.Year =((newTime.Year - 30) + 1)% 100 + 30; ломать; case DATE_MONTH:newTime.Month =((newTime.Month - 1) + 1)% 12 + 1; ломать; case DATE_DAY:uint8_t md =daysInMonth (newTime.Year, newTime.Month); newTime.Day =(newTime.Day% md) + 1; ломать; } showSetup (true); } ломать; case ALARM_SET:if (inSubMenu) {переключатель (alarmSetMode) {case ALARM_HOUR:EepromData.hours =(EepromData.hours + 1)% 24; ломать; case ALARM_MIN:EepromData.minutes =(EepromData.minutes + 1)% 60; ломать; case ALARM_STATE:EepromData.alarm =! EepromData.alarm; ломать; } showSetup (true); } ломать; case TUNE_SET:EepromData.tune =(EepromData.tune + 1)% NUM_OF_MELODIES; showSetup (правда); ломать; case BRIGHT_SET:EepromData.brightness =(EepromData.brightness + 1)% MAX_INTENSITY; mx.control (MD_MAX72XX ::ИНТЕНСИВНОСТЬ, EepromData.brightness); //0..MAX_INTENSITY showSetup (true); ломать; case FORMAT_SET:if (inSubMenu) {switch (formatSetMode) {case DAY_MONTH:EepromData.formatDmy =! EepromData.formatDmy; ломать; case FONT_STYLE:EepromData.squareFont =! EepromData.squareFont; ломать; }} showSetup (true); ломать; }} // ---------------------------------------------- ----------------- // Отключаем будильник, если проигрывается tunebool cancelAlarm () {if (musicPlaying) {musicPlaying =false; alarmCancelled =alarmRinging; вернуть истину; } урожай(); return false;} // -------------------------------------------- ------------------- // Отображение меню настройки и мигание текущего выбранного элементаvoid showSetup (bool force) {setupDisplayState =setupDisplayState | сила; сила =сила || (миллис ()> setupTimeout); если (сила) {setupTimeout =миллис () + SETUP_FLASH_RATE; bool on =setupDisplayState; setupDisplayState =! setupDisplayState; mx.clear (); if (on ||! (clockMode ==TIME_SET &&! inSubMenu)) displayString (0,7, "TINE"); if (on ||! (clockMode ==TIME_SET &&inSubMenu &&timeSetMode ==TIME_HOUR)) displayNumber (0,13, newTime.Hour, 2, true); if (on ||! (clockMode ==TIME_SET &&inSubMenu &&timeSetMode ==TIME_MIN)) displayNumber (0,16, newTime.Minute, 2, true); if (on ||! (clockMode ==TIME_SET &&inSubMenu &&timeSetMode ==TIME_FORMAT)) displayString (0,19, (EepromData.format12hr)? "12HR":"24HR"); if (on ||! (clockMode ==DATE_SET &&! inSubMenu)) displayString (1,7, "DATE"); if (on ||! (clockMode ==DATE_SET &&inSubMenu &&dateSetMode ==DATE_YEAR)) displayNumber (1,13, tmYearToCalendar (newTime.Year), 4, true); if (on ||! (clockMode ==DATE_SET &&inSubMenu &&dateSetMode ==DATE_MONTH)) displayNumber (1,18, newTime.Month, 2, true); if (on ||! (clockMode ==DATE_SET &&inSubMenu &&dateSetMode ==DATE_DAY)) displayNumber (1,21, newTime.Day, 2, true); if (on ||! (clockMode ==ALARM_SET &&! inSubMenu)) displayString (2,6, "ALARN"); if (on ||! (clockMode ==ALARM_SET &&inSubMenu &&alarmSetMode ==ALARM_HOUR)) displayNumber (2,13, EepromData.hours, 2, true); if (on ||! (clockMode ==ALARM_SET &&inSubMenu &&alarmSetMode ==ALARM_MIN)) displayNumber (2,16, EepromData.minutes, 2, true); if (on ||! (clockMode ==ALARM_SET &&inSubMenu &&alarmSetMode ==ALARM_STATE)) displayString (2,19, (EepromData.alarm)? "ON":"OFF"); if (on ||! (clockMode ==TUNE_SET &&! inSubMenu)) displayString (3,7, "TUNE"); if (on ||! (clockMode ==TUNE_SET &&inSubMenu)) {переключатель (EepromData.tune) {case 0:displayString (3,13, "ELISE"); ломать; случай 1:displayString (3,13, «ДИАПАЗОН»); ломать; случай 2:displayString (3,13, «СОЛНЦЕ»); ломать; }} if (on ||! (clockMode ==BRIGHT_SET &&! inSubMenu)) displayString (4,1, "ЯРКОСТЬ"); if (on ||! (clockMode ==BRIGHT_SET &&inSubMenu)) displayNumber (4,13, EepromData.brightness, 0, false); if (on ||! (clockMode ==FORMAT_SET &&! inSubMenu)) displayString (5,0, "DATE ​​FORNAT"); if (on ||! (clockMode ==FORMAT_SET &&inSubMenu &&formatSetMode ==DAY_MONTH)) displayString (5,13, ​​(EepromData.formatDmy)? "DD-NN":"NN-DD"); if (on ||! (clockMode ==FORMAT_SET &&inSubMenu &&formatSetMode ==FONT_STYLE)) displayString (5,19, (EepromData.squareFont)? "FONT1":"FONT2"); mx.update (); }} // ---------------------------------------------- ----------------- // Отображение текущего времени на дисплее при изменении // force - всегда показывать время, даже если не измененоvoid showTime (bool force) {force =force || (последние секунды! =секунда ()); если (сила) {lastSeconds =второй (); showTime (час (), минута (), истина, истина, (секунда () &0x01), (clockMode! =ЧАСЫ ||! EepromData.format12hr)); }} // ---------------------------------------------- ----------------- // Отображение времени на дисплее // h - час // m - минута // he - час enable // me - минута включить // ce - двоеточие enable void showTime (int h, int m, bool he, bool me, bool ce, bool f24) {mx.clear (); если (он) {если (! f24 &&h> 12) {h =h - 12; } если (h> 9 || f24) {displayLargeDigit (0, h / 10); } displayLargeDigit (5, h% 10); } если (я) {displayLargeDigit (13, м / 10); displayLargeDigit (18, m% 10); } if (ce) {displayLargeDigit (11, 10); } mx.update ();} // ---------------------------------------- ----------------------- void showDate (int d, int m, int y) {#define XOFS 3 mx.clear (); если (EepromData.formatDmy) {displayDateDigit (XOFS + 0, d / 10); displayDateDigit (XOFS + 4, d% 10); displayDateDigit (XOFS + 8, 10); // двоеточие displayDateDigit (XOFS + 12, m / 10); displayDateDigit (XOFS + 16, m% 10); } еще {displayDateDigit (XOFS + 0, м / 10); displayDateDigit (XOFS + 4, m% 10); displayDateDigit (XOFS + 8, 10); // двоеточие displayDateDigit (XOFS + 12, d / 10); displayDateDigit (XOFS + 16, d% 10); } displayNumber (5, 10, y, 0, ложь); mx.update ();} // ----------------------------------------- ---------------------- // Записываем квадратную или маленькую цифру в зависимости от настройки конфигурации // x =от 0 до 23 // v =большая или квадратная цифра для display (0..10) void displayDateDigit (uint8_t x, uint8_t v) {if (EepromData.squareFont) {displaySquareDigit (x, v); } еще {displaySmallDigit (x, v); }} // ---------------------------------------------- ----------------- // Записываем битовую маску сегмента // x =от 0 до 23 // v =большая цифра для отображения (0..10) void displayLargeDigit (uint8_t x , uint8_t v) {if (x <24 &&v <11) {for (uint8_t row =0; row <6; row ++) {for (uint8_t col =0; col <6; col ++) {writePhysicalDigit (row, col + x, pgm_read_byte (&largeDigits [v] [row] [col]), ложь); }}}} // -------------------------------------------- ------------------- // Записываем битовую маску сегмента // x =от 0 до 23 // v =большая цифра для отображения (0..10) void displaySmallDigit ( uint8_t x, uint8_t v) {if (x <24 &&v <11) {for (uint8_t row =0; row <5; row ++) {for (uint8_t col =0; col <3; col ++) {writePhysicalDigit (row, col + x, pgm_read_byte (&smallDigits [v] [строка] [col]), ложь); }}}} // -------------------------------------------- ------------------- // Записываем битовую маску сегмента // x =от 0 до 23 // v =большая цифра для отображения (0..10) void displaySquareDigit ( uint8_t col, uint8_t v) {// Порядок сегментов defbca _ g uint8_t mask =ascii [v]; if (mask ==B00000000) {// Маска дефиса =B00000001; } if (маска &B00000100) {// сегмент A writePhysicalDigit (0, col + 0, 0xff, false); writePhysicalDigit (0, столбец + 1, 0xff, ложь); writePhysicalDigit (0, столбец + 2, 0xff, ложь); } if (маска &B00010000) {// сегмент B writePhysicalDigit (0, col + 2, 0xff, false); writePhysicalDigit (1, столбец + 2, 0xff, ложь); writePhysicalDigit (2, столбец + 2, 0xff, ложь); } if (маска &B00001000) {// сегмент C writePhysicalDigit (2, col + 2, 0xff, false); writePhysicalDigit (3, столбец + 2, 0xff, ложь); writePhysicalDigit (4, столбец + 2, 0xff, ложь); } if (маска &B10000000) {// сегмент D writePhysicalDigit (4, col + 0, 0xff, false); writePhysicalDigit (4, столбец + 1, 0xff, ложь); writePhysicalDigit (4, столбец + 2, 0xff, ложь); } if (маска &B01000000) {// сегмент C writePhysicalDigit (2, col, 0xff, false); writePhysicalDigit (3, столбец, 0xff, ложь); writePhysicalDigit (4, столбец, 0xff, ложь); } if (маска &B00100000) {// сегмент E writePhysicalDigit (0, col, 0xff, false); writePhysicalDigit (1, столбец, 0xff, ложь); writePhysicalDigit (2, столбец, 0xff, ложь); } if (маска &B00000001) {// сегмент D writePhysicalDigit (2, col + 0, 0xff, false); writePhysicalDigit (2, столбец + 1, 0xff, ложь); writePhysicalDigit (2, столбец + 2, 0xff, ложь); }} // ---------------------------------------------- ----------------- // Записываем строку символов uint8_t displayString (uint8_t row, uint8_t col, String s) {for (int i =0; i  0x5F) {c =0x3F; // Используется как пробел} c =c - 0x30; writePhysicalDigit (строка, столбец, ascii [c], истина); col =col + 1; }} // ---------------------------------------------- ----------------- // Записываем число uint8_t displayNumber (uint8_t row, uint8_t col, int number, int padding, booladingZeros) {if (padding ==0) {padding =(число> 0)? этаж (лог10 (число)) + 1:1; } col =col + padding; bool first =true; для (int я =0; я <заполнение; я ++) {col--; если (число! =0 || первый) {writePhysicalDigit (строка, столбец, ascii [число% 10], истина); число =число / 10; первый =ложь; } else {writePhysicalDigit (строка, столбец, ascii [(leadingZeros)? 0:0x0F], истина); }}} // --------------------------------------------- ------------------ // Записываем битовую маску сегмента // row =от 0 до 5 // col =от 0 до 23 // v =сегментная маска // erase =true заменит весь старый шаблон, false будет ИЛИ существующимvoid writePhysicalDigit (uint8_t row, uint8_t col, uint8_t v, bool erase) {if (row <6 &&col <24) {uint8_t dig =(col &0x03) + ((row &0x01)? 4:0); uint8_t dev =(столбец>> 2) * 3 + (строка>> 1); uint16_t c =((uint16_t) dev <<3) | digitMap [копать]; если (! стереть) {v =v | mx.getColumn (c); } mx.setColumn (c, v); }} // ---------------------------------------------- ----------------- // Возвращает дни в заданном году и месяце // В феврале 28, кроме високосного года или рубежа веков uint8_t daysInMonth (int y, int m) {return dom [m - 1] + ((m ==2 &&(y% 4) ==0 &&(y% 100)! =0)? 1:0);} // ------- -------------------------------------------------- ------ // Записать структуру EEPROMData в EEPROMvoid writeEepromData () {// Эта функция использует EEPROM.update () для выполнения записи, поэтому не перезаписывает значение, если оно не изменилось. EEPROM.put (EEPROM_ADDRESS, EepromData);} // -------------------------------------- ------------------------- // Считываем структуру EEPROMData из EEPROM, инициализируем, если необходимо, избегайте readEepromData () {// EEPROM EEPROM.get (EEPROM_ADDRESS, EepromData); //Serial.println("magic:"+ String (EepromData.magic, 16) +", будильник:"+ String (EepromData.alarm) +", время:"+ String (EepromData.hours) +":"+ Строка (EepromData.minutes) + ", 12ч:" + Строка (EepromData.format12hr) + ", яркость:" + Строка (EepromData.brightness)); if (EepromData.magic! =EEPROM_MAGIC) {Serial.println ("Инициализация EEPROM ..."); EepromData.magic =EEPROM_MAGIC; EepromData.alarm =false; EepromData.minutes =30; EepromData.hours =5; EepromData.format12hr =false; EepromData.brightness =8; EepromData.tune =0; EepromData.formatDmy =false; writeEepromData (); } Serial.println ("alarm:" + String (EepromData.alarm) + ", время:" + String (EepromData.hours) + ":" + String (EepromData.minutes) + ", 12hr:" + String (EepromData) .format12hr) + ", яркость:" + String (EepromData.brightness));} // ----------------------------- ---------------------------------- // Играть мелодиюint playSong (const uint16_t * melody) {// Играть каждая нота в мелодии до тех пор, пока не будет встречена нота END_OF_TUNE musicPlaying =true; int thisNote =0; uint16_t noteRaw =pgm_read_word (&мелодия [thisNote ++]); в то время как (musicPlaying &¬eRaw! =END_OF_TUNE) {testButtons (); урожай(); playNote (noteRaw); noteRaw =pgm_read_word (&мелодия [thisNote ++]); } // while delay (50);} // -------------------------------------- ------------------------- // Воспроизвести одну ноту. тип примечания. // например четвертная нота =1000/4, восьмая нота =1000/8 и т. д. uint16_t frequency =noteRaw &0x1FFF; uint16_t duration =(noteRaw &0xE000)>> 13; if (duration ==7) duration =8; uint16_t noteDuration =1800 / продолжительность; если (частота! =ОТДЫХ) {тон (ДИНАМИК, частота, noteDuration); } // чтобы различать ноты, установите минимальное время между ними. // длительность заметки + 30% вроде работает хорошо:uint16_t pauseBetweenNotes =(noteDuration * 13) / 10; задержка (pauseBetweenNotes); if (frequency! =REST) ​​{// останавливаем воспроизведение тона:noTone (SPEAKER); }} 
Digits.h C / C ++
 / * --------------------------------------------- ------ * Часы массива 7 сегментов * определяют каждую цифру в массиве 6x6 байт * ----------------------------- ---------------------*/ #pragma once//---------------------- -----------------------------// Standard MAX7219 wiring// Digit order 0,1,2,3,4,5/ *// Segment order _ abcdefg#define _______ B00000000#define __cd___ B00011000#define _bcde_g B00111101#define abcdefg B01111111#define __cdefg B00011111#define __c____ B00010000#define ab__efg B01100111#define abcd_fg B01111011#define abcde_g B01111101#define ab_defg B01101111#define _bc____ B00110000#define a__defg B01001111#define ____ef_ B00000110#define ___defg B00001111#define abc__fg B01110011#define a___ef_ B01000110#define _b_____ B00100000#define ab___f_ B01100010#define _bcd___ B00111000#define a___ef_ B01000110#define ab_____ B01100000#define ____e__ B00000100#define __cde_g B00011101# define a____f_ B01000010#define a_cdefg B01011111#define ___de__ B00001100#define _____f_ B00000 010#define ab___fg B01100011#define a__def_ B01001110#define __cde__ B00011100#define a___efg B01000111#define a__d___ B01001000#define abc____ B01110000#define _bc_ef_ B00110110#define ___def_ B00001110#define abc_ef_ B01110110#define _bcdef_ B00111110#define a__def_ B01001110#define abcd___ B01111000*///Segment order d e f b c a _ g#define _______ B00000000#define __cd___ B10001000#define _bcde_g B11011001#define abcdefg B11111101#define __cdefg B11101001#define __c____ B00001000#define ab__efg B01110101#define abcd_fg B10111101#define abcde_g B11011101#define ab_defg B11110101#define _bc____ B00011000#define a__defg B11100101#define ____ef_ B01100000#define ___defg B11100001#define abc__fg B00111101#define a___ef_ B01100100#define _b_____ B00010000#define ab___f_ B00110100#define _bcd___ B10011000#define a___ef_ B01100100#define ab_____ B00010100#define ____e__ B01000000#define __cde_g B11001001#define a____f_ B00100100#define a_cdefg B11101101#define ___de__ B11000000#define _____f _ B00100000#define ab___fg B00110101#define a__def_ B11100100#define __cde__ B11001000#define a___efg B01100101#define a__d___ B10000100#define abc____ B00011100#define _bc_ef_ B01111000#define ___def_ B11100000#define abc_ef_ B01111100#define _bcdef_ B11111000#define a__def_ B11100100#define abcd___ B10011100//Square Numbers//ASCII Character Set//Numbers 0 - 9//Letters A - Z//Segment order d e f b c a _ guint8_t ascii[] ={ B11111100, B00011000, B11010101, B10011101, B00111001, B10101101, B11101101, B00011100, B11111101, B10111101, B00000000, B00000000, B00000000, B00000001, B00000000, B00000000, B00000000, B01111101, B11101001, B11100100, B11011001, B11100101, B01100101, B10111101, B01111001, B00011000, B11011000, B00000000, B11100000, B00000000, B01001001, B11001001, B01110101, B00000000, B01000001, B10101101, B11100001, B11001000, B00000000, B00000000, B00000000, B10111001, B00000000, B11001100, B01010001, B10011100, B00000000, B10000000};//Digit sequence for each device (MAX7219)u int8_t digitMap[] ={5, 2, 6, 4, 1, 7, 3, 0};//------------------------------------------------------------// Digits using logical coordinates//------------------------------------------------------------const int8_t largeDigits[11][6][6] PROGMEM ={ { //0 { _______, _______, __cd___, _bcde_g, abcdefg, __cdefg }, { _______, __c____, abcdefg, ab__efg, abcd_fg, abcdefg }, { _______, abcde_g, ab_defg, _______, _bc____, a__defg }, { _______, abcdefg, ____ef_, __c____, abcdefg, ____ef_ }, { _______, abcdefg, __cdefg, abcdefg, a___efg, _______ }, { _______, abc__fg, abcdefg, ab__efg, _______, _______ } }, { //1 { _______, _______, _______, __c____, abcdefg, __cdefg }, { _______, _______, _______, abcdefg, abcdefg, ____ef_ }, { _______, _______, _bcde_g, abcdefg, a__defg, _______ }, { _______, _bc____, abcdefg, abcdefg, ____ef_, _______ }, { _______, abcdefg, abcdefg, a___ef_, _______, _______ }, { _b_____, abcdefg, abcdefg, _______, _______, _______ } }, { //2 { _______, _______, __cd___, _b cde_g, abcdefg, __cdefg }, { _______, _bc____, abcdefg, ab___f_, abcd_fg, abcdefg }, { _______, _______, _______, _bcd___, abcdefg, a___ef_ }, { _______, _______, _bcde_g, abcdefg, a___ef_, _______ }, { __c____, abcdefg, abcdefg, a___ef_, _______, _______ }, { _b_____, abc__fg, abcdefg, abcdefg, ab__efg, _______ } }, { //3 { _______, _______, __cd___, abcdefg, abcdefg, __cdefg }, { _______, _b_____, abcdefg, ab___f_, abcd_fg, abcdefg }, { _______, _______, __cd___, _bcde_g, abcdefg, a___ef_ }, { _______, _______, ab_____, abc__fg, abcdefg, ____e__ }, { _______, __cd___, __cde_g, _bcde_g, abcdefg, ____ef_ }, { _b_____, abc__fg, abcdefg, abcdefg, a____f_, _______ } }, { //4 { _______, _______, _bcd___, abcdefg, __c____, abcdefg }, { _______, __c____, abcdefg, a___ef_, abcde_g, a__defg }, { _______, abcde_g, abcdefg, _bcd___, abcdefg, ____ef_ }, { __c____, abcdefg, abcdefg, abcdefg, abcdefg, _______ }, { _______, _______, __c____, abcdefg, ____ef_, _______ }, { _______, _______, abcdefg, ab__efg, _______, _______ } }, { //5 { _______, _______, _bcde_g, abcdefg, abcdefg, abcdefg }, { _______, _bc____, abcdefg, a_cdefg, ___de__, _______ }, { _______, _______, abc__fg, abcdefg, abcdefg, ____ef_ }, { _______, _______, _______, _bc____, abcdefg, ____ef_ }, { _______, __cde_g, __cde_g, _bcde_g, abcdefg, _____f_ }, { _b_____, abcdefg, abcdefg, ab__efg, a____f_, _______ } }, { //6 { _______, _______, _______, __cd___, abcdefg, ____ef_ }, { _______, _______, _bcde_g, abcdefg, a____f_, _______ }, { _______, _bcd___, abcdefg, abcdefg, abcdefg, ____e__ }, { __c____, abcdefg, a___ef_, ab_____, abcdefg, ____ef_ }, { _bc____, abcdefg, __cdefg, _bcde_g, abcdefg, _______ }, { _______, abc__fg, abcdefg, ab__efg, _______, _______ } }, { //7 { _______, _bc____, abcdefg, abcdefg, abcdefg, __cdefg }, { _______, _b_____, ab___fg, ab___fg, abcdefg, abcdefg }, { _______, _______, _______, _bcde_g, abcdefg, a___ef_ }, { _______, _______, _bcde_g, abcdefg, ab__efg, _______ }, { _______, _bcde_g, abcdefg, a___ef_, _______, _______ }, { _b_____, abcdefg, abcdefg, _______, _______, _______ } }, { //8 { _______, _______, __cd___, abcdefg, abcdefg, __cdefg }, { _______, _bc____, abcdefg, ab___f_, abcd_fg, abcdefg }, { _______, _b_____, abcdefg, _bcde_g, abcdefg, a___ef_ }, { _______, _bcde_g, ab__efg, abc__fg, abcdefg, ____e__ }, { _bc____, abcdefg, __cde_g, _bcde_g, abcdefg, ____ef_ }, { _______, abc__fg, abcdefg, abcdefg, a____f_, _______ } }, { //9 { _______, _______, __cde_g, abcdefg, __cdefg, ___de__ }, { _______, _bcd___, abcdefg, ab___fg, abcd_fg, abcdefg }, { _______, abcdefg, a_cdefg, __cde__, abcdefg, a__defg }, { _______, ab_____, abcd_fg, abcdefg, abcdefg, _____f_ }, { _______, __cd___, abcdefg, ab__efg, _______, _______ }, { _b_____, abcdefg, a___ef_, _______, _______, _______ } }, { //Colon { _______, _______, _______, _______, _______, _______ }, { _______, __cde_g, _______, _______, _______, _______ }, { _______, _______, _______, _______, _______, _______ }, { ___ ____, _______, _______, _______, _______, _______ }, { __cde_g, _______, _______, _______, _______, _______ }, { _______, _______, _______, _______, _______, _______ } }};const int8_t smallDigits[11][5][3] PROGMEM ={ { //0 { a___ef_, a__d___, abc____ }, { _bc_ef_, _______, _bc_ef_ }, { _bc_ef_, _______, _bc_ef_ }, { _bc_ef_, _______, _bc_ef_ }, { ___def_, a__d___, _bcd___ } }, { //1 { _______, abc_ef_, _______ }, { _______, _bc_ef_, _______ }, { _______, _bc_ef_, _______ }, { _______, _bc_ef_, _______ }, { _______, _bcdef_, _______ } }, { //2 { a__def_, a__d___, abc____ }, { _______, _______, _bc_ef_ }, { a___ef_, a__d___, _bcd___ }, { _bc_ef_, _______, _______ }, { ___def_, a__d___, abcd___ } }, { //3 { a__def_, a__d___, abc____ }, { _______, _______, _bc_ef_ }, { _______, a__def_, _bc____ }, { _______, _______, _bc_ef_ }, { a__def_, a__d___, _bcd___ } }, { //4 { abc_ef_, _______, abc_ef_ }, { _bc_ef_, _______, _bc_ef_ }, { ___def_, a__d___, _bc____ }, { _______, _______, _bc_ef_ }, { _______, _______, _bcdef_ } }, { //5 { a___ef_, a__d___, abcd___ }, { _bc_ef_, _______, _______ }, { ___def_, a__d___, abc____ }, { _______, _______, _bc_ef_ }, { a__def_, a__d___, _bcd___ } }, { //6 { a___ef_, a__d___, abcd___ }, { _bc_ef_, _______, _______ }, { ____ef_, a__d___, abc____ }, { _bc_ef_, _______, _bc_ef_ }, { ___def_, a__d___, _bcd___ } }, { //7 { a__def_, a__d___, abc____ }, { _______, _______, _bc_ef_ }, { _______, _bc_ef_, _______ }, { _______, _bc_ef_, _______ }, { _______, _bcdef_, _______ }, }, { //8 { a___ef_, a__d___, abc____ }, { _bc_ef_, _______, _bc_ef_ }, { ____ef_, a__d___, _bc____ }, { _bc_ef_, _______, _bc_ef_ }, { ___def_, a__d___, _bcd___ } }, { //9 { a___ef_, a__d___, abc____ }, { _bc_ef_, _______, _bc_ef_ }, { ___def_, a__d___, _bc____ }, { _______, _______, _bc_ef_ }, { a__def_, a__d___, _bcd___ } }, { //Hyphen { _______, _______, _______ }, { _______, _______, _______ }, { a__def_, a__d___, abcd___ }, { _______, _______, _______ }, { _______, _____ __, _______ } }};
Tunes.hC/C++
 Нет предварительного просмотра (только загрузка). 
Button.hC/C++
/*Class:ButtonAuthor:John Bradnam ([email protected])Purpose:Arduino library to handle buttons*/#pragma once#include "Arduino.h"#define DEBOUNCE_DELAY 10//Repeat speed#define REPEAT_START_SPEED 500#define REPEAT_INCREASE_SPEED 50#define REPEAT_MAX_SPEED 50class Button{ public://Simple constructor Button(int pin); Button(int name, int pin); Button(int name, int pin, int analogLow, int analogHigh, bool activeLow =true); //Background function called when in a wait or repeat loop void Background(void (*pBackgroundFunction)()); //Repeat function called when button is pressed void Repeat(void (*pRepeatFunction)()); //Test if button is pressed bool IsDown(void); //Test whether button is pressed and released //Will call repeat function if one is provided bool Pressed(); //Return button state (HIGH or LOW) - LOW =Pressed int State(); //Return button name int Name(); private:int _name; int _pin; bool _range; int _low; int _high; bool _activeLow; void (*_repeatCallback)(void); void (*_backgroundCallback)(void);};
Button.cppC/C++
/*Class:ButtonAuthor:John Bradnam ([email protected])Purpose:Arduino library to handle buttons*/#include "Button.h"Button::Button(int pin){ _name =pin; _pin =pin; _range =false; _low =0; _high =0; _backgroundCallback =NULL; _repeatCallback =NULL; pinMode(_pin, INPUT_PULLUP);}Button::Button(int name, int pin){ _name =name; _pin =pin; _range =false; _low =0; _high =0; _backgroundCallback =NULL; _repeatCallback =NULL; pinMode(_pin, INPUT_PULLUP);}Button::Button(int name, int pin, int analogLow, int analogHigh, bool activeLow){ _name =name; _pin =pin; _range =true; _low =analogLow; _high =analogHigh; _activeLow =activeLow; _backgroundCallback =NULL; _repeatCallback =NULL; pinMode(_pin, INPUT);}//Set function to invoke in a delay or repeat loopvoid Button::Background(void (*pBackgroundFunction)()){ _backgroundCallback =pBackgroundFunction;}//Set function to invoke if repeat system requiredvoid Button::Repeat(void (*pRepeatFunction)()){ _repeatCallback =pRepeatFunction;} bool Button::IsDown(){ if (_range) { int value =analogRead(_pin); return (value>=_low &&value <_high); } else { return (digitalRead(_pin) ==LOW); }}//Tests if a button is pressed and released// returns true if the button was pressed and released// if repeat callback supplied, the callback is called while the key is pressedbool Button::Pressed(){ bool pressed =false; if (IsDown()) { unsigned long wait =millis() + DEBOUNCE_DELAY; while (millis() =time) { _repeatCallback(); unsigned long faster =speed - REPEAT_INCREASE_SPEED; if (faster>=REPEAT_MAX_SPEED) { speed =faster; } time =millis() + speed; } } pressed =true; } } return pressed;}//Return current button stateint Button::State(){ if (_range) { int value =analogRead(_pin); if (_activeLow) { return (value>=_low &&value <_high) ? LOW :HIGH; } else { return (value>=_low &&value <_high) ? HIGH :LOW; } } else { return digitalRead(_pin); }}//Return current button nameint Button::Name(){ return _name;}
Hardware_Test_V1.zipC/C++
Hardware test sketch - Turns on all segments and tests speaker
No preview (download only).

Изготовленные на заказ детали и корпуса

Схема

Schematic for each MAX7219 (repeated 18 times) Holds six 7 segment 4 digit displays (6 boards required) PCB files in Eagle format eagle_files_KPhUOj6Ezv.zip

Производственный процесс

  1. Часы видения Arduino pov
  2. Простые часы со словами (Arduino)
  3. Часы Arduino с исламским временем молитв
  4. Основные часы
  5. Перекидные часы Arduino с одной светодиодной матрицей
  6. Управление светодиодной матрицей с помощью Arduino Uno
  7. eDOT - точные часы и метеостанция на базе Arduino
  8. Мини-радар с Arduino
  9. Отображение температуры Arduino OLED с часами реального времени
  10. Простой будильник с DS1302 RTC