Курс програмування avr контролерів для початківців. Ви ще не програмуєте мікроконтролери? Тоді ми йдемо до вас! Установка окремого біта

Мікроконтролери (далі МК) міцно увійшли в наше життя, на просторах інтернету можна зустріти дуже багато цікавих схем, які виконані на МК. Чого тільки не можна зібрати на МК: різні індикатори, вольтметри, прилади для дому (пристрої захисту, комутації, термометри ...), металошукачі, різні іграшки, роботи і т.д. перераховувати можна дуже довго. Першу схему на мікроконтролері я побачив років 5-6 назад в журналі радіо, і практично відразу ж перегорнув сторінку, подумавши про себе "все одно не зможу зібрати". Дійсно, в той час МК для мене були чимось дуже складним і незрозумілим пристроєм, я не уявляв як вони працюють, як їх прошивати, і що робити з ними в разі неправильної прошивки. Але приблизно рік тому, я вперше зібрав свою першу схему на МК, це була схема цифрового вольтметра на 7 сегментних індикаторах, і микроконтроллере ATmega8. Так вийшло, що мікроконтролер я купив випадково, коли стояв у відділі радіодеталей, хлопець переді мною купував МК, і я теж вирішив купити, і спробувати зібрати що-небудь. У своїх статтях я розповім вам про мікроконтролери AVR , Навчу вас працювати з ними, розглянемо програми для прошивки, виготовимо простий і надійний програматор, розглянемо процес прошивки і найголовніше проблеми, які можуть виникнути і не тільки у новачків.

Основні параметри деяких мікроконтролерів сімейства AVR:

мікроконтролер

пам'ять FLASH

пам'ять ОЗУ

пам'ять EEPROM

Порти введення / виводу

U харчування

Розширені можливості пошуку МК AVR mega:

Робоча температура: -55 ... + 125 * С
Температура зберігання: -65 ... + 150 * С
Напруга на виводі RESET щодо GND: max 13В
Максимальна напруга живлення: 6.0В
Максимальний струм лінії введення / виводу: 40мА
Максимальний струм по лінії живлення VCC і GND: 200мА

Розташування висновків моделей ATmega 8X

Розташування висновків моделей ATmega48x, 88x, 168x

Розташування висновків у моделей ATmega8515x

Розташування висновків у моделей ATmega8535x

Розташування висновків у моделей ATmega16, 32x

Розташування висновків у моделей ATtiny2313

В кінці статті прикріплений архів з даташіта на деякі мікроконтролери

Установчі FUSE біти MK AVR

Запам'ятайте, запрограмований фьюз - це 0, не запрограмований - 1. Обережно варто ставитися до виставлення фьюз, помилково запрограмований фьюз може заблокувати мікроконтролер. Якщо ви не впевнені який саме фьюз потрібно запрограмувати, краще на перший раз прошийте МК без фьюз.

Найпопулярнішими микроконтроллерами у радіоаматорів є ATmega8, потім йдуть ATmega48, 16, 32, ATtiny2313 і інші. Мікроконтролери продаються в TQFP корпусах і DIP, новачкам рекомендую купувати в DIP. Якщо купите TQFP, буде проблематичніше їх прошити, доведеться купити або і паяти плату тому у них ніжки розташовуються дуже близько один від одного. Раджу мікроконтролери в DIP корпусах, ставити на спеціальні панельки, це зручно і практично, не доведеться випоювати МК якщо закортить перепрошити, або використовувати його для іншої конструкції.

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

Для програмування використовується 6 висновків:
RESET - Вхід МК
VCC - Плюс харчування, 3-5в, залежить від МК
GND - Загальний провід, мінус харчування.
MOSI - Вхід МК (інформаційний сигнал в МК)
MISO - Вихід МК (інформаційний сигнал з МК)
SCK - Вхід МК (тактовий сигнал в МК)

Іноді ще використовують виведення XTAL 1 і XTAL2, на ці виведення чіпляється кварц, якщо МК буде працювати від зовнішнього генератора, в ATmega 64 і 128 виведення MOSI і MISO не застосовуються для ISP програмування, замість них виведення MOSI підключають до ніжки PE0, a MISO до PE1. При з'єднанні мікроконтролера з програматором, що з'єднують дроти повинні бути якомога коротше, а кабель йде від програматора на порт LPT так-же не повинен бути занадто довгим.

