Контакти

Схема годин на мікроконтролері avr. Прості годинник на мікроконтролері. Відео роботи пристрою на Ютуб-каналі

Іноді корисно мати в системі годинник відлічує час в секундах, та ще з високою точністю. Часто для цих цілей застосовують спеціальні мікросехми RTC (Real Time Clock) на зразок. Ось тільки це додатковий корпус, та й коштує вона часом як сам МК, хоча можна обійтися і без неї. Тим більше, що багато МК мають вбудований блок RTC. У AVR його справді немає, але там є асинхронний таймер, службовець напівфабрикатом для виготовлення годин.

Насамперед нам потрібен часовий кварц на 32768Герц.

Чому кварц саме 32768Гц і чому його звуть годинним? Та все дуже просто - 32768 є ступенем двійки. Два в п'ятнадцятій ступені. Тому п'ятнадцяти розрядний лічильник, цокаючий з частотою 32768 Гц, буде переповнюватися раз в секунду. Це дає можливість будувати годинник на звичайній логічної рассипуху без будь-яких проблем. А в микроконтроллере AVR організувати годинник з секундами можна майже без використання мозку, на рефлексах периферії.

Асинхронний режим таймера
Пам'ятайте як працюють таймери? Тактова частота з основного тактового генератора (RC зовнішня чи внутрішня, зовнішній кварц або зовнішній генератор) надходить на предделителя, а з виходу предделителя вже клацає значеннями регістра TCNT. Або сигнал на вхід йде з рахункового входу Тn і також клацає регістром TCNT

Для цього на висновки TOSC2 і TOSC1 вішається кварцовий резонатор. Низькочастотний, зазвичай це часовий кварц на 32768Гц. На він змонтований праворуч від контролера і підключається перемичками. причому тактова частота процесора повинна бути вище як мінімум в чотири рази. У нас тактова від внутрішнього генератора 8МГц, так що нас ця умова взагалі не парить :)

І не потрібно вираховувати кількість тактів основного кварцу, а якщо його немає, то морочитися на плаваючу частоту вбудованого RC генератора. Часовий кварц має куди більш компактні розміри ніж звичайний кварц, та й коштує дешевше.


Також важливим є той факт, що асинхронний таймер може тікати сам по собі, від часового кварцу, адже тактова частота процесора йому не потрібна, а це значить тактирование ядра контролера (саме жручее, що у нього є) можна відключити, загнавши процесор в сплячку, істотно знизивши споживання енергії і прокидаючись тільки по переповнення таймера (1-2 рази на секунду), щоб записати нові свідчення часу.

конфігурація
Для включення треба всього лише встановити біт AS2 регістра ASSR - і все, таймер працює в асинхронному режимі. Але є тут одна фіча яка мені коштувала багато головняков свого часу. Справа в тому, що при роботі від свого кварцу всі внутрішні регістри таймера починають синхронізуватися за своїм же кварцу. А він повільний і основна програма може змінювати вже введене значення набагато швидше ніж воно буде опрацьовано таймером.

Тобто, наприклад, попередньо встановити ти значення TCNT2, таймер на своїй 32кГц молотарці його ще навіть прожувати не встиг, а твій алгоритм вже пробіг і знову туди що то записав - в результаті в TCNT2 напевно потрапить сміття. Щоб цього не сталося запис буфферізіруется. Тобто це ти думаєш, що записав дані в TCNT2, але насправді вони потрапляють під тимчасовий регістр і в рахунковий потраплять тільки через три такту повільного генератора.

Також буфферізіруется регістри порівняння OCR2 і регістр конфігурації TCCR2

Як дізнатися дані вже внесли в таймер або висять в проміжних осередках? Та дуже просто - по прапорам в регістрі ASSR. Це біти TCN2UB, OCR2UB і TCR2UB - кожен відповідає за свій регістр. Коли ми, наприклад, записуємо значення в TCNT2 то TCNUB стає 1, а як тільки наше число з проміжного регістра таки перейшло в реальний рахунковий регістр TCNT2 і початок уже тікати, то цей прапор автоматом скидається.

Таким чином, в асинхронному режимі, при записі в регістри TCNT2, OCR2 і TCCR2 спочатку потрібно перевіряти прапори TCN2UB, OCR2UB і TCR2UB і запис проводити тільки якщо вони дорівнюють нулю. Інакше результат може бути непередбачуваним.

Так, ще один важливий момент - при перемиканні між синхронним і асинхронним режимом значення в рахунковому регістрі TCNT може побитися. Так що для надійності перемикається так:

  • Забороняємо переривання від цього таймера
  • Перемикаємося в потрібний режим (синхронний або асинхронний)
  • Заново налаштовуємо таймер як нам потрібно. Тобто виставляємо попередню TCNT2 якщо треба, заново налаштовуємо TCCR2
  • Якщо перемикається в асинхронний режим, то чекаємо поки всі прапори TCN2UB, OCR2UB і TCR2UB будуть скинуті. Тобто настройки застосували і готові до роботи.
  • Скидаємо прапори переривань таймера / лічильника. Оскільки при всіх цих пертурбацій вони можуть випадково встановитися
  • Дозволяємо переривання від цього таймера

