Подключаем кнопку к микроконтроллеру ATtiny2313, простая программа. Запуск микроконтроллера (сброс в начальное состояние) Подключение кнопки к мк

Сегодня мы расширим свой кругозор по изучению работы портов микроконтроллера и изучим второе назначение порта — работу на вход. И для изучения работы на вход мы применим обычную тактовую кнопку.

Как всегда, создадим проект в Atmel Studio, выберем Atmega8A, назовем проект Test04 и код также в main.c, как обычно, скопируем с проекта предыдущего урока.

В качестве подопытного порта давайте возьмём порт B. Можно с успехом использовать любой порт. И в качестве ножки возьмем нулевую ножку. Итак у нас ножка B0.

Также опять мы соберём проект, скопируем и переименуем файл протеуса, откроем его и в свойствах контроллера покажем путь к новому проекту. Запустим на выполнение и убедимся, что всё работает.

Добавим кнопку в протеусе, для этого в поиске компонентов найдём Button

Затем подключим нашу кнопку вот таким вот образом к ножке B0 контроллера

Судя по данной схеме, когда кнопка будет в нажатом состоянии, то Ножка PB0 у нас будет иметь низкий логический уровень, а при отжатом — непонятный уровень, поэтому мы применим подтягивающий к питанию резистор, который можно не паять физически, а подключить опционально определенной командой.

Для этого мы, во-первых настроим порт B. Мы можем объявить все ножки порта B на вход, так как нам не важны настройки остальных ножке, ибо мы их не используем

DDRD = 0xFF;

DDRB = 0x00;

В случае, когда мы работали с портом D на выход, биты регистра PORTD отвечали за уровень на соответствующих ножках. А в случае, когда порт инициализирован на вход, как наш порт B, то биты регистра PORTB будут уже отвечать за подтягивание к соответствующим ножкам порта резисторов на шину питания. Если будет логическая единица, то регистр будет подтягиваться, а если логический ноль — то не будет. Поэтому мы в 0 бите регистра установим 1

PORTD = 0b00000001;

PORTB = 0b00000001;

Соберём код и запустим его в протеусе. Мы видим, что на ножке B0 у нас установилась логическая 1 , а если мы нажмём кнопку, то увидим, что на ней будет логический 0 , о чём свидетельствует синий цвет квадратиков на ножке и на кнопке.

В бесконечном цикле закомментируем весь код. В видеоверсии урока показано, как данную операцию можно выполнить одним движением (выделяем весь текст, который мы хотим закомментировать, затем нажимаем одновременно Shift и обычный слэш (не обратный))

// for(i=0;i<=7;i++)

// {

// PORTD = (1<

// _delay_ms(500);

// }

В данном цикле мы и будем отслеживать состояние ножки PB0. Делается это с помощью определения состояния соответствующего бита в регистре PINB, который собственно за это и отвечает.

Чтобы нам следить за каким-либо действием или состоянием, нам необходимо будет обработать условие.

Условие в языке C добавляется с помощью команды if .

И в качестве условия мы возьмём состояние ножки 0 порта B или состояние бита 0 регистра PINB .

Как же можно получить состояние одного бита, ведь в языке C в отличие от ассемблера нет битовых операций?

Можно пойти на хитрость и применить вот такую конструкцию PINB &0b00000001 .

Данная конструкция нам и проверит нулевой бит. То есть если в регистре PINB также будет 1 в нулевом его бите, то независимо от состояния остальных битов в данном регистре мы получим ненулевой результат, что также является истиной. То есть если ни с чем не сравнивать в условии результат, то условие эквивалентно сравниванием с нулём, только наоборот. Для истинности результат должен быть ненулевым — (результат!=0 ).

Но нам с вами наоборот нежелательно, чтобы ножка была в высоком логическом состоянии, так как кнопка у нас подключена к общему проводу. Поэтому мы должны поставить отрицание и написать код следующим образом

while (1)

if (!( PINB &0b00000001))

{

}

else

{

}

Теперь нам необходимо добавить тело условия. При выполнении условия, что кнопка нажата, мы будем зажигать светодиод на ножке D0. А если условие не будет выполняться (кнопка будет отжата), то мы будем его гасить. Также мы погасим данный светодиод и в начале программы. Поэтому получим следующий код

DDRB =0x00;

PORTD =0b00000000 ;

PORTB =0b00000001;

while (1)

If (!(PINB &0b00000001))

PORTD =0b00000001;

Else

PORTD =0b00000000;

Теперь давайте пересоберём проект и пойдём в протеус смотреть, удалось ли нам что-то.

Чтобы у нас при сборке не было даже предупреждений, уберём объявление переменной i, так как она в коде не используется

