Задача: Разработаем устройство управления светодиодом при помощи одной кнопки. При каждом нажатии на кнопку выход порта к которому подключен светодиод должен менять свое состояние на противоположное. Эта задача легко решается при помощи 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"

Комментарии  

+3 #81 AntonChip 17.07.2014 06:11
Попробуй написать так
Код:
while (PIND&(1 << PD1)) {}
Сообщить модератору
+4 #82 Scroodge 26.07.2014 15:15
Антон, спасибо за уроки, реально помогают чайникам, вроде меня. Такой вопрос- при нажатии на кнопку светодиод моргает с одной частотой, при каждом последующем нажатии кнопки частота морганий увеличивается, а при последнем нажатии выключается. Как реализовать это в АВР студии? Спасибо!
Сообщить модератору
+3 #83 AlexVenture 03.06.2015 21:29
не понятно изначальное равенство PD0 нулю в этом условии:

Код:((PIND&(1 << PD0)) == 1)

насколько я узнал из даташита есть 3 регистра отвечающие за каждый порт:
1. DDRxn - регистр направления;
2. PORTxn - регистр данных;
3. PINxn - регистр состояния.

Так вот, не понятно, что такое PD0, PB0?
это ячейки какого-то регистра?
если ячейки регистра PORTxn, то почему мы считаем, что PD0 равен 0? (ведь записали вначале Код:PORTD = 0xFF;)
Сообщить модератору
0 #84 AntonChip 03.06.2015 21:48
Перед while(1) обычно предварительно настраиваются регистры микроконтроллер а. Этой записью
DDRD = 0x00; // Порт D Настраиваем на вход
PORTD = 0xFF; // Подключаем подтягивающие резисторы к выводам порта D
В бесконечном цикле, настройки регистров могут много раз меняться
Сообщить модератору
+1 #85 ПАВЛИК 03.09.2015 23:24
ПРИВЕТ ВСЕМ!!! РЕБЯТА ПОМОГИТЕ СТАРОМУ ЧАЙНИКУ Я СТАРЫЙ РАДИОЛЮБИТЕЛЬ И ЭЛЕКТРОНШИК НА ПЕНСИИ РЕШИЛ ВЗЯТЬСЯ ЗА СТАРОЕ РЕМЕСЛО. Я выписал из КИТАЯ программаторы. Один СН341а другой АТМЕГА 8 ТЕПЕРЬ надо найти программы для них. посаветуйте какой из них лутче и легче и какую программу вы пасаветуетhttp: //radioparty.ru /components/com _jcomments/imag es/smilies//lol .gifе? Спасибо!!! НЕ СМЕЙТЕСЬ СИЛЬНО ЗА МОИ ОШИБКИ :lol:
Сообщить модератору
0 #86 AntonChip 04.09.2015 20:03
Программаторами такими не пользовался, думаю что программы прошивальщики должны идти в комплекте. Сами же программы пишу в avrstudio 4 или 6, другими пользуюсь редко.
Сообщить модератору
+1 #87 Alex_och 07.12.2015 17:30
Здравствуйте. Решил себе сделать триггер или одновибратор (ждущий мультивибратор) такого плана:
-нажал на кнопку - светодиод моргнул 1 раз, даже если кнопка продолжает быть нажата;
-отпустил кнопку - ни чего не происходит.
А у меня получается, что при нажатой кнопке постоянно моргает светодиод, а нужно чтоб один раз.
Код: / ТРИГГЕР /

#include <avr/io.h>
#include <util/delay.h>

int main(void)
{
DDRB = 0b00001111;
PORTB = 0b00010000;
while (1) {
if ((PINB&(1 << PB4)) == 0)
{
PORTB |= _BV(PB3);
_delay_ms(100);
PORTB &= ~_BV(PB3);
_delay_ms(100);
} } }

Правда это для Attiny13.
Понимаю, что можно сделать через прерывания, но может можно и без них?
Сообщить модератору
0 #88 Tolik vtr 07.02.2018 22:43
В атмел студии этот код не компилируется
Сообщить модератору
0 #89 Tolik vtr 07.02.2018 22:45
Не понятно зачем писать статью, потом показать на общее обозрение код, который с ошибками
Сообщить модератору
0 #90 Tolik vtr 07.02.2018 22:49
Простите проглядел
Сообщить модератору
0 #91 serega061 21.11.2018 12:12
Добрый день! Подскажите пожалуйста, что я делаю не так? При компилляции программы из занятия №1 получается нормальная прошивка, а при компилляции программы из занятия №2 получается очень длинная прошивка, она рабочая, но не реально длинная. Я так понимаю это из-за добавления библиотеки задержек util/delay.h, но почему так? Пишу в AVR Studio 5
Сообщить модератору
0 #92 serega061 23.11.2018 20:02
Здравствуйте, Антон! Вы не можете мне помочь в этом вопросе?
Сообщить модератору
0 #93 uuu000 29.11.2019 11:19
Код работает только для кнопки,подключе нной к нулевому биту(не важно какого порта).
При изменении номера бита на 1,2,...7,код не работает,а лед моргает с частотой,завися щей от тактовой частоты.
В железе тоже не работает.
Сообщить модератору
0 #94 AntonChip 29.11.2019 12:35
Цитирую uuu000:
Код работает только для кнопки,подключенной к нулевому биту(не важно какого порта).
При изменении номера бита на 1,2,...7,код не работает,а лед моргает с частотой,зависящей от тактовой частоты.
В железе тоже не работает.

Попробуйте использовать
Код:
while(PIND&(1 << PD1)) {}

Вместо
Код:
while((PIND&(1 << PD1)) == 1){}
Сообщить модератору
0 #95 uuu000 29.11.2019 14:53
Спасибо большое за отклик, AntonChip .
Не думал,что эта ветка еще работает
и рад,что получил ответ.Надеюсь,ч то и в дальнейшем можно рассчитывать на
помощь автора этого сайта.Перед тем,как приступить к изучению программирования
для МК я уделил довольно много времени языку Си,но ,конечно ,остаюсь в категории
начинающих т.к. делал это самостоятельно с помощью Интернета.
На этом сайте я нашел то что нужно для меня-простоту изложения материала и возможность(как вижу)
получать консультацию по необходимости.

Что касается моего вопроса,действи тельно после замены while ((PIND&(1
Сообщить модератору
0 #96 Alexandr Kobzev 02.12.2019 23:47
Минут 20 ломал голову над этим кодом и только тогда до меня дошло, что это просто какой-то высер.
Сообщить модератору
0 #97 uuu000 03.12.2019 01:18
Все работает нормально с учетом #94
Сообщить модератору
0 #98 uuu000 03.10.2022 23:09
Как сделать программу для управления одним выходом с помощью нескольких
кнопок, причем при нажатии одной кнопки остальные просто в режиме
ожидания. И конечно для каждой кнопки должно при нажатии выполняться
какое то действие (например мигание с разными частотами ,включение светодиодов и прочее - но только одно действие для данной кнопки)
Т.е. что- то вроде переключателя с фиксацией
Есть какие то мысли на этот счет?
Сообщить модератору
0 #99 AntonChip 06.10.2022 22:25
Вариант использовать оператор switch-case
Сообщить модератору
0 #100 uuu000 07.10.2022 10:07
спасибо
Сообщить модератору