Мигающий светодиод на микроконтроллере AVR Atmega8. Мигание встроенным на плату Arduino светодиодом Мигание светодиода в avr studio

В статье будет рассмотрено подключение светодиодов к микроконтроллеру, работа с портами и написание программы на СИ. Статья, прежде всего, предназначена новичкам, которые только взялись за микроконтроллеры AVR.

Для начала нужно выбрать микроконтроллер. В моем случае это ATmega8535. В данном случае микроконтроллер можно брать любой, так как данная задача легко реализуется под любой МК. Писать программу для микроконтроллера можно на Ассемблере, СИ, Pascal-е и Bascom. Я использовал язык СИ, все эти языки разные.
Конкретную разницу между Си и Паскалем можно увидеть ниже.

//Мигающий светодиод void main() { ddrB = 0b11111111; //задаём порты B на выход portB = 0b11111111; //по умолчанию всё выключено while(1) { portB = ˜portB; //переключаем состояние светодиода на обратное delay_ms(100); //делаем задержку на 100 миллисекунд } }

Program First; begin ddrB:= $FF; //задаём порт B на выход portB:= $FF; //по умолчанию ничего не горит while(1) do begin portB:= not(portB); //переключаем состояние светодиода на обратное delay_ms(100); //делаем небольшую задержку end; end.

Список радиоэлементов

Обозначение Тип Номинал Количество Примечание Магазин Мой блокнот
U1 МК AVR 8-бит

ATmega8535

1 В блокнот
R1-R8 Резистор

220 Ом - 1 кОм

8 В блокнот
R9-R11 Резистор

10 кОм

3 В блокнот
V1-V8 Светодиод 8 В блокнот
Тактовая кнопка 3

При написании программы часто возникает необходимость в формировании определенного интервала времени между отдельными командами. Наглядным примером тому может послужить гирлянда, в которой лампочки загораются в определенной последовательности через промежутки времени. В нашем случае для индикации задержки времени будем использовать мигающий светодиод, а лучше два и разного цвета. Мы будем управлять длительностью их включения и выключения, т. е. изменять частоту мигания.

Большинство команд микроконтроллеров AVR выполняются в один такт генератора задающей частоты. В качестве которого широко используют встроенную в МК RC-цепочку или подключают к выводам XTAL1 и XTAL2 кварцевый резонатор.

Например, если МК работает с частотой 1 Гц, то одна команда будет выполняться за одну секунду

По умолчанию у МК ATmega8 задействован собственный внутренний генератор частоты, а точнее RC-цепочка, которая работает на частоте 1000 000 Гц = 1 МГц. Поэтому время выполнения одной команды равно:

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

#include

int main (void )

DDRD = 0b000000011;

while (1)

PORTD = 0b000000001; // Подаем питание на 1-й светодиод

PORTD = 0b000000010; // Подаем питание на 2-й светодиод

Но на самом деле второй LED загорится с разницей во времени 0,000001 секунды от первого. Наши глаза не могут заметить такой малой разницы во времени. Уже при частоте изображений более 24 Гц (t = 1/24 ≈ 0,042 с) наше зрение формирует из отдельных картинок непрерывный фильм. Поэтому в большинстве случаев мы не различаем 25-й кадр.

Для того, чтобы оба светодиода засветились с разницей во времени 0,5 секунды необходимо между соответствующими двумя командами (PORTD = 0b000000001; и PORTD = 0b000000010; ) поместит еще 500 000 однотактных пустых команд, т. е. заставить МК полсекунды не выполнять никаких полезных действий. Или, как говорят, нужно “убить” 500 000 тактов. Если код пишется на Ассемблере, то программисты применяют различных циклы, которые “съедают” определенное число тактов и тем самым получают различные интервалы времени.

#include

int main (void )

DDRD = 0b000000011;

while (1)

PORTD = 0b000000001; // Подаем питание на 1-й светодиод

Для получения задержки 0,5 секунды сюда нужно вставить

500 000 однотактных команд

PORTD = 0b000000010; // Подаем питание на 2-й

Функция _delay_ms() и мигающий светодиод

При написании кода на Си в Atmel Studio имеется очень удобная функция _delay_ms () . Для работы данной функции ее необходимо предварительно подключить директивой препроцессора .