int main ( void )

// unsigned char i;

Unsigned char butcount =0;

Запустим проект в протеусе и увидим, что при нажатии на кнопку у нас начинает светиться самый верхний светодиод

Казалось бы, что мы своей цели уже добились. Но чтобы сделать наш код более ответственным и совершенным, мы просто обязаны провести борьбу с дребезгом контактов, так как такое явление может иметь место, это только в протеусе всё идеально, на практике такое бывает не всегда.

И чтобы это как-то отследить и определить, что это было именно нажатие, а не дребезг, то мы будим отслеживать нажатие некоторое время, ну или некоторое количество тактов или циклов. Для этого в начале функции main() до бесконечного цикла мы добавим другую переменную (i нам ещё пригодится и мы её портить не будем). Назовём мы переменную butcount , так как имя переменной должно как-то само за себя говорить и тем самым достигается ещё большая читабельность кода

// unsigned char i;

unsigned char butcount =0;

И чтобы воспользоваться данной переменной, мы применим ещё одно условие. И у нас будет условие в условии. Это всё допустимо и очень широко используется. И в зависимости от этого условия мы данную переменную будем наращивать (инкрементировать). Условием будет у нас достижение данной переменной определённой величины. То есть попробуем сделать так, чтобы значение переменной не достигало 5

if (!( PINB &0b00000001))

if ( butcount < 5)

{

butcount ++;

}

А когда значение данной переменной достигнет значения 5, то мы уже в данный цикл не попадём, а попадём мы в тело оператора else , который мы сейчас и добавим и в его теле напишем следующий код

Butcount ++;

else

PORTD =0b00000001;

То есть мы как раз после достижения пятёрки и будем обрабатывать нажатие кнопки и включать на нулевой ножке порта D высокое состояние.

По идее, здесь мы должны обнулить нашу переменную, но мы это будем делать также постепенно, используя тело оператора else, только другого — того, который у нас был и тело которого выполняется при низком уровне на ножке, к которой подключена кнопка. Вот таким будет его тело

else

if (butcount >0)

{

butcount —;

}

else

{

PORTD =0b00000000;

}

Данный код чем то похож на предыдущий, только здесь у нас идёт, наоборот декрементирование переменной, и как только её значение опять достигнет нуля, то мы и попадём в обработку отжатия кнопки, тем самым полностью избавимся от дребезга. И чем старее и некачественнее будет наша тактовая кнопка, тем большее значение переменной в условии мы будем применять.

Давайте теперь соберём проект и проверим его работу сначала в протеусе, а затем и на практике. Выглядит это приблизительно так. Интереснее конечно это смотреть в видеоуроке

Смотреть ВИДЕОУРОК

Post Views: 13 083

Описан простой эксперимент с подключением кнопки к AVR микроконтроллеру, разобрана не сложная программа на языке Си для обработки нажатий кнопки. Разберемся с особенностями подключения кнопки к портам МК, а также с методами считывания состояний кнопки на языке Си.

В предыдущих статьях были рассмотрены эксперименты со светодиодами, которые подключались к портам микроконтроллера, сконфигурированных на вывод (Output).

В этой статье мы подключим к микроконтроллеру кнопку, контакты которой при нажатии замыкаются, а при отжатии - размыкаются (замыкающая кнопка).

Принципиальная схема эксперимента

Для того чтобы можно было хоть как-то наблюдать и управлять чем-то с помощью кнопки мы подключим к микроконтроллеру еще два светодиода. Схемка очень простая, вот она:

Рис. 1. Принципиальная схема эксперимента с микроконтроллером ATtiny2313 и кнопкой.

Как видим, к двум портам PB0 и PB1 через ограничивающие резисторы подключены два светодиода, а к порту PD2 - кнопка и она также с ограничивающим резистором. Для подключения программатора к МК используется разъем Conn 1 (AVR-ISP), а для подключения схемы к отдельному источнику питания +5В предназначены два контакта - P1 и P2.

Рис. 2. Собранная на беспаечной макетной панели схема эксперимента с микроконтроллером и кнопкой.

Важно заметить что для безопасного использования порта с кнопкой, последовательно ей подключен резистор с сопротивлением на 1 КОм (можно подключить и на другое сопротивление 600 Ом - 2 КОм). Примите это как правило хорошего тона в работе с пинами, которое обережет порт МК от выхода из строя в случае ошибочной подачи на пин высокого уровня и при замкнутой кнопке.

Структура портов ввода-вывода в AVR микроконтроллерах

Пины микроконтроллера являются универсальными GPIO (General Purpose Input Output), к ним можно подключать как исполнительные устройства (индикаторы, силовые ключи), так и разнообразные цифровые датчики (кнопки, переключатели).

