Светодиодная гирлянда на микроконтроллере
Ранее мы уже научились мигать светодиодами, однако гораздо интересней управлять этим процессов с помощью кнопок, а светодиодная гирлянда послужит хорошим наглядным примером.
Подключение кнопки к микроконтроллеру
Схема гирлянды приведена ниже.
Когда кнопка (ключ) подключается к микроконтроллеру, то соответствующий вывод МК должен быть настроен на вход. При этом микроконтроллер будет постоянно считывать состояние, а точнее уровень потенциала на данном выводе. Поэтому алгоритм программы можно построить таким образом, что если на определенном выводе МК произойдет смена потенциала с высокого на низкий или наоборот, то выполнится определенное действие, например засветится светодиод.
Чтобы настроить определенные выводы (пин) МК на вход, следует в соответствующие биты регистра DDR записать нули. Кстати, если пины МК не задействованы, то их рекомендуется также настроить на вход. Поскольку к порту B мы будем подключать только кнопки, то в регистр DDRB мы запишем все нули следующий командой:
DDRB = 0b00000000;
Когда вывод микроконтроллера настроен на вход, то изначально он может находиться в двух состояниях, которые устанавливаются с помощью регистра PORT.
Если в бит регистра PORT записан ноль, то пин имеет высокое входное сопротивление.
При установке бита в единицу к ножке МК подключается подтягивающий резистор. Резистор называется так потому, что посредством его “подтягивается” высокий потенциал (+ 5 В) к соответствующей точке электрической цепи; в данном случае – к пину микроконтроллера.
Проверка состояния вывода МК с помощью PINx
Чтобы в любой момент времени знать, какой потенциал присутствует на выводе, следует проверить (считать) соответствующий бит в регистре PIN.
Данный регистр по аналогии можно сравнить с датчиком. С него можно только считывать информацию. Записать в него ничего нельзя. PIN является противоположность регистра PORT, в который выполняется только запись, но не считывание данных.
Боле предпочтительным является установка регистра PORT в единицу, т.е. применение внутреннего подтягивающего резистора МК. Такой вариант имеет значительную помехоустойчивость, поскольку для изменения высокого потенциала на низкий, вывод необходимо напрямую соединить с землей или общим проводом.
Если же пин сделать с высоким входным сопротивлением, то любая более-менее мощная электромагнитная помеха, может навести на нем некоторый потенциал, превышающий определенное значение и микроконтроллер воспримет помеху, как смена низкого потенциала на высокий. Поэтому в нашей программе мы будем использовать внутренний подтягивающий резистор.
Один контакт ключа соединим с землей (общим проводом), а второй – с выводом микроконтроллера. Когда ключ разомкнут, — вывод находится под высоким потенциалом (+ 5 В), подтянутый внутренним резистором МК. При этом соответствующий бит регистра PIN будет установлен в единицу.
При нажатии на кнопку данный вывод соединится с общим проводом (“минусом”) и на нем возникнет низкий потенциал. А бит регистра PIN автоматически установится в ноль.
Обратите внимание, что подтягивающий резистор еще защищает цепь от короткого замыкания при нажатой кнопке.
Светодиодная гирлянда в коде
Теперь давайте напишем целиком код программы, а затем рассмотрим его отдельные элементы. Алгоритм работы программы следующий: при замыкании первого ключа “лампочки” будут включаться в одной последовательности, а при замыкании второго – “лампочки” будут загораться иначе. Если обе кнопки на нажаты, то все светодиоды должны быть выключены.
#define F_CPU 1000000UL // Объявляем частоту работы микроконтроллера 1 МГц
#include <avr/io.h>
#include <util/delay.h> // Подключаем библиотеку задержек
#define Z 300 // Значению задержки присваиваем имя Z
#define VD PORTD // Присваиваем порту D имя VD
#define K PORTB // Присваиваем порту B, к которому подключены кнопки, имя K
int main(void)
{
DDRB = 0b00000000; // Настраиваем порт B на вход
DDRD = 0b11111111; // Настраиваем порт D на выход
VD = 0b00000000; // Выключаем все огни
K = 0b11111111; // Включаем подтягивающие резисторы
while (1)
{
if (PINB == 0b11111110) // Проверяем, нажата ли 1-я кнопка
{
VD = 0b11111111; // Если ключ замкнут, то мигаем «лампочками»
_delay_ms(Z);
VD = 0b00000000;
_delay_ms(Z);
}
else
{
VD = 0b00000000; // Если ключ разомкнут, то все LED выключены
}
if (PINB == 0b11111101) // Проверяем, нажата ли 2-я кнопка
{
VD = 0b00000001; // Если кнопка нажата, то поочередно включаем LED
_delay_ms(Z); // с задержкой 0,3 с
VD = 0b00000011;
_delay_ms(Z);
VD = 0b00000111;
_delay_ms(Z);
VD = 0b00001111;
_delay_ms(Z);
LED = 0b00011111;
_delay_ms(Z);
VD = 0b00111111;
_delay_ms(Z);
VD = 0b01111111;
_delay_ms(Z);
VD = 0b11111111;
_delay_ms(Z);
VD = 0b00000000;
_delay_ms(Z);
}
else
{
VD = 0b00000000; // Если ключ не замкнут, то все LED выключены
}
}
}
Операторы if и else
Назначение препроцессоров #include и #define ним хорошо известны из предыдущих статей. Здесь новым для нас есть оператор if. If переводится с английского «если». Если условие, указанное в круглых скобках, выполнятся, т.е. истинное, то выполняется код программы в фигурных скобках. Например, если переменная a больше 1 единицы, то переменной c присвоится значение a + b.
if (a >1)
{
c = a + b;
}
В противном случае, когда значение a меньше или рвано единице, код программы в фигурных скобках не будет выполняться.
Если в фигурных скобках выполняется только одна команда, то синтаксис языка Си позволяет упростить запись и обойтись без фигурных скобок:
if (a >1) c = a + b;
Также оператор if работает в связке с оператором else.
if (a >1) → если a >1, то = a + b
{
c = a + b;
}
else → в противном случае, c = a — b
{
c = a — b;
}
Работает это так. Если a > 1, то c = a + b. В противном случае, т.е. когда а меньше или равно единице, то c = a – b.
Пояснение кода программы
Теперь возвращаемся к нашей программе. Если кнопка, соединенная с PB0 нажата, то на выводе появляется низкий потенциал и соответствующий бит регистра PINB устанавливается в ноль. При этом будет выполняться условие в фигурных скобках, т.е. начнет мигать гирлянда.
Обратите внимание, что команда присвоения состоит из одного знака равно «=», а команда проверки условия «равно» состоит из двух знаков равно, написанных без пробела «==».
Когда кнопка не нажата, в бите регистра PINB появится единица, вызванная высоким потенциалом подтягивающего резистора. В этом случае управление перейдет к оператору else и все LED будут выключены.
При замыкании второго ключа, вывод которого соединен с портом PB1, выполнится второй код программы, и светодиоды начнут поочередно включаться с задержкой времени 0,3 секунды.
Таким образом, гирлянда на микроконтроллере может содержать разное количество LED и ключей. Причем для каждого замыкания или размыкания контактов ключа можно прописать свой алгоритм работы гирлянды.
Также ею можно управлять с помощью всего одной кнопки. Такой вариант имеет несколько сложнее код, и его мы рассмотрим в отдельной статье. Там же мы рассмотрим, как подключать мощные LED к МК.
Ранее в статье вы подробно рассмотрели настройку портов ввода-вывода микроконтроллера на выход, а здесь – на вход. Теперь объединим все вместе и приведем простой наглядный алгоритм.
1. Я так понимаю две нажатые кнопки вариант не рассматривается?
2. Не понял, если один и тот же порт используется частью для входа и частью для выхода, то изменения на выходных пинах влияют на значение PINx?