Как вы уже догадались из заголовка статьи, сегодня мы постараемся помигать светодиодом. Для начала немного теории. В сегодняшней программе будем использовать цикл while (что это и с чем его едят, читаем в Циклы, условный оператор, switch, break, continue) и задержку выполнения команд программы. Кроме этого познакомимся с операциями битового сдвига (далее – БС) и сдвоенными операторами (далее - СО).
Начнём с того, что создадим новый проект (о том, как создавать проект можете прочитать Программирование AVR урок 1 — введение) и настроим симулятор отладки. Копировать текст программы настоятельно не рекомендую, перенабираем всё своими руками :-)
Для того, чтобы задержка кода отрабатывалась правильно, необходимо задать частоту работы МК. Частоту задаем через маркоопределение.
#define F_CPU 8000000
Чтобы иметь возможность использовать функцию задержки, необходимо подключить стандартный библиотечный файл.
#include <util/delay.h>
Идём дальше.
Выставляем на всех лапках порт D нули.
PORTD = 0b00000000;
По умолчанию на лапках порта выставлены 0. Но для 100% гарантии рекомендую использовать данную команду, которая выставляет 0 на порте принудительно.
Сам функционал необходимо записать в теле цикла. Цикл while будет молотить постоянно включая/выключая светодиод.
Для начала введём команду PORTD |= (1<<(PORTD0));
При помощи СО «|=» результат, что расположен в правой части выражения логически складывается с предыдущим значением переменной, и только после этого переменной присваивается новое значение (значение, что полученное в результате операции логического сложения «ИЛИ»).
В круглых скобках показан один из вариантов БС. Существует два сдвига:
- "<<" — сдвиг влево,
- ">>" — сдвиг вправо.
При использовании БС все биты числа сдвигаются или вправо или влево на заданное число знаков, что задаётся числом, расположенным справа от стрелок.
После сдвига значения крайних битов (с той стороны куда сдвигаем), пропадают, а те биты, что находятся с другого края заполняются 0.
На словах все запутано, приведём пример.
value | 0 | 1 | 1 | 1 | 0 | 1 | 0 | 1 | value<<3 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 |
value | 0 | 1 | 1 | 1 | 0 | 1 | 0 | 1 | value>>4 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 |
PORTD0 — это макроопределение, которое прописано в стандартном файле библиотеки io.h.
#define PORTD0 0
Для тех, кто подзабыл напоминаю, каждый раз, когда компилятор встречает «PORTD0 » (в данном случае), он заменяет определение на «0».
1 сдвигается влево на 0 (иными словами – она остается на месте). Звучит бредово, но зато наглядно. Мы выставили на нулевой ножке порта 1. Если нужно выставить 1 на другой ножке, проводим сдвиг на величину, что соответствует номеру желаемого вывода порта.
После того, как значение нулевого бита было «сдвинуто», выполняется операция логического сложения "ИЛИ" между первоначальным значением, что присвоено переменной PORTD и результатом сдвига бита. Первоначально в переменной PORTD записаны одни 0 (0b00000000), а после операции сдвига и сложение, переменной присваивается новое значение (0b00000001).
СО «|=» позволяет вносить изменения в значения битов регистра, при этом не изменяя ранее записанные в него значения. Иными словами, мы изменяем только нулевой бит, при этом оставляя нетронутыми остальные биты регистра.
После того, как засветили светодиод, необходимо воспользоваться задержкой, прежде чем выключать его.
Задержку можно задать через одну из двух функций.
- _delay_ms(значение задается в миллисекундах);
- _delay_us(значение задается в микросекундах);
Вызываем функцию задержки и задаём значение миллисекунд.
_delay_ms(1000);
Выключаем светодиод
PORTD &= ~(1<<(PORTD0));
В данной команде мы используем другой СО «&=» (логический оператор умножения «И»).
Давайте разберём написанную нами команду.
Как вы помните, сдвигаем 1 на 0. В результате получаем 0b00000001. После инверсии (~ - знак инверсии) результат меняется на противоположный 0b11111110. Проведём операции логического умножения значение переменной и результата полученного после инверсии.
0b00000001 * 0b11111110 = 0b00000000.
Добавляем задержку.
_delay_ms(1000);
Собираем проект.
Открываем проект proteus, который создали в одном из предыдущих уроков. Нам нужно загрузить прошивку в виртуальный МК, чтобы посмотреть все ли работает корректно. Откроем свойства МК и выбираем другую прошивку (только что написанную нами программу). Кроме этого выставим частоту тактирования 8 МГц.
Запускаем выполнение программы. Если всё прошло успешно, собираем схему в железе и прошиваем наш МК. Как это сделать рассказано в статье Программирование AVR урок 3 — прошиваем микроконтроллер.
Схема с одним светодиодом.
Бонус для тех, кто дочитал до конца :-)
Я тут подумал, как-то скучно, давайте сделаем что-то прикольное, используя для этого те знания, что мы получили ;-)
Для начала определимся с тем, что мы будем делать. Предлагаю сделать:
- бегущий огонёк (8 светодиодов: 7 выключенных, 1 включён);
- растущий/спадающий световой отрезок (не смог придумать умного названия).
Видоизменить программу. Временную задержку будем задавать не числом, а через переменную. Мы делали подобное при программировании платы ардуино. Сейчас задержка составляет 1 секунду, а если мы захотим изменить данное значение, а таких задержек будет не один десяток?... Вообще-то использовать задержки – это дурной тон. Ведь во время задержки «камушек» абсолютно ничего не делает, а это расточительное отношении к вычислительным мощностям МК. Однако об этом мы поговорим позже, пока будем «колхозить» :-)
Собираем бегущий огонёк. Схема поделки.
Стоит забежать наперед и сказать, что схема «светового отрезка» аналогична представленной.
Скриншоты фрагментов готовых программ. Думаю комментарии излишни.
lesson_avr
Картотека программирования
На этом всё. Продолжение следует.