Несколько пинов в МК могут быть подключены к АЦП/ЦАП (Аналогово-Цифровой-Преобразователь и наоборот), с их помощью можно выполнять анализ и генерацию аналоговых сигналов. Обычные GPIO не умеют работать с аналоговыми сигналами, у них на входе/выходе может быть только 0 (0В) или 1 (+5В).

К каждому пину GPIO внутри микроконтроллера подключены несколько блоков и электронных компонентов, о которых полезно знать:

  • Между пином порта и каждой из шин питания (GND и VCC) подключено по диоду . Они используются для "гашения" кратковременных помех, скачков напряжения относительно пина и каждой из шин питания;
  • Также между пином и GND включен конденсатор . Точно не знаю зачем он нужен, возможно для защиты от помех, для предотвращения дребезга контактов при использовании кнопок и переключателей подключенных к пину, или еще для чего-то;
  • К каждому пину подключен электронный ключ с резистором - это подтяжка пина к напряжению источника питания (Pull-UP) . Данный электронный ключ включается программно и служит для установки по умолчанию высокого логического уровня 1 (+5В) при работе с пином в режиме ввода (Input);
  • Между пином и каждой из шин питания (GND и VCC) включены еще два электронных ключа (без резисторов), они нужны для установки на пине высокого (+5В) или низкого (0В) логического уровня при работе пина в режиме вывода (Output).

Для программного управления и конфигурирования каждого из портов применяются три специальных регистра, к примеру для порта "B":

  • DDRB - регистр (8 бит) для установки режимов работы пинов - на ввод или вывод. Осуществляется установкой соответствующих бит в регистре;
  • PORTB - регистр для управление состоянием пинов порта в режиме вывода - высокий или низкий уровень. Также используется в режиме ввода, применяется для включения подтягивающих резисторов (Pull-UP) и установки высокого уровня на входе по умолчанию;
  • PINB - регистр, который содержит логические состояния пинов в порте, используется для чтения значений портов, которые сконфигурированы в режиме ввода.

Более детально узнать об устройстве портов для конкретной модели микроконтроллера можно из его даташита, в разделе "I/O-Ports", также там могут быть приведены примеры кода на Си и Ассемблере для работы с портами.

Пин RESET в качестве порта ввода-вывода

Полезно знать что пин "RESET" микросхемы (у нас на схеме это пин под номером 1), который предназначен для сброса выполнения программы микроконтроллера (перезагрузки), также можно использовать для подключения кнопок, светодиодов и других устройств ввода-вывода, то есть он может быть превращен в обычный GPIO.

Это может быть полезно если у микросхемы не хватает пинов для вашей конструкции. Например при сборке какого-то устройства на чипе ATtiny13 (8 выводов, 2шт - питание, 5шт - порты ввода-вывода, 1шт -для RESET) у вас оказалось что не хватает одного пина для светодиода. Здесь может быть несколько вариантов решения проблемы:

  1. Перепрограммирование пина с RESET под порт ввода-вывода;
  2. Подключение светодиода к одному из соседних уже использованных пинов, применив некоторые хистросты в схемном решении и с учетом возможности его общего использования;
  3. Использование другого МК у которого больше пинов, например ATtiny2313.

Что из этих вариантов проще и дешевле по финансам/времени - судите по своему случаю.

Для превращения пина "RESET" в порт ввода-вывода придется изменить специальный фьюз - RSTDISBL (Reset Disable). Но прежде чем это сделать нужно помнить что после данной операции перепрограммировать микроконтроллер станет возможным только с применением высоковольтного программатора (на 12В), обычный USB ISP или другой программатор с питанием от 5В сделать свою работу уже не сможет.

Программа на Си

Итак, у нас есть одна кнопка и два светодиода которые подключены к микроконтроллеру, что же с ними можно сделать? - а сделаем мы вот что (алгоритм):

  1. После включения питания светодиоды будут мигать попеременно и с задержкой в 300 миллисекунд;
  2. При нажатии и удержании кнопки будет светиться только синий светодиод;
  3. После отжатия кнопки синий светодиод мигнет 3 раза с задержкой 500 миллисекунд, после чего светодиоды снова будут мигать поочередно и с задержкой 300 миллисекунд.

Пример реализации такого алгоритма на языке Си под AVR приведен ниже. Создадим новый файл для нашей программы и откроем его для редактирования:

Nano /tmp/avr-switch-test.c

Поместим следующий код в тело файла:

