Программирование, радиоэлектроника,
саморазвитие и частичка из моей жизни здесь...

Подключаем кнопку к микроконтроллеру ATtiny2313, простая программа

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

Содержание:

  1. Принципиальная схема эксперимента
  2. Структура портов ввода-вывода в AVR микроконтроллерах
  3. Пин RESET в качестве порта ввода-вывода
  4. Программа на Си
  5. Настройка Geany под ATtiny2313
  6. Компиляция и прошивка программы в МК
  7. Заключение

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

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

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

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

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

Рис. 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://ph0en1x.net 
 */

#define F_CPU 1000000UL  // Частота ядра = 1 МГц
#include <avr/io.h>
#include <util/delay.h>

// -- Макросы для управления светодиодами --
#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(1)" в котором мы с некоторыми задержками включаем и выключаем светодиоды, используя для этого созданные ранее макросы.

Для проверки нажата ли кнопка (подключение пина к GND через резистор 1К = логический 0) используется следующая конструкция: "if( !(PIND & (1 << PD2)) )". Здесь мы проверяем состояние разряда PD2 в регистре PIND для порта "D". Для срабатывания условия когда на пине логический ноль используем операцию логической инверсии "!" (логическое НЕ).

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

После отлова нажатия кнопки выполняем небольшую задержку в 50 миллисекунд "_delay_ms(50)", она нужна для программного подавления дребезга контактов кнопки.

Дальше, используя макросы, мы гасим красный светодиод и зажигаем синий. Теперь при помощи еще одного вечного цикла но у же с условием мы выполним ожидание до того момента, пока кнопка не будет отжата: "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".

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

Рис. 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.

В качестве заключения приведу видео для рассмотренного в статье примера работы с кнопкой и двумя светодиодами:

Начало цикла статей: Программирование AVR микроконтроллеров в Linux на языках Asembler и C.

Комментарии к публикации (4):
Ham #1Ham
26 Декабрь 2016 20:28

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

+1
SeWIR #2SeWIR
30 Декабрь 2016 00:05

Как-то муторно с этим Geany, скомпилировать, потом перегнать, потом залить. Я даже для одного файла-исходника пишу простенький Makefile. Итого собираю и прошиваю из Emacsa (да пофиг вообще из какого редактора) одной горячей клавишей.

0
ph0en1x #3ph0en1x
30 Декабрь 2016 02:22

Makefile - очень мощная штука, отличный вариант для сборки и подготовки софта из консоли, годится для автоматизации почти всех процессов сборки+прошивки+тестирования для AVR.
Также, если лень разбираться с Makefile, можно написать простой скрипт на Bash/Sh, который по сути запустит те же команды из статьи, что указаны в настройках для Geany. А тем кто любит GUI, вполне простым окажется Geany или Eclipse с плагином для AVR.
Emacs + Makefile = отличная связка, правда не всем по зубам ее осилить сразу, особенно на ранних стадиях знакомства с богатым миром консоли в Linux/Unix. smile

0
SeWIR #4SeWIR
30 Декабрь 2016 10:24

ох, Eclipse я мучал 2 недели, тяжелый он для машины моей, но мог бы быть средой

0