Это цифровые часы, оснащенные четырьмя большими светодиодными дисплеями, которые показывают время в формате, который вы можете прочитать с другого конца комнаты:
Большие часы времени, основанные на ATtiny3216, используют гигантские 7-сегментные светодиодные дисплеи. Коробок для масштаба.
Введение
Эти часы были были задуманы как идея использования 2.3" одноразрядных 7-сегментных индикаторов, которые я видел на AliExpress. Я решил, что было бы интересно иметь часы, которые можно ясно видеть издалека. Дисплеи бывают разных цветов и напряжений; я выбрал красные версии 4V, чтобы я мог управлять ими непосредственно от линий ввода/вывода микроконтроллера без необходимости использования транзисторов. Мои дисплеи имеют общий катод, но при небольшом изменении в программе можно работать и с дисплеями собщим анодом.
Схема
Вот такая схема:
Схема больших часов времени, основанная на ATtiny3216.
Схема основана на одном из новых контроллеров ATtiny, которые имеют встроенный счетчик часов реального времени, который можно тактироватьс внешнего кварца на 32.768 кГц. Я выбрал ATtiny3216, 20-контактный микроконтроллер с 32кбайт флэш-памяти, который имеет достаточно линий ввода/вывода, чтобы управлять дисплеями простым способом, не прибегая к методу чарлиплексинга.
Токоограничивающие резисторы последовательно соединены с каждым сегментом для обеспечения постоянной яркости дисплея. Кнопка предусмотрена, чтобы устанавливать время, также установлен разъем, подключенный выводу UPDI для программирования ATtiny3216, и вохд, RX, в случае, если вы захотите подключить часы к модулю GPS.
Сборка
Общий размер дисплея часов составляет 95 мм х 140 мм. Печатная плата, достаточно большая, чтобы вместить все четыре дисплея, была бы дорогой, поэтому часы собраны на трех небольших печатных платах, которые соединяются вместе двумя отрезками плоского кабеля:
ATtiny3216 в корпусе SOIC, резисторы и конденсатор размера 0805 установлены на главной плате.
Задняя часть главной главной платы часов.
Я случайно спроектровал кнопку SMD на неправильной стороне печатной платы, поэтому мне пришлось просверлить два отверстия и использовать кнопку с выводами; я исправил эту ошибку это на винальных платах, выложенных ниже.
Я установил восемь 5-контактных разъемов для подключения индикаторов, но вы можете также просто припаять их.
Общее потребление часов составляет около 25 мА; я питаю часы от большого литий-полимерного аккумулятора, которого хватает на несколько дней работы, но также можно использовать и внешний блок питания на 5 вольт.
Программа
Отображение цифр
Индикация на 7-сегментных индикаторах обновляется из четырех значений в масиве Digits[], используя прерывания, генерируемые таймером / счетчиком часов. Например:
Digits[0] = 1;
Digits[1] = 2;
Digits[2] = 3;
Digits[3] = 4;
будет отображаться "1234". Дисплей настраивается с помощью обычной функции DisplaySetup():
void DisplaySetup () { // Драйверы сегментов ВОРОТА.DIR = PIN4_bm | PIN5_bm | PIN6_bm | PIN7_bm; / / установить PA4-PA7 в качестве выходных данных PORTC.DIR = PIN0_bm | PIN1_bm | PIN2_bm | PIN3_bm; / / установить PC0-PC3 в качестве выходов // Драйверы цифр PORTB.DIR = PIN0_bm | PIN1_bm | PIN4_bm | PIN5_bm; / / установить выходы PB0 PB1 PB4 PB5 PORTB.OUT = PIN0_bm / PIN1_bm | PIN4_bm | PIN5_bm; / / установить PB0 PB1 PB4 PB5 high // Настройка таймера / счетчика для мультиплексирования дисплея TCB0.CCMP = 19999; / / разделить 5 МГц на 20000 = 250 Гц TCB0.CTRLA = TCB_CLKSEL_CLKDIV1_gc | TCB_ENABLE_bm; / / включить таймер, разделить на 1 TCB0.CTRLB = 0; / / режим периодического прерывания TCB0.INTCTRL = TCB_CAPT_bm; / / включить прерывание }
Это во-первых делает все сегментные и цифровые линии выходами, и устанавливает четыре выхода PB0, PB1, PB4 и PB5 в высокий уровень, чтобы погасить цифры.
Таймер затем настраивается в режиме периодического прерывания, генерируя прерывание на частоте 250 Гц для мультиплексирования дисплеев.
Подпрограмма службы прерывания часов просто очищает прерывание и вызывает функцию DisplayNextDigit():
ISR(TCB0_INT_vect) { TCB0.INTFLAGS = TCB_CAPT_bm; / / снимает флаг прерывания DisplayNextDigit(); }
Текущая цифра хранится в глобальной переменной Digit . Каждый вызов функции DisplayNextDigit () выключает текущую цифру, задает сегменты для следующей цифры, а затем включает ее:
void DisplayNextDigit()
{
PORTB.OUTSET = 1<<Pins[Digit]; // Take digit high
Digit = (Digit+1) % Ndigits;
uint8_t segs = charArray[Digits[Digit]];
PORTA.OUT = segs & 0xF0; // Set PA4-PA7
PORTC.OUT = segs & 0x0F; // Set PC0-PC3
PORTB.OUTCLR = 1<<Pins[Digit]; // Take digit low
}
Кнопка установки времени
Кнопка Set Time позволяет установить часы на правильное время. При удержании ее нажатой, значение часов увеличивается дважды в секунду. При отпускании и снова нажатии накнопку, значение минут увеличивается два раза в секунду.
Кнопка использует порт ввода-вывода PA1 и подтягивается к питанию:
void ButtonSetup ()
{ PORTA.PIN1CTRL = PORT_PULLUPEN_bm; // PA1 input pullup
}
Состояние кнопки считывается методом ButtonDown (), который возвращает true, если кнопка нажата:
boolean ButtonDown ()
{
return (PORTA.IN & PIN1_bm) == 0; // True if button pressed
}
Часы реального времени
Периферийное устройство часов реального времени настроено как периодический таймер прерывания (PIT), генерирующий регулярное прерывание. В этом проекте для прерывания используется делитель 16384, который делит частоту кварца 32.768 кГц, чтобы дать два прерывания в секунду; это позволяет прерыванию увеличивать значений часов или минут дважды в секунду при настройке времени.
Подпрограмма обработки прерывания вычисляет текущее время в часах и минутах из глобальной переменной Time in half-seconds. Если кнопка Set Time не нажата, то она увеличивает время и обновляет массив Digits[] текущими значениями:
ISR(RTC_PIT_vect)
{ int minutes, hours;
RTC.PITINTFLAGS = RTC_PI_bm; // Clear interrupt flag
minutes = (Time / 120) % 60;
hours = (Time / 7200) % 12;
if (ButtonDown())
{ if (ButtonState == 1 || ButtonState == 3)
{ ButtonState = (ButtonState + 1) % 4;
}
if (ButtonState == 0)
{ // Advance hours
hours = (hours + 1) % 12;
minutes = 0;
}
else { // Advance minutes
minutes = (minutes + 1) % 60;
}
Time = (unsigned long)hours * 7200 + minutes * 120;
}
else
{ // Button up
if (ButtonState == 0 || ButtonState == 2)
{ ButtonState = (ButtonState + 1) % 4;
}
Time = (Time + 1) % 172800; // Wrap around after 24 hours
}
Digits[0] = (hours+1)/10;
Digits[1] = (hours+1)%10;
Digits[2] = minutes/10;
Digits[3] = minutes%10;
}
Нажатие кнопки Set Time приводит к переходу переменной ButtonState между двумя состояниями: 1, которое изменяет значения часов, и 3, которое изменяет значения минут. В промежуточных состояниях 0 и 2 часы работают нормально.
Компиляция программы
Скомпилируйте программу с помощью megaTiny Core от Spence Konde's на GitHub. Выберите ATtiny3216/1616/1606/816/806/416/406 в разделе megaTinyCore в меню платы. Убедитесь, что последующие параметры установлены следующим образом (игнорируйте любые другие параметры):
Чип: "ATtiny3216"
тактовая частота:" 5 МГц "
программатор:" jtag2updi (megaTinyCore)"
Затем загрузите программу в контроллер с помощью программатора UPDI. В качестве альтернативы вы можете сделать программатор UPDI из Arduino Uno или другой платы на основе ATmega328P, как описано здесь.
Вы можете игнорировать ошибку "не удается найти Флэш-и загрузочные накопители в описании".
Вот весь текст программы: bigtime.txt .
Изготовление печатной платы
Скачать файлы Eagle для печатных плат часов с GitHub : https://github.com/technoblogy/big-time .
Дальнейшие предложения
Хотя я не использовал их в своем прототипе, десятичные точки индикаторов подключены к PA7 на плате, поэтому вы можете изменить программу, чтобы использовать их, например, чтобы мигать ими каждую секунду.
Также порт PA2 (RX) подключен к разъему на плате, для возможности расширения функция часов, например, подключения модуля GPS, чтобы автоматически корректировать время. Вы также можете использовать этот вход для запуска, остановки или сброса таймера.
Перевод с английского