/* Эксперимент с кнопкой на ATtiny2313 * https://сайт */ #define F_CPU 1000000UL // Частота ядра = 1 МГц #include #include // -- Макросы для управления светодиодами -- #define LED_BLUE_ON PORTB |= (1 << PB0) // Засвечиваем синий диод #define LED_BLUE_OFF PORTB &= ~(1 << PB0) // Гасим синий диод #define LED_RED_ON PORTB |= (1 << PB1) // Засвечиваем красный диод #define LED_RED_OFF PORTB &= ~(1 << PB1) // Гасим красный диод // Основная программа void main(void) { DDRD |= (0 << PD2); // Пин 6 - на вход PORTD |= (1 << PD2); // Включаем подтягивающий (Pull-UP) резистор для пина 6 DDRB |= (1 << PB0); // Пин 12 - на вывод DDRB |= (1 << PB1); // пин 13 - на вывод // -- Бесконечный цикл -- while(1) { _delay_ms(300); // Задержка 300 мс LED_BLUE_ON; // Включаем синий диод LED_RED_OFF; // Гасим красный диод _delay_ms(300); LED_RED_ON; // Включаем красный диод LED_BLUE_OFF; // Гасим синий диод if(!(PIND & (1 << PD2))) { // Проверяем нажата ли кнопка _delay_ms(50); // Задержка 50 мс (дребезг контактов) LED_RED_OFF; LED_BLUE_ON; while(!(PIND & (1 << PD2))); // Ждем пока кнопка не будет отпущена _delay_ms(500); // Дальше мигаем синим диодом LED_BLUE_OFF; _delay_ms(500); LED_BLUE_ON; _delay_ms(500); LED_BLUE_OFF; _delay_ms(500); LED_BLUE_ON; _delay_ms(500); LED_BLUE_OFF; _delay_ms(200); } // Конец блока работы с кнопкой } // Конец блока с вечным циклом }

Первым делом мы задаем константу F_CPU , которая укажет компилятору рабочую частоту ядра микроконтроллера, это нужно чтобы некоторые подпрограммы и функции работали корректно. В нашем примере используется функция задержки по времени - "_delay_ms" из библиотеки "util/delay.h", которая просчитывает время затраченное на холостые такты, опираясь на значение в константе F_CPU.

Посмотреть код библиотеки "delay" для организации задержки по времени и в котором используется константа F_CPU, можно в GNU Linux при помощи любого текстового редактора, к примеру можно выполнить вот такую команду:

Nano /usr/lib/avr/include/util/delay.h

Заводская установленная частота внутреннего RC генератора в микроконтроллере ATtiny2313 равняется 8000000Гц (8МГц), также по умолчанию установлен фьюз деления частоты - CKDIV8 (Clock Divide by 8), поэтому реальная рабочая частота кристалла = 8000000Гц / 8 = 1000000Гц = 1МГц.

Посмотреть какие фьюзы установлены в микроконтроллере можно при помощи avrdude или же графической оболочке к нему под названием AVR8 Burn-O-Mat .

Дальше в программе определены макросы для управления состоянием портов к которым подключены светодиоды: LED_BLUE_ON, LED_BLUE_OFF, LED_RED_ON, LED_RED_OFF. Вызвав подобный макрос в любом месте программы мы очень просто можем зажечь или погасить каждый из светодиодов, не придется повторять его код, что в свою очередь упростит программу и сделает ее более наглядной.

В основной программе "void main(void)" мы начинаем работу с конфигурации портов:

  • DDRD |= (0 << PD2) - установка разряда PD2 регистра DDRD на ввод, к нему подключена кнопка (пин 6);
  • PORTD |= (1 << PD2) - включение подтягивающего резистора для пина к которому привязан разряд PD2 регистра PORTD (пин 6);
  • DDRB |= (1 << PB0) - установка разряда PB0 в регистре DDRB на вывод, к нему подключен СИНИЙ светодиод (пин 12);
  • DDRB |= (1 << PB1) - установка разряда PB1 в регистре DDRB на вывод, к нему подключен КРАСНЫЙ светодиод (пин 13).

Дальше, используя макросы, мы гасим красный светодиод и зажигаем синий. Теперь при помощи еще одного вечного цикла но у же с условием мы выполним ожидание до того момента, пока кнопка не будет отжата: "while(!(PIND & (1 << PD2)));".

При отжатой кнопке на пине 6 появится высокий уровень (это сделает внутренний подтягивающий резистор, который мы включили раньше), а в разряде PD2 регистра PIND будет установлена логическая 1.

После этого выполняется трехразовое мигание (включение-выключение) синего светодиода с задержкой в 0,5 секунды и основной вечный цикл начинает работу по новому - будут поочередно зажигаться два светодиода.

Очень простая программа, но тем не менее, она является хорошим примером и почвой для дальнейших экспериментов.

