Програмування мікроконтролерів на си з нуля. CodeVisionAVR. Загальні відомості для початківців програмувати мовою Сі. Який мікроконтролер вибрати для роботи

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

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

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

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

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

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

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

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

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

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


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


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

(Visited 7 377 times, 1 visits today)

Здрастуйте, шановні Хабражителі!

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

Тема мікроконтролерів мене зацікавила дуже давно, року так у 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=="usb", ATTR(idVendor)=="16c0", ATTR(idProduct)=="05dc", GROUP="plugdev", MODE="0666"

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

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

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

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

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

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

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

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

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

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

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

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

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

ISR (TIMER0_OVF_vect) ( display(); if (_buzzer > 0) ( _buzzer--; if (_buzzer == 0) sound_off(); ) ) ISR(TIMER1_COMPA_vect) ( if (ActiveTimer == 1 && Timer1 > 0) ( Timer1--;if (Timer1 == 0) process_timeoff(); ) if (ActiveTimer == 2 && Timer2 > 0) ( Timer2--; if (Timer2 == 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) , 0b00000010), _delay_ms(0.25), display_number((Timer1%60)%10, 0b00000001); number((Timer2/ 60)%10, 0b01000000), _delay_ms(0.25), display_number((Timer2%60)/10, 0b00100000); 5);PORTD = 0; ) void display_number(int number, int mask) ( PORTB = number_mask(number); PORTD = mask; )

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

Напруга по черзі подається на кожен із загальних контактів, що дозволяє висвітлити на відповідному індикаторі потрібну цифру за допомогою тих самих 8 керуючих контактів. При досить високій частоті виведення це виглядає для ока як статична картинка. Саме тому всі 8 живлячих контактів обох індикаторів на схемі підключені до 8 виходів порту D, а 16 управляючих сегментами контактів з'єднані попарно і підключені до 8 виходів порту B. Таким чином, функція display із затримкою в 0.25 мс поперемінно виводить потрібну цифру на кожен . Під кінець відключаються усі виходи, що подають напругу на індикатори (команда PORTD = 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); ) = SETUP_BIT; break; case KEY_RESET: bit = RESET_BIT; break; case KEY_PAUSE: bit = PAUSE_BIT; break; case KEY_PLAYER1: bit = PLAYER1_BIT; _is_clear( BUTTON_PIN, bit)) ( if (_pressed == 0) ( _delay_ms(DEBOUNCE_TIME); if (bit_is_clear(BUTTON_PIN, bit))) ( _pressed |= key; // key action switch (key) ( case KEY_SETUP: process_ break; case KEY_RESET: process_reset(); break; case KEY_PAUSE: process_pause(); break; case KEY_PLAYER1: process_player1(); break; &= ~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_00 000010 #define KEY_PAUSE 0b00000100 #define KEY_PLAYER1 0b00001000 #define KEY_PLAYER2 0b00010000 volatile int ActiveTimer = 0; volatile int Timer1 = 0; volatile int Timer2 = 0; volatile int _buzzer = 0; volatile int _pressed = 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 > 0) ( _buzzer--; if (_buzzer == 0) sound_off(); ) ) ISR(TIMER1_COMPA_vect) ( if (ActiveTimer == 1 && Timer1 > 0) ( Timer1--; if (Timer1 == 0) process_timeoff(); ) if (ActiveTimer == 2 && Timer2 > 0) ( Timer2--; if (Timer2 == 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 = 0xFF; DDRD = 0xFF // Set input DDRC = 0b11100000; // Pull-up Resistors PORTC | = 0b00011111;<5940 || Timer2 > 5940) ( Timer1 = 0; Timer2 = 0; ) ) void process_reset() ( init_data(); ) void process_timeoff() ( init_data(); sound_on(30); ) void process_pause() ( ActiveTimer = 0; ) void process_player1() ( ActiveTimer = 2; ) void process_player2() ( ActiveTimer = 1; ) void handle_button(int key) ( int bit; switch (key) ( case KEY_SETUP: bit = SETUP_BIT; break; case KEY_RESET: break; case KEY_PAUSE: bit = PAUSE_BIT; break; case KEY_PLAYER1: bit = PLAYER1_BIT; break; case KEY_PLAYER2: bit = PLAYER2_BIT; break; 0) ( _delay_ms(DEBOUNCE_TIME); якщо (bit_is_clear(BUTTON_PIN, bit)) ( _pressed |= key; // key action switch (key) ( case KEY_SETUP: process_setup(); break; case KEY_RESET: process; case KEY_PAUSE: process_pause(); break; case KEY_PLAYER1: process_player1(); break; case KEY_PLAYER2: process_player2(); break; ) sound_on(15); ) ))) ) ) 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()0 ) ; _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); play_number((Timer2 %60)/10, 0b00100000), _delay_ms(0.25); display_number((Timer2%60)%10, 0b00010000); (number); PORTD = mask;

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