У маркуванні мікроконтролера можуть бути присутніми незрозумілі букви з цифрами, наприклад Atmega 8L 16PU, 8 16AU, 8A PU тощо. Буква L означає, що МК працює від більш низької напруги, ніж МК без букви L, зазвичай це 2.7В. Цифри після дефіса або пробілу 16PU або 8AU говорять про внутрішній частоті генератора, який є в МК. Якщо фьюз виставлені на роботу від зовнішнього кварцу, кварц повинен бути встановлений на частоту, що не перевищує максимальну по даташіту, це 20МГц для ATmega48 / 88/168, і 16МГц для інших атмег.

Якось відразу потягнуло давати поради з приводу вибору середовища програмування для AVR контролерів. Тільки не треба кидати в мене тапками. Я зовсім трохи 🙂

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

Якщо Ви, в даний момент, стоїте перед вибором, на чому почати працювати, то ось Вам декілька рекомендацій.

Колишній досвід програмування. Не варто нехтувати колишнім досвідом в програмуванні. Навіть якщо це був Бейсік. Навіть якщо це було давно в школі. Програмування як їзда на велосипеді - варто тільки почати і швидко згадуєш все забуте. Почніть з Бейсика - освойтесть - пізніше буде простіше вибрати щось більш підходяще для Ваших цілей.

Допомога оточення.Ваші друзі пишуть на Паскалі? Для Вас питання вирішене - пишіть на Паскалі! Вам завжди допоможуть порадою, підкинуть бібліотек, дадуть на вивчення готові проекти. Вобщем раді будуть прийняти до своєї спільноти. Якщо зробите навпаки - отримаєте зворотний результат. Друзі сішнікі заклюють Вас, який вирішив вивчати Асемблер. Допомоги не чекайте.

Хороша книга з програмування AVR дуже здорово допоможе. На жаль їх дуже мало. Якщо Вам в руки потрапила книга, і ви вважаєте що в ній дуже доступно все розписано - спробуйте. Не раджу вчитимуться за електронними книгами, в крайньому випадку, роздрукуйте. Дуже незручно переключатися між середовищем і текстом файлу книги. Набагато приємніше читаючи книгу тут же пробувати, не відволікаючись на перемикання, крім того, на полях можна робити позначки, записувати виникли ідеї.

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

Бібліотеки. Наявність бібліотек спірно для вивчення мови. Звичайно, пізніше вони дуже полегшать життя, але спочатку «Чорні ящики» -бібліотеки незрозумілі і не дуже сприяють розумінню мови. З іншого боку полегшують читання програми і дозволяють новачкові, не особливо напружуючись, будувати складні програми. Так що, їх наявністю особливо не морочитися. По крайней мере, по початку.

Ефективний код. Вибір середовища програмування для вивчення програмування тільки по тому, наскільки ефективний код та Компільо - погана ідея. Вам головне комфортно почати вивчення - що там виходить «на виході» справа десята. Звичайно, пізніше можна над цим і попрацювати.

Візард.Будь-який пристрій на борту кристала потребує налаштування за допомогою портів. Процедура досить марудна і даташіта обов'язкові. Крім того, є нюанси, в які новачкові не просто вкурил. Тому в середовищі дуже бажано наявність візард. Визарди це автоматичні настройщики SPI, I2C, USART і т.д. Чим більше пристроїв підтримується, тим краще. Виставляєш необхідні параметри периферії, а візард сам генерує код, який забезпечить задані параметри. Дуже спрощує життя.


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


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

(Visited 7 554 times, 2 visits today)

Завдання: Розробимо програму управління одним світлодіодом. При натисканні на кнопку світлодіод горить, при відпуску гасне.

Для початку розробимо принципову схему пристрою. Для підключення до мікроконтролеру будь-яких зовнішніх пристроїв використовуються порти введення-виведення. Кожен з портів здатний працювати як на вхід так і на вихід. Підключимо світлодіод до одного з портів, а кнопку до іншого. Для цього досвіду ми будемо використовувати контролер Atmega8. Ця мікросхема містить 3 порту введення-виведення, має 2 восьмирозрядних і 1 шестнадцатіразрядний таймер / лічильник. Також на борту є 3-х канальний ШІМ, 6-ти канальний 10-ти бітний аналого-цифровий перетворювач і багато іншого. На мою думку мікроконтролер прекрасно підходить для вивчення основ програмування.