Настройка Geany под ATtiny2313

В предыдущих публикациях я проводил эксперименты с микроконтроллером ATMega8, здесь же используется менее "нафаршированный" МК - ATTiny2313.

Для компиляции программы и прошивки ее в МК следует немножко перенастроить команды для сборки в интегрированной среде программирования Geany.

Идем в меню Build - Set Build Commands. В команде для компиляции (C commands) нужно изменить модель применяемого чипа: "-mmcu=attiny2313". В команде для прошивки МК нужно изменить тип чипа для avrdude: "-p t2313".

Рис. 3. Перенастройка Geany для работы с микроконтроллером ATTiny2313.

Все команды приведены для ОС GNU Linux, если у вас Windows то возможно придется прописать полные пути к бинарным файлам "avr-gcc.exe", "avr-objcopy.exe", "avrdude.exe".

Более подробно о том как настроить Geany в GNU Linux я рассматривал в одной из предыдущих статей цикла.

Компиляция и прошивка программы в МК

Компиляцию, сборку и прошивку программы можно выполнить нажав в среде Geany поочередно три кнопки: "Compile", "Build" и "Run". Также все эти операции можно выполнить из консоли, вот команды для данных действий (выполнять последовательно):

Avr-gcc -mmcu=attiny2313 -Os /tmp/avr-switch-test.c -o /tmp/avr-switch-test.o avr-objcopy -j .text -j .data -O ihex /tmp/avr-switch-test.o /tmp/avr-switch-test.hex avrdude -c usbasp -p t2313 -P usb -U flash:w:/tmp/avr-switch-test.hex

Все команды почти полностью (за исключением подстановок имен файлов) идентичны тем, которые мы исправляли в настройках Geany.

Заключение

Несмотря на простоту эксперимента я также постарался осветить некоторые очень важные технические моменты работы с портами, приведенные знания и опыт будут полезны в дальнейшем изучении и работе с микроконтроллерами ATMEL.

На первом уроке мы научились подавать напряжение ножкой микроконтроллера. Теперь нужно научиться управлять микроконтроллером без перепрошивки.

Зачем это нужно? Например, вы сделали часы на микроконтроллере, нужно выставить время, но очень не удобно каждый раз перепрошивать, когда собьется время. Намного удобнее пользоваться кнопками, например, одной менять часы, другой минуты.

Помните в первом уроке мы настраивали ножку как выход, т.е. мы могли ей подавать напряжение. Так вот, ножку можно настроить как вход. В таком режиме можно проверить есть ли на ней напряжение или нет.

Пример: создаем проект при помощи мастера проектов. Первую ногу настраиваем как выход, вторую как вход. При создании мастером проектов указываем, что ножка PB1 будет входом, на ней же включаем подтягивающий резистор, реализуется это так:

После создания проекта приведем код к такому виду:

#include #include void main(void ) { PORTB= 0x02 ; DDRB= 0x01 ; while (1 ) { if (PINB.1== 0 ) { PORTB.0= 1 ; delay_ms(100 ) ; PORTB.0= 0 ; delay_ms(100 ) ; } } ; }

#include #include void main(void) { PORTB=0x02; DDRB=0x01; while (1) { if(PINB.1==0) { PORTB.0=1; delay_ms(100); PORTB.0=0; delay_ms(100); } }; }

Как мы видим, по сравнению с первым уроком изменилась настройка порта

if(PINB.1==0) {}

данную строчку нужно читать так — если на ножке 1 порта В подключили землю (0 потенциал), то выполнить код в фигурных скобках. В нашем примере это код из первого урока. Если кнопка не замкнута, то ничего не делать. Промоделировать можно в Proteuse.

Вместо кнопки можно поставить датчик, реле и т.п., вместо светодиода — пищалку, получится сигнализация.

Архив с прошивкой и файлом протеуса доступен

Update1: Зачем нужна подтяжка порта?
У входа мк большое сопротивление, если будут течь даже микротоки вызванные помехами, то по закону Ома U=R*I это может привести к тому, что на входе появится лог 1. Чтобы не было таких проблем в AVR микроконтроллерах можно подключить ножку к плюсу питания, через подтягивающий резистор. В этом случае даже, логика работы меняется наоборот — но если появится помеха, нам это не важно, ведь у нас на входе уже логическая единица.

Почему подключение через резистор? Допустим мы подключили вход к плюсу напрямую без резистора. Когда кнопка сработает, она притянет вход к земле, поэтому на входе будет короткое замыкание между + и землей. Если же стоит резистор, то при замыкании кнопки с одной стороны он так и останется подключен к +, а со второй стороны на нем появится земля от кнопки. Через резистор потечет ток, но его величина будет не такой большой.

