Задача: Разработаем устройство управления светодиодом при помощи одной кнопки. При каждом нажатии на кнопку выход порта к которому подключен светодиод должен менять свое состояние на противоположное. Эта задача легко решается при помощи 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"
Комментарии
Код:
while (PIND&(1 << PD1)) {}
Код:
((PIND&(1 << PD0)) == 1)
насколько я узнал из даташита есть 3 регистра отвечающие за каждый порт:
1. DDRxn - регистр направления;
2. PORTxn - регистр данных;
3. PINxn - регистр состояния.
Так вот, не понятно, что такое PD0, PB0?
это ячейки какого-то регистра?
если ячейки регистра PORTxn, то почему мы считаем, что PD0 равен 0? (ведь записали вначале Код:
PORTD = 0xFF;
)DDRD = 0x00; // Порт D Настраиваем на вход
PORTD = 0xFF; // Подключаем подтягивающие резисторы к выводам порта D
В бесконечном цикле, настройки регистров могут много раз меняться
-нажал на кнопку - светодиод моргнул 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,...7,код не работает,а лед моргает с частотой,завися щей от тактовой частоты.
В железе тоже не работает.
Попробуйте использовать
Код:
while(PIND&(1 << PD1)) {}
Вместо
Код:
while((PIND&(1 << PD1)) == 1){}
Не думал,что эта ветка еще работает
и рад,что получил ответ.Надеюсь,ч то и в дальнейшем можно рассчитывать на
помощь автора этого сайта.Перед тем,как приступить к изучению программирования
для МК я уделил довольно много времени языку Си,но ,конечно ,остаюсь в категории
начинающих т.к. делал это самостоятельно с помощью Интернета.
На этом сайте я нашел то что нужно для меня-простоту изложения материала и возможность(как вижу)
получать консультацию по необходимости.
Что касается моего вопроса,действи тельно после замены while ((PIND&(1
кнопок, причем при нажатии одной кнопки остальные просто в режиме
ожидания. И конечно для каждой кнопки должно при нажатии выполняться
какое то действие (например мигание с разными частотами ,включение светодиодов и прочее - но только одно действие для данной кнопки)
Т.е. что- то вроде переключателя с фиксацией
Есть какие то мысли на этот счет?