Для підключення світлодіода ми будемо використовувати лінію PB0, а для зчитування інформації з кнопки скористаємося лінією PD0. Схема наведена на рис.1.

Заняття №2. перемикання світлодіода

Заняття №3. миготіння світлодіодом

Заняття №4. біжать вогні

Заняття №5. Біжать вогні з використанням таймера

Заняття №6. Біжать вогні. Використання переривань за таймером

Заняття №7. Оператори управління битами

Заняття №8. Реалізація ШІМ

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

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

Загальна інформація

Мікроконтролери зустрічаються всюди. Їх можна знайти в холодильниках, пральних машинках, телефонах, заводських верстатах і великій кількості інших технічних пристроїв. Мікроконтролери бувають як простими, так і надзвичайно складними. Останні пропонують значно більше можливостей і функціонала. Але розбиратися відразу в складній техніці не вийде. Спочатку необхідно освоїти щось просте. І в якості зразка буде взятий Atmega8. Програмування на ньому не є складним завдяки грамотній архітектурі і доброзичливому інтерфейсу. До того ж він є володарем достатньої продуктивності, щоб використовувати в більшості Більш того, вони застосовуються навіть в промисловості. У випадку з Atmega8 програмування передбачає знання таких мов як AVR (C / Assembler). З чого ж почати? Освоєння цієї технології можливо трьома шляхами. І кожен вибирає сам, з чого почати роботу з Atmega8:

  1. Програмування через Arduino.
  2. Купівля готового пристрою.
  3. Збирання мікроконтролера.

Нами буде розглянуто перший і третій пункт.

Arduino

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

  1. Низький поріг вимог. Не потрібно володіти спеціальними навичками і вміннями для розробки технічних пристроїв.
  2. Широкий спектр елементів буде доступний для підключення без додаткової підготовки.
  3. Швидкий початок розробки. З Arduino можна відразу переходити до створення пристроїв.
  4. Наявність великої кількості навчальних матеріалів і прикладів реалізацій різних конструкцій.

Але є і певні мінуси. Так, Arduino програмування Atmega8 не дозволяє глибше зануритися в світ мікроконтролера і розібратися в багатьох корисних аспектах. Крім цього, доведеться вивчити мову програмування, що відрізняється від застосовуваних AVR (C / Assembler). І ще: Arduino має досить вузьку лінійку моделей. Тому рано чи пізно виникне необхідність використовувати мікроконтролер, що не використовується в платах. А в цілому це непоганий варіант роботи з Atmega8. Програмування через Arduino дозволить отримати впевнений старт в світі електроніки. І у людини навряд чи опустяться руки через невдачі і проблем.

збирання

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

Що ж потрібно для збірки?

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

Програмування Atmega8 для початківців на прикладі

Давайте розглянемо, як в загальних рисах здійснюється створення якогось пристрою. Отже, припустимо, що у нас є мікроконтролер, світлодіод, резистор, програматор, з'єднувальні дроти, і джерело живлення. Перший крок - це написання прошивки. Під нею розуміють набір команд для мікроконтролера, що представлений в якості кінцевого файлу, що має спеціальний формат. У ньому необхідно прописати підключення всіх елементів, а також взаємодія з ними. Після цього можна приступати до складання схеми. На ніжку VCC слід подати харчування. До будь-якої іншої, призначеної для роботи з пристроями і елементами, підключається спочатку резистор, а потім світлодіод. При цьому потужність першого залежить від потреб в харчуванні другого. Можна орієнтуватися за такою формулою: R \u003d (Up-Ups) / Is. Тут p - це харчування, а s - світлодіод. Давайте уявимо, що у нас є світлодіод, який споживає 2В і вимагає ток харчування на рівні 10 мА, переводимо в більш зручний для математичних операцій вид і отримуємо 0.01А. Тоді формула буде виглядати наступним чином: R \u003d (5В-2В) /0.01А\u003d3В/0.01А\u003d300 Ом. Але на практиці часто виявляється неможливим підібрати ідеальний елемент. Тому береться найбільш підходящий. Але потрібно використовувати резистор з опором вище значення, отриманого математичним шляхом. Завдяки такому підходу ми продовжимо термін його служби.

А що ж далі?