Update2: Добавлен тест, в котором вы можете проверить на сколько хорошо вы усвоили материал урока

This movie requires Flash Player 9

Что нужно для того, чтобы стать профессиональным разработчиком программ для микроконтроллеров и выйти на такой уровень мастерства, который позволит с лёгкостью найти и устроиться на работу с высокой зарплатой (средняя зарплата программиста микроконтроллеров по России на начало 2017 года составляет 80 000 рублей). ...

О том, как подать дискретный сигнал на вход микроконтроллера, я рассказывал . Такой подход вполне работоспособен и будет прекрасно выполнять свою миссию, если в качестве источника сигнала будет, например, транзистор или другого микроконтроллера.

Однако, если вы таким образом подключите к входу микроконтроллера кнопку или контакт реле, то здесь вас могут поджидать неожиданные эффекты в виде сбоев работы устройства и разных глюков. А вызваны эти эффекты будут таким явлением, как дребезг контактов .

В этой статье я расскажу о том, как устранить дребезг контактов, подключаемых к микроконтроллера. Но сначала (для тех, кто слышит это словосочетание впервые), расскажу непосредственно о том, что же такое этот самый дребезг контактов.


Дребезг контактов возникает во время замыкания или размыкания контактов. Посмотрите на рисунок:

Изначально контакт разомкнут.

Когда мы начинаем замыкать контакт (нажимаем на кнопку), то замыкание происходит не сразу.

Это нам кажется, что мы нажали на кнопку мгновенно. Однако на самом деле, если растянуть время достаточно сильно, по получится, что мы нажимаем кнопку постепенно. На механическом контакте надо обеспечить достаточное усилие, чтобы он окончательно замкнулся, а контакты, как правило, пружинят, и поэтому какое-то время контакт находится в переходном процессе. То есть быстро-быстро замыкается-размыкается.

Если мы включаем этой кнопкой лампочку, то мы не заметим этот переходный процесс. Нам будет казаться, что лампочка сразу включилась после нажатия кнопки.

Однако быстродействие микроконтроллера таково, что он заметит все (или почти все) замыкания-размыкания переходного процесса. Это будет означать, что программа микроконтроллера столько раз отреагирует на сигнал от кнопки, сколько раз будет изменяться сигнал во время переходного процесса.

А мы то ожидаем, что одно нажатие кнопки - это одно переключение входа микроконтроллера. Но на самом деле это не так. Потому что дребезг контактов вносит свою лепту в усложнение жизни инженеров.

Представьте, что наши кнопки - это клавиатура телефона. Мы нажимаем цифру 8, подразумевая, что эта цифра будет набрана телефоном один раз. Но телефон вместо этого набирает 5 или 10 восьмёрок, потому что разработчики телефона не удосужились предусмотреть защиту от дребезга контактов. Станете вы пользоваться таким телефоном?

Ну и напоследок надо сказать, что время дребезга контактов зависит от качества контактов, и обычно составляет от 10 до 100 мс.

Устранение дребезга контактов

Думаю, уже не надо объяснять, что в случае, если к входам вашего микроконтроллера подключены механические контакты, то ваше устройство должно как-то бороться с дребезгом контактов.

Есть два способа борьбы с дребезгом контактов:

  1. Аппаратный
  2. Программный

Аппаратное подавление дребезга контактов

Аппаратное подавление дребезга - это схемные решения, которые позволяют устранить этот неприятный эффект. Чаще всего это простая RC-цепь, или вообще только один конденсатор.

Принцип работы такой схемы простой: конденсатору требуется какое-то время для зарядки (или разрядки). А пока он полностью не зарядится, на вход микроконтроллера не поступит нужный сигнал. Этого времени хватает на то, чтобы переходный процесс успел завершиться. Таким образом и выполняется подавление дребезга.

Простая схема устранения дребезга контактов приведена на рисунке:

Номиналы элементов приблизительные. По идее надо их рассчитывать для каждого отдельного случая. Но в большинстве случаев они вполне подойдут.

Есть и более сложные схемы подавления дребезга контактов, которые не требуют расчёта, потому что выполняются на цифровых элементах. Например, схема на RS-триггере. Но в устройствах на микроконтроллерах использовать подобные ухищрения нет смысла.

Программное подавление дребезга контактов

Если уж мы используем микроконтроллер, то в подавляющем большинстве случаев нет смысла усложнять схему устройства и встраивать в неё элементы устранения дребезга. Потому что проще и дешевле организовать программное подавление дребезга.

Использовать аппаратное подавление дребезга в устройствах на микроконтроллерах имеет смысл только в очень редких случаях. Например, если микроконтроллер маломощный и даже малейшее расходование его ресурсов не на основную задачу нежелательно.

