- Чому таймер, коли у нас є Delay ()?
- Таймери мікроконтролера PIC:
- Програмування та робоче пояснення:
- Принципова схема та моделювання Протея:
Це буде п’ятий підручник з нашої навчальної серії PIC, який допоможе вам навчитися та користуватися таймерами в PIC16F877A. У наших попередніх навчальних посібниках ми почали з Введення в PIC та MPLABX IDE, тоді ми написали нашу першу програму PIC, щоб блимати світлодіодом за допомогою PIC, а потім створили послідовність миготіння світлодіодів, використовуючи функцію затримки в мікроконтролері PIC. Тепер давайте використаємо ту саму послідовність миготіння світлодіодів, яку ми використовували в попередньому навчальному обладнанні, і завдяки цьому ми навчимось використовувати таймери в нашому PIC MCU. Для цього підручника ми щойно додали ще одну кнопку на світлодіодній дошці. Пройдіть підручник, щоб дізнатись більше.
Таймери є одним з важливих робочих коней для вбудованого програміста. Кожна програма, яку ми розробляємо, якимось чином включатиме програму синхронізації, наприклад, ввімкнення чи вимкнення чогось через певний проміжок часу. Гаразд, але навіщо нам таймери, коли у нас вже є макроси затримки (__delay_ms ()), які роблять те саме !!
Чому таймер, коли у нас є Delay ()?
Макрос затримки називається затримкою "дампа". Оскільки під час виконання функції затримки MCU сидить дамп просто створюючи затримку. Під час цього процесу MCU не може слухати свої значення АЦП або читати що-небудь зі своїх Реєстрів. Отже, недоцільно використовувати функції затримки, за винятком таких програм, як блимання світлодіодів, де затримка часу не повинна бути точною чи довгою.
Макроси затримки також мають такі короткі надходження,
- Значення затримки повинно бути постійним для макросів затримки; його не можна змінити під час виконання програми. Отже, це залишається визначеним програмістом.
- Затримка не буде точною порівняно з використанням таймерів.
- Більші значення затримок не можуть бути створені за допомогою макросів, наприклад, затримка на півгодини не може бути створена за допомогою макросів затримки. Максимальна затримка, яку можна використати, базується на використаному кристалічному генераторі.
Таймери мікроконтролера PIC:
Фізично таймер - це регістр, значення якого постійно зростає до 255, а потім починається спочатку: 0, 1, 2, 3, 4… 255…. 0, 1, 2, 3…… тощо.
PIC16F877A PIC MCU має три модуля таймера. Вони називаються Timer0, Timer1 і Timer2. Таймери 0 і Таймер 2 є 8-бітними таймерами, а Таймер 1 - 16-бітовими таймерами. У цьому підручнику ми будемо використовувати таймер 0 для нашого додатку. Як тільки ми зрозуміємо таймер 0, буде легко працювати і над таймером 1 і таймером 2.
Таймер / лічильник модуля Timer0 має наступні функції:
- 8-бітний таймер / лічильник
- Читається та доступна для запису
- 8-розрядний програмний програмований прескалер
- Вибір внутрішнього або зовнішнього годинника
- Переривання при переливі з FFh до 00h
- Вибір краю для зовнішнього годинника
Щоб почати використовувати таймер, ми повинні зрозуміти деякі вигадані терміни, такі як 8-бітний / 16-бітний таймер, Prescaler, переривання таймера та Focs. А тепер давайте подивимось, що насправді означає кожен із них. Як вже було сказано раніше, у нашому PIC MCU є як 8-бітні, так і 16-бітові таймери, головна різниця між ними полягає в тому, що 16-бітний таймер має набагато кращу роздільну здатність, ніж 8-бітний таймер.
Прескалер - це назва частини мікроконтролера, яка ділить годинник генератора, перш ніж він досягне логіки, яка збільшує стан таймера. Діапазон ідентифікатора прескалера становить від 1 до 256, і значення прескалера можна встановити за допомогою реєстру OPTION (того самого, що ми використовували для підтягуючих резисторів). Наприклад, якщо значення попереднього лічильника дорівнює 64, то для кожного 64- го імпульсу Таймер збільшується на 1.
У міру збільшення таймера і коли він досягає максимального значення 255, він ініціює переривання і ініціалізується до 0 назад. Це переривання називається тимчасовим перериванням. Це переривання повідомляє MCU про те, що цей конкретний час минув.
Fosc позначає частоту генератора, то частота кварцового резонатора. Час, необхідний для реєстрації таймера, залежить від значення прескалера та значення Fosc.
Програмування та робоче пояснення:
У цьому підручнику ми встановимо дві кнопки як два входи та 8 світлодіодів як 8 виходів. Перша кнопка використовуватиметься для встановлення часової затримки (500 мс на кожне натискання), а друга кнопка - для запуску мигання послідовності таймера. Наприклад, якщо тричі натиснути першу кнопку (500 * 3 = 1500 мс), затримка буде встановлена на 1,5 секунди, а при натисканні кнопки дві кожний світлодіод увімкнеться та вимкнеться із заданою затримкою часу. Перегляньте демонстраційне відео в кінці цього підручника.
Тепер, маючи на увазі ці основи, давайте розглянемо нашу програму, подану в кінці в розділі Коду.
Це нормально, якщо ви не отримали програму, але якщо отримали !! Дайте собі cookie і скиньте програму, щоб насолоджуватися вашими результатами. Для інших я розберу програму на змістовні частини і поясним вам, що відбувається в кожному блоці.
Як завжди перші кілька рядків коду - це налаштування конфігурації та файли заголовків, я не збираюся пояснювати це, оскільки я це вже робив у своїх попередніх підручниках.
Далі, пропустимо всі рядки і перейдемо прямо до головної функції void, всередині якої ми маємо конфігурацію PORT для Timer0.
void main () {/ ***** Конфігурація порту для таймера ****** / OPTION_REG = 0b00000101; // Таймер0 із зовнішнім частотним значенням і 64 як прескаляром // Також включає функцію PULL UPs TMR0 = 100; // Завантажуємо значення часу для 0,0019968 с; delayValue може бути в межах від 0-256 TMR0IE = 1; // Увімкнути біт переривання таймера в регістрі PIE1 GIE = 1; // Увімкнути глобальне переривання PEIE = 1; // Увімкнути периферійне переривання / *********** ______ *********** /
Щоб зрозуміти це, ми повинні поглянути на реєстр ВАРІАНТІВ у нашому паспорті даних ПОС.
Як обговорювалося в попередньому підручнику, біт 7 використовується для включення слабкого підтягуючого резистора для PORTB. Подивіться на малюнок вище, біт 3 зроблений 0, щоб проінструктувати MCU, що наступний прескалер, який встановлюється, повинен використовуватися для таймера, а не для WatchDogTimer (WDT). Режим таймера вибирається очищенням біта 5 T0CS
(OPTION_REG <5>)
Тепер bits2-0 використовується для встановлення значення попереднього масштабу для таймера. Як показано в таблиці вище, щоб встановити значення попереднього масштабування 64, біти повинні бути встановлені як 101.
Далі розглянемо Реєстри, пов’язані з Timer0
Таймер почне збільшуватися після встановлення та переповнення після досягнення значення 256, щоб увімкнути переривання таймера в цей момент, регістр TMR0IE повинен бути встановлений високим. Оскільки сам Таймер 0 є периферійним пристроєм, ми повинні активувати периферійне переривання, зробивши PEIE = 1. Нарешті, ми маємо увімкнути глобальне переривання, щоб MCU отримував повідомлення про переривання під час будь-якої операції, це робиться шляхом введення GIE = 1.
Затримка = ((256-REG_val) * (Prescal * 4)) / Fosc
Наведена вище формула використовується для розрахунку значення затримки.
Де
REG_val = 100;
Прескаль = 64
Fosc = 20000000
Це при розрахунку дає, Затримка = 0,0019968с
Наступним набором рядків є встановлення портів вводу-виводу.
/ ***** Конфігурація порту для вводу / виводу ****** / TRISB0 = 1; // Інструктуємо MCU, що контакт PORTB 0 використовується як вхід для кнопки 1. TRISB1 = 1; // Інструктуємо MCU, що штифт 1 PORTB використовується як вхід для кнопки 1. TRISD = 0x00; // Інструктуємо MCU, що всі штифти на PORT D виводяться PORTD = 0x00; // Ініціалізуємо всі шпильки до 0 / *********** ______ *********** /
Це те саме, що і в нашому попередньому підручнику, оскільки ми використовуємо одне і те ж обладнання. За винятком того, що ми додали ще одну кнопку як вхід. Це робиться рядком TRISB1 = 1.
Далі, всередині з нескінченного у час циклу ми маємо два блоки коду. Один використовується для отримання вхідних даних таймера від користувача, а інший для виконання послідовності затримки над світлодіодами. Я пояснив їх, використовуючи коментарі до кожного рядка.
while (1) {count = 0; // Не запускати таймер, перебуваючи в головному циклі // ******* Отримати затримку номера у користувача **** ////// if (RB0 == 0 && flag == 0) // Коли введення дано {get_scnds + = 1; // get_scnds = get_scnds + http: // Збільшити прапорець змінної = 1; } if (RB0 == 1) // Щоб запобігти безперервному зростанню прапор = 0; / *********** ______ *********** /
Змінна, яка називається get_scnds, збільшується кожного разу, коли користувач натискає кнопку 1. Змінна прапора (визначена програмним забезпеченням) використовується для утримання процесу нарощування, поки користувач не видалить палець із кнопки.
// ******* Виконати послідовність із затримкою **** ////// while (RB1 == 0) {PORTD = 0b00000001 <
Наступний блок починає діяти, якщо натиснути кнопку дві. Оскільки користувач вже визначив необхідну затримку за допомогою кнопки перший, і вона була збережена у змінній get_scnds. Ми використовуємо змінну hscnd, ця змінна контролюється ISR (процедура переривання служби).
Процедура обслуговування переривань - це переривання, яке викликається кожного разу, коли Timer0 переповнюється. Давайте подивимося, як цим керує ISR у наступному блоці, як ми хочемо збільшити затримку часу на половину секунди (0,5 с) при кожному натисканні кнопки, тоді нам потрібно збільшити змінну hscnd кожні півсекунди. Оскільки ми запрограмували наш таймер на надмірний потік на кожні 0,0019968 с (~ 2 мс), тому для підрахунку півсекундної змінної підрахунку має бути 250, оскільки 250 * 2 мс = 0,5 секунди. Отже, коли рахунок отримує 250 (250 * 2 мс = 0,5 секунди), це означає, що минуло півсекунди, тому ми збільшуємо hscnd на 1 і ініціалізуємо відлік до нуля.
void interrupt timer_isr () {if (TMR0IF == 1) // Прапор таймера спрацьовував через переповнення таймера {TMR0 = 100; // Завантажуємо значення таймера TMR0IF = 0; // Очистити кількість прапорів переривання таймера ++; } if (count == 250) {hscnd + = 1; // hscnd буде отримувати приріст за кожні півсекунди count = 0; }}
Отже, ми використовуємо це значення і порівнюємо його з нашим hscnd і зміщуємо наш світлодіод на основі визначеного користувачем часу. Це також дуже схоже на останній підручник.
Ось у нас наша програма зрозуміла і працює.
Принципова схема та моделювання Протея:
Як звичайно, давайте спочатку перевіримо вихід, використовуючи Proteus, я зв’язав тут схематичні файли Proteus.
Додайте кнопку до нашої попередньої світлодіодної плати, і наше обладнання готове до роботи. Це повинно виглядати приблизно так:
Після підключення завантажте код і перевірте вихідні дані. Якщо у вас виникли проблеми, скористайтесь розділом коментарів. Також перегляньте відео нижче, щоб зрозуміти весь процес.