Урок 0

Сьогодні ми відкриваємо цикл уроків програмування мікроконтролерів сімейства AVR.

Сьогодні будуть розглянуті такі питання:

  1. Що таке мікроконтролер?
  2. Де застосовуються мікроконтролери?

Вступ.

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

То що таке, мікроконтролер?

Мікроконтролер (Micro Controller Unit, MCU) - мікросхема, призначена для управління електронними пристроями. Можна уявити його у вигляді найпростішого комп'ютера, здатного взаємодіяти із зовнішніми пристроями. Наприклад, відкривати та закривати транзистори, отримувати дані з датчиків температури, виводити дані на lcd екрани тощо. Крім того, мікроконтролер може проводити різну обробку вхідних даних, як і Ваш персональний комп'ютер.

Тобто, мікроконтролери відкривають нам практично безмежні можливості управління будь-якими пристроями, завдяки наявності портів I/0 (портів введення (input) / виводу (output)), а також можливості їх програмування.

Де використовуються мікроконтролери?

  1. Побутова техніка (Пральні машини, мікрохвильові печі і т.д.).
  2. Мобільна техніка (Роботи, робототехнічні системи, засоби зв'язку та ін.).
  3. Промислове обладнання (Системи керування верстатами).
  4. Обчислювальна техніка (Материнські плати, системи управління периферійними пристроями).
  5. Розважальна техніка (Дитячі іграшки, прикраси).
  6. Транспорт(Системи керування двигуном автомобіля, системи безпеки)

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

Початок знайомства з AVR

AVR- Сімейство мікроконтролерів фірми Atmel. Мають достатню продуктивність для більшості аматорських пристроїв. Також знаходять широке застосування у промисловості.

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

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

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

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

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

Одним словом, Сі - найзручніша мова як для початківців знайомитися з мікроконтролерами AVR, так і для серйозних розробників.

Щоб перетворити вихідний текст програми на файл прошивки мікроконтролера, застосовують компілятори.

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

В даний час представлено багато компіляторів Сі для AVR. Найпотужнішим з них вважається компілятор фірми IAR Systems зі Стокгольма. Саме її співробітники в середині 90-х брали участь у розробці системи команд AVR. IAR C Compiler має широкі можливості з оптимізації коду і поставляється у складі інтегрованого середовища розробки IAR Embedded Workbench (EWB), що включає також компілятор асемблера, лінкер, менеджер проектів і бібліотек, а також відладчик. Ціна повної версії пакету складає 2820 EUR. На сайті компанії можна безкоштовно скачати оцінну версію на 30 днів або безстрокову з обмеженням розміру коду в 4 Кбайти.

Американською фірмою Image Craft з каліфорнійського Пало-Альто випускається компілятор мови Сі, який здобув досить широку популярність. JumpStart C for AVR має прийнятну оптимізацію коду та не надто високу ціну (від $50 до $499 залежно від версії). Демо-версія JumpStart C для AVR повністю функціональна протягом 45 днів.

Не меншу популярність завоював румунський Code Vision AVR C Compiler, ціна повної версії компілятора відносно невисока і становить 150 EUR. Компілятор поставляється разом з інтегрованим середовищем розробки, в яке, крім стандартних можливостей, включено досить цікаву функцію - CodeWizardAVR Automatic Program Generator. Наявність у середовищі розробки послідовного терміналу дозволяє проводити налагодження програм з використанням послідовного порту мікроконтролера. У розробників можна завантажити безкоштовну оцінну версію з обмеженням розміру коду в 4 Кбайта та відключеним збереженням згенерованого вихідного коду на Сі.

Компанія MikroElektronika, розташована в сербському місті Белграді, випускає цілу родину компіляторів для AVR-мікроконтролерів. Компілятор для мови Сі під назвою mikroC PRO for AVR коштує $249. Є також mikroBasic та mikroPascal за ту ж ціну. На сайті розробників є демоверсії з обмеженням розміру коду 4096 bytes. Плюсом цього сімейства компіляторів є єдина платформа та єдина ідеологія, що може забезпечувати легкий перехід не лише між мовами, а й між мікроконтролерами (є версії компіляторів для PIC, STM32, 8051…).

Воістину культовою стало інтегроване середовище розробки. Вона включає потужні компілятори Сі та асемблера, програматор AVRDUDE, відладчик, симулятор та безліч інших допоміжних програм та утиліт. WinAVR чудово інтегрується із середовищем розробки AVR Studio від Atmel. Асемблер ідентичний за вхідним кодом асемблеру AVR Studio. Компілятори Сі та асемблера мають можливість створення налагоджувальних файлів у форматі COFF, що дозволяє застосовувати не тільки вбудовані засоби, але й використовувати потужний симулятор AVR Studio. Ще одним важливим плюсом є те, що WinAVR поширюється безкоштовно без обмежень (виробники підтримують GNU General Public License).

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

Кисельов Роман, Травень 2007 Статтю оновлено 26 Травня 2014

Отже, що таке мікроконтролер (далі МК)? Це, умовно кажучи, невеликий комп'ютер, розміщений в одній інтегральній мікросхемі. У нього є процесор (арифметично-логічний пристрій, або АЛУ), flash-пам'ять, EEPROM-пам'ять, безліч регістрів, порти введення-виводу, а також додаткові «навороти», такі як таймери, лічильники, компаратори, USART і т.п. Мікроконтролер після подачі живлення завантажується і починає виконувати програму, записану в його flash-пам'яті. При цьому він може через порти вводу/виводу керувати різноманітними зовнішніми пристроями.

Що це означає? Це означає, що у МК можна реалізувати будь-яку логічну схему, яка виконуватиме певні функції. Це означає, що МК – мікросхема, внутрішній вміст якої, власне, ми створюємо самі. Що дозволяє, купивши кілька абсолютно однакових МК, зібрати на них абсолютно різні схеми та пристрої. Якщо вам захочеться внести якісь зміни в роботу електронного пристрою, то не потрібно буде використовувати паяльник, достатньо лише перепрограмувати МК. При цьому не потрібно навіть виймати його з вашого дивайсу, якщо ви використовуєте AVR, оскільки ці МК підтримують внутрішньосхемне програмування. Таким чином, мікроконтролери ліквідують розрив між програмуванням та електронікою.

AVR – це 8-бітні мікроконтролери, тобто їх АЛУ може за один такт виконувати найпростіші операції лише з 8-ми бітними числами. Тепер настав час поговорити про те, який МК ми будемо використовувати. Я працюю з МК ATMega16. Він дуже поширений і придбати його можна практично в будь-якому магазині радіодеталей десь за 100 руб. Якщо ви його не знайдете – тоді можна купити будь-який інший МК серії MEGA, але в цьому випадку доведеться шукати до нього документацію, тому що одні й ті самі «ніжки» різних МК можуть виконувати різні функції, і, підключивши, здавалося б, правильно всі висновки, ви, можливо, отримаєте робочий пристрій, а, можливо, лише хмара смердючого диму. При покупці ATMega16 перевірте, щоб він був у великому 40-ніжному DIP-корпусі, а також купіть панельку, в яку його можна буде вставити. Для роботи з ним будуть потрібні також додаткові пристрої: світлодіоди, кнопки, роз'єми тощо.

ATMega16 має дуже велику кількість найрізноманітніших функцій. Ось деякі його характеристики:

  • Максимальна тактова частота – 16 МГц (8 МГц для ATMega16L)
  • Більшість команд виконуються за один такт
  • 32 8-бітових робочих регістру
  • 4 повноцінні 8-бітові порти вводу/виводу
  • два 8-бітні таймери/лічильники і один 16-бітний
  • 10-розрядний аналогово-цифровий перетворювач (АЦП)
  • внутрішній тактовий генератор на 1 МГц
  • аналоговий компаратор
  • інтерфейси SPI, I2C, TWI, RS-232, JTAG
  • внутрішньосхемне програмування та самопрограмування
  • модуль широтно-імпульсної модуляції (ШІМ)

Повні характеристики цього пристрою, а також інструкції щодо їх застосування можна знайти в довіднику (Datasheet) до цього МК. Щоправда, він англійською мовою. Якщо ви знаєте англійську, то обов'язково завантажте цей Datasheet, у ньому багато корисного.

Приступимо нарешті до справи. Я рекомендую виготовити для мікроконтролера спеціальну макетно-налагоджувальну плату, на якій можна буде без паяльника (або майже без нього) зібрати будь-яку електричну схему з мікроконтролером. Використання такої плати значно полегшить роботу з МК та прискорить процес вивчення його програмування. Виглядає це так:

Що для цього знадобиться?

По-перше, знадобиться сама плата. Я купив уже готову в магазині радіодеталей за 115 руб. Потім припаяла до неї всі необхідні деталі. Вийшла неймовірно зручна річ, на якій можна за лічені хвилини зібрати якусь електричну схему шляхом перетикання шлейфів та встановлення мікросхем та індикаторів.

Для з'єднання елементів схеми дуже зручно використовувати шлейфи, на кінцях яких встановлені гнізда. Ці роз'єми надягають на «ніжки», що стирчать поруч із кожним портом МК. Мікроконтролер слід встановлювати в панельку, а не припаювати до плати, інакше його дуже важко буде вийняти, якщо ви його випадково спалите. Нижче наведено цоколівку МК ATMEGA16:

Пояснимо, які ніжки нас зараз цікавлять.

  • VCC - сюди подається харчування (4,5 - 5,5 В) від стабілізованого джерела
  • GND – земля
  • RESET – скидання (при низькому рівні напруги)
  • XTAL1, XTAL2 – сюди підключається кварцовий резонатор
  • PA, PB, PC, PD – порти вводу/виводу (A, B, C та D відповідно).

Як джерело живлення можна використовувати все, що видає 7-11 В постійного струму. Для стабільної роботи МК потрібне стабілізоване харчування. Як стабілізатор можна використовувати мікросхеми серії 7805. Це лінійні інтегральні стабілізатори, на вхід яких подають 7-11 постійного нестабілізованого струму, а на виході отримують 5 стабілізованого. Перед 7805 і після нього потрібно поставити конденсатори, що фільтрують (електролітичні для фільтрації перешкод низьких частот і керамічні для високих). Якщо не вдається знайти стабілізатор, то як джерело живлення можна використовувати батарейку на 4,5 В. Від неї МК потрібно живити безпосередньо.

Нижче наведу схему підключення МК:

Давайте тепер розберемося, що тут навіщо.

BQ1 – це кварцовий резонатор, що задає робочу частоту МК. Можна поставити будь-який до 16 МГц, але оскільки ми плануємо працювати в майбутньому і з COM-портом, то рекомендую використовувати резонатори на наступні частоти: 14,7456 МГц, 11,0592 МГц, 7,3725 МГц, 3,6864 МГц або 1 ,8432 МГц (пізніше стане зрозуміло, чому). Я використав 11,0592 МГц. Зрозуміло, що чим більша частота, тим вища і швидкість роботи пристрою.

R1 – підтягуючий резистор, який підтримує напругу 5 на вході RESET. Низький рівень напруги цьому вході означає скидання. Після скидання МК завантажується (10-15 мс) і починає виконувати програму заново. Оскільки це високоомний вхід, то не можна залишати його «болтаючим у повітрі» - невелике наведення на ньому призведе до непередбачуваного скидання МК. Саме для цього і потрібний R1. Для надійності також рекомендую встановити конденсатор С6 (не більше 20 мкФ).

SB1 – кнопка скидання.

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

Синім прямокутником на схемі обведений власне програматор. Його зручно виконати у вигляді дроту, один кінець якого встромляється в LPT порт, а інший - в якийсь роз'єм поруч із МК. Провід не повинен бути надмірно довгим. Якщо виникнуть проблеми з цим кабелем (зазвичай не виникають, але всяке буває) доведеться спаяти адаптер Altera ByteBlaster. Про те, як це зробити, написано в описі програматора AVReal.

Тепер, коли розібралися із залізом, настав час перейти до програмного забезпечення.

Для програмування AVR є кілька середовищ розробки. По-перше, це AVR Studio – офіційна система програмування Atmel. Вона дозволяє писати на асемблері та налагоджувати програми, написані на асемблері, С та С++. IAR – це комерційна система програмування на C, С++ та асемблері. WinAVR – компілятор із відкритими вихідними джерелами. AtmanAVR – система програмування для AVR з інтерфейсом, майже «один на один» таким же, як у Visual C++ 6. AtmanAVR також дозволяє налагоджувати програми та містить безліч допоміжних функцій, що полегшують написання коду. Ця система програмування є комерційною, але, відповідно до ліцензії, її можна протягом місяця використовувати «нахаляву».

Я пропоную розпочати роботу з IAR як із найбільш «прозорим» середовищем розробки. У IAR проект цілком створюється «ручками», відповідно, зробивши кілька проектів, ви вже чітко знатимете, що означає кожен рядок коду і що буде, якщо його змінити. При роботі ж з AtmanAVR доведеться або користуватися заздалегідь створеним шаблоном, який дуже громіздкий і важкий для розуміння для людини, яка не має досвіду, або мати безліч проблем із заголовними файлами при складанні проекту «з нуля». Розібравшись із IAR, ми згодом розглянемо інші компілятори.

Отже, спочатку роздобудьте IAR. Він дуже поширений і його перебування не має бути проблемою. Завантаживши десь IAR 3.20, встановлюємо компілятор / робоче середовище і запускаємо його. Після цього можна розпочинати роботу.

Запустивши IAR, вибираємо file/new/workspace, вибираємо шлях до нашого проекту та створюємо для нього папку та даємо ім'я, наприклад, «Prog1». Тепер створюємо проект: Project / Create new project…Назвемо його також - "Prog1". Клацаємо правою кнопкою миші на заголовку проекту у дереві проектів та вибираємо «Options»

Тут налаштовуватимемо компілятор під конкретний МК. По-перше, потрібно вибрати на вкладці Target тип процесора ATMega16, на вкладці Library Configuration встановити галочку Enable bit definitions in I/O-include files (щоб можна було використовувати в коді програми імена бітів різних регістрів МК), там вибрати тип бібліотеки С /ЄС++. У категорії ICCAVR потрібно на вкладці Language встановити галочку Enable multibyte support, а на вкладці Optimization вимкнути оптимізацію (інакше вона зіпсує нашу першу програму).

Далі вибираємо категорію XLINK. Тут потрібно визначити формат відкомпілюваного файлу. Оскільки зараз ми задаємо опції для режиму налагодження (Debug), про що написано в заголовку, то на виході потрібно отримати файл налагодження. Пізніше ми його відкриємо у AVR Studio. Для цього потрібно вибрати розширення .cof, а тип файлу – ubrof 7.

Тепер натискаємо ОК, після чого змінюємо Debug на Release.

Знову заходимо в Options, де всі параметри, окрім XLINK, виставляємо самі. У XLINK змінюємо розширення на .hex, а формат файлу на intel-standart.

От і все. Тепер можна розпочинати написання першої програми. Створюємо новий Source/text і набираємо в ньому наступний код:

#include"iom16.h" short unsigned int i; void main ( void) (DDRB = 255; PORTB = 0; while(1) { if(PORTB == 255) PORTB = 0; else PORTB++; for(i=0; i

Файл iom16.h знаходиться в папці (C:\Program Files)\IAR Systems\Embedded Workbench 3.2\avr\inc. Якщо ви використовуєте інший МК, наприклад, ATMega64, вибирайте файл «iom64.h». У цих заголовних файлах зберігається інформація про МК: імена регістрів, бітів у регістрах, визначені імена переривань. Кожна окрема "ніжка" порту A, B, C або D може працювати або як вхід, або як вихід. Це визначається регістрами Data Direction Register (DDR). 1 робить "ніжку" виходом, 0 - входом. Отже, виставивши, наприклад, DDRA = 13, ми робимо виходами «ніжки» PB0, PB2, PB3, інші – входи, т.к. 13 у двійковому коді буде 00001101.

PORTB – це регістр, у якому визначається стан «ніжок» порту. Записавши туди 0, ми виставляємо всіх виходах напруга 0 У. Далі йде нескінченний цикл. При програмуванні МК завжди роблять нескінченний цикл, в якому МК виконує будь-яку дію, доки його не скинуть або поки не відбудеться переривання. У цьому циклі пишуть як би «фоновий код», який МК виконує в останню чергу. Це може бути, наприклад, виведення інформації на екран. У нашому випадку збільшується вміст регістру PORTB до того часу, поки він заповниться. Після цього все починається спочатку. Нарешті, цикл на десять тисяч тактів. Він необхідний формування видимої затримки у перемиканні стану порту.



Тепер зберігаємо цей файл у папці з проектом як Prog1.c, копіюємо в папку з проектом файл iom16.h, вибираємо Project/Add Files і додаємо "iom16.h" та "Prog1.c". Вибираємо Release, натискаємо F7, програма компілюється та має з'явитися повідомлення:


Total number of errors: 0
Total number of warnings: 0

Наведу фотографію свого програматора:

Завантажуємо програматор AVReal. Копіюємо його (AVReal32.exe) до папки Release/exe, де має лежати файл Prog1.hex. Подаємо харчування на МК, підключаємо кабель-програматор. Відкриваємо Far Manager (у ньому найзручніше прошивати МК), заходимо в цю папку, натискаємо Ctrl+O. Оскільки в нас абсолютно новий МК, то набиваємо

avreal32.exe +MEGA16 -o11.0592MHZ -p1 -fblev=0,jtagen=1,cksel=F,sut=1 –w

Не забудьте правильно вказати частоту, якщо використовуєте 11059200 Гц! При цьому МК прошиваються т.зв. fuses – регістри, які керують його роботою (використання внутрішнього генератора, Jtag тощо). Після цього він готовий до прийому першої програми. Програматору як параметри передають використовуваний LPT-порт, частоту, ім'я файлу та інші (всі вони перераховані в описі до AVReal). Набираємо:

Avreal32.exe +Mega16 -o11.0592MHz -p1 -e -w -az -% Prog1.hex

У разі правильного підключення програматор повідомить про успішне програмування. Немає гарантії, що це вийде з першого разу (у разі першого виклику програми). У мене самого буває програмується з другого разу. Можливо, LPT-порт є глючним або виникають наведення в кабелі. У разі виникнення проблем ретельно перевірте свій кабель. За своїм досвідом знаю, що 60% несправностей пов'язані з відсутністю контакту в потрібному місці, 20% - з наявністю в непотрібному і ще 15% - з помилковою пайкою не до того. Якщо нічого не вийде, читайте опис до програматора, спробуйте зібрати Byte Blaster.

Припустимо, у вас все працює. Якщо тепер підключити до порту В МК вісім світлодіодів (робіть це у вимкненому стані МК, і бажано послідовно зі світлодіодами включити резистори в 300-400 Ом) і подати живлення, то станеться маленьке диво – по них побіжить хвиля!

© Кисельов Роман
Травень 2007


Top