ESP8266:Примеры/Взаимодействие с GPIO-контактами ESP8266 при помощи прошивки NodeMCU

Материал из Онлайн справочника
Перейти к навигацииПерейти к поиску

Перевод: Максим Кузьмин
Проверка/Оформление/Редактирование: Мякишев Е.А.


Черновик


Взаимодействие с GPIO-контактами ESP8266 при помощи прошивки NodeMCU

Аббревиатура «GPIO» означает «general purpose input/output», т.е. «Интерфейс ввода/вывода общего назначения». Эта фраза описывает то, что могут делать контакты, работающие в этом режиме: быть входными или выходными контактами во множестве различных ситуаций.

В этой статье мы познакомимся с API NodeMCU, отвечающим за работу с GPIO-контактами. Более подробно о нем можно узнать в его официальной документации.

В частности, ниже мы узнаем, как задать разные режимы для работы GPIO-контактов. Это будет проиллюстрировано фрагментами-примерами, применимыми для работы с ESP8266, так что можете проверить их и поэкспериментировать с ними в своих проектах!

Справочная информация

Основы программирования на Lua

Это скриптовый язык программирования, написанный на C. Разработка этого проекта началась в 1993 году силами Роберту Иерузалимски, Луиша Энрике де Фигейреду и Валдемара Келе, работавшими тогда в подразделении Tecgraf при Католическом университете Рио-де-Жанейро.

Более подробно об этом языке программирования можно почитать в «Википедии».

Прошивка NodeMCU для ESP8266 основана на Lua, поэтому если вы хотите писать собственные скрипты для ESP8266, вам важно знать основы этого языка.

Переменные

Переменные в языке Lua не делятся по типу данных, но делятся по области видимости. Это значит, что переменные в Lua могут быть глобальными или локальными.

  • Глобальные переменные. Все переменные по умолчанию считаются глобальными (если в коде специально не задано, что они локальные).
pin = 3
test = "It works!"
  • Локальные переменные. Если переменная задана локальной, область ее видимости будет ограничена лишь ее функцией.
local pin = 3
local test = "It works!"
  • Поля таблиц. Это особый тип переменных, в которых может храниться все, за исключением «nil» (мы это затрагивать не будем).

Примечание: Lua – это язык, чувствительный к регистру. Поэтому переменная «PIN» – это не то же самое, что «Pin» или «pin».

Типы данных (типы значений)

Lua – это язык с динамической типизацией, поэтому у переменных нет типов данных. Типы данных есть только у значений. Значения могут храниться в переменных, передаваться в виде параметров и возвращаться в виде результатов.

В таблице ниже показаны типы данных для значений в языке Lua.

Тип значения Описание
Строка (string) Массив символов
Число (number) Действительное (двойной точности с плавающей запятой) число
Булево значение (boolean) Значение «true» или «false». Как правило, используется для проверки выполнения условий
Функция (function) Функция, написанная на Lua
Неопределенное значение (nil) В такой переменной не хранится никаких данных
Таблица (table), пользовательские данные (userdata) и поток (thread) Эти три типа данных мы затрагивать не будем

Вот примеры некоторых из этих типов значений:

print(type("Hello world!")) - строка
print(type(7))              -- число
print(type(true))           -- булево значение
print(type(print))          -- функция
print(type(nil))            -- неопределенное значение

Примечание: Работая с ESP8266 и прошивкой NodeMCU, вы изредка будете встречать тип данных «nil». Это будет значить лишь, что такая переменная не определена. Также, если вы хотите удалить какое-то значение в какой-то переменной, просто присвойте ей значение «nil».

Комментарии

Комментарии – это просто текст, в котором программист объясняет, как работает его код. Если какой-то фрагмент кода помечен как комментарий, то ESP-модуль проигнорирует его и не будет обрабатывать. Комментарии начинаются с двух тире («--»). Вот два типа комментариев:

  • Однострочные комментарии:
print("Hello World!") - комментарий в одну строчку
  • Многострочные комментарии:
--[[
print("Hello World!") – это многострочный комментарий
--]]

Операторы

Оператор – это символ, который говорит интерпретатору выполнить определенное математическое или логическое действие. В язык Lua встроено много операторов разных типов:

  • Арифметические операторы;
  • Операторы сравнения;
  • Логические операторы;
  • Прочие операторы;

Читая таблицы и примеры ниже, представьте, что имеете дело с двумя переменными: «А», в которой хранится значение «1», и «B», в которой хранится значение «2».

A = 1
B = 2
Арифметические операторы
Оператор Пример Результат
+ A + B 3
- A - B -1
* A * B 2
/ B / A 2
% B % A 0
^ B^2 4
- -A -1
Операторы сравнения
Оператор Пример Результат
== (A == B) false
~= (A ~= B) true
> (A > B) false
< (A < B) true
>= (A >= B) false
<= (A <= B) true
Логические операторы
Оператор Пример Результат
and (и) (A and B) false
or (или) (A or B) true
not (не) !(A and B) true
Оператор конкатенации

