Осваиваем микроконтроллеры на примере Atmega8
В рамках данной статьи мы не станем сильно погружаться в многообразие внутренних процессов и дебри архитектуры микроконтроллера. А основной нашей задачей будет являться освоение азов практической работы с микроконтроллером и получение навыков для самостоятельной разработки и изготовления какого-либо интересующего нас электронного устройства.
В качестве подопытного выберем популярный и довольно высокопроизводительный 8-разрядный AVR микроконтроллер Atmega8 в удобном для наших целей 28-выводном DIP корпусе.
Итак, что нам нужно для полного счастья?
1. Простая и желательно бесплатная среда разработки, в которой посредством слов и цифр можно написать программу, а затем скомпилировать её, т. е. перевести на язык, понятный микроконтроллеру.
Одним из удачных примеров такой среды является Atmel Studio. Скачать эту программу не составит никакого труда, в том числе и на официальном сайте разработчика – https://www.microchip.com/.
2. Отладочная плата для микроконтроллера с DIP28 панелькой для микросхемы.

Удачным вариантом такой платы я бы счёл изделие под названием «плата разработки ATmega8 – сделай сам», предлагаемое китайскими товарищами за символические 150 отечественных рублей.
В комплект поставки входят:
– собственно, сама плата;
– Панелька DIP28;
– Кварцевый резонатор на 8 МГц;
– Разъём для подключения программа- тора;
– Разные деталюшки в виде: конденсаторов, резисторов, кнопок, светодиодов, т. е. всего того, что позволит легко запрограммировать и проверить микропроцессор в работе.
Можно, конечно, обойтись и без отладочной платы и произвести прошивку ATmega8 непосредственно в готовом устройстве, тем более что микропроцессор это сделать позволяет. Однако на практике произвести эти манипуляции заранее, а уже потом устанавливать микросхему по месту прописки оказывается значительно удобнее.
3. Программатор AVR USB, для того чтобы запрограммировать микроконтроллер, то есть перенести в него информацию с компьютера.

Такой программатор оценивается на aliexpress примерно в ту же стоимость, что и предыдущее изделие.
Программатор подсоединяется к USB порту компьютера, а другим своим концом к плате микроконтроллера.
Данное соединение осуществляется через ISP разъём кабеля, который также входит в комплект поставки.
Питание берётся от USB разъёма компьютера.
Работать программатор может под разными операционными системами, в том числе – под Windows.
Если тип приобретённого программатора не будет поддерживаться Atmel Studio, то придётся скачать и бесплатную программу прошивки микроконтроллеров, например, AVRDude.
4. Контактная макетная плата для монтажа без пайки.

Такая макетная плата совместно с набором соединительных проводов (джамперов) будет весьма полезна на начальном этапе освоения микроконтроллера.
Она без какого-либо напряга и паяльника позволит соединить любые электронные элементы обвеса микроконтроллера в законченную конструкцию, превращая весь процесс создания схемы в увлекательную игру с конструктором LEGO.
Подобный набор, состоящий из беспаечной макетной платы и комплекта проводов, обойдётся не дороже 200 рублей.
5. Для того чтобы в процессе отладки не перепрошивать ATmega8 бесчисленное количество раз, жизненно необходима программа, позволяющая отладить прошивку без участия микроконтроллера.
Для этой цели как нельзя лучше подходит программа для автоматизированного проектирования электронных схем (в том числе и микроконтроллеров) – Proteus. Она значительно упрощает процесс отладки программы без участия микроконтроллера, ведь любой накопитель имеет конечное число перезаписей, хотя это число и достаточно большое.
6. Если написать и отладить программу для микроконтроллера можно и без его непосредственного участия, то, по-любому, рано или поздно встанет конкретный вопрос: «А на фига мы всё это делали?».
Поэтому хочешь, не хочешь, а приобрести ATmega8 нам также всё ж таки придётся. Стоит она на Али, как и всё остальное, довольно-таки гуманных денег – около 100 рублей за единицу продукции, поэтому кошелёк опорожнит не сильно, но уважительного к себе отношения потребует.
А теперь давайте-ка посмотрим: А что это за штука – ATMEGA8 попала нам в руки?