В круглых скобках данной функции можно задавать время в миллисекундах, тогда перед скобками нужно записать ms, или в микросекундах – us:

При использовании данной функции для того, чтобы при компиляции Atmel Studio не выдавала никаких предупреждений, следует объявить частоту с помощью оператора #define . Так как по умолчанию для ATmega8 она равна 1 000 000 Гц, то это значение мы и объявим. Это делается следующей строкой:

#define F_CPU 1000000UL

В дальнейшем, когда мы будем подключать к МК кварцевый резонатор, без данной строки уже не обойтись. Структура ее останется прежней, только вместо 1 000 000 нужно будет записать частоту кварцевого резонатора.

Давайте улучшим нашу программу, так, чтобы сначала загорался один светодиод, затем через полсекунды он гаснул и еще через полсекунды загорался второй и снова через 0,5 с гаснул.

# define

Давайте посмотрим на код, приведенной выше, еще раз. Если нам необходимо изменить значение задержки времени в функции _ delay из 500, например на 300, то мы должны отыскать все строки с ее именем и выполнить соответствующую замену. Теперь представим, что таких строк сотня, а то и тысяча. Изменять значение каждого числа по отдельности крайне неудобно и долго. К тому же можно случайно пропустить строку. Поэтому необходимо применять другой, более удобный и практичный подход.

Таких подходов существует несколько. Самый простой – это объявить переменную и присвоить ей нужное значение. Далее эта переменная подставляется в соответствующие функции. Это хороший способ. В дальнейшем мы его рассмотрим детальнее. Сейчас же мы рассмотрим еще более лучший!

С помощью оператора #define мы присвоим числовому значению какое-либо имя. Это имя называется константа . В отличие от переменной, константа не может изменяться в программе. Выглядит это так:

#define MIG 300

_ delay _ ms (MIG);

Имя константы можно задавать практически любым, используя латинские символы и цифры. В данном случае имя MIG говорит о том, что мы применяем задержку для миг ания светодиодами.

После строки с директивой препроцессора #define точка с запятой не ставится. Между именем константы и числовым значением ставится пробел.

Данная строка работает следующим образом. Перед началом компиляции выполняется замена числом 300 всех констант с именем MIG.

#define и регистры

Также оператор #define хорош тем, что с помощью него можно задавать имена регистрам. Например, если мы подключаем к порту D светодиоды, то вместо PORTD мы можем записать, например VD:

#define VD PORTD

VD = 0b00000001;

Давайте перепишем программу, применяю директиву #define :

#define F_CPU 1000000UL

#include

#include

Добавлено: 28.06.2017 в 13:00

В этом примере мы напишем нашу первую программу на Си для микроконтроллера ATtiny13. Предполагается, что у нас уже подготовлено к работе всё необходимое: среда разработки, компилятор и т.д. Подопытным у меня будет самодельная отладочная плата , соответственно весь код буду приводить применительно к ней.
В качестве тестовой программы напишем классический, простейший пример "blink", который будет мигать светодиодом с определённой частотой.

Итак, создаём новый проект и приступаем. Приведу сразу полный код программы, а затем поясню всё более подробно:

/* * tiny13_board_blink * Демо-прошивка отладочной платы на ATtiny13 * с целью проверки работоспособности МК. * Мигаем светодиодом. */ #define F_CPU 1200000UL // Указываем тактовую частоту МК #define LED PB2 // Используем светодиод, подключенный к PB2 (7 пин) #include // Подключаем определения ввода/вывода #include // Подключаем библиотеку функций задержки int main(void) { // Светодиод DDRB |= (1<

В самом начале задаём значения констант и подключаем заголовочные файлы и библиотеки.
Файл avr/io.h подключает определения ввода/вывода для конкретного типа микроконтроллера (тип МК указывается в виде опции для компилятора).
Библиотеку util/delay.h подключаем для использования функций задержки, в нашем случае: _delay_ms() . Для работы функций задержки мы должны указать тактовую частоту процессора. Поэтому ДО подключения util/delay.h определяем константу F_CPU (в данном случае - 1,2МГц).

Затем у нас идёт основная функция main - это, собственно, тело нашей программы. Здесь мы должны, сначала, описать все действия, которые будут происходить при старте микроконтроллера, а затем, в бесконечном цикле запустить выполнение основной программы:

while (1) { ... }

Для начала, мы должны сконфигурировать порт ввода/вывода. В МК AVR старших моделей портов в/в может быть несколько (A, B, C, D). К каждому порту может быть подключено до восьми ножек. Каждая из ножек может быть настроена как на вход, так и на выход. ATtiny13 имеет только один порт (B), к которому подключены шесть ножек (PB0-PB5, см. datasheet). По умолчанию все ножки настроены на вход, а чтобы управлять светодиодом, мы должны использовать соответствующую ножку как выход. В микроконтроллерах AVR вся аппаратная часть настраивается посредством восьмибитных регистров. Направление (вход-выход) устанавливается битами регистров DDRx (где x - буква порта, в нашем случае B). Значение бита "0" - соответствует входу, "1" - выходу. Таким образом, чтобы использовать ножку PB2, как выход, мы должны установить второй бит регистра DDRB в единицу:

DDRB |= (1<

Для управления состоянием выхода предназначены регистры PORTx. Например, чтобы выключить светодиод, подключенный к ножке PB2 (подать низкий уровень сигнала), мы должны записать ноль во второй бит регистра PORTB :

PORTB &= ~(1<

Чтобы включить (подать высокий уровень сигнала) - соответственно, записываем единицу:

PORTB |= (1<

Теперь, когда порт в/в сконфигурирован, мы запускаем основной цикл, в котором будем инвертировать состояние выхода PB2 (чередовать высокий и низкий уровень сигнала) с задержкой 500мс. Таким образом, светодиод у нас будет мигать с частотой 1 раз в секунду.

разработчик 80-го уровня 17 июля 2015 в 11:33

Мигаем светодиодами на AVR без Arduino

  • DIY или Сделай сам *

События в статье происходили год назад, поэтому что-то могло устареть, а что-то я мог упустить. Начну с того, что я не программист, не разбираюсь в цифровой электронике, и всю свою жизнь интересуюсь аналоговой электроникой. Я не знал что такое микроконтроллеры ибо не читал Habr. Признаюсь честно, если бы знал тогда про ардуино то сделал бы на ардуино. Итак начнем.

Возникла потребность в устройстве генерирующем псевдослучайные числа. Почему не случайные а псевдослучайные, так это потому, что невозможно генерировать случайные числа программно: когда-нибудь цикл повторится, к примеру, после очередного включения устройства. Чтобы генерировать случайные числа нужно задействовать внешнее воздействие, вариантов много, давайте обсудим в комментариях. Это было бы сложнее, поэтому вернемся к псевдослучайной генерации. Также в качестве индикаторов чисел будут сетодиоды, ибо так легче.

После длительного гугления, чтения статей, форумов, изучая даташиты и не найдя готового решения решил делать сам. Как мигать светодиодом есть везде, а как мигать случайно - нет. Неужели никто не делал гирлянду? Надеюсь моя инструкция будет интересна начинающему.

Первым делом чертим схему. Схема не моя, свою потерял, поэтому исходника для протеус не будет.

Для тек кто не знает что это за программа, очень советую, очень удобно наблюдать как все работает без пайки и прошивки контроллера. Микроконтроллер фирмы Atmel Atmega8. Почему именно атмел, предлагаю обсудить в комментариях.

Собственно сам код:

#include //Включаем библиотеку для работы с микроконтроллером ATMega8 #include //Включаем библиотеку для организации задержек #include //Включаем библиотеку для генерации псевдослучайных чисел (rand) void main(void) //Обязательный заголовок (тело) { char i; //Объявляем переменную (i) PORTD=0x00; //Выставляем все выходы порта D на 0, то есть, выключаем весь порт D DDRD=0xFF; //Делаем порт D, как выход, чтобы на выходах порта было напряжение 5В PORTC=0x00; //Выставляем все выходы порта C на 0, то есть, выключаем весь порт C DDRC=0xFF; //Делаем порт C, как выход, чтобы на выходах порта было напряжение 5В PORTB=0x00; //Выставляем все выходы порта B на 0, то есть, выключаем весь порт B DDRB=0xFF; //Делаем порт B, как выход, чтобы на выходах порта было напряжение 5В while (1) //Добавляем бессконечный цикл, код ниже выполняется в цикле { i = rand() % 22 + 1; /*Присваеваем переменной функцию, которая принимает значения от 0 до 32767. (В нашем случае делим по модулю)*/ delay_ms(5); //Исполюзуем задержку 5мс if (i==1){PORTD.0=1;} else PORTD.0=0; //Если переменная (i) равна (1) то 0-вой бит порта (D) равен (1), if (i==2){PORTD.1=1;} else PORTD.1=0; // если иначе, то 0-лю if (i==3){PORTD.2=1;} else PORTD.2=0; //Во всех остальных ниже условиях по аналогии if (i==4){PORTD.3=1;} else PORTD.3=0; if (i==5){PORTD.4=1;} else PORTD.4=0; if (i==6){PORTD.5=1;} else PORTD.5=0; if (i==7){PORTD.6=1;} else PORTD.6=0; if (i==8){PORTD.7=1;} else PORTD.7=0; if (i==9){PORTC.0=1;} else PORTC.0=0; if (i==10){PORTC.1=1;} else PORTC.1=0; if (i==11){PORTC.2=1;} else PORTC.2=0; if (i==12){PORTC.3=1;} else PORTC.3=0; if (i==13){PORTC.4=1;} else PORTC.4=0; if (i==14){PORTC.5=1;} else PORTC.5=0; if (i==15){PORTB.0=1;} else PORTB.0=0; if (i==16){PORTB.1=1;} else PORTB.1=0; if (i==17){PORTB.2=1;} else PORTB.2=0; if (i==18){PORTB.3=1;} else PORTB.3=0; if (i==19){PORTB.4=1;} else PORTB.4=0; if (i==20){PORTB.5=1;} else PORTB.5=0; if (i==21){PORTB.6=1;} else PORTB.6=0; if (i==22){PORTB.7=1;} else PORTB.7=0; }; }

Код писал 2 дня, пока понял что к чему. Опишу кратко. Подключаем необходимые библиотеки, в цикле с помощью функции rand() генерируем числа, условия открывают закрывают порты в зависимости от значения переменной «i». А как бы сделали вы? Можно ли сократить код?

Для проверки работоспособности кода перед заливкой в микроконтроллер рекомендую запустить в протеусе и посмотреть что происходит.

После необходимо прошить сам микроконтроллер. Тут такая же ситуация. Существует всеми хвалимая программа AVRDUDE, но мне понравилась KhazamaAVRProgrammer. В качестве программатора выступал обычный USBASP:

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

Печатную плату в формате lay можете скачать

На этом уроке Вы научитесь программировать свою плату Arduino на примере мигания встроенным светодиодом.

Необходимые элементы

Для данного примера Вам понадобится плата Arduino (в данном случае – Arduino Uno R3 , но Вы сможете проработать данный пример, имея в наличии и другую плату) и кабель USB (типа A (4х12 мм) – B (7х8 мм) – более подробно можно почитать на Вики).

Что такое ” L” светодиод


На Arduino Uno присутствуют ряды коннекторов типа мама по бокам платы, которые используются для подключения периферийных электронных устройств или “шилдов” .

Кроме того, на плате присутствует встроенный светодиод (англ. – LED), которым Вы можете управлять с помощью скетчей. Этот встроенный светодиод условно назовем “L” светодиод, как это принято на многих англоязычных ресурсах.

Расположение данного светодиода на плате отмечено на фото снизу.


Загрузка примера “Blink” (мигание) в Arduino IDE

При подключении новой платы к персональному компьютеру, обратите внимание, что светодиод начинает мигать, так как все платы от производителей поступают с уже “залитым” скетчем “Blink ”.

На этом уроке мы перепрограммируем нашу плату, изменив частоту мигания светодиода. Не забудьте настроить оболочку Arduino IDE и выбрать нужный серийный порт, по которому Вы подключили Вашу плату.

Пришло время проверить Ваше подключение и запрограммировать плату.

В оболочке Arduino IDE существует большая коллекция скетчей, которые уже готовы к использованию. Среди них находится и пример, который заставляет мигать “L” светодиод.

Откройте пример “Blink”, который находится в пункте меню File – Examples – 01.Basics

После открытия, расширьте окно оболочки Arduino IDE, чтобы Вы могли весь скетч в одно окне.

Скетчи из примеров, включенные в Arduino IDE предусматривают режим “только чтение” (“read only”). То есть, загрузить их на плату Вы сможете, но после изменения кода, Вы не сможете их сохранить в том же файле.

Мы будем изменять скетч, так что в первую очередь Вам необходимо сохранить собственную копию, которую Вы сможете изменять.

Вы сохранили копию скетча “Blink” в Вашей библиотеке. Теперь открыть этот файл Вы можете в любой момент, перейдя по вкладке File – Scetchbook.

Загрузка примера “Blink” (мигание) на плату

Подключите свою плату Arduino к компьютеру с помощью USB и проверьте тип платы (“Board type”) и серийный порт (“Serial Port”), по которому она подключена.

Текущие настройки отображаются внизу окна оболочки Arduino IDE

Кликните на кнопку “Загрузить” (“Upload”)

Во время загрузки в нижней части окна IDE появятся ползунок загрузки и сообщения. Вначале появляется фраза “Компилирование” (“Compiling scetch..”), что означает процесс конвертирования Вашего скетча в формат, подходящий для загрузки на плату Arduino.

В конце статус сменится на ”Загрузка завершена” (“Done uploading”). В сообщении, которое появится в текстовой строке отобразится информация о том, что загруженный скетч занимает 1,084 байта из 32,256 доступных.

Иногда при компиляции у Вас может возникнуть подобная ошибка:

Причин может быть несколько: Вы не подключили плату к компьютеру; Вы не установили необходимые драйвера; Вы выбрали некорректный серийный порт.

Пояснения к скетчу “Blink”

Ниже представлен код скетча “Blink”.

Turns on an LED on for one second, then off for one second, repeatedly.

This example code is in the public domain.

// Pin 13 has an LED connected on most Arduino boards.

// give it a name:

pinMode(led, OUTPUT);

delay(1000); // wait for a second

Первое, на что стоит обратить внимание: в данном скетче множество “комментариев”. Обратите внимание, что комментарии не являются инструкцией по работе программы. Это исключительно пояснения отдельных функций и задач, которые выполняются на определенном этапе кода. Это не обязательная часть кода. Все между символами /* и */ в верхней части скетча – это комментарии, в которых описаны задачи программы. Так же есть комментарии, которые ограничиваются одной строкой. Они начинаются с символов // и заканчиваются по умолчанию в конце строки. Первая важная, по сути, часть данного кода это строка:

В комментариях над строкой указано, что мы присваиваем имя пину, к которому подключен светодиод. На большинстве плат Arduino это будет 13 пин. Дальше используется функция “Setup”. Опять-таки, в комментариях указано, что функция срабатывает после нажатия кнопки “reset”. Также эта функция срабатывает, когда плата перезагрузится по каким-либо другим причинам. Например, подача питания или после загрузки скетча.

// the setup routine runs once when you press reset:

// initialize the digital pin as an output.

pinMode(led, OUTPUT);

Каждый скетч Arduino обязан включать в себя функцию “setup” и часть, в которую вы можете добавлять собственные инструкции, заключенные между { }. В нашем примере в функции присутствует только одна команда, в которой указано, что пин, который мы используем, настраивается на “вывод” (“Output”). Также обязательным для любого скетча является функция цикла “Loop”. В отличие от функции “Setup ”, которая отрабатывает один раз после перезагрузки, функция “Loop” после окончания работы команд, вновь запустится.

// the loop routine runs over and over again forever:

digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)

delay(1000); // wait for a second

digitalWrite(led, LOW); // turn the LED off by making the voltage LOW

delay(1000); // wait for a second

В теле функции “Loop” светодиод включается (HIGH), данное значение задерживается на 1000 миллисекунд (1 секунда), светодиод отключается (LOW) и остается выключенным на 1 секунду, после чего цикл повторится.

Изменение частоты мигания светодиода

Для того, чтобы обеспечить более частое мигание светодиода, необходимо изменить параметр, указываемый в скобках () в команде “delay ”.

Как уже было указано, период задержки указывается в миллисекундах. То есть, для того, чтобы заставить светодиод мигать в два раза чаще, необходимо изменить значение с 1000 на 500. В результате, пауза между включением/выключением светодиода составит половину секунды и светодиод будет мигать быстрее.

Для проверки, не забудьте загрузить измененный скетч на плату Arduino.