Самое простое и самое распространённое программное решение для борьбы с дребезгом - это временная задержка. Алгоритм простой:

  1. При изменении уровня сигнала на входе на противоположный включаем таймер (например, на 100 миллисекунд).
  2. После истечения задержки проверяем сигнал. Если он остался изменённым, то считаем, что кнопка нажата (или отпущена - в зависимости от того, какое изменение сигнала обнаружено). Если же он вернулся в исходное состояние, то считаем это помехой и не реагируем на сигнал.

Бывают особые случаи, когда быстрое переключение контактов - это обычное состояние системы. Ну например, если есть какой-то датчик, который по логике работы не может принимать фиксированное значение на длительное время. То есть идёт как бы непрерывный дребезг контактов. И в этом бесконечном потоке нам надо как-то определить, какой же всё-таки сигнал на входе.

В этом случае можно применить следующий алгоритм:

  1. Посчитать количество и/или продолжительность замкнутого и разомкнутого состояния контакта в единицу времени (например, в секунду).
  2. По наибольшему количеству (или времени) определить конечное состояние сигнала.

Например, если за секунду на входе у нас 50 раз была логическая 1, и 20 раз - логический 0, то можно считать, что на входе единица. Разумеется, здесь нужен индивидуальный подход в зависимости от задачи.

Примеры исходных кодов приводить здесь не буду, потому как статья эта не о программировании. Если кому интересно, то способы подключения разных устройств к микроконтроллеру можно найти .


В следующих статьях будут устройства, которые должны управлять внешней нагрузкой. Под внешней нагрузкой я понимаю все, что прицеплено к ножкам микроконтроллера – светодиоды, лампочки, реле, двигатели, исполнительные устройства … ну Вы поняли. И как бы не была заезжена данная тема, но, чтобы избежать повторений в следующих статьях, я все-же рискну быть не оригинальным — Вы уж меня простите:). Я кратенько, в рекомендательной форме, покажу наиболее распространенные способы подключения нагрузки (если Вы что-то захотите добавить – буду только рад).
Сразу договоримся, что речь идет о цифровом сигнале (микроконтроллер все-таки цифровое устройство) и не будем отходить от общей логики: 1 -включено, 0 -выключено. Начнем.

Нагрузкой постоянного тока являются: светодиоды, лампы, реле, двигатели постоянного тока, сервоприводы, различные исполнительные устройства и т.д. Такая нагрузка наиболее просто (и наиболее часто) подключается к микроконтроллеру.

1.1 Подключение нагрузки через резистор.
Самый простой и, наверно, чаще всего используемый способ, если речь идет о светодиодах.

Резистор нужен для того, чтобы ограничить ток протекающий, через ножку микроконтроллера до допустимых 20мА . Его называют балластным или гасящим. Примерно рассчитать величину резистора можно зная сопротивление нагрузки Rн.

Rгасящий = (5v / 0.02A) – Rн = 250 – Rн

Как видно, даже в самом худшем случае, когда сопротивление нагрузки равно нулю достаточно 250 Ом для того, что бы ток не превысил 20мА. А значит, если неохота чего-то там считать — ставьте 300 Ом и Вы защитите порт от перегрузки. Достоинство способа очевидно – простота.

1.2 Подключение нагрузки при помощи биполярного транзистора.
Если так случилась, что Ваша нагрузка потребляет более 20мА, то, ясное дело, резистор тут не поможет. Нужно как-то увеличить (читай усилить) ток. Что применяют для усиления сигнала? Правильно. Транзистор!

Для усиления удобней применять n-p-n транзистор, включенный по схеме ОЭ . При таком способе можно подключать нагрузку с большим напряжением питания, чем питание микроконтроллера. Резистор на базе – ограничительный. Может варьироваться в широких пределах (1-10 кОм), в любом случае транзистор будет работать в режиме насыщения. Транзистор может быть любой n-p-n транзистор. Коэффициент усиления, практически не имеет значения. Выбирается транзистор по току коллектора (нужный нам ток) и напряжению коллектор-эмиттер (напряжение которым запитывается нагрузка). Еще имеет значение рассеиваемая мощность — чтоб не перегрелся.

Из распространенных и легко доступных можно заюзать BC546, BC547, BC548, BC549 с любыми буквами (100мА), да и тот-же КТ315 сойдет (это у кого со старых запасов остались).
- Даташит на биполярный транзистор BC547