Рис.1 Внешний вид и назначение выводов Atmega8
У данного типа МК есть два типа питания – цифровое VCC (выв.7) и аналоговое AVCC (выв.20). В стандартном включении, когда на входы/выходы контроллера подаются логические 1 и 0, оба вывода питания соединяют (физически соединяются VCC и AVCC, поскольку GND выводы 8 и 22 уже замкнуты внутри ИМС через сопротивление 0,7 Ом). Однако при подключении нагрузки, эти земляные выводы необходимо замкнуть на плате, т. к. внутри они соединены тонким проводником, который при существенном токе не следует рассматривать как «перемычку».
Если используется встроенный АЦП, или входы/выходы задействованы для работы с аналоговыми сигналами, то для уменьшения помех производитель рекомендует использовать последовательный LC-фильтр по AVCC.
Между выводами питания и землёй (в непосредственной близости от выводов питания микросхемы) всегда следует устанавливать керамические конденсаторы ёмкостью 0,1 Мкф, которые обычно называют блокировочными конденсаторами.
Ещё один непомеченный цветом вывод (Рис.1) – 21 вывод (AREF).
AREF означает Analog Reference и является входом для подачи (при необходимости) опорного напряжения от внешнего источника питания.
Все раскрашенные выводы микроконтроллера (Рис.1) – это порты ввода-вывода, через которые микроконтроллер общается с внешним миром. У ATmega8 их три: PB0. PB7, PC0. PC6, PD0. PD7.
PB0. PB7 и PD0. PD7 – это полные, т. е. 8-разрядные порты, PC0. PC6 – неполный 7-разрядный порт, т. к. для полноты ему тупо не хватило лишнего вывода у микросхемы.
Каждый вывод порта может работать либо как вход, либо как выход. Для того чтобы выбрать режим работы ножки микроконтроллера необходимо прописать нужные биты в соответствующие регистры.
Однако есть у части портов ввода-вывода и специфические функции, прописанные в документации на микросхему. Давайте посмотрим, что это за функции:
1. Порты PB0. РВ7. Два вывода (РВ6 и PB7) используются для подключения кварцевого резонатора. Выводы РВ2. РВ5 зарезервированы для программирования МК. Таким образом, для общего применения остаются порты PB0 и PB1.
2. Порты PC0. РС6. Порты PC0. РС5 есть возможность использовать в качестве аналоговых входов. РС6 обычно используется для общего внешнего сброса настроек, т. е. перезагрузки прошивки МК.
3. Порты PD0. РD7. Эти порты можно использовать для общего применения.
Atmega8 выпускается с уже настроенным для использования встроенным RC-генератором с частотой 1МГц, который позволяет запустить МК без внешних элементов. Посредством конфигурационных манипуляций, значения этой частоты могут принимать также значения: 2, 4 и 8 MHz. Однако для решения многих задач стабильности RC-генератора оказывается явно недостаточно, в связи с чем для тактирования микроконтроллера используется внешний кварцевый резонатор.
Следует запомнить, что МК не является устройством, которое управляет большими мощностями, для этого есть транзисторы, тиристоры и прочие силовые элементы. Максимальный ток линии ввода/вывода составляет 40мА, максимальный суммарный ток по цепям питания и GND – 200мА.
И под занавес:
Основные технические параметры ATmega8:
— Память для программ составляет 8 Кб с возможностью перезаписать 10 000 раз;
— 512 байт флеш-памяти для хранения переменных (100 000 циклов перезаписи);
— 1 Кб ОЗУ и 32 регистра общего назначения;
— Два 8-разрядных Таймера/Счетчика с раздельным прескалером, режим сравнения;
— 16-разрядный Таймер/Счетчик с раздельным прескалером, режим сравнения, режим захвата;
— Таймер реального времени с независимым генератором;
— 3 канала ШИМ;
— 6 каналов 10-разрядного АЦП;
— Двухпроводный последовательный интерфейс;
— Программируемый последовательный USART;
— Интерфейс SPI с режимами Master/Slave;
— Программируемый сторожевой таймер с отдельным независимым генератором;
— Встроенный аналоговый компаратор;
— Сброс при включении питания, программируемая защита от провалов питания;
— Встроенный калиброванный RC-генератор;
— Обработка внутренних и внешних прерываний;
— 5 режимов с пониженным энергопотреблением: Idle, ADC Noise Reduction, Power-save, Power-down и Standby;
— Напряжение питания 4.5 — 5.5В;
— Тактовая частота 0-16 МГц.
Ну, на этом, пожалуй, и всё.
Для желающих посерьёзней углубиться в знания, могу порекомендовать datasheet производителя и русскоязычное описание ATmega8, с которым можно познакомиться по ссылке — ATMEGA8.
А на следующих страницах будем осваивать язык программирования, а также запускать несложные устройства, выполненные на микроконтроллерах.
Мигающий светодиод на микроконтроллере
Ну что ж, будем считать, что всё необходимое для эволюционного развития отечественного МК-строения у нас куплено, скачано и собрано воедино. Теперь остаётся придумать простенький проект, написать программу в Atmel Studio, скомпилировать код, после чего проверить его работоспособность с помощью симулятора микроконтроллеров, а также прочих электронных устройств – Proteus.
Писать программу будем на одном из популярных языков, используемых для программирования МК – языке Си.
В качестве проекта по сформировавшейся традиции выберем светодиод, подключённый к выходу микроконтроллера, и заставим его мигать с некоторой заданной нами периодичностью.
Забегая вперёд, приведу схему готового проекта на Atmega8, собранного в Протеусе, которую нам ещё предстоит запрограммировать в Atmel Studio и только потом проверить в симуляторе.
Рис.1 Мигающий светодиод на микроконтроллере Atmega8
Теперь по порядку:
1. Для начала запускаем программу Atmel Studio:
— Кликаем по вкладке New и далее Project.
— В открывшемся окне выбираем язык программирования C/C++.
В строке для ввода Name – название проекта, например, Svetodiod.
В графе Location – место желаемого расположения папки с файлами проекта.
В качестве типа проекта выбираем – GCC C Executable Project.
Жмём – ОК.
— В новом окне находим и выделяем микроконтроллер ATmega8 и опять нажимаем кнопку OK.
— После проделанных манипуляций Atmel Studio нам автоматически сформировала заготовку (шаблон) программы:
/*
* GccApplication2.c
*
* Created: 22.06.2021 11:37:14
* Author : Vpayaem.ru
*/
int main(void)
<
/* Replace with your application code */
while (1)
<
>
>
Текст, в нашем случае выделенный зелёным цветом, является комментариями, которые полностью игнорируются компилятором.
Комментарии могут быть многострочными (как в приведённом шаблоне), где текст помещается между /* и */ , а могут быть однострочными.
Однострочный комментарий обозначается двумя косыми линиями перед текстом и действует в пределах одной строки, например: // Здесь написан однострочный комментарий.
Переходим к собственно программе прошивки.
Знак # в начале строки означает, что данная команда является директивой препроцессора, т. е. содержит в себе некоторые инструкции, которые выполняются в первую очередь и работают, невзирая на весь остальной код.
В данной строке подключается библиотека микроконтроллера, в которой находятся определения констант, имён регистров и всего прочего, что может понадобиться для выполнения базового ввода-вывода информации. Для корректного выполнения микроконтроллером некоторых функций (например, таких как задержка), в настройках проекта необходимо прописать директиву, указывающую – с какой тактовой частотой будет работать микроконтроллер. Такой директивой является:
2. #define F_CPU 1000000UL
Так как частота по умолчанию для ATmega8 (при работе со встроенным генератором) равна 1 000 000 Гц, то это значение мы и объявим в виде числа 1000000.
При написании кода на языке Си в Atmel Studio имеется очень удобная функция задержки выполнения программы _delay_ms(). Для включения данной функции её необходимо предварительно прописать директивой:
На этом с директивами, пожалуй, закончим.
Далее заготовка из Atmel Studio выдаёт нам следующую строку:
Здесь ничего мудрить не надо. В данной строке объявляется функция main, с которой начинается выполнение программы.
А вот теперь нам необходимо сконфигурировать единственный задействованный нами сигнальный вывод Atmega8 PC0 как выход (Рис.1).
Давайте-ка немного отвлечёмся и поговорим об этом поподробнее. Ведь мы знаем, что большинство выводов (портов) микроконтроллера могут работать и как входы, и как выходы. Поэтому любой задействованный разряд МК предварительно нужно настроить на соответствующий режим. Для этого в микроконтроллере есть специальный регистр, который называется DDRx (direct data register – регистр направления данных), где x обозначает букву соответствующего порта, т. е. DDRС, к примеру, определяет направление передачи данных для интересующего нас порта С.
Чтобы настроить вывод порта как вход, в регистр DDRх необходимо записать ноль, а для настройки в качестве выхода – единицу.
Так как же нам записать в регистр интересующего нас разряда PC0 единицу, чтобы задействовать его в качестве выхода?
В нашем случае лучше всего это сделать побитовой настройкой, хотя, в первом приближении, она и выглядит довольно мудрёной:
Эта запись означает, что для нулевого разряда порта С (номер разряда указывает последняя цифра), т. е. для вывода PC0 мы прописали в DDR единицу и тем самым настроили его как выход.
А вот, если бы нам туда понадобилось прописать ноль, т. е. настроить PC0 как вход, то команда для начинающего программиста выглядела бы ещё более странной:
Но тут, как говорится – что уж? Поэтому на первых порах надо эту причудливую лабуду: либо просто запомнить, либо куда-нибудь сохранить и оттуда копировать, не сильно запариваясь по поводу её высокой роли в языке программирования Си.
Довольно распространён способ настройки DDR регистров и в виде двоичного кода. Данная форма записи удачно сочетается с количеством битов порта, так как количество битов соответствует количеству выводов порта, а порядковый номер бита отвечает номеру бита внутри порта.
В нашем случае, чтобы настроить PC0 на выход следует написать следующую команду:
Здесь префикс 0b идентифицирует следующее за ним число как двоичное, а порядковый номер бита отвечает номеру бита внутри порта. То есть последний (крайний правый) разряд этого числа соответствует PC0, предпоследний – PC1 и т. д. Как итог: PC0 настроен как выход, все остальные разряды (PC1. PC6) – как высокоимпедансные входы.
По большому счёту данная команда (в виде двоичного кода) выполняет ту же функцию, что и побитовая настройка порта. Однако, если побитовая команда DDR аккуратно настраивает каждый отдельный выбранный нами разряд, то двоичная форма записи конфигурирует сразу все разряды порта, что повышает вероятность (особенно на первых этапах освоения программирования) всяческих неприятных ошибок.
Далее в нашей заготовке прописана функция:
Данная функция обозначает бесконечный цикл. Это говорит о том, что код программы, находящийся в теле данной функции (внутри фигурных скобок), будет повторяться бесконечное число раз, т. е. программа будет зациклена. Теперь внутри цикла можно записывать команды управления светодиодом.
Для того, чтобы управлять уровнем напряжения на любом выходе служит регистр PORTх, где, опять же, x — обозначает букву соответствующего порта. Если бит установлен в единицу, то на выходе будет уровень близкий к напряжению питания микроконтроллера, если бит установлен в ноль, то на выводе будет напряжение близкое к нулю.
Установим логическую 1 на выходе PC0, т. е. заставим светодиод светиться:
Здесь всё записывается аналогично форме, которую мы использовали для программирования регистров DDRx. В виде двоичного кода эта форма имела бы вид:
После того как светодиод зажжётся, пусть некоторое время погорит. Для этого существует команда _delay_ms(). Эта функция осуществляет задержку выполнения последующей команды на время, выраженное в миллисекундах и численно равное числовому значению, находящемуся внутри круглых скобок.
То бишь команда:
будет поддерживать высокий уровень на PC0 в течении 500 мс (0,5 сек) или до бесконечности, пока мы его не сбросим в ноль.
А сбросим мы его в ноль сразу по прошествии 0,5 сек посредством команды:
Теперь опять полсекунды подождём:
После чего заканчиваем цикл и возвращаемся к его началу, то есть к первой команде управления светодиодом. Давайте посмотрим на код, который у нас получился в сухом остатке:
/*
* GccApplication2.c
*
* Created: 22.06.2021 11:37:14
* Author : Vpayaem.ru
*/
#include
#define F_CPU 1000000UL // Выбираем частоту МК
#include // Включаем функцию задержек
int main(void)
< // Начало основной программы
DDRC |= ( 1 // Устанавливаем вывод порта PC0 — как выход
PORTC |= (1 // Лог. 1 на выходе PC0
_delay_ms(500); // Задержка 500мс
PORTC &= ~(1 // Лог. 0 на выходе PC0
_delay_ms(500); // Задержка 500мс
Ну вот и всё!
Теперь нужно перенести готовый код в Atmel Studio и скомпилировать его. Для этого необходимо кликнуть по кнопке Build и в выпавшем меню выбрать Build Solution.
Если ошибок нет, то файл успешно скомпилируется, а в нижней части экрана появится надпись:
==== Build: 1 succeeded or up-to-date, 0 failed, 0 skipped ====
Теперь нам надо войти в папку, в которой мы сохранили наш проект, найти там ещё одну папку с названием Debug и убедиться в существовании там файла с расширением HEX. При помощи этого файла производится прошивка микроконтроллера или проверка работоспособности устройства в программе для автоматизированного проектирования Proteus.
Скачать файл svetodiod.hex можно по ссылке – скачать файл
А на следующей странице будем подключать к Atmega8 кнопку, устранять дребезг контактов и управлять ей свечением светодиода.
![]() |
|
Мигающий светодиод на микроконтроллере
Делаем первые шаги в программировании микроконтроллера Atmega8 – пишем программу прошивки.
Как задавать значения битов в регистрах ввода/вывода?
Ну что ж, будем считать, что всё необходимое для эволюционного развития отечественного МК-строения у нас куплено, скачано и собрано воедино. Теперь остаётся придумать простенький проект, написать программу в Atmel Studio, скомпилировать код, после чего проверить его работоспособность с помощью симулятора микроконтроллеров, а также прочих электронных устройств – Proteus.
Писать программу будем на одном из популярных языков, используемых для программирования МК – языке Си.
В качестве проекта по сформировавшейся традиции выберем светодиод, подключённый к выходу микроконтроллера, и заставим его мигать с некоторой заданной нами периодичностью.
Забегая вперёд, приведу схему готового проекта на Atmega8, собранного в Протеусе, которую нам ещё предстоит запрограммировать в Atmel Studio и только потом проверить в симуляторе.
Рис.1 Мигающий светодиод на микроконтроллере Atmega8
Теперь по порядку:
1. Для начала запускаем программу Atmel Studio:
— Кликаем по вкладке New и далее Project.
— В открывшемся окне выбираем язык программирования C/C++.
В строке для ввода Name – название проекта, например, Svetodiod.
В графе Location – место желаемого расположения папки с файлами проекта.
В качестве типа проекта выбираем – GCC C Executable Project.
Жмём – ОК.
— В новом окне находим и выделяем микроконтроллер ATmega8 и опять нажимаем кнопку OK.
— После проделанных манипуляций Atmel Studio нам автоматически сформировала заготовку (шаблон) программы:
/*
* GccApplication2.c
*
* Created: 22.06.2021 11:37:14
* Author : Vpayaem.ru
*/
int main(void)
<
/* Replace with your application code */
while (1)
<
>
>
Текст, в нашем случае выделенный зелёным цветом, является комментариями, которые полностью игнорируются компилятором.
Комментарии могут быть многострочными (как в приведённом шаблоне), где текст помещается между /* и */ , а могут быть однострочными.
Однострочный комментарий обозначается двумя косыми линиями перед текстом и действует в пределах одной строки, например: // Здесь написан однострочный комментарий.
Переходим к собственно программе прошивки.
Знак # в начале строки означает, что данная команда является директивой препроцессора, т. е. содержит в себе некоторые инструкции, которые выполняются в первую очередь и работают, невзирая на весь остальной код.
В данной строке подключается библиотека микроконтроллера, в которой находятся определения констант, имён регистров и всего прочего, что может понадобиться для выполнения базового ввода-вывода информации. Для корректного выполнения микроконтроллером некоторых функций (например, таких как задержка), в настройках проекта необходимо прописать директиву, указывающую – с какой тактовой частотой будет работать микроконтроллер. Такой директивой является:
2. #define F_CPU 1000000UL
Так как частота по умолчанию для ATmega8 (при работе со встроенным генератором) равна 1 000 000 Гц, то это значение мы и объявим в виде числа 1000000.
При написании кода на языке Си в Atmel Studio имеется очень удобная функция задержки выполнения программы _delay_ms(). Для включения данной функции её необходимо предварительно прописать директивой:
На этом с директивами, пожалуй, закончим.
Далее заготовка из Atmel Studio выдаёт нам следующую строку:
Здесь ничего мудрить не надо. В данной строке объявляется функция main, с которой начинается выполнение программы.
А вот теперь нам необходимо сконфигурировать единственный задействованный нами сигнальный вывод Atmega8 PC0 как выход (Рис.1).
Давайте-ка немного отвлечёмся и поговорим об этом поподробнее. Ведь мы знаем, что большинство выводов (портов) микроконтроллера могут работать и как входы, и как выходы. Поэтому любой задействованный разряд МК предварительно нужно настроить на соответствующий режим. Для этого в микроконтроллере есть специальный регистр, который называется DDRx (direct data register – регистр направления данных), где x обозначает букву соответствующего порта, т. е. DDRС, к примеру, определяет направление передачи данных для интересующего нас порта С.
Чтобы настроить вывод порта как вход, в регистр DDRх необходимо записать ноль, а для настройки в качестве выхода – единицу.
Так как же нам записать в регистр интересующего нас разряда PC0 единицу, чтобы задействовать его в качестве выхода?
В нашем случае лучше всего это сделать побитовой настройкой, хотя, в первом приближении, она и выглядит довольно мудрёной:
Эта запись означает, что для нулевого разряда порта С (номер разряда указывает последняя цифра), т. е. для вывода PC0 мы прописали в DDR единицу и тем самым настроили его как выход.
А вот, если бы нам туда понадобилось прописать ноль, т. е. настроить PC0 как вход, то команда для начинающего программиста выглядела бы ещё более странной:
Но тут, как говорится – что уж? Поэтому на первых порах надо эту причудливую лабуду: либо просто запомнить, либо куда-нибудь сохранить и оттуда копировать, не сильно запариваясь по поводу её высокой роли в языке программирования Си.
Довольно распространён способ настройки DDR регистров и в виде двоичного кода. Данная форма записи удачно сочетается с количеством битов порта, так как количество битов соответствует количеству выводов порта, а порядковый номер бита отвечает номеру бита внутри порта.
В нашем случае, чтобы настроить PC0 на выход следует написать следующую команду:
Здесь префикс 0b идентифицирует следующее за ним число как двоичное, а порядковый номер бита отвечает номеру бита внутри порта. То есть последний (крайний правый) разряд этого числа соответствует PC0, предпоследний – PC1 и т. д. Как итог: PC0 настроен как выход, все остальные разряды (PC1. PC6) – как высокоимпедансные входы.
По большому счёту данная команда (в виде двоичного кода) выполняет ту же функцию, что и побитовая настройка порта. Однако, если побитовая команда DDR аккуратно настраивает каждый отдельный выбранный нами разряд, то двоичная форма записи конфигурирует сразу все разряды порта, что повышает вероятность (особенно на первых этапах освоения программирования) всяческих неприятных ошибок.
Далее в нашей заготовке прописана функция:
Данная функция обозначает бесконечный цикл. Это говорит о том, что код программы, находящийся в теле данной функции (внутри фигурных скобок), будет повторяться бесконечное число раз, т. е. программа будет зациклена. Теперь внутри цикла можно записывать команды управления светодиодом.
Для того, чтобы управлять уровнем напряжения на любом выходе служит регистр PORTх, где, опять же, x — обозначает букву соответствующего порта. Если бит установлен в единицу, то на выходе будет уровень близкий к напряжению питания микроконтроллера, если бит установлен в ноль, то на выводе будет напряжение близкое к нулю.
Установим логическую 1 на выходе PC0, т. е. заставим светодиод светиться:
Здесь всё записывается аналогично форме, которую мы использовали для программирования регистров DDRx. В виде двоичного кода эта форма имела бы вид:
После того как светодиод зажжётся, пусть некоторое время погорит. Для этого существует команда _delay_ms(). Эта функция осуществляет задержку выполнения последующей команды на время, выраженное в миллисекундах и численно равное числовому значению, находящемуся внутри круглых скобок.
То бишь команда:
будет поддерживать высокий уровень на PC0 в течении 500 мс (0,5 сек) или до бесконечности, пока мы его не сбросим в ноль.
А сбросим мы его в ноль сразу по прошествии 0,5 сек посредством команды:
Теперь опять полсекунды подождём:
После чего заканчиваем цикл и возвращаемся к его началу, то есть к первой команде управления светодиодом. Давайте посмотрим на код, который у нас получился в сухом остатке:
/*
* GccApplication2.c
*
* Created: 22.06.2021 11:37:14
* Author : Vpayaem.ru
*/
#include
#define F_CPU 1000000UL // Выбираем частоту МК
#include // Включаем функцию задержек
int main(void)
< // Начало основной программы
DDRC |= ( 1 // Устанавливаем вывод порта PC0 — как выход
PORTC |= (1 // Лог. 1 на выходе PC0
_delay_ms(500); // Задержка 500мс
PORTC &= ~(1 // Лог. 0 на выходе PC0
_delay_ms(500); // Задержка 500мс
Ну вот и всё!
Теперь нужно перенести готовый код в Atmel Studio и скомпилировать его. Для этого необходимо кликнуть по кнопке Build и в выпавшем меню выбрать Build Solution.
Если ошибок нет, то файл успешно скомпилируется, а в нижней части экрана появится надпись:
==== Build: 1 succeeded or up-to-date, 0 failed, 0 skipped ====
Теперь нам надо войти в папку, в которой мы сохранили наш проект, найти там ещё одну папку с названием Debug и убедиться в существовании там файла с расширением HEX. При помощи этого файла производится прошивка микроконтроллера или проверка работоспособности устройства в программе для автоматизированного проектирования Proteus.
Скачать файл svetodiod.hex можно по ссылке – скачать файл
А на следующей странице будем подключать к Atmega8 кнопку, устранять дребезг контактов и управлять ей свечением светодиода.
Шпаргалка начинающего программиста AVR МК

На этой странице мы будем поэтапно собирать информацию, которая в том или ином виде проскальзывала в наших, пока не сильно многочисленных статьях, посвящённых программированию МК. Причём, как мне кажется, это должно быть удобно не только начинающему программисту, так как вся базовая информация будет сосредоточена в одном месте, но и, собственно, мне, по причине отсутствия необходимости часто и нудно повторяться.
Напоминаю, что в качестве примера у нас выбран популярный AVR микроконтроллер Atmega8, а в качестве основного языка программирования – Си.
Однако приступим к делу:
И начнём мы с программирования портов ввода-вывода микроконтроллера.
1. Регистр выбора направления передачи данных DDR
Выводы (порты) микроконтроллера могут работать как входы и как выходы. Поэтому предварительно нужно настроить вывод МК на соответствующий режим посредством специального регистра, который называется DDR.
У каждого порта есть свой DDR регистр. Например, у Atmega8 три порта: B, C и D, а соответствующие им регистры называются: DDRB, DDRC и DDRD.
В том случае, если нам необходимо сконфигурировать вывод МК как вход, то в соответствующий разряд DDR регистра записывается ноль, если – как выход, то единица.
Одним из распространённых способов настройки DDR регистров является запись в виде двоичного кода с количеством разрядов, совпадающим с разрядностью порта. К примеру, чтобы настроить вывод PC0 как выход, мы должны написать следующую команду:
Здесь префикс 0b идентифицирует следующее за ним число как двоичное, а порядковый номер бита отвечает номеру бита внутри порта. То есть последний (крайний правый) разряд этого числа соответствует PC0, предпоследний – PC1 и т. д. Как итог: PC0 настроен как выход, все остальные разряды (PC1. PC6) – как высокоимпедансные входы.
Поскольку порт С в Atmega8 содержит не 8 разрядов, а 7, то и количество битов в двоичном коде равно 7.
Ещё один пример с 8-разрядным портом D:
Здесь третий и седьмой биты порта D сконфигурированы как выход, а остальные биты – как вход.
Если подставить двоичное число (то, что находится после 0b) в калькулятор и конвертировать его в шестнадцатеричный код, то можно полученное число также использовать в настройке бита, только при этом – 0b заменить на 0x.
Перепишем наши примеры с шестнадцатеричными числами:
DDRC = 0x01;
DDRD = 0x88;
Часто функциональное назначение отдельно взятого вывода удобнее задавать побитовой настройкой. Для того, чтобы нам настроить PC0 как выход, в этом случае следует записать следующую команду:
Эта запись означает, что для нулевого разряда порта С (номер разряда указывает последняя цифра), т. е. для вывода PC0 мы прописали в DDR единицу и тем самым настроили его как выход.
А вот, если бы нам туда понадобилось прописать ноль, т. е. настроить PC0 как вход, то команда выглядела бы так:
Запишем в побитовой форме и второй пример – настроим третий и седьмой биты порта D как выходы:
Эти две команды можно заменить одной:
2. Регистр выходных данных порта PORT
Служит для управления состоянием вывода.
Если вывод (контакт) сконфигурирован как выход, то единица в соответствующем бите регистра PORTx формирует на выводе сигнал высокого уровня, а ноль – формирует сигнал низкого уровня.
Если вывод (контакт) сконфигурирован как вход, то единица в бите регистра PORTx подключает к выводу внутренний подтягивающий pull-up резистор, который обеспечивает высокий уровень на входе при отсутствии внешнего сигнала.
Воспользуемся предыдущими примером, в котором мы установили вывод PC0 как выход, т. е. использовали команду:
Тогда, чтобы установить на этом выходе высокий логический уровень, нам надо прописать:
PORTС = 0b0000001; – в двоичном коде, либо
PORTС = 0x01; – в 16-ричном, либо
PORTC |= (1
А для того, чтобы установить низкий уровень –
PORTС = 0b0000000; – в двоичном коде, либо
PORTС = 0x00; – в 16-ричном, либо
PORTC &= ~(1
PORTС = 0b0000101; – в двоичном коде, либо
PORTС = 0x05; – в 16-ричном, либо
PORTC |= (1
то это будет означать, что на выходе PC0 присутствует высокий логический уровень, а ко входу PC2 подключён внутренний подтягивающий к питанию резистор.
Все остальные разряды порта С настроены как обычные высокоимпедансные входы.
Для некоторых приложений может оказаться полезной команда, которая переключает отдельный бит в противоположное состояние, т. е. единицу в ноль и наоборот. К примеру, для вывода PD3 данная логическая операция выглядит следующим образом:
3. Регистр считывания состояния вывода PIN
Данный регистр непрерывно отражает текущее состояние выводов порта, причём независимо от того, используется вывод как вход или как выход. То есть, обратившись к нему, мы можем узнать, какое напряжение подано на входной вывод, либо установлено в ходе работы программы на выходном. Из всего этого следует, что PIN – это регистр, из которого можно только читать.
Давайте посмотрим, как можно считывать информацию из регистра PIN на примере оператора if.
Как правило, у разработчика возникает необходимость проверять состояние не одновременно всех битов регистра, а какого-то конкретного, отдельно взятого бита, а потому и применять в этом случае следует побитовую операцию.
К примеру, команда:
ожидает появления на выводе PB1 высокого уровня (единицы).
ожидает появления на выводе PB1 низкого уровня (нуля).
![]() |
|
Шпаргалка начинающего программиста AVR МК
Делаем первые шаги в программировании микроконтроллера на языке Си. Порты ввода-вывода AVR – простые, но необходимые знания

На этой странице мы будем поэтапно собирать информацию, которая в том или ином виде проскальзывала в наших, пока не сильно многочисленных статьях, посвящённых программированию МК. Причём, как мне кажется, это должно быть удобно не только начинающему программисту, так как вся базовая информация будет сосредоточена в одном месте, но и, собственно, мне, по причине отсутствия необходимости часто и нудно повторяться.
Напоминаю, что в качестве примера у нас выбран популярный AVR микроконтроллер Atmega8, а в качестве основного языка программирования – Си.
Однако приступим к делу:
И начнём мы с программирования портов ввода-вывода микроконтроллера.
1. Регистр выбора направления передачи данных DDR
Выводы (порты) микроконтроллера могут работать как входы и как выходы. Поэтому предварительно нужно настроить вывод МК на соответствующий режим посредством специального регистра, который называется DDR.
У каждого порта есть свой DDR регистр. Например, у Atmega8 три порта: B, C и D, а соответствующие им регистры называются: DDRB, DDRC и DDRD.
В том случае, если нам необходимо сконфигурировать вывод МК как вход, то в соответствующий разряд DDR регистра записывается ноль, если – как выход, то единица.
Одним из распространённых способов настройки DDR регистров является запись в виде двоичного кода с количеством разрядов, совпадающим с разрядностью порта. К примеру, чтобы настроить вывод PC0 как выход, мы должны написать следующую команду:
Здесь префикс 0b идентифицирует следующее за ним число как двоичное, а порядковый номер бита отвечает номеру бита внутри порта. То есть последний (крайний правый) разряд этого числа соответствует PC0, предпоследний – PC1 и т. д. Как итог: PC0 настроен как выход, все остальные разряды (PC1. PC6) – как высокоимпедансные входы.
Поскольку порт С в Atmega8 содержит не 8 разрядов, а 7, то и количество битов в двоичном коде равно 7.
Ещё один пример с 8-разрядным портом D:
Здесь третий и седьмой биты порта D сконфигурированы как выход, а остальные биты – как вход.
Если подставить двоичное число (то, что находится после 0b) в калькулятор и конвертировать его в шестнадцатеричный код, то можно полученное число также использовать в настройке бита, только при этом – 0b заменить на 0x.
Перепишем наши примеры с шестнадцатеричными числами:
DDRC = 0x01;
DDRD = 0x88;
Часто функциональное назначение отдельно взятого вывода удобнее задавать побитовой настройкой. Для того, чтобы нам настроить PC0 как выход, в этом случае следует записать следующую команду:
Эта запись означает, что для нулевого разряда порта С (номер разряда указывает последняя цифра), т. е. для вывода PC0 мы прописали в DDR единицу и тем самым настроили его как выход.
А вот, если бы нам туда понадобилось прописать ноль, т. е. настроить PC0 как вход, то команда выглядела бы так:
Запишем в побитовой форме и второй пример – настроим третий и седьмой биты порта D как выходы:
Эти две команды можно заменить одной:
2. Регистр выходных данных порта PORT
Служит для управления состоянием вывода.
Если вывод (контакт) сконфигурирован как выход, то единица в соответствующем бите регистра PORTx формирует на выводе сигнал высокого уровня, а ноль – формирует сигнал низкого уровня.
Если вывод (контакт) сконфигурирован как вход, то единица в бите регистра PORTx подключает к выводу внутренний подтягивающий pull-up резистор, который обеспечивает высокий уровень на входе при отсутствии внешнего сигнала.
Воспользуемся предыдущими примером, в котором мы установили вывод PC0 как выход, т. е. использовали команду:
Тогда, чтобы установить на этом выходе высокий логический уровень, нам надо прописать:
PORTС = 0b0000001; – в двоичном коде, либо
PORTС = 0x01; – в 16-ричном, либо
PORTC |= (1
А для того, чтобы установить низкий уровень –
PORTС = 0b0000000; – в двоичном коде, либо
PORTС = 0x00; – в 16-ричном, либо
PORTC &= ~(1
PORTС = 0b0000101; – в двоичном коде, либо
PORTС = 0x05; – в 16-ричном, либо
PORTC |= (1
то это будет означать, что на выходе PC0 присутствует высокий логический уровень, а ко входу PC2 подключён внутренний подтягивающий к питанию резистор.
Все остальные разряды порта С настроены как обычные высокоимпедансные входы.
Для некоторых приложений может оказаться полезной команда, которая переключает отдельный бит в противоположное состояние, т. е. единицу в ноль и наоборот. К примеру, для вывода PD3 данная логическая операция выглядит следующим образом:
3. Регистр считывания состояния вывода PIN
Данный регистр непрерывно отражает текущее состояние выводов порта, причём независимо от того, используется вывод как вход или как выход. То есть, обратившись к нему, мы можем узнать, какое напряжение подано на входной вывод, либо установлено в ходе работы программы на выходном. Из всего этого следует, что PIN – это регистр, из которого можно только читать.
Давайте посмотрим, как можно считывать информацию из регистра PIN на примере оператора if.
Как правило, у разработчика возникает необходимость проверять состояние не одновременно всех битов регистра, а какого-то конкретного, отдельно взятого бита, а потому и применять в этом случае следует побитовую операцию.
К примеру, команда:
ожидает появления на выводе PB1 высокого уровня (единицы).
ожидает появления на выводе PB1 низкого уровня (нуля).
Программирование микроконтроллеров AVR для начинающих
Микроконтроллер – микросхема, предназначенная для управления электронными устройствами, или по другому – простенький компьютер (микро-ЭВМ), способный выполнять несложные задачи.

Рано или поздно, любой радиолюбитель (я так думаю), приходит к мысли о применении в своих разработках микроконтроллеров. Микроконтроллер позволяет существенно «облегчить» радиолюбительскую конструкцию, сделать ее проще и намного функциональнее.
Что нужно для того, чтобы начать пользоваться всеми возможностями микроконтроллеров? Я считаю, что не так уж и много. Главное в этом деле — желание. Будет желание, будет и результат.
В этом разделе (и в разделе «Устройство AVR») сайта я постараюсь помочь начинающим «микроконтроллерщикам» сделать первый, он же самый трудный шаг навстречу микроконтроллерам — попробуем разобраться в устройстве и программировании микроконтроллеров AVR семейства ATtiny и ATmega.
В сети существует множество сайтов затрагивающих так или иначе «микроконтроллерную» тематику, много также и различной литературы для начинающих. Поэтому я не собираюсь «переплюнуть» всех и вся и создать очередной шедевр мыслительных мук в виде пособия по микроконтроллерам для начинающих. Я постараюсь систематизировать, собрать в кучу все нужное на мой взгляд, для первого шага в мир микроконтроллеров, и изложить более-менее доступным языком.
В своих статьях я буду опираться на материалы из публикаций популярных авторов микроконтроллерной тематики: Рюмика С.М., Белова А.В., Ревича Ю.В., Евстифеева А.В., Гребнева В.В., Мортона Д., Трамперта В., Фрунзе А.В. и Фрунзе А.А. (и многих других), а также материалы радиолюбительских сайтов. Ну и, может быть, немного своих «умных мыслей».
Программирование микроконтроллеров AVR фирмы Atmel

1. Микроконтроллеры — первый шаг
Эта статья, как и все последующие, — маленький шажок в мир микроконтроллеров. И таких «шажков» у нас будет много, пока не дойдем до того момента, когда сможем сказать: «Микроконтроллер — последний шаг». Но и это, скорее всего, из области фантастики — нельзя объять необъятное, — мир микроконтроллеров постоянно развивается и совершенствуется. Наша задача — сделать первый шаг, логическим итогом которого должна стать первая, самостоятельно разработанная и собранная конструкция на микроконтроллере.

2. Системы счисления: десятичная, двоичная и шестнадцатиричная
Как вы наверняка знаете, существует много разных систем счисления, одними пользуются и сейчас (наша, родная, десятичная система; римская система, известная нам как «римские цифры»), другие остались в глубоком прошлом (системы счисления инков и майя, древнеегипитская система, вавилонская).
Тут, я думаю, вопросов у нас нет, что такое системы счисления нам понятно — отображение чисел символами. А вот какая связь систем счисления с микроконтроллерами.

3. Логические операции, логические выражения, логические элементы
Все современные цифровые технологии основываются на логических операциях, без них никуда не деться. Все цифровые микросхемы в своей работе используют логические схемы (выполняют логические операции, в том числе и микроконтроллер).
Создавая программу, мы прописываем все действия микроконтроллера основываясь на своей логике с применением логических операций, иногда даже и не подозревая об этом, которые применяем к логическим выражениям.

4. Битовые операции
В прошлой статье была рассмотрена тема логических операций и выражений. В этой статье мы рассмотрим логические битовые операции. Битовые операции очень близки к логическим операциям, можно даже сказать, что это одно и тоже. Разница только в том,что логические операции применяются к высказываниям, а битовые операции, с такими же правилами и результатами применяются к битам.

5. Прямой, обратный и дополнительный коды двоичного числа
Прямой, обратный и дополнительный коды двоичного числа — способы представления двоичных чисел с фиксированной запятой в компьютерной (микроконтроллерной) арифметике, предназначенные для записи отрицательных и неотрицательных чисел

6. USBASP программатор для микроконтроллеров AVR — идеальное решение для начинающих, и не только
Сегодня мы рассмотрим как, без особых затрат и быстро, запрограммировать любой микроконтроллер AVR поддерживающий режим последовательного программирования (интерфейс ISP) через USB-порт компьютера. В качестве программатора мы будем использовать очень простой и популярный программатор USBASP, а в качестве программы — AVRdude_Prog V3.3, которая предназначена для программирования МК AVR.

7. Программа AVRDUDE_PROG: программирование микроконтроллеров AVR ATmega и ATtiny
Популярнейшая программа AVRDUDE_PROG 3.3 предназначена для программирования микроконтроллеров AVR ATmega и ATtiny

8. Основы программирования микроконтроллеров AVR
С этой статьи мы начнем конкретно заниматься одним вопросом — программирование микроконтроллеров. Процесс будет проходить следующим образом — сначала статья по устройству микроконтроллера (к примеру, первая статья будет по портам ввода-вывода), а затем статья по программированию. Сегодняшний наш разговор вводный, и будет посвящен вопросам материального и программного обеспечения процесса изучения основ программирования микроконтроллеров.

9. Русификация программы Atmel Studio
В этой статье мы поговорим о проблемах русификации программы Atmel Studio, как перевести программу на русский (или другой) язык, и как сделать более удобной работу программы с программатором USBASP. После установки программы Atmel Studio весь интерфейс будет на английском языке. Кому-то, кто знаком с английским, или уже привык работать с программами с английским интерфейсом, это вполне устроит. Меня лично, такой подход создателей программы к великому и могучему не устраивает, мне более комфортно работать с русскими меню.

10. Введение в язык программирования С (Си) для микроконтроллеров
В этой статье будут рассмотрены основные сведение о языке С, структура программы на языке С, дано понятие о функциях, операторах и комментариях данного языка программирования.

11. Переменные и константы в языке С (Си) для микроконтроллеров AVR
В этой статье будут рассмотрены типы переменных в языке С (Си) для микроконтроллеров AVR, объявление переменных, способы задания констант, будет дан обзор арифметических операций языка С, присваивания, инкремента и декремента.
В этой статье будет рассмотрено управление портами микроконтроллеров AVR на языке программирования С (Си): установка выводов порта на вход или выход, считывание значений на входах портов, программа для управления миганием светодиода.

13. Циклы в языке С (Си) для микроконтроллеров AVR
В данной статье будут рассмотрены циклы в языке программирования Си для микроконтроллеров AVR. Будут рассмотрены циклы типа «для» (for) и циклы типа «пока» (while), будет показано как осуществить принудительное прерывание цикла и организовать бесконечный цикл.

14. Массивы в программировании микроконтроллеров AVR
В данной статье мы рассмотрим основы использования массивов в языке С для микроконтроллеров AVR и рассмотрим их практическое применение в программе для изменения цифр на семисегментном индикаторе.

15. Конечные автоматы в микроконтроллерах AVR
В данной статье мы рассмотрим применительно к микроконтроллерам AVR такой интересный стиль программирования микроконтроллеров как автоматное программирование. Точнее это даже не стиль программирования а целая концепция, благодаря которой программист микроконтроллеров может существенно облегчить свою жизнь. Благодаря ей многие задачи, поставленные перед программистом, решаются гораздо легче и проще, избавляя программиста от многих сложностей. Автоматное программирование часто также называют Switch-технологией
(29 голосов, оценка: 4,76 из 5)