Отже, у нас є невелика схема. Тепер залишилося підключити до мікроконтролеру програматор і записати в його пам'ять прошивку, що була створена. Тут є один момент! Вибудовуючи схему, необхідно її створювати таким чином, щоб мікроконтролер можна було прошивати без розпаювання. Це дозволить зберегти час, нерви і продовжить термін служби елементів. У тому числі і Atmega8. Внутрішньосхемне програмування, потрібно відзначити, вимагає знань і умінь. Але воно ж дозволяє створювати більш досконалі конструкції. Адже часто буває, що під час розпаювання елементи пошкоджуються. Після цього схема готова. Можна подавати напругу.

важливі моменти

Хочеться дати новачкам корисні поради про програмування Atmega8. Вбудовані змінні і функції не міняти! Прошивати пристрій створеної програмою бажано після її перевірки на відсутність «вічних циклів», що заблокують будь-яке інше втручання, і з використанням хорошого передавача. У разі використання саморобки для цих цілей слід бути морально готовим до виходу мікроконтролера з ладу. Коли будете прошивати пристрій за допомогою програматора, то слід з'єднувати відповідні виходи VCC, GND, SCK, MOSI, RESET, MISO. І не порушуйте техніку безпеки! Якщо технічними характеристиками передбачено, що повинно бути харчування в 5В, то потрібно дотримуватися саме такої напруги. Навіть використання елементів на 6В може негативно позначитися на працездатності мікроконтролера і скоротити термін його служби. Звичайно, батареї на 5В мають певні розбіжності, але, як правило, там все в розумних рамках. Наприклад, максимальна напруга буде триматися на рівні 5,3В.

Навчання і вдосконалення навичок

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

Чи складно почати створювати щось своє?

Досить мати 500-2000 рублів і кілька вільних вечорів. Цього часу з лишком вистачить, щоб ознайомитися з архітектурою Atmega8. Після невеликої практики можна буде спокійно створювати свої власні проекти, які виконують певні завдання. Наприклад, роботизовану руку. Одного Atmega8 має з лишком вистачити, щоб передати основні моторні функції пальців і кисті. Звичайно, це досить складне завдання, але цілком посильне. В подальшому взагалі можна буде створювати складні речі, для яких знадобляться десятки мікроконтролерів. Але це все попереду, перед цим необхідно отримати хорошу школу практики на щось просте.

Привіт, шановні Хабражітелі!

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

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

1. Программатор
На ринку пропонується багато варіантів - від найдешевших ISP (In-System Programming) программаторов за кілька доларів, до потужних программаторов-отладчиков за пару сотень. Не маючи великого досвіду в цій справі, для початку я вирішив спробувати один з найпростіших і дешевих - USBasp. Купив свого часу на eBay за $ 12, зараз можна знайти навіть за $ 3-4. Насправді це китайська версія програматора від Thomas Fischl. Що можу сказати про нього? Тільки одне - він працює. До того ж підтримує досить багато AVR контролерів серій ATmega і ATtiny. Під Linux не вимагає драйвера.

Для прошивки треба з'єднати виходи програматора VCC, GND, RESET, SCK, MOSI, MISO з відповідними виходами мікроконтролера. Для простоти я зібрав допоміжну схему прямо на макетної платі:

Зліва на платі - той самий мікроконтролер, який ми збираємося прошивати.

2. Микроконтроллер
З вибором мікроконтролера я особливо не морочився і взяв ATmega8 від Atmel - 23 Піна введення / виведення, два 8-бітних таймера, один 16-бітний, частота - до 16 Мгц, маленьке споживання (1-3.6 мА), дешевий ($ 2). Загалом, для початку - більш ніж достатньо.

Під Linux для компіляції і завантаження прошивки на контролер відмінно працює зв'язка avr-gcc + avrdude. Установка тривіальна. Слідуючи інструкції, можна за кілька хвилин встановити все необхідне ПЗ. Єдиний нюанс, на який слід звернути увагу - avrdude (ПО для запису на контролер) може зажадати права супер-користувача для доступу до программатору. Вихід - запустити через sudo (не дуже гарна ідея), або прописати спеціальні udev права. Синтаксис може відрізнятися в різних версіях ОС, але в моєму випадку (Linux Mint 15) спрацювало додавання наступного правила в файл /etc/udev/rules.d/41-atmega.rules:

# USBasp programmer SUBSYSTEM \u003d\u003d "usb", ATTR (idVendor) \u003d\u003d "16c0", ATTR (idProduct) \u003d\u003d "05dc", GROUP \u003d "plugdev", MODE \u003d "0666"

Після цього, природно, необхідний перезапуск сервісу
service udev restart
Компілювати і прошивати без проблем можна прямо з командного рядка (хто б сумнівався), але якщо проектів багато, то зручніше поставити плагін і робити все прямо з середовища Eclipse.

Під Windows доведеться поставити драйвер. В іншому проблем немає. Заради наукового інтересу спробував зв'язку AVR Studio + eXtreme Burner в Windows. Знову-таки, все працює на ура.

починаємо програмувати

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

Після знайомства з архітектурою і основними принципами, вирішив зібрати щось корисне і цікаве. Тут мені допомогла донька, вона займається шахами і в один прекрасний вечір заявила, що хоче мати годинник-таймер для партій на час. БАЦ! Ось вона - ідея першого проекту! Можна було звичайно замовити їх на тому ж eBay, але захотілося зробити свої власні годинник, з блек ... еее ... з індикаторами і кнопочками. Сказано зроблено!

Як дисплея вирішено було використовувати два 7-сегментних діодних індикатора. Для управління досить було 5 кнопок - "Гравець 1", "Гравець 2", "Скидання", "Налаштування" і "Пауза". Ну і не забуваємо про звукову індикацію закінчення гри. Начебто все. На малюнку нижче представлена \u200b\u200bзагальна схема підключення мікроконтролера до індикаторів і кнопок. Вона знадобиться нам при розборі вихідного коду програми:

Розбір польоту

Почнемо, як і годиться, з точки входу програми - функції main. Насправді нічого примітного в ній немає - настройка портів, ініціалізація даних і нескінченний цикл обробки натискань. Ну і виклик sei () - дозвіл обробки переривань, про них трохи пізніше.

Int main (void) (init_io (); init_data (); sound_off (); sei (); while (1) (handle_buttons ();) return 0;)
Розглянемо кожну функцію окремо.