1.3 Подключение нагрузки при помощи полевого транзистора.
Ну а если ток нашей нагрузки лежит в пределах десятка ампер? Биполярный транзистор применить не получиться, так как токи управления таким транзистором велики и скорей всего превысят 20мА. Выходом может служить или составной транзистор (читать ниже) или полевой транзистор (он же МОП, он же MOSFET). Полевой транзистор просто замечательная штука, так как он управляется не током, а потенциалом на затворе. Это делает возможным микроскопическим током на затворе управлять большими токами нагрузки.

Для нас подойдет любой n-канальный полевой транзистор. Выбираем, как и биполярный, по току, напряжению и рассеиваемой мощности.

При включении полевого транзистора нужно учесть ряд моментов:
— так как затвор, фактически, является конденсатором, то в моменты переключения транзистора через него текут большие токи (кратковременно). Для того чтобы ограничить эти токи в затвор ставиться ограничивающий резистор.
— транзистор управляется малыми токами и если выход микроконтроллера, к которому подключен затвор, окажется в высокоимпедансном Z-состоянии полевик начнет открываться-закрываться непредсказуемо, вылавливая помехи. Для устранения такого поведения ножку микроконтроллера нужно «прижать» к земле резистором порядка 10кОм.
У полевого транзистора на фоне всех его положительных качеств есть недостаток. Платой за управление малым током является медлительность транзистора. ШИМ, конечно, он потянет, но на превышение допустимой частоты он Вам ответит перегревом.

1.4 Подключение нагрузки при помощи составного транзистора Дарлингтона.
Альтернативой применения полевого транзистора при сильноточной нагрузке является применение составного транзистора Дарлингтона. Внешне это такой-же транзистор, как скажем, биполярный, но внутри для управления мощным выходным транзистором используется предварительная усилительная схема. Это позволяет малыми токами управлять мощной нагрузкой. Применение транзистора Дарлингтона не так интересно, как применение сборки таких транзисторов. Есть такая замечательная микросхема как ULN2003. В ее составе аж 7 транзисторов Дарлингтона, причем каждый можно нагрузить током до 500мА, причем их можно включать параллельно для увеличения тока.

Микросхема очень легко подключается к микроконтроллеру (просто ножка к ножке) имеет удобную разводку (вход напротив выхода) и не требует дополнительной обвязки. В результате такой удачной конструкции ULN2003 широко используется в радиолюбительской практике. Соответственно достать ее не составит труда.
- Даташит на сборку Дарлингтонов ULN2003

Если Вам нужно управлять устройствами переменного тока (чаще всего 220v), то тут все сложней, но не на много.

2.1 Подключение нагрузки при помощи реле.
Самым простым и, наверное, самым надежным есть подключение при помощи реле. Катушка реле, сама собой, является сильноточной нагрузкой, поэтому напрямую к микроконтроллеру ее не включишь. Реле можно подключить через транзистор полевой или биполярный или через туже ULN2003, если нужно несколько каналов.

Достоинства такого способа большой коммутируемый ток (зависит от выбранного реле), гальваническая развязка. Недостатки: ограниченная скорость/частота включения и механический износ деталей.
Что-то рекомендовать для применения не имеет смысла — реле много, выбирайте по нужным параметрам и цене.

2.2 Подключение нагрузки при помощи симистора (триака).
Если нужно управлять мощной нагрузкой переменного тока а особенно если нужно управлять мощностью выдаваемой на нагрузку (димеры), то Вам просто не обойтись без применения симистора (или триака). Симистор открывается коротким импульсом тока через управляющий электрод (причем как для отрицательной, так и для положительной полуволны напряжения). Закрывается симистор сам, в момент отсутствия напряжения на нем (при переходе напряжения через ноль). Вот тут начинаются сложности. Микроконтроллер должен контролировать момент перехода через ноль напряжения и в точно определенный момент подавать импульс для открытия симистора — это постоянная занятость контроллера. Еще одна сложность это отсутствие гальванической развязки у симистора. Приходится ее делать на отдельных элементах усложняя схему.


Хотя современные симисторы управляются довольно малым током и их можно подключить напрямую (через ограничительный резистор) к микроконтроллеру, из соображений безопасности приходится их включать через оптические развязывающие приборы. Причем это касается не только цепей управления симистором, но и цепей контроля нуля.

Довольно неоднозначный способ подключения нагрузки. Так как с одной стороны требует активного участия микроконтроллера и относительно сложного схемотехнического решения. С другой стороны позволяет очень гибко манипулировать нагрузкой. Еще один недостаток применения симисторов — большое количество цифрового шума, создаваемого при их работе — нужны цепи подавления.

Симисторы довольно широко используются, а в некоторых областях просто незаменимы, поэтому достать их не составляет каких либо проблем. Очень часто в радиолюбительстве применяют симисторы типа BT138.