Top.Mail.Ru
Занятие №2. Переключение светодиода - Микроконтроллеры и Технологии

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

Код:


while (PIND&(1 << PD1)) {}

+4
Антон, спасибо за уроки, реально помогают чайникам, вроде меня. Такой вопрос- при нажатии на кнопку светодиод моргает с одной частотой, при каждом последующем нажатии кнопки частота морганий увеличивается, а при последнем нажатии выключается. Как реализовать это в АВР студии? Спасибо!
+3
не понятно изначальное равенство PD0 нулю в этом условии:


Код:

((PIND&(1 << PD0)) == 1)



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

Так вот, не понятно, что такое PD0, PB0?
это ячейки какого-то регистра?
если ячейки регистра PORTxn, то почему мы считаем, что PD0 равен 0? (ведь записали вначале

Код:

PORTD = 0xFF;

)
Перед while(1) обычно предварительно настраиваются регистры микроконтроллера. Этой записью
DDRD = 0x00; // Порт D Настраиваем на вход
PORTD = 0xFF; // Подключаем подтягивающие резисторы к выводам порта D
В бесконечном цикле, настройки регистров могут много раз меняться
+1
ПРИВЕТ ВСЕМ!!! РЕБЯТА ПОМОГИТЕ СТАРОМУ ЧАЙНИКУ Я СТАРЫЙ РАДИОЛЮБИТЕЛЬ И ЭЛЕКТРОНШИК НА ПЕНСИИ РЕШИЛ ВЗЯТЬСЯ ЗА СТАРОЕ РЕМЕСЛО. Я выписал из КИТАЯ программаторы. Один СН341а другой АТМЕГА 8 ТЕПЕРЬ надо найти программы для них. посаветуйте какой из них лутче и легче и какую программу вы пасаветуетhttp://radioparty.ru/components/com_jcomments/images/smilies//lol.gifе? Спасибо!!! НЕ СМЕЙТЕСЬ СИЛЬНО ЗА МОИ ОШИБКИ :lol:
Программаторами такими не пользовался, думаю что программы прошивальщики должны идти в комплекте. Сами же программы пишу в avrstudio 4 или 6, другими пользуюсь редко.
+1
Здравствуйте. Решил себе сделать триггер или одновибратор (ждущий мультивибратор) такого плана:
-нажал на кнопку - светодиод моргнул 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.
Понимаю, что можно сделать через прерывания, но может можно и без них?
В атмел студии этот код не компилируется
Не понятно зачем писать статью, потом показать на общее обозрение код, который с ошибками
Простите проглядел
Добрый день! Подскажите пожалуйста, что я делаю не так? При компилляции программы из занятия №1 получается нормальная прошивка, а при компилляции программы из занятия №2 получается очень длинная прошивка, она рабочая, но не реально длинная. Я так понимаю это из-за добавления библиотеки задержек util/delay.h, но почему так? Пишу в AVR Studio 5
Здравствуйте, Антон! Вы не можете мне помочь в этом вопросе?
Код работает только для кнопки,подключенной к нулевому биту(не важно какого порта).
При изменении номера бита на 1,2,...7,код не работает,а лед моргает с частотой,зависящей от тактовой частоты.
В железе тоже не работает.

Цитирую uuu000:

Код работает только для кнопки,подключенной к нулевому биту(не важно какого порта).
При изменении номера бита на 1,2,...7,код не работает,а лед моргает с частотой,зависящей от тактовой частоты.
В железе тоже не работает.


Попробуйте использовать

Код:


while(PIND&(1 << PD1)) {}


Вместо

Код:


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

Спасибо большое за отклик, AntonChip .
Не думал,что эта ветка еще работает
и рад,что получил ответ.Надеюсь,что и в дальнейшем можно рассчитывать на
помощь автора этого сайта.Перед тем,как приступить к изучению программирования
для МК я уделил довольно много времени языку Си,но ,конечно ,остаюсь в категории
начинающих т.к. делал это самостоятельно с помощью Интернета.
На этом сайте я нашел то что нужно для меня-простоту изложения материала и возможность(как вижу)
получать консультацию по необходимости.

Что касается моего вопроса,действительно после замены while ((PIND&(1
Минут 20 ломал голову над этим кодом и только тогда до меня дошло, что это просто какой-то высер.
Все работает нормально с учетом #94
Как сделать программу для управления одним выходом с помощью нескольких
кнопок, причем при нажатии одной кнопки остальные просто в режиме
ожидания. И конечно для каждой кнопки должно при нажатии выполняться
какое то действие (например мигание с разными частотами ,включение светодиодов и прочее - но только одно действие для данной кнопки)
Т.е. что- то вроде переключателя с фиксацией
Есть какие то мысли на этот счет?
Вариант использовать оператор switch-case
спасибо