Недотримання цієї послідовності веде до непередбачуваних і важко що виявляється глюків.

Сплячі режими і асинхронний таймер
Оскільки асинхронний таймер часто використовується в різних зберігаючих режимах, то тут виникає одна особливість, розкладають ціле поле з граблів.

Суть в тому, що таймер, що працює від повільного кварцу, не встигає за головним процесором, а в тому дофіга залежностей від периферії - ті ж переривання, наприклад. І коли проц спить, то ці залежності не можуть реалізуватися, в результаті виникають глюки на кшталт непрацюючих переривань або пошкоджених значень в регістрах. Так що логіка роботи з асинхронним таймером і сплячим режимом повинна бути побудована таким чином, щоб між пробудженням і сваліваенім в сплячку асинхронний таймер встиг відпрацювати кілька своїх тактів і виконав всі свої справи.

приклади:
Контролер використовує режим енергозбереження і відключення ядра, а прокидається по перериваннях від асинхронного таймера. Тут треба враховувати той факт, що якщо ми будемо змінювати значення регістрів TCNT2, OCR2 і TCCR2, то відхід у сплячку потрібно делат ТІЛЬКИ після того, як прапори TCN2UB, OCR2UB і TCR2UB впадуть. Інакше вийде така лажа - асинхронний таймер ще не встиг забрати дані з проміжних регістрів (він же повільний, в сотні разів повільніше ядра), а ядро \u200b\u200bвже вирубилася. І якби ж то конфігурація нова не застосовуючи, це дурниця.

Гірше те, що на час модифікацій регістрів TCNT або OCR блокується робота блоку порівняння, а значить якщо ядро \u200b\u200bзасне раніше, то блок порівняння так і не запуститься - нікому його включити буде. І у нас пропаде переривання в порівнянні. Що черевато тим, що подія ми прогавили і будемо їх втрачати до наступного пробудження зі сплячки.
А якщо контролер будиться перериванням в порівнянні? То він засне остаточно. От чорт!
Ось і лови такий глюк потім.

Так що перед відходом в режими енергозбереження треба обов'язково дати асинхронного таймера прожувати введені значення (якщо вони були введені) і дочекатися обнулення прапорів.

Ще один прикол з асинхронним режимом і енергозбереженням полягає в тому, що підсистема переривань при виході зі сплячки стартує за 1 такт повільного генератора. Так що навіть якщо ми нічого не змінювали, то назад в сплячку звалюватися не можна - НЕ прокинемося, тому що переривання не встигнуть запуститися.

Так що вихід зі сплячки і засипання по перериванню асинхронного таймера має бути в такому вигляді:

  • прокинулися
  • Що то зробили потрібне
  • заснули

І тривалість операції між Прокинулися і Заснули НЕ ПОВИННА БУТИ МЕНШЕ ніж один тик асинхронного таймера. Інакше анабіоз буде вічним. Можеш delay поставити, а можеш зробити як даташит радить:

  • прокинулися
  • Що то зробили потрібне
  • Заради приколу записали що то в будь-який з буфферізіуемих регістрів. Наприклад, в TCNT було 1, а ми ще раз 1 записали. Нічого не змінилося, але сталася запис, піднявся прапор TCN2UB який протримається гарантовано три такту повільного генератора.
  • Почекали поки прапор впаде
  • А поснули.

Також не рекомендується при виході зі сплячки відразу ж читати значення TCNT - можна вважати лажу. Краще почекати один тик асинхронного таймера. Або зробити прикол із записом в регістр і очікуванням поки прапор спаде, як було написано вище.

Ну і останній, але важливий, момент - після подачі живлення, або виходу з глибокої сплячки, з відключенням не тільки ядра, а взагалі всієї периферії, користуватися повільним генератором настійно рекомендується не раніше ніж через 1 секунду (Не мілісекунду, а ціла секунда!). Інакше генератор може ще бути нестабільним і в регістрах буде ще каша і сміття.

І, на завершення статті, невеликий приклад. Запуск асинхронного таймера на Atmega16 (Як полігон використовується плата)