Теперь представьте, что у нас две новые переменные:

a = "Hello!"
b = "World!"
Оператор Пример Результат
.. a..b "Hello World!"

Циклы

Цикл позволяет выполнить блок кода несколько раз, пока выполняется заданное условие. Во фрагменте кода ниже – пока значением в переменной «boolean_value» является «true».

-- цикл while
while boolean_value
do
 -- код будет выполняться, пока в «boolean_value» будет «true»
end

-- и цикл for
for min, max, increment
do
  -- код будет выполняться, пока не будет достигнуто макс. значение
end

Операторы if… else

Операторы if... else (т.е. «если... иначе») – один из самых важных инструментов для управления программой. Они используются следующим образом:

if boolean_value then
    -- если в переменной «boolean_value» значение «true»
else 
    -- если в переменной «boolean_value» значение «false»
end

Названия этих операторов говорят сами за себя. Если выполнено условие «boolean_value=true», то программа выполнит код, идущий после «if». Но если условием является «boolean_value=false», то программа выполнит код, идущий после «else».

Функции

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

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

function displayTemperature(kelvin)
  celsius = kelvin  273.15
  print("Temperature in Celsius is: ", celsius)

  fahrenheit = (celsius*9/5+32)
  print("Temperature in Fahrenheit is: ", fahrenheit)
end

k = 294 - температура в градусах Кельвина

displayTemperature(k) - эта строчка вызывает функцию, созданную выше

Режим контакта

Чтобы воспользоваться GPIO-контактом, нам нужно задать режим его работы. Вы можете задать для него один из трех доступных режимов (контакт не может одновременно работать в нескольких режимах).

Режим В коде Описание
OUTPUT (вывод данных) gpio.OUTPUT Значение контакта можно задать как «LOW» или «HIGH»
INPUT (ввод данных) gpio.INPUT Мы будем считывать текущее состояние контакта
INTERRUPT (прерывание) gpio.INT Аналогично «INPUT», но ESP8266 также постоянно проверяет, изменилось ли состояние контакта. Если изменилось, ESP8266 выполнит заданную функцию

Как обращаться к контактам

В таблице ниже показано, как номер контакта ESP8266 в Lua-коде соотносится с его GPIO-номером. У платы ESP-01 только два контакта: GPIO0 и GPIO2.

Номер контакта в Lua-коде GPIO-номер контакта
0 [*] GPIO16
1 GPIO5
2 GPIO4
3 GPIO0
4 GPIO2
5 GPIO14
6 GPIO12
7 GPIO13
8 GPIO15
9 GPIO3
10 GPIO1
11 GPIO9
12 GPIO10

Режим вывода данных (OUTPUT)

Если вы хотите переключить GPIO-контакт в состояние «HIGH» (3.3В) или «LOW» (0В), то воспользуйтесь для этого методом gpio.write(). С его помощью можно, к примеру, включить и выключить светодиод.

Во фрагменте ниже показано, как переключить контакт GPIO2 в состояние «HIGH» (3.3В):

pin = 4
gpio.mode(pin, gpio.OUTPUT)
gpio.write(pin, gpio.HIGH)

А вот так контакт GPIO2 переключается в состояние «LOW» (0В):

pin = 4
gpio.mode(pin, gpio.OUTPUT)
gpio.write(pin, gpio.LOW)

Режим ввода данных (INPUT)

Если вы хотите прочесть текущее состояние GPIO-контакта, воспользуйтесь методом gpio.read(). Во фрагменте ниже показано, как проверить, нажата ли кнопка, подключенная к контакту GPIO2.

pin = 4
gpio.mode(pin, gpio.INPUT)
print(gpio.read(pin))

Если «print(gpio.read(pin))=1», то это значит, что кнопка нажата, а если «print(gpio.read(pin))=0», то это значит, что кнопка отпущена (т.е. не нажата).

Режим прерывания (INTERRUPT)

Если вам нужно обнаружить изменение значения GPIO-контакта (например, если оно сменилось с «HIGH» на «LOW» или наоборот), воспользуйтесь методом gpio.trig(). Кроме того, одним из параметров gpio.trig() служит функция, запускаемая при изменении значения.

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

Ниже – фрагмент для создания прерывания:

pin = 4
gpio.mode(pin, gpio.INT)

function onChange ()
    print(̍Motion Detected̍)
end

gpio.trig(pin, ̍up̍, onChange)

Вторым параметром метода gpio.trig() служит тип события, вызывающего прерывание. Всего их 5:

Название события Что происходит при этом событии
up Значение контакта сменяется на «HIGH»
down Значение контакта сменяется на «LOW»
both Значение контакта сменяется с «HIGH» на «LOW» или с «LOW» на «HIGH»
low Пока контакт находится в состоянии «LOW»
high Пока контакт находится в состоянии «HIGH»

См.также

Внешние ссылки