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

Схема устройства такая же как в занятии 1. Алгоритм программы прост. Сначала настраиваем порты ввода-вывода. Проверяем состояние младшего разряда порта D(PD0) к которому подключена кнопка, а затем выполняем операцию сравнения, где PD0 проверяется на равенстве единице. Если условие выполняется программа переходит к началу цикла, если нет то выполняется еще одна операция сравнения, но уже линии PB0. Сначала оператор сравнения проверяет PB0 на равенство нулю, если результат истина(PB0=0), то разряд сбрасывается в единицу (PB0=1). Если ложно, устанавливается в ноль (PB0=0). Далее в программу вносим процедуру ожидания, без нее наш светодиод будет так часто мигать, что наш глаз не заметит этого. Основной цикл программы будет приостанавливается как только произойдет переключение светодиода и будет возобновляться как только будет отпущена кнопка.

Настраиваем порты ввода вывода как в задании 1:

DDRD = 0x00; //порт D - вход

PORTD = 0xFF; //подключаем нагрузочные резисторы

DDRB = 0xFF; //порт B - выход

PORTB = 0x00; //устанавливаем 0 на выходе

Пишем основной цикл программы. Здесь мы будем использовать условный оператор if else. Этот оператор выполняет различные операции в зависимости от некоторого условия и записывается так:

If (условие)

{набор операторов A;}

else

{набор операторов B;}

Условие это любое логическое выражение. Если результат этого выражения истина, то выполняется «набор операторов А», в противном случае выполняется «набор операторов В»

Процедура ожидания нажатия кнопки представляет собой пустой цикл while, и этот цикл будет выполняться до тех пор когда условие истинно. Условием будет равенство линии PD0 единице, т.е до тех пор пока кнопка не нажата.

while ((PIND&(1 << PD0)) == 1){}

Проверяем состояние линии PB0 следующим выражением

if ((PINB&(1 << PB0)) == 0) //если PB0 равен нулю

Переключаем состояние PB0 на противоположное

PORTB |= (1 << PB0); //устанавливаем в PB0 единицу

В противном случае оставляем в PB0 ноль

PORTB &= ~(1 << PB0); //устанавливаем в PB0 ноль

Далее снова проверяем состояние кнопки

while ((PIND&(1<< PD0)) == 0){}
//если кнопка нажата будет выполняться пустой цикл

Так же в этой программе можно решить проблему дребезга контактов. Самый простой способ внедрение в программу специальных задержек. Дребезг приводит к тому, что на соответствующем разряде порта D вместо простого перехода с единицы в ноль мы получаем серию импульсов. Чтобы избавиться от этого программе нужно перейти в режим ожидания как только она обнаружит первый нулевой уровень на входе. В режиме ожидания программа приостанавливает все свои действия и просто отрабатывает задержку. Для того чтобы ввести задержку воспользуемся стандартной библиотекой процедуры задержки util/delay.h.

Воспользуемся функцией которая реализует задержку:

_delay_ms(200); //задержка на 200 миллисекунд

Она обеспечивает задержку в любое целое количество микросекунд. Далее эту функцию просто вставляем после каждого цикла while.

Код программы будет таким:

#include <avr/io.h>
#include <util/delay.h>
int main(void)
{
DDRD = 0x00; // Порт D вход
PORTD = 0xFF; // Подключаем подтягивающие резисторы
DDRB = 0xFF; // Порт B выход
PORTB = 0x00; // Лог. 0 на выходе
while(1)
{
while ((PIND&(1 << PD0)) == 1){} // Ждем пока на выводе PDO лог. 1
_delay_ms(200); // Задержка 200мс
if ((PINB&(1 << PB0)) == 0) // Если на выводе PB0 лог. 0
{
PORTB |= (1 << PB0); // Лог. 1 на выводе PB0
}
else
{
PORTB &= ~(1 << PB0); // Лог. 0 на выводе PB0
}
while ((PIND&(1 << PD0)) == 0){} // Ждем пока на выводе PDO лог. 0
_delay_ms(200); // Задержка 200мс
}
} 

В статье были использованы материалы из книги Белова А.В. "Самоучитель разработчика устройств на AVR"