Проект типовий, на базі диспетчера, одне лише відмінність - діспечтер перекинутий на таймер0, щоб звільнити таймер2.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 int main (void) (InitAll (); // ініціалізувавши периферію InitRTOS (); // ініціалізувавши ядро RunRTOS (); // Старт ядра. UDR \u003d "R"; // Маркер старту, для налагодження SetTimerTask (InitASS_Timer 1000); // Так як таймер в асинхронному режимі // запускається повільно, то робимо // Витяг для запуску ініціалізації таймера. while (1) // Головний цикл диспетчера (Wdt_reset (); // Скидання собачого таймера TaskManager (); // Виклик диспетчера ) Return 0; )

int main (void) (InitAll (); // ініціалізувавши периферію InitRTOS (); // ініціалізувавши ядро \u200b\u200bRunRTOS (); // Старт ядра. UDR \u003d "R"; // Маркер старту, для налагодження SetTimerTask (InitASS_Timer 1000) ; // Так як таймер в асинхронному режимі // запускається повільно, то робимо // Витяг для запуску ініціалізації таймера. while (1) // Головний цикл диспетчера (wdt_reset (); // Скидання собачого таймера TaskManager (); // Виклик диспетчера) return 0;)

Сама процедура ініціалізації таймера в асинхронному режимі зроблена у вигляді кінцевого автомата. При першому запуску вона зводить біт асинхронного режиму і робить приготування, після запускає сама себе знову ж, через диспетчер, щоб дати можливість ще чого небудь проскочити в черзі, не блокіруюя систему на очікування.

При наступних входах перевіряються флагової біти готовності регістрів таймера. Якщо вони все по нулях, то ми про всяк випадок зануляют прапори переривання таймера, щоб не було глюків і помилкових спрацьовувань, а потім дозволяємо потрібне нам переривання. І виходимо.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 void InitASS_Timer (void) (if (ASSR & (1<< AS2) ) // Якщо це другий вхід то (If (ASSR & (1<< TCN2UB | 1 << OCR2UB | TCR2UB) ) // перевіряємо чи є хоч один біт флагової (SetTask (InitASS_Timer); // Якщо є, то відправляємо на повторний цикл очікування ) else // Якщо все чисто, то можна запускати переривання (TIFR | \u003d 1<< OCF2 | 1 << TOV2; // Скидаємо прапори переривань, про всяк випадок. TIMSK | \u003d 1<< TOIE2; // Дозволяємо переривання по переповнення return; )) TIMSK & \u003d ~ (1<< OCIE2 | 1 << TOIE2) ; // Забороняємо переривання таймера 2 ASSR \u003d 1<< AS2; // Включаємо асинхронний режим TCNT2 \u003d 0; TCCR2 \u003d 5<< CS20; // Переддільник на 128 на 32768 дасть 256 тиків в секунду // Що дасть 1 переривання по переповнення в секунду. SetTask (InitASS_Timer); // Проганяємо через диспетчер, щоб зайти знову. }

void InitASS_Timer (void) (if (ASSR & (1<

ISR (TIMER2_OVF_vect) // Прерирваніе по переповнення таймера 2 (UDR \u003d i; i ++;)

Можна було зробити змінні містять годинник: хвилини: секунди і клацати цими змінними з усією їхньою логікою переповнення годин / хвилин, але мені було лінь. І так все зрозуміло.

Оновлене 23.07.2018. Всім привіт. Для роботи з годинником, в минулій статті було розглянуто інтерфейс TWI, на який ми сьогодні будемо посилатися. Ну що ж почнемо. Дані годинник є TWI сумісними, тобто принцип обміну даними по шині буде таким же як ми і розглядали.

На малюнку нижче представлено розташування висновків, опис, і сам вид наших годин або як далі будемо їх називати RTC (Real-time clock) - годинник реального часу або генератор імпульсів часу. Даний "девайс" DS1307 вважає секунди, хвилини, години, день місяця, місяць, день тижня і рік разом з високосними. Календар дійсний до 2100 року. Я думаю на наш вік вистачить :).

Як видно з опису є вхід для аварійного живлення від батареї, при відключеному зовнішньому харчування. В цьому режимі RTC підтримує тільки своє основне призначення - відлік часу, без зовнішніх запитів. Напруга живлення батареї повинно бути 2 - 3.5V. У технічному опис пишеться що при заряді більше 48 мА / год, при температурі 25 град Цельсія, наша схема протримається близько 10 років. Більш ніж треба. На малюнку нижче представлена \u200b\u200b"пігулку" CR2032 і кріплення, які будемо використовувати.

Тепер пройдемося по зовнішньому харчуванню. Робоча напруга годин 5В з невеликим діапазоном 4,5 -5,5. Напруга від батареї 3В (мінімум 2, максимум 3,5 В) Робота RTC ділиться на три режими за напругою:

1. Vcc \u003d 5В - читання, запис, відлік;
2. Vcc \u003d нижче 1,25 * Vbat, але вище Vbat + 0.2V - тільки відлік батареї від зовнішнього живлення.
3. Vcc нижче Vbat: RTC і ОЗУ переходить на живлення від батареї. Споживання в активному стані 1,5 мА, від батареї 500-800нА.
Напруга для передачі / прийому інформації:
Логічний 0: -0.5В - + 0.8В
Логічна 1: 2.2 В - Vcc + 0.3В

Як і в минулих постах спробуємо запустити в Proteus. Налагодимо код. І перенесемо все в залізо. Нижче наведена схема підключення.

Де SQW / OUT - це висновок годин який можна запрограмувати на висновок частоти 1 Гц, 4.096Гц, 8.192Гц і 32,768Гц. Тобто можна використовувати для зовнішнього переривання контролера з періодичністю в 1 с. Дуже корисна функція. Але нам не знадобиться. До речі він теж з відкритим колектором, тому необхідний підтягаючий резистор. Номінал 4,7 кОм.

Висновки Х1 і Х2 - до них підключаємо кварцовий резонатор з частотою 32,768 кГц. Або можна застосувати зовнішній тактовий генератор з тією ж частотою. Але при цьому висновок X1 підключається до сигналу, а X2 залишається непідключеним (висіти в повітрі.).

Ну і висновки SDA і SCL, з якими ми познайомилися в минулій статті.

Трохи зупинимося на резонаторі (малюнок нижче). Який можна назвати серцем годин, і від якого залежить точність ходу. Якість самого резонатора, лежить на совісті виробника, але зі свого боку, ми можемо зменшити похибка, яку вносять зовнішні чинники, якщо будемо дотримуватися наступних рекомендацій по розміщенню резонатора:

2. Ширину траси також по можливості робити менше, для зменшення ймовірності прийняття перешкод з інших джерел.

3. Контур у вигляді захисного кільця необхідно помістити навколо кристала, що допомагає ізолювати кристал від шуму.

4. Провідники помістити в кільце і та підключити до заземлення.

5. Припаюємо резонатор до землі. Якщо земля розлучена вірно і є впевненість.

На малюнку нижче видно контур і місце припая до землі.

Як підключати розібралися. Йдемо далі - розберемося як з ним працювати. RTC є програмованим і має 8 байт спеціальних регістрів для його конфігурації і незалежну статичну пам'ять 56 байтів. Для обміну інформацією необхідна 2-х дротова шина даних, тобто послідовна шина даних-який ми розглянули в минулій статті. Отже для роботи пробіжить по даташіту. Що нам необхідно:

Таблиця регістрів. Малюнок нижче. Перші вісім регістрів - для виведення і програмування наших годин. При зверненні за адресою 00H до 7-му битку (CH) і установкою його в 0 -Запускаємо годинник. Хочеться відзначити, що конфігурація регістрів може бути будь-яка, тому при першому запуску необхідно його налаштувати під свої вимоги. Решта сім бітів одиниці і десятки секунд.

01H - Хвилини.
02H - Годинники, які налаштовуються:
- Біт 6 - при 1 висновок 12 годинний формат, 0 - 24.
- Біт 5 - при 1 (при 12 годинному форматі) PM, 0-AM
- Біт 5 - (при 24 ч форматі) це висновок другого десятка годин (20-23часа.)
- Біт4 - перший десяток годин, інші біти це одиниці годин.
03H - день тижня;
04H - дата;
05H - місяць року
06H - рік.

Ну і останній регістр 07H. Даний регістр є управляющім.Где OUT відповідає за управління висновком SQW / OUT. Нижче таблиця включення виведення.

OUT
SQWE
SQW / OUT
1
0
1
0
0
0

SQWE - при установці цього біта в, 1 на виведення виходять імпульси з заданою частотою, яка встановлюється, битами RS1 і RS0.

Цей висновок нам не знадобиться в проекті. Хоча для нього я розвів на платі доріжку. Як експериментів може бути десь у майбутньому і застосуємо, адже тут можна зробити переривання в 1 с.

Тепер маючи всю необхідну інформацію, напишемо функції для роботи з годинником. А також запустимо проект в Proteus . Який матиме такий вигляд:

Зверніть увагу, що резонатор в Proteus, можна і не підключати до годинника (обведене червоним).

На малюнку виведений термінал годин, який відображає час, яке в свою чергу прив'язана до системного часу. Термінал відладчика протоколу I2C або TWI, на якому відображається час відправки і прийому сигналу, де D0 - передана команда, D1 - прийом. Нижче я буду виводити скріншоти терміналу з результатом роботи програми.

Програма. Розглянувши основні настройки годин напишемо функцію ініціалізації.

/ * Функція ініціалізації включає в себе установку швидкості обміну даних за формулою (в попередній статті), установка перед подільника і включення модуля TWI * /
void init_DS1307 (void)
{
TWBR \u003d 2; / * При частоті 1 МГц * /
TWSR \u003d (0<< TWPS1)|(0 << TWPS0); / * Перед дільник на 64 * /
TWCR | \u003d (1<< TWEN); / * Включення модуля TWI * /
}

void write_DS1307 (uint8_t reg, uint8_t time)/ * Передаємо два параметри: адреса регістра, до якого будемо звертатися і передану інформацію * /
{
/ * Формуємо стан СТАРТ, виставляючи розряди регістра управління * /
TWCR \u003d (1<
/ * Дозволити роботу модуля TWEN; Сформувати стан старт TWSTA; Скинути прапор TWINT * /
/ * Чекаємо закінчення формування умови старт, тобто поки не встановиться прапор, код статусу \u003d 08 * /
while (! (TWCR & (1<
/ * Далі перелається пакет адреси (адресу пристрою). Вміст пакету завантажується в регістр TWDR * /
TWDR \u003d 0xd0; / * 0b1101000 + 0 - адреса + біт записи * /
/ * Скидаємо прапор для передачі інформації * /
TWCR \u003d (1<
/ * Чекаємо установки прапора * /
while (! (TWCR & (1<
/ * Передаємо регістр до якого будемо звертатися * /
TWDR \u003d reg;
TWCR \u003d (1<
while (! (TWCR & (1<
/ * Передаємо інформацію для запису в байт регістра * /
TWDR \u003d time;
TWCR \u003d (1<
while (! (TWCR & (1<
/ * Формуємо стан СТОП * /
TWCR \u003d (1<
}

У цій функції ми передали три байта, адреса пристрою, адреса регістра і байт інформації для запису в цей регістр і сформували стан СТОП.

Залишилася остання функція читання. Нижче формат читання.

У даній функції виконується передача байта адреси пристрою + біт записи, байт адреси регістра для установки на нього покажчик, виконання умови ПОВСТАР, передача байта адреси пристрою + біт читання, читання регістра, адреса якого ми передали раніше.

Якщо ми будемо звертатися до годинника в форматі читання, то при повторному зверненні до годинника покажчик зсувається на один байт вниз включаючи 56 байт ОЗУ, від 00H до 3FH. При досягненні останнього адреси, покажчик переходить на адресу 00.

/ * Функція читання даних з DS1307 * /
uint8_t read_DS1307 (uint8_t reg)/ * Передаємо адреса регістра * /
{
uint8_t time;
/ * Формуємо стан СТАРТ * /
TWCR \u003d (1<
while (! (TWCR & (1<
TWDR \u003d 0xd0; / * Передаємо адреса + біт записи * /
TWCR \u003d (1<
while (! (TWCR & (1<
TWDR \u003d reg; / * Адреса регістра * /
TWCR \u003d (1<
while (! (TWCR & (1<
/ * Формуємо стан ПОВСТАР * /
TWCR \u003d (1<
while (! (TWCR & (1<
TWDR \u003d 0xd1; / * Передаємо адреса + біт читання * /
TWCR \u003d (1<
while (! (TWCR & (1<
/ * Зчитуємо дані * /
TWCR \u003d (1<
while (! (TWCR & (1<
time \u003d TWDR;
time \u003d (((time & 0xF0) \u003e\u003e 4) * 10) + (time & 0x0F);
/ * Формуємо стан СТОП * /
TWCR \u003d (1<
return time;
}

Отже вище ми написали три функції, які нам необхідні для роботи з годинником. Використовуючи ці функції запустимо програму в Proteus. Виведемо, наприклад дату.

#include
#include
uint8_t time;
void init_DS1307 (void);
uint8_t read_DS1307 (uint8_t reg);
void write_DS1307 (uint8_t reg, uint8_t time);
int main (void)
{
DDRC \u003d 0 × 00; / * Виставляємо порт як вхід * /
PORTC \u003d 0xFF; / * Підтягаємо опір * /
init_DS1307;
while (1)
{
_delay_ms (50);
read_DS1307 (0 × 04); / * Читання регістра дати * /
}
}

Нижче результат виконання програми читання дати.

У вікні відладчика I2C ( TWI ) Видно що спочатку надсилається адреса регістра в RTC (зелений кружечок), в даному випадку 04, який відповідає за дату місяця, і далі годинник передають відповідь 21 (червоний кружечок).

Коли ми запустимо годинник в залозі, нам необхідно буде занести даний час. Нижче приклад програми зміни хвилин.

while (1)
{
_delay_ms (500);
read_DS1307 (0 × 01); / * Прочитуємо хвилину * /
_delay_ms (500);
write_DS1307 (0 × 01, 15); / * Записуємо необхідну хвилину * /
_delay_ms (500);
read_DS1307 (0 × 01); / * Прочитуємо хвилину * /
}

На малюнку видно, що спочатку йде звернення до регістру 01, зчитується хвилина 23. Далі ми використовуємо функцію запису, і вносимо значення 15. При наступної функції читання у нас на табло годинника значення 15.

Ну і останній приклад програми це висновок значень всіх регістрів

while (1)
{
delay_ms (500);
read_DS1307 (0 × 00);
_delay_ms (500);
read_DS1307 (0 × 01);
_delay_ms (500);
read_DS1307 (0 × 02);
_delay_ms (500);
read_DS1307 (0 × 03);
_delay_ms (500);
read_DS1307 (0 × 04);
_delay_ms (500);
read_DS1307 (0 × 05);
_delay_ms (500);
read_DS1307 (0 × 06);
_delay_ms (500);
}

На малюнку нижче видно, що вивелися дані 7-ми регістрів.

Исходник з проектом додається:

(Завантажили: 601 чол.)

На цьому все. У наступній статьеподключім годинник в залозі, виведемо час на індикатор і познайомимося з двійковій-десятковим форматом для роботи з годинником. Бувайте усі.

Схема і програма дуже простих годин на мікроконтролері AVR з використанням мікросхеми реального часу DS1307

Доброго дня шановні радіоаматори!
Вітаю вас на сайті ""

Сьогодні, шановні радіоаматори, вашій увазі пропонується дуже проста схема годин на мікроконтролері AVR і годин реального часу з послідовним інтерфейсом I2C DS1307.

Конструкція зібрана на мікроконтролері ATyni26 (просто саме цей МК був під рукою). Але ви можете застосувати будь-який інший МК, головне щоб у нього було 13 вільних входів - 11 для виведення поточного часу на чотирьохрозрядний семисегментний світлодіодний індикатор і 2 виведення - на кнопки установки і корекції часу.

Схема годин:

У схемі застосовані наступні деталі:
- Мікроконтролер - ATyni26 в DID корпусі
- Годинник реального часу - DS1307 в DIP корпусі
- Кварц - 32,768 кГц, з вхідною ємністю 12 пф (можна взяти з ремонту материнської плати), від цього кварцу залежить точність ходу годинника
- резервне живлення DS1307 - 3 вольта літієвий елемент CR2032
- 4-розрядний семисегментний світлодіодний індикатор - FYQ-5641UB -21 із загальним катодом (ультраяскравий, блакитного кольору світіння)
- все транзистори - NPN-структури, можна застосувати будь-які (КТ3102, КТ315 і їх зарубіжні аналоги), я застосував ВС547С
- мікросхемний стабілізатор напруги типу 7805
- все резистори потужністю 0,25 ват
- полярні конденсатори на робочу напругу 50 вольт
Струм споживання пристроєм становить до 30 мА.
Для харчування конструкції можна використовувати будь-який непотрібне зарядний пристрій від телефону або відповідний блок живлення з вихідною напругою 7-9 вольт.
Спілкування мікроконтролера з годинником DS1307 відбувається по шині I2C і організовано програмним шляхом.
Батарейку резервного живлення годин DS1307 можна і не ставити, але в цьому випадку, при пропажі напруги в мережі, поточний час доведеться встановлювати заново.
Друкована плата пристрою не наводиться, конструкція була зібрана в корпусі від несправних механічних годинників. Світлодіод (з частотою миготіння 1 Гц) служить для розділення годин і хвилин в конструкції.

Робота програми.
Тактова частота роботи мікроконтролера - 1 мГц (заводська установка, FUSE-біти чіпати і встановлювати не треба). Розмір програми - 1 кілобайт.
При запуску програми відбувається:
- запуск таймера Т0 з попередньо встановленою частотою СК / 8 і викликом переривання по переповнення (при такій встановленою частоті виклик переривання відбувається кожні 2 мілісекунди)
- ініціалізація портів (порти РА0-6 і РВ0-3 налаштовуються на висновок, РА7 і РВ6 на введення)
- ініціалізація шини I2C (висновки РВ4 і РВ5)
- при першому запуску, або перезапуску при відсутності резервного живлення DS307, перевіряється 7 біт (СН) нульового регістру DS1307 і відбувається перехід до первісної установку поточного часу. При цьому, кнопка S1 - для установки часу, кнопка S2 - перехід до наступного розряду. Встановлений час - годинник і хвилини записуються в DS1307 (секунди встановлюються в нуль), а також висновок SQW / OUT (7-й висновок) налаштовується на генерацію прямокутних імпульсів з частотою 1 Гц
- дозволяється глобальне переривання
- програма переходить в цикл з опитуванням копки S2
При переповнення лічильника таймера Т0 програма переходить до обслуговування переривання (кожні 2 мс):
- зчитується даний час з DS1307 яке записується в чотири змінні SRAM (десятки годин, одиниці годин, десятки хвилин, одиниці хвилин)
- підпрограмою виведення поточного часу проводиться динамічна індикація поточного часу на світлодіодному індикаторі
- при натисканні кнопки S2 програма забороняє глобальне переривання і переходить в підпрограму корекції часу (кнопками S1 і S2 встановлюються десятки і одиниці хвилин, потім, з 0 секунд, натисканням кнопки S2 відбувається запис уточненого часу в DS1307, розв'язання глобальної переривання і повернення в основну програму ).

Застосовані в схемі годинник DS1307 дозволяють виводити на індикацію секунди, хвилини, години, день тижня, дату і рік.
Якщо в схемі замість світлодіодних індикаторів застосувати LCD дисплей, наприклад WH0802 (двухстрочний, з висновком восьми символів в рядку) або аналогічний, то можна організувати повноцінні годинник з повним виведенням поточного часу, а живлення пристрою організувати від гальванічних елементів або акумуляторних батарей.

Розташування висновків мікроконтролера ATyni26:

Розташування висновків DS1307:

Типова схема підключення D1307:

урок 23

Частина 1

Збираємо годинник на DS1307 і LED індикаторі

Сьогодні ми продовжимо нашу роботу з мікросхемою, яка є годинами реального часу, розпочату в, і, і спробуємо тепер зібрати на ній годинник з використанням не рідкокристалічного індикатора, а з застосування індикатора світлодіодного четирёхразрядного працює за принципом динамічної індикації. Все ми це з вами проходили, індикацію також проходили, подібний індикатор підключали в, тому нам буде не так складно це реалізувати.

Але, незважаючи на всі наші знання урок не обіцяє бути коротким, а навпаки буде дуже великим, так як збірка годин на таких індикаторах вимагає рішення дуже багатьох додаткових завдань особливо тому, що у нас не 32 знакомісця, як на нашому LCD, а всього 4 і точка або двокрапка. І все показання треба виводити буде в порядку певної черги, а також вимагатиме від нас вміння організувати зміна показань (переведення) з допомогою кнопок, а може бути взагалі за допомогою однієї лише кнопки в рамках використання всього чотирьох цифр.

Але ми не боїмося труднощів, з ними навіть цікавіше.

Тому почнемо щось вигадувати.

Індикатор буде ось такого ось типу, з них саме типу із загальним анода

А ось так індикатор виглядає вживу

Судячи по клітинках розміром 5 міліметрів нескладно оцінити його розміри.

Ось його вид зі зворотної сторони

Також у мене є ще один індикатор меншим розміром, але по терморегулятори точнісінько такий же як і попередній. Тобто я просто виймаю з макетної плати і вставляю в нього інший, і все працює.

Ось вони обидва для порівняння

Ось маркування маленького індикатора

Також ми можемо використовувати роздільні індикатори для кожної цифри, підключивши їх відповідним чином, результат буде той же. Даний тип підключення зазвичай використовується, коли потрібні годинник з великими цифрами і важко знайти суміщений індикатор великих розмірів. Спосіб підключення наочно демонструючи в нашій схемі в протеус, так як я знайшов в протеус і суміщений індикатор, але він у мене, чомусь належно не заробив (натисніть на картинку для збільшення зображення)

Дану схему ми добре пам'ятаємо з уроку по. Тільки там було всього 2 індикатора, тому підключимо ще два, також будуть використані ще два транзисторних ключа, на базу яких підуть команди через струмообмежуючі резистора на 2 кілоомах від ніжок портів PB2 і PB4. Третю ніжку порту B ми пропустимо з метою її подальшого використання в іншому альтернативному якості, як ніжки апаратного ШІМ для регулювання яскравості світіння індикатора.

Створимо проект з ім'ям MyClock1307LED, А код весь в головний модуль візьмемо як раз з уроку по динамічної індикації, з проекту Test08. В ту пору у нас поки не було модульного програмування і весь корисний код містився в одному головному модулі.

Для початку зберемо наш проект, підключимо контролер і його прошьyoм і подивимося для інтересу результат роботи коду

Ми бачимо що два правих індикатора у нас нормально працюють. Але нам потрібно чотири.

Для початку для цього ми додамо ще дві змінні для двох невикористовуваних розрядів

unsignedinti;

unsignedcharR1=0, R2=0, R3=0, R4 =0 ; // цифри розрядів індикатора

Оголосимо ще відповідають даним анодам ніжки порту на вихід в функції port_ini (), також включає і ніжку для ШІМ

DDRB= 0b000 111 11;

Також додамо код в функцію ledprint

voidledprint( unsignedintnumber)

R1= number%10;

R2= number%100/10;

R3= number%1000/100;

R4= number/1000;

У нас тут ще обчислюється результат цифр відсутніх, так само в другому розряді відбулися деякі зміни в силу того. що він тепер не останній, і треба сотні і тисячі відкинути.

Змінні ми розрахували, залишилося їх якось відобразити на індикаторі.

Для цього ми змінимо код в обробнику переривання від таймера

ISR( TIMER1_COMPA_vect)

if( n_count==0) { PORTB&=~(1<< PORTB0); PORTB|=(1<< PORTB1)|(1<< PORTB2)|(1<< PORTB4); segchar( R1);}

if( n_count==1) { PORTB&=~(1<< PORTB1); PORTB|=(1<< PORTB0)|(1<< PORTB2)|(1<< PORTB4); segchar( R2);}

if( n_count==2) { PORTB&=~(1<< PORTB2); PORTB|=(1<< PORTB0)|(1<< PORTB1)|(1<< PORTB4); segchar( R3);}

if( n_count==3) { PORTB&=~(1<< PORTB4); PORTB|=(1<< PORTB0)|(1<< PORTB1)|(1<< PORTB2); segchar( R4);}

N_count++;

If( n_count>3 ) n_count=0;

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

З цим все.

Але, так як у нас тепер кількість індикаторів збільшилася, тепер черга до того ж індикатора доходить пізніше, тобто швидкість обнолвенія показань одного індикатора у нас впала, і ми повинні трохи переналаштувати таймер. Як це робити, нас вчити не треба

OCR1AH= 0b00001111; // записуємо в регістр число для порівняння

OCR1AL=0b01000010;

Ну і зробимо можливість нашому лічильнику вважати не до 99, а до 9999 для цього в циклі ми напишемо не 100, а 10000

for( i=0; i< 10000 ; i++)

І також зменшимо затримку, інакше з такою швидкістю ми четвертої цифри довго не дочекаємося

Delay_ms(10 );

Зберемо код, прошьyoм контролер і подивимося результат нашої роботи

Ось тепер інша справа. У нас тепер є робочий код для організації динамічної індикації четирёхразрядного динамічного індикатора, тому в наступній частинінашого заняття нам до цього питання вже більше повертатися не доведеться.

5 542 Цей варіант годинника зроблений таким чином, щоб максимально спростити схему, знизити енергоспоживання, і в підсумку отримати прилад, який легко поміщається в кишені. Вибравши мініатюрні акумулятори для живлення схеми, SMD - монтаж і мініатюрний динамік (наприклад від неробочого мобільного телефону), Ви можете отримати конструкцію, розміром трохи більше сірникової коробки.
Застосування над'яскравих індикатора дозволяє знизити струм, споживаний схемою. Зниження струму споживання також досягається в режимі "LoFF" - індикатор погашений, при цьому включена тільки миготлива точка молодшого розряду годин.

індикація
Регульована яскравість індикаторів дозволяє вибрати найбільш комфортне відображення показань (і знову ж знизити енергоспоживання).
У годиннику реалізовано 9 режимів індикації. Перехід по режимам здійснюється за допомогою кнопок "плюс" і "мінус". Перед виведенням на індикацію самих свідчень, на індикатори виводиться коротка підказка назви режиму. Тривалість виведення підказки - одна секунда. Застосування короткочасних підказок дозволило досягти гарної ергономічності годин. При переходах по режимам відображення (яких вийшло чимало, для такого простого приладу, як звичайний годинник) не виникає плутанини, і завжди зрозуміло, які саме свідчення виведені на індикатор.

Корекція показань, виведених на індикатор включається при натисканні на кнопку "Корекція". При цьому короткочасна підказка виводиться на 1/4 секунди, після чого коректовані значення починає блимати з частотою 2 Гц. Коригуються показання кнопками "плюс" і "мінус". При тривалому натисканні на кнопку, включається режим автоповтора, із заданою частотою. Частоти автоповтора натискання кнопки складають: для годин, місяців і дня тижня - 4 Гц; для хвилин, року і яскравості індикатора - 10 Гц; для коригуючого значення - 100 Гц.
Все відкориговані значення, крім годин, хвилин і секунд, записуються в EEPROM і відновлюються після виключення - включення харчування. Секунди при корекції обнуляються. З усіх режимів, крім годинник-хвилини, хвилини-секунди і LoFF організований автоматичне повернення. Якщо протягом 10 секунд жодна з кнопок не натиснута, то годинник переходять в режим відображення годин - хвилин.
Натисканням на кнопку "вмикання / вимикання буд." включається / вимикається будильник. Включення будильника підтверджується коротким Двотональна звуком. При включеному будильнику світиться точка в молодшому розряді індикатора.
У режимі "Corr" на індикатор виведена коригуюча константа, початкове значення якої 5000 мікросекунд в секунду. При відставанні годин константу збільшуємо на величину відставання, обчислене в мікросекундах за одну секунду. Якщо годинник поспішають, то константу зменшуємо за тим же принципом.

схема



Сподобалася стаття? поділіться їй