Void init_io () (// set output DDRB \u003d 0xFF; DDRD \u003d 0xFF; // set input DDRC \u003d 0b11100000; // pull-up resistors PORTC | \u003d 0b00011111; // timer interrupts TIMSK \u003d (1<

Налаштування портів введення / виводу відбувається дуже просто - в регістр DDRx (де x - літера, що позначає порт) запісівается число, кожний біт якого означає, чи буде відповідний пін пристроєм введення (відповідає 0) або виведення (відповідає 1). Таким чином, заславши в DDRB і DDRD число 0xFF, ми зробили B і D портами виводу. Відповідно, команда DDRC \u003d 0b11100000; перетворює перші 5 пинов порту C у вхідні Піни, а що залишилися - у вихідні. Команда PORTC | \u003d 0b00011111; включає внутрішні підтягує резистори на 5 входах контролера. Згідно зі схемою, до цих входів підключені кнопки, які при натисканні замкнутий їх на землю. Таким чином контролер розуміє, що кнопка натиснута.

Далі слід настройка двох таймерів, Timer0 і Timer1. Перший ми використовуємо для поновлення індикаторів, а другий - для зворотного відліку часу, попередньо налаштувавши його на спрацьовування кожну секунду. Детальний опис всіх констант і методу налаштування таймера на определенноий інтервал можна знайти в документації до ATmega8.

Обробка переривань

ISR (TIMER0_OVF_vect) (display (); if (_buzzer\u003e 0) (_buzzer--; if (_buzzer \u003d\u003d 0) sound_off ();)) ISR (TIMER1_COMPA_vect) (if (ActiveTimer \u003d\u003d 1 && Timer1\u003e 0) ( Timer1--; if (Timer1 \u003d\u003d 0) process_timeoff ();) if (ActiveTimer \u003d\u003d 2 && Timer2\u003e 0) (Timer2--; if (Timer2 \u003d\u003d 0) process_timeoff ();))

При спрацьовуванні таймера управління передається відповідному обробнику переривання. У нашому випадку це обробник TIMER0_OVF_vect, який викликає процедуру виведення часу на індикатори, і TIMER1_COMPA_vect, який обробляє зворотний відлік.

Висновок на індикатори

Void display () (display_number ((Timer1 / 60) / 10, 0b00001000); _delay_ms (0.25); display_number ((Timer1 / 60)% 10, 0b00000100); _delay_ms (0.25); display_number ((Timer1% 60) / 10 , 0b00000010); _delay_ms (0.25); display_number ((Timer1% 60)% 10, 0b00000001); _delay_ms (0.25); display_number ((Timer2 / 60) / 10, 0b10000000); _delay_ms (0.25); display_number ((Timer2 / 60)% 10, 0b01000000); _delay_ms (0.25); display_number ((Timer2% 60) / 10, 0b00100000); _delay_ms (0.25); display_number ((Timer2% 60)% 10, 0b00010000); _delay_ms (0.25); PORTD \u003d 0;) void display_number (int number, int mask) (PORTB \u003d number_mask (number); PORTD \u003d mask;)

Функція display використовує метод динамічної індикації. Справа в тому, що кожен окремо взятий індикатор має 9 контактів (7 для управління сегментами, 1 для точки і 1 для харчування). Для управління 4 цифрами знадобилося б 36 контактів. Занадто марнотратно. Тому висновок розрядів на індикатор з декількома цифрами організований за наступним принципом:

Напруга по черзі подається на кожен із загальних контактів, що дозволяє висвітлити на відповідному індикаторі потрібну цифру за допомогою одних і тих же 8 керуючих контактів. При досить високій частоті виведення це виглядає для ока як статична картинка. Саме тому всі 8 живлять контактів обох індикаторів на схемі підключені до 8 виходів порту D, а 16 керівників сегментами контактів з'єднані попарно і підключені до 8 виходів порту B. Таким чином, функція display з затримкою в 0.25 мс поперемінно виводить потрібну цифру на кожен з індикаторів . Під кінець відключаються всі виходи, які подають напругу на індикатори (команда PORTD \u003d 0;). Якщо цього не зробити, то остання виводиться цифра буде продовжувати горіти до наступного виклику функції display, що призведе до її більш яскравого світіння в порівнянні з іншими.

Обробка натискань

Void handle_buttons () (handle_button (KEY_SETUP); handle_button (KEY_RESET); handle_button (KEY_PAUSE); handle_button (KEY_PLAYER1); handle_button (KEY_PLAYER2);) void handle_button (int key) (int bit; switch (key) (case KEY_SETUP: bit \u003d SETUP_BIT; break; case KEY_RESET: bit \u003d RESET_BIT; break; case KEY_PAUSE: bit \u003d PAUSE_BIT; break; case KEY_PLAYER1: bit \u003d PLAYER1_BIT; break; case KEY_PLAYER2: bit \u003d PLAYER2_BIT; break; default: return;) if (bit_is_clear ( BUTTON_PIN, bit)) (if (_pressed \u003d\u003d 0) (_delay_ms (DEBOUNCE_TIME); if (bit_is_clear (BUTTON_PIN, bit)) (_pressed | \u003d key; // key action switch (key) (case KEY_SETUP: process_setup (); break; case KEY_RESET: process_reset (); break; case KEY_PAUSE: process_pause (); break; case KEY_PLAYER1: process_player1 (); break; case KEY_PLAYER2: process_player2 (); break;) sound_on (15);))) else (_pressed & \u003d ~ key;))

Ця функція по черзі опитує всі 5 кнопок і обробляє натискання, якщо таке сталося. Натискання реєструється перевіркою bit_is_clear (BUTTON_PIN, bit), тобто кнопка натиснута в тому випадку, якщо відповідний їй вхід з'єднаний з землею, що і станеться, згідно зі схемою, при натисканні кнопки. Затримка тривалістю DEBOUNCE_TIME і повторна перевірка потрібна, щоб уникнути множинних зайвих спрацьовувань через брязкоту контактів. Збереження статусу натискання в відповідних бітах змінної _pressed використовується для виключення повторного спрацьовування при тривалому натисканні на кнопку.
Функції обробки натискань досить тривіальні і вважаю, що в додаткових коментарів не потребують.

Повний текст програми

#define F_CPU 4000000UL #include #include #include #define DEBOUNCE_TIME 20 #define BUTTON_PIN PINC #define SETUP_BIT PC0 #define RESET_BIT PC1 #define PAUSE_BIT PC2 #define PLAYER1_BIT PC3 #define PLAYER2_BIT PC4 #define KEY_SETUP 0b00000001 #define KEY_RESET 0b00000010 #define KEY_PAUSE 0b00000100 #define KEY_PLAYER1 0b00001000 #define KEY_PLAYER2 0b00010000 volatile int ActiveTimer \u003d 0; volatile int Timer1 \u003d 0; volatile int Timer2 \u003d 0; volatile int _buzzer \u003d 0; volatile int _pressed \u003d 0; // function declarations void init_io (); void init_data (); int number_mask (int num); void handle_buttons (); void handle_button (int key); void process_setup (); void process_reset (); void process_pause (); void process_timeoff (); void process_player1 (); void process_player2 (); void display (); void display_number (int mask, int number); void sound_on (int interval); void sound_off (); // interrupts ISR (TIMER0_OVF_vect) (display (); if (_buzzer\u003e 0) (_buzzer--; if (_buzzer \u003d\u003d 0) sound_off ();)) ISR (TIMER1_COMPA_vect) (if (ActiveTimer \u003d\u003d 1 && Timer1\u003e 0) (Timer1--; if (Timer1 \u003d\u003d 0) process_timeoff ();) if (ActiveTimer \u003d\u003d 2 && Timer2\u003e 0) (Timer2--; if (Timer2 \u003d\u003d 0) process_timeoff ();)) int main (void) (init_io (); init_data (); sound_off (); sei (); while (1) (handle_buttons ();) return 0;) void init_io () (// set output DDRB \u003d 0xFF; DDRD \u003d 0xFF ; // set input DDRC \u003d 0b11100000; // pull-up resistors PORTC | \u003d 0b00011111; // timer interrupts TIMSK \u003d (1< 5940 || Timer2\u003e 5940) (Timer1 \u003d 0; Timer2 \u003d 0;)) void process_reset () (init_data ();) void process_timeoff () (init_data (); sound_on (30);) void process_pause () (ActiveTimer \u003d 0;) void process_player1 () (ActiveTimer \u003d 2;) void process_player2 () (ActiveTimer \u003d 1;) void handle_button (int key) (int bit; switch (key) (case KEY_SETUP: bit \u003d SETUP_BIT; break; case KEY_RESET: bit \u003d RESET_BIT ; break; case KEY_PAUSE: bit \u003d PAUSE_BIT; break; case KEY_PLAYER1: bit \u003d PLAYER1_BIT; break; case KEY_PLAYER2: bit \u003d PLAYER2_BIT; break; default: return;) if (bit_is_clear (BUTTON_PIN, bit)) (if (_pressed \u003d\u003d 0) (_delay_ms (DEBOUNCE_TIME); if (bit_is_clear (BUTTON_PIN, bit)) (_pressed | \u003d key; // key action switch (key) (case KEY_SETUP: process_setup (); break; case KEY_RESET: process_reset (); break; case KEY_PAUSE: process_pause (); break; case KEY_PLAYER1: process_player1 (); break; case KEY_PLAYER2: process_player2 (); break;) sound_on (15);))) else (_pre ssed & \u003d ~ key; )) Void handle_buttons () (handle_button (KEY_SETUP); handle_button (KEY_RESET); handle_button (KEY_PAUSE); handle_button (KEY_PLAYER1); handle_button (KEY_PLAYER2);) void display () (display_number ((Timer1 / 60) / 10, 0b00001000) ; _delay_ms (0.25); display_number ((Timer1 / 60)% 10, 0b00000100); _delay_ms (0.25); display_number ((Timer1% 60) / 10, 0b00000010); _delay_ms (0.25); display_number ((Timer1% 60)% 10, 0b00000001); _delay_ms (0.25); display_number ((Timer2 / 60) / 10, 0b10000000); _delay_ms (0.25); display_number ((Timer2 / 60)% 10, 0b01000000); _delay_ms (0.25); display_number ((Timer2 % 60) / 10, 0b00100000); _delay_ms (0.25); display_number ((Timer2% 60)% 10, 0b00010000); _delay_ms (0.25); PORTD \u003d 0;) void display_number (int number, int mask) (PORTB \u003d number_mask (number); PORTD \u003d mask;) void sound_on (int interval) (_buzzer \u003d interval; // put buzzer pin high PORTC | \u003d 0b00100000;) void sound_off () (// put buzzer pin low PORTC & \u003d ~ 0b00100000;)

Прототип був зібраний на макетної платі.