Site Loader

Конспект хакера Эксперименты

Начало работы с Arduino

1.Скачайте Arduino IDE с официального сайта (http://arduino.cc/en/Main/Software)

2.Если у вас Windows и Arduino IDE из zip-файла, установите драйверы из папки drivers

3.Подключите Arduino к компьютеру через USB

4.Запустите Arduino IDE

5.В «Tools → Board» выберите модель вашей платы

6.В «Tools → Serial Port» выберите порт, куда она подключена

7.Пишите программу или загружайте готовый пример из «File → Examples»

8.Жмите «Upload» на панели инструментов для прошивки платы!

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

Внешний вид Arduino IDE

Если прошивка не удаётся

Проверьте, что:

Плата получает питание, горит светодиод «ON»

Драйверы под Windows установились корректно, и в диспетчере устройств вы видите устройство «Arduino Uno»

Вы выбрали правильную модель платы и правильный порт (пункты 5 и 6)

USB-кабель исправен

Эксперимент 1. Маячок

Список деталей для эксперимента

1 плата Arduino Uno

1 беспаечная макетная плата

1 светодиод

1 резистор номиналом 220 Ом

2 провода «папа-папа»

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

Схема на макетке

Обратите внимание

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

Катод («минус») светодиода — короткая ножка, именно её нужно соединять с землёй (GND)

Не пренебрегайте резистором, иначе светодиод выйдет из строя

Выбрать резистор нужного номинала можно с помощью таблицы маркировки или с помощью мультиметра в режиме измерения сопротивления

Плата Arduino имеет три пина GND, используйте любой из них

Скетч

void setup()

{

// настраиваем пин №13 в режим выхода,

// т.е. в режим источника напряжения pinMode(13, OUTPUT);

}

void loop()

{

// подаём на пин 13 «высокий сигнал» (англ. «high»), т.е.

// выдаём 5 вольт. Через светодиод побежит ток.

// Это заставит его светиться digitalWrite(13, HIGH);

// задерживаем (англ. «delay») микроконтроллер в этом

// состоянии на 100 миллисекунд delay(100);

// подаём на пин 13 «низкий сигнал» (англ. «low»), т.е.

// выдаём 0 вольт или, точнее, приравниваем пин 13 к земле.

// В результате светодиод погаснет digitalWrite(13, LOW);

// замираем в этом состоянии на 900 миллисекунд delay(900);

// после «размораживания» loop сразу же начнёт исполняться

// вновь, и со стороны это будет выглядеть так, будто

// светодиод мигает раз в 100 мс + 900 мс = 1000 мс = 1 сек

}

Пояснения к коду

Процедура setup выполняется один раз при запуске микроконтроллера. Обычно она используется для конфигурации портов микроконтроллера и других настроек

После выполнения setup запускается процедура loop, которая выполняется в бесконечном цикле. Именно этим мы пользуемся в данном примере, чтобы маячок мигал постоянно

Процедуры setup и loop должны присутствовать в любой программе (скетче), даже если вам не нужно ничего выполнять в них — пусть они будут пустые, просто не пишите ничего между фигурными скобками. Например:

void setup()

{

}

Запомните, что каждой открывающей фигурной скобке { всегда соответствует закрывающая }. Они обозначают границы некого логически завершенного фрагмента кода. Следите за вложенностью фигурных скобок. Для этого удобно после каждой открывающей скобки увеличивать отступ на каждой новой строке на один символ табуляции (клавиша Tab)

Обращайте внимание на ; в концах строк. Не стирайте их там, где они есть, и не добавляйте лишних. Вскоре вы будете понимать, где они нужны, а где нет.

Функция digitalWrite(pin, value) не возвращает никакого значения и принимает два параметра:

o pin — номер цифрового порта, на который мы отправляем сигнал

ovalue — значение, которое мы отправляем на порт. Для цифровых портов значением может бытьHIGH (высокое, единица) или LOW (низкое, ноль)

Если в качестве второго параметра вы передадите функции digitalWrite значение,

отличное от HIGH,LOW, 1 или 0, компилятор может не выдать ошибку, но считать, что передано HIGH. Будьте внимательны

Обратите внимание, что использованные нами константы: INPUT, OUTPUT, LOW, HIGH, пишутся заглавными буквами, иначе компилятор их не распознает и выдаст ошибку. Когда ключевое слово распознано, оно подсвечивается синим цветом в Arduino IDE

Вопросы для проверки себя

1.Что будет, если подключить к земле анод светодиода вместо катода?

2.Что будет, если подключить светодиод с резистором большого номинала (например, 10 кОм)?

3.Что будет, если подключить светодиод без резистора?

4.Зачем нужна встроенная функция pinMode? Какие параметры она принимает?

5.Зачем нужна встроенная функция digitalWrite? Какие параметры она принимает?

6.С помощью какой встроенной функции можно заставить микроконтроллер ничего не делать?

7.В каких единицах задается длительность паузы для этой функции?

Задания для самостоятельного решения

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

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

Эксперимент 2. Маячок с нарастающей яркостью

Список деталей для эксперимента

1 плата Arduino Uno

1 беспаечная макетная плата

1 светодиод

1 резистор номиналом 220 Ом

2 провода «папа-папа» Для дополнительного задания

еще 1 светодиод

еще 1 резистор номиналом 220 Ом

еще 2 провода

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

Схема на макетке

Обратите внимание

Не любой порт Arduino поддерживает широтно-импульсную модуляцию, если вы хотите регулировать напряжение, вам подойдут пины, помеченные символом тильда «~». Для

Arduino Uno это пины 3, 5, 6, 9, 10, 11

Скетч

// даём разумное имя для пина №9 со светодиодом

// (англ. Light Emitting Diode или просто «LED»)

// Так нам не нужно постоянно вспоминать куда он подключён

#define LED_PIN 9

void setup()

{

// настраиваем пин со светодиодом в режим выхода,

// как и раньше pinMode(LED_PIN, OUTPUT);

}

void loop()

{

// выдаём неполное напряжение на светодиод

// (он же ШИМ-сигнал, он же PWM-сигнал).

// Микроконтроллер переводит число от 0 до 255 к напряжению

// от 0 до 5 В. Например, 85 — это 1/3 от 255, // т.е. 1/3 от 5 В, т.е. 1,66 В. analogWrite(LED_PIN, 85);

// держим такую яркость 250 миллисекунд delay(250);

// выдаём 170, т.е. 2/3 от 255, или иными словами — 3,33 В.

// Больше напряжение — выше яркость! analogWrite(LED_PIN, 170); delay(250);

// все 5 В — полный накал! analogWrite(LED_PIN, 255);

// ждём ещё немного перед тем, как начать всё заново delay(250);

}

Пояснения к коду

Идентификаторы переменных, констант, функций (в этом примере идентификатор LED_PIN)

являются одним словом (т.е. нельзя создать идентификатор LED PIN).

Идентификаторы могут состоять из латинских букв, цифр и символов подчеркивания _. При этом идентификатор не может начинаться с цифры.

 

PRINT

//

верно

 

 

 

 

 

 

PRINT_3D

//

верно

 

MY_PRINT_3D //

верно

 

_PRINT_3D

//

верно

 

3D_PRINT

//

ошибка

 

ПЕЧАТЬ_3Д //

ошибка

 

PRINT:3D

//

ошибка

 

 

 

 

 

 

 

 

 

 

Регистр букв в идентификаторе имеет значение. Т.е. LED_PIN, LED_pin и led_pin с точки зрения компилятора — различные идентификаторы

Идентификаторы, создаваемые пользователем, не должны совпадать с предопределенными идентификаторами и стандартными конструкциями языка; если среда разработки подсветила введенный идентификтор каким-либо цветом, замените его на другой

Директива #define просто говорит компилятору заменить все вхождения заданного идентификатора на значение, заданное после пробела (здесь 9), эти директивы помещают в начало кода. В конце данной директивы точка с запятой ; не допустима

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

Также полезно снабжать код программы комментариями: в примерах мы видим однострочные комментарии, которые начинаются с двух прямых слэшей // и многострочные, заключённые между /* */

// однострочный комментарий следует после двойного слеша до конца строки

/* многострочный комментарий

помещается между парой слеш-звездочка и звездочка-слеш */

комментарии игнорируются компилятором, зато полезны людям при чтении давно написанного, а особенно чужого, кода

Функция analogWrite(pin, value) не возвращает никакого значения и принимает два параметра:

o pin — номер порта, на который мы отправляем сигнал

ovalue — значение скважности ШИМ, которое мы отправляем на порт. Он может принимать целочисленное значение от 0 до 255, где 0 — это 0%, а 255 — это 100%

Вопросы для проверки себя

1.Какие из следующих идентификаторов корректны и не вызовут ошибку?

13pin

MOTOR_1

контакт_светодиода

sensor value

leftServo

my-var

distance_eval2

2.Что произойдет, если создать директиву #define HIGH LOW?

3.Почему мы не сможем регулировать яркость светодиода, подключенного к порту 7?

4.Какое усреднённое напряжение мы получим на пине 6, если вызовем функцию analogWrite(6, 153)?

5.Какое значение параметра value нужно передать функции analogWrite, чтобы получить усреднённое напряжение 2 В?

Задания для самостоятельного решения

1.Отключите питание, отключите светодиод от 9-го порта и подключите к 11-му. Измените программу так, чтобы схема снова заработала

2.Измените код программы так, чтобы в течение секунды на светодиод последовательно подавалось усреднённое напряжение 0, 1, 2, 3, 4, 5 В

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

Эксперимент 3. Светильник с управляемой яркостью

Список деталей для эксперимента

1 плата Arduino Uno

1 беспаечная макетная плата

1 светодиод

1 резистор номиналом 220 Ом

6 проводов «папа-папа»

1 потенциометр Для дополнительного задания

еще 1 светодиод

еще 1 резистор номиналом 220 Ом

еще 2 провода

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

Эксперимент 1. Маячок [Амперка / Вики]

Видеоурок

Прочтите перед выполнением

Список деталей для эксперимента

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

Схема на макетке

Обратите внимание

  • Не забудьте, как соединены рельсы в беспаечной макетной плате. Если на вашей макетке красная и синяя линии вдоль длинных рельс прерываются в середине, значит проводник внутри макетки тоже прерывается!
  • Катод («минус») светодиода — короткая ножка, именно её нужно соединять с землёй (GND)

  • Не пренебрегайте резистором, иначе светодиод выйдет из строя

  • Выбрать резистор нужного номинала можно с помощью таблицы маркировки или с помощью мультиметра в режиме измерения сопротивления
  • Плата Arduino имеет три пина GND, используйте любой из них

Скетч

p010_blink.ino
void setup()
{
  // настраиваем пин №13 в режим выхода,
  // т.е. в режим источника напряжения
  pinMode(13, OUTPUT);
}
 
void loop()
{
  // подаём на пин 13 «высокий сигнал» (англ. «high»), т.е.
  // выдаём 5 вольт. Через светодиод побежит ток.
  // Это заставит его светиться
  digitalWrite(13, HIGH);
 
  // задерживаем (англ. «delay») микроконтроллер в этом
  // состоянии на 100 миллисекунд
  delay(100);
 
  // подаём на пин 13 «низкий сигнал» (англ. «low»), т.е.
  // выдаём 0 вольт или, точнее, приравниваем пин 13 к земле.
  // В результате светодиод погаснет
  digitalWrite(13, LOW);
 
  // замираем в этом состоянии на 900 миллисекунд
  delay(900);
 
  // после «размораживания» loop сразу же начнёт исполняться
  // вновь, и со стороны это будет выглядеть так, будто
  // светодиод мигает раз в 100 мс + 900 мс = 1000 мс = 1 сек
}

Пояснения к коду

  • Процедура setup выполняется один раз при запуске микроконтроллера. Обычно она используется для конфигурации портов микроконтроллера и других настроек

  • После выполнения setup запускается процедура loop, которая выполняется в бесконечном цикле. Именно этим мы пользуемся в данном примере, чтобы маячок мигал постоянно

  • Процедуры setup и loop должны присутствовать в любой программе (скетче), даже если вам не нужно ничего выполнять в них — пусть они будут пустые, просто не пишите ничего между фигурными скобками. Например:

void setup()
{
}
  • Запомните, что каждой открывающей фигурной скобке { всегда соответствует закрывающая }. Они обозначают границы некого логически завершенного фрагмента кода. Следите за вложенностью фигурных скобок. Для этого удобно после каждой открывающей скобки увеличивать отступ на каждой новой строке на один символ табуляции (клавиша Tab)

  • Обращайте внимание на ; в концах строк. Не стирайте их там, где они есть, и не добавляйте лишних. Вскоре вы будете понимать, где они нужны, а где нет.

  • Функция digitalWrite(pin, value) не возвращает никакого значения и принимает два параметра:

    1. pin — номер цифрового порта, на который мы отправляем сигнал

    2. value — значение, которое мы отправляем на порт. Для цифровых портов значением может быть HIGH (высокое, единица) или LOW (низкое, ноль)

  • Если в качестве второго параметра вы передадите функции digitalWrite значение, отличное от HIGH, LOW, 1 или 0, компилятор может не выдать ошибку, но считать, что передано HIGH. Будьте внимательны

  • Обратите внимание, что использованные нами константы: INPUT, OUTPUT, LOW, HIGH, пишутся заглавными буквами, иначе компилятор их не распознает и выдаст ошибку. Когда ключевое слово распознано, оно подсвечивается синим цветом в Arduino IDE

Вопросы для проверки себя

  1. Что будет, если подключить к земле анод светодиода вместо катода?

  2. Что будет, если подключить светодиод с резистором большого номинала (например, 10 кОм)?

  3. Что будет, если подключить светодиод без резистора?

  4. Зачем нужна встроенная функция pinMode? Какие параметры она принимает?

  5. Зачем нужна встроенная функция digitalWrite? Какие параметры она принимает?

  6. С помощью какой встроенной функции можно заставить микроконтроллер ничего не делать?

  7. В каких единицах задается длительность паузы для этой функции?

Задания для самостоятельного решения

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

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


Оглавление | Маячок с нарастающей яркостью →

Конспект хакера Эксперименты — Стр 7

// откройте окно Serial Monitor в среде Arduino, оставьте на

// сутки, скопируйте данные в Excel, чтобы построить графики

}

Пояснения к коду

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

В данном эксперименте мы знакомимся со стандартным объектом Serial, который предназначен для работы с последовательным портом (UART) Arduino, и его методами (функциями, созданными для работы с данным объектом) begin(), print() и println(),

которые вызываются после точки, идущей за именем объекта:

o

чтобы обмениваться данными, нужно начать соединение,

 

 

 

 

 

 

 

 

 

 

 

 

поэтому

Serial.begin(baudrate)

вызывается в

setup()

 

 

 

отправляет содержимое

 

. Если мы хотим отправить текст,

o

Serial.print(data)

data

 

 

 

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

«»

. Кириллица, скорее всего,

 

будет отображаться некорректно.

oSerial.println(data) делает то же самое, только добавляет в конце невидимый символ новой строки.

В print() и println() можно использовать второй необязательный параметр: выбор системы счисления, в которой выводить число (это может быть DEC, BIN, HEX, OCT для десятичной, двоичной, шестнадцатеричной и восьмеричной систем счисления соответственно) или количество знаков после запятой для дробных чисел.

Например,

Serial.println(18,BIN);

Serial.print(3.14159,3);

в мониторе порта даст результат

10010

3.142

Монитор порта, входящий в Arduino IDE, открывается через меню Сервис или сочетанием клавиш Ctrl+Shift+M. Следите за тем, чтобы в мониторе и в скетче была указана одинаковая скорость обмена данными, baudrate. Скорости 9600 бит в секунду обычно достаточно. Другие стандартные значения можете посмотреть в выпадающем меню справа внизу окна монитора порта.

Вам не удастся использовать цифровые порты 0 и 1 одновременно с передачей данных по последовательному порту, потому что по ним также идет передача данных, как и через USBпорт платы.

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

Если вы хотите читать какие-то данные в реальном времени, не забывайте

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

Последовательность \t выводится как символ табуляции (8 пробелов с выравниванием).

Также вы можете использовать, например, последовательность \n для перевода строки.

Если вы хотите использовать обратный слеш, его нужно экранировать вторым таким же: \\.

Вопросы для проверки себя

1.Какие действия нужно предпринять, чтобы читать на компьютере данные с Arduino?

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

3.Как избежать ошибки в передаче данных, содержащих обратный слэш (\)?

Задания для самостоятельного решения

1.Перед таблицей данных о температуре добавьте заголовок (например, «Meteostation»).

2.Добавьте столбец, содержащий количество секунд, прошедших с момента запуска микроконтроллера. Можно уменьшить интервал передачи данных.

Эксперимент 17. Пантограф

Список деталей для эксперимента

1 плата Arduino Uno

1 беспаечная макетная плата

1 сервопривод

1 конденсатор емкостью 220 мкФ

1 потенциометр

11 проводов «папа-папа»

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

Схема на макетке

Обратите внимание

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

Не забывайте про то, что нужно соблюдать полярность элетролитического конденсатора. Короткая ножка (со стороны белой полосы на корпусе) — «минус».

Вы можете соединить провод сервопривода с макетной платой проводами «папа-папа»: коричневый это земля, красный — питание, оранжевый — сигнал.

В данном эксперименте мы подключаем питние сервопривода к 5V-выходу Arduino. С одним сервоприводом плата справится, но если в каком-либо проекте вам нужно больше серв, используйте специальные платы-драйвера с отдельным источником питания для серв.

Скетч

// управлять сервоприводами (англ. servo motor) самостоятельно

// не так то просто, но в стандартной библиотеке уже всё

// заготовлено, что делает задачу тривиальной

#include <Servo.h>

#define POT_MAX_ANGLE 270.0 // макс. угол поворота потенциометра

// объявляем объект типа Servo с именем myServo. Ранее мы

// использовали int, boolean, float, а теперь точно также

// используем тип Servo, предоставляемый библиотекой. В случае

// Serial мы использовали объект сразу же: он уже был создан

// для нас, но в случае с Servo, мы должны сделать это явно.

// Ведь в нашем проекте могут быть одновременно несколько

// приводов, и нам понадобится различать их по именам

Servo myServo;

void setup()

{

// прикрепляем (англ. attach) нашу серву к 9-му пину. Явный

// вызов pinMode не нужен: функция attach сделает всё за нас myServo.attach(9);

}

void loop()

{

int val = analogRead(A0);

// на основе сигнала понимаем реальный угол поворота движка.

// Используем вещественные числа в расчётах, но полученный

// результат округляем обратно до целого числа int angle = int(val / 1024.0 * POT_MAX_ANGLE);

// обычная серва не сможет повторить угол потенциометра на

// всём диапазоне углов. Она умеет вставать в углы от 0° до

// 180°. Ограничиваем угол соответствующе

angle = constrain(angle, 0, 180);

// и, наконец, подаём серве команду встать в указанный угол

myServo.write(angle);

}

Пояснения к коду

В данном эксперименте мы также имеем дело с объектом, на этот раз он нужен для простого управления сервоприводом. Как отмечено в комментариях, в отличие от объекта Serial,

объекты типа Servo нам нужно явно создать: Servo myServo, предварительно подключив библиотеку <Servo.h>.

Далее мы используем два метода для работы с ним:

omyServo.attach(pin) — сначала «подключаем» серву к порту, с которым физически соединен его сигнальный провод. pinMode() не нужна, метод attach() займется

этим.

omyServo.write(angle) — задаем угол, т.е. позицию, которую должен принять вал сервопривода. Обычно это 0—180°.

myServo здесь это имя объекта, идентификатор, который мы придумываем так же, как названия переменных. Например, если вы хотите управлять двумя захватами, у вас могут быть объекты leftGripи rightGrip.

Мы использовали функцию int() для явного преобразования числа с плавающей точкой в целочисленное значение. Она принимает в качестве параметра значение любого типа, а возвращает целое число. Когда в одном выражении мы имеем дело с различными типами данных, нужно позаботиться о том, чтобы не получить непредсказуемый ошибочный результат.

Вопросы для проверки себя

1.Зачем нужен конденсатор при включении в схему сервопривода?

2.Каким образом библиотека <Servo.h> позволяет нам работать с сервоприводом?

3.Зачем мы ограничиваем область допустимых значений для angle?

4.Как быть уверенным в том, что в переменную типа int после вычислений попадет корректное значение?

Задания для самостоятельного решения

1.Измените программу так, чтобы по мере поворота ручки потенциометра, сервопривод последовательно занимал 8 положений: 45, 135, 87, 0, 65, 90, 180, 150°.

2.Предположим, что сервопривод управляет шторкой, и нам нужно поддерживать постоянное количество света в помещении. Создайте такой механизм.

Эксперимент 18. Тестер батареек

Список деталей для эксперимента

1 плата Arduino Uno

1 беспаечная макетная плата

2 резистора номиналом 10 кОм

1 выпрямительный диод

1 текстовый экран

16 проводов «папа-папа»

1 клеммник

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

Схема на макетке

Обратите внимание

Мы подключаем «плюс» батарейки через делитель напряжения с равными плечами (R1 = R2 = 10 кОм), таким образом деля подаваемое напряжение пополам. Поскольку в аналоговый вход Arduino мы можем подавать до 5В, мы можем измерять напряжение до 10В. Не пробуйте измерять большее напряжение, вы можете повредить плату!

На принципиальной схеме внутри изображения дисплея подписаны названия его выводов согласно datasheet, а снаружи — номера его ножек.

Ножки нашего ЖК-дисплея нумеруются не подряд: 15 и 16 ножки находятся перед 1.

Диод пригодится, если пользователь тестера перепутает «+» и «-» батарейки, главное нам самим не забыть про направление, в котором через диод может течь ток, и установить его верно!

Скетч

// Подключаем библиотеку для работы с жидкокристаллическим

// экраном (англ. Liquid Crystal Display или просто LCD) #include <LiquidCrystal.h>

// на диоде, защищающем от неверной полярности, падает доля

// напряжения (англ. voltage drop). Необходимо это учитывать

#define DIODE_DROP 0.7

// Объявляем объект, для управления дисплеем. Для его создания

// необходимо указать номера пинов, к которым он подключен в

// порядке:

RS E DB5 DB6 DB7 DB8

LiquidCrystal lcd(13, 12, 11, 10, 9, 8);

void

setup()

 

{

 

 

//

начинаем работу с экраном. Сообщаем объекту количество

//

строк и столбцов. Опять же, вызывать pinMode не требуется:

//

функция begin сделает всё за нас

lcd.begin(16, 2);

//

печатаем сообщение на первой строке

lcd.print(«Battery voltage:»);

}

 

 

void

loop()

 

{

 

 

 

 

//

высчитываем напряжение подключенной батарейки

float voltage = analogRead(A0) / 1024.0 * 10.0;

//

если напряжение на делителе напряжения было зафиксировано,

//

нужно прибавить напряжение на диоде, т.к. оно было съедено

if

(voltage > 0.1)

 

voltage += DIODE_DROP;

//

устанавливаем курсор, колонку 0, строку 1. На деле — это

//

левый квадрат 2-й строки, т.к. нумерация начинается с нуля

 

 

 

lcd.setCursor(0, 1);

// печатаем напряжение в батарейке с точностью до сотых долей lcd.print(voltage, 2);

// следом печатаем единицы измерения lcd.print(» Volts»);

}

Пояснения к коду

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

В этом эксперименте мы снова пользуемся готовой библиотекой <LiquidCrystal.h> для создания объекта lcd и использования его методов

o lcd.begin(cols,rows) с помощью которого мы задаем количество колонок и строк нашего дисплея

o lcd.print(data) для вывода данных. У него есть второй необязательный

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

примере с Serial.print().

olcd.setCursor(col,row) устанавливает курсор в переданную колонку и строку. Последующий вывод будет осуществляться с этого места.

При создании lcd мы передали параметрами пины, к которым подключены выводы дисплея, через которые мы будем им управлять и передавать данные.

О том, как выводить текст кириллицей, и о других подробностях работы с дисплеем в нашей вики есть отдельная статья.

Вопросы для проверки себя

1.Из-за чего измерения напряжения в этом эксперименте могут быть неточными (на что мы можем повлиять)?

2.Какая библиотека облегчает работу с нашим текстовым экраном? Какие шаги нужно предпринять до начала вывода текста на него?

3.Каким образом мы задаем позицию, с которой на экран выводится текст?

4.Можем ли мы писать на экране кириллицей? Как?

Задания для самостоятельного решения

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

1.Создайте секундомер, который будет отсчитывать время, прошедшее с начала работы Arduino и выводить секунды и сотые секунд на экран.

2.Совместите отсчет времени и измерение напряжения. Отобразите все данные на дисплее. Отправляйте их раз в 10 секунд на компьютер.

Теперь вы можете выводить без компьютера и проводов любые данные, с которыми работаете, и использовать это как в режиме эксплуатации вашего устройства, так и во время отладки!

Эксперимент 19. Светильник, управляемый по USB

Список деталей для эксперимента

1 плата Arduino Uno

1 беспаечная макетная плата

1 светодиод

1 резистор номиналом 220 Ом

2 провода «папа-папа»

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

Схема на макетке

Скетч

#define LED_PIN 9

// для работы с текстом существуют объекты-строки (англ. string)

String message;

void setup()

{

РОБОТОТЕХНИЧЕСКИЙ НАБОР

Робототехнический набор Матрешка Z выпускается отечественной фирмой «Амперка». Этот производитель предлагает достаточно широкий ассортимент Arduino – совместимых устройств, узлов и датчиков. При этом осуществляется не только перепродажа импортных комплектующих, но имеются и собственные разработки (по крайней мере, в теории, где расположена производственная база фирмы я не знаю). Далее будет много ссылок на эту фирму, которые просьба не расценивать как рекламу — просто так удобнее проводить обзор. Итак, робототехнический набор Матрешка Z предназначен для первоначального знакомства с Arduino. Набор поставляется в красивой подарочной коробке. 

 

В эту коробку вложено несколько декоративных наклеек.

 

Брошюра «Конспект хакера».

 

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

 

Разобравшись со вспомогательным материалом можно посмотреть, что же составляет суть набора. 

В комплект входит набор разноцветных соединительных проводов с наконечниками для удобного подключения проводов к макетной плате или разъемам портов на плате Arduino. В него входят 45 проводов длинной 8 см, 10 проводников длинной 13 см, 5 длинной 18 см и 5 длинной 23,5 см.

 

LCD дисплей для вывода текстовой информации такой. 

 

Соединительный кабель для подключения Arduino к комппьютеру:

 

В одной из внутренних коробок мы находим главную часть набора – плату Arduino UNO, вместе с макетной платой Breadboard Half.

 

Для сравнения фирменная плата Arduino UNO и ее копия от стороннего производителя.

 

В остальном эта коробка заполнена полиэтиленовыми пакетами с радиодеталями и мелкими комплектующими. А именно: 4 нейлоновых винта М3х8, 8 нейлоновых стоек с резьбой М3 в двух пакетах по 4 штуки, переменный (судя по виду скорее подстроечный) резистор 10 кОм, в комплекте с ним идет съемная ручка.  

 

 

Пять тактовых кнопок, каждая в отдельном пакете.

 

Набор постоянных резисторов 220 Ом (30 шт. в трех пакетах), 1 кОм (10 шт.), 10 кОм (10 шт.), заявленная мощность 0,5 Вт.

 

Светодиоды: красные (12 шт. в трех пакетах), 4 зеленых, 4 желтых. Также в наборе имеется один трехцветный светодиод.

 

Гребенка на 40 штырьковых контактов.

 

На этом содержимое первой внутренний коробки исчерпано, переходим ко второй.

Второй комплект

 

Во второй коробке находится микросервопривод.

 

Электромотор FA-130

 

Светодиодная шкала

 

Конденсаторы: керамические 100 нФ (10 шт.), электролитические конденсаторы 10 мкФ х 50 В (10 шт.), 220 мкФ х 16 В (10 шт.). Фоторезистор с темновым сопротивлением 500 кОм (как заявлено производителем, но скорее около 1 МОм). Терморезистор, при комнатной температуре 24°С его сопротивление около 9 кОм. Пять выпрямительных диодов с обратным сопротивлением 1000 В и прямым током 1 А. 

 

Пять биполярных транзисторов BC337-16. Полевой транзистор IRF530. Пьезоизлучатель. Выходной сдвиговый регистр 74HC595. Триггер Шмитта. Нажимной клеммник.

 

Семисегментный индикатор.

 

Колодка для автономного питания Arduino от батареи типа «Крона» 

 

В целом, составители набора явно не стали экономить на упаковочных полиэтиленовых пакетиках, детали тщательно рассортированы, каждый пакетиков подписан, что несомненно методически оправдано. Однако значительную часть стоимости набора составляют широко распространенные радиодетали, которые, несомненно, имеются у любого более или менее опытного радиолюбителя. Причем заявленная стоимость этих радиодеталей весьма высока, не только по сравнению с другими Интернет-магазинами, но и по сравнению с обычными магазинами радиодеталей. Как итог набор хорошо подходит для первоначального знакомства с электроникой вообще и микроконтроллерами в частности, но приобретение его опытным радиолюбителем не оправдано. Автор обзора: Denev.

   Форум по Ардуино

   Обсудить статью РОБОТОТЕХНИЧЕСКИЙ НАБОР


Книга КОНСПЕКТ ХАКЕРА (Краткое пособие по быстрому старту с Arduino)

Хотите попробовать Arduino, но нет времени на чтение книжек? С этим руководством вы сможете в кратчайшие сроки опробовать в действии бо́льшую часть функций Arduino.

В брошюре кратко, но в то же время доступно описываются все основные понятия, необходимые для реализации собственных электронных идей. Брошюра идеально подходит в качестве руководства по использованию наборов «Матрёшка». На самом деле конспект создан специально для них и уже включён в комплект «Матрёшек». Однако, если у вас уже есть Arduino и радиодетали, можете приобрести конспект отдельно.

Первая часть брошюры представляет собой вводную в электричество. В ней объясняются такие простые понятия, как резистор, электрическая схема, закон Ома и т.д. Чтобы теория не забылась, а прочно укоренилась в уме начинающего, во второй части брошюры приведены 20 простых заданий.

При написании брошюры приоритетными задачами были краткость и доступность, а не точность и общность. На 84-х страницах описаны, конечно, далеко не все аспекты схемотехники и функции Arduino. Брошюра призвана заинтересовать начинающего, избавить от рутины и в максимально сжатые сроки помочь определиться: нужно ему это или нет.

Данные

Формат: 110×150 мм

84 страницы

Мягкая обложка, цветная печать

Издатель: Амперка

Оглавление

Электричество

Схемы

Основные законы электричества

Управление электричеством

Сборка схем

Резистор

Делитель напряжения

Диод

Светодиод

Светодиодные сборки

Кнопка

Биполярный транзистор

Полевой транзистор

Широтно-импульсная модуляция

Конденсатор

Пьезодинамик

Мотор

Сервопривод

Микросхема

Сдвиговый регистр

Триггер Шмитта

Начало работы с Arduino

Пример №1. Маячок

Пример №2. Маячок с нарастающей яркостью

Пример №3. Светильник с управляемой яркостью

Пример №4. Терменвокс

Пример №5. Ночной светильник

Пример №6. Пульсар

Пример №7. Бегущий огонёк

Пример №8. Мерзкое пианино

Пример №9. Миксер

Пример №10. Кнопочный переключатель

Пример №11. Светильник с кнопочным управлением

Пример №12. Кнопочные ковбои

Пример №13. Секундомер

Пример №14. Счётчик нажатий

Пример №15. Комнатный термометр

Пример №16. Метеостанция

Пример №17. Пантограф

Пример №18. Тестер батареек

Пример №19. Светильник, управляемый по USB

Пример №20. Перетягивание каната

Электронная версия

Теория

Практика

Конспект хакера Эксперименты — Стр 5

Эксперимент 11. Светильник с кнопочным управлением

Список деталей для эксперимента

1 плата Arduino Uno

1 беспаечная макетная плата

2 тактовых кнопки

1 резистор номиналом 220 Ом

1 светодиод

7 проводов «папа-папа»

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

Схема на макетке

Обратите внимание

Если вы переделываете схему из схемы предыдущего эксперимента, обратите внимание, что на этот раз нам нужно подключить светодиод к порту, поддерживающему ШИМ.

Скетч

#define PLUS_BUTTON_PIN

2

 

 

 

#define

MINUS_BUTTON_PIN

3

#define

LED_PIN

9

 

 

 

int brightness = 100; boolean plusUp = true; boolean minusUp = true;

void setup()

{

pinMode(LED_PIN, OUTPUT); pinMode(PLUS_BUTTON_PIN, INPUT_PULLUP); pinMode(MINUS_BUTTON_PIN, INPUT_PULLUP);

}

void loop()

{

analogWrite(LED_PIN, brightness);

// реагируем на нажатия с помощью функции, написанной нами plusUp = handleClick(PLUS_BUTTON_PIN, plusUp, +35); minusUp = handleClick(MINUS_BUTTON_PIN, minusUp, -35);

}

// Собственная функция с 3 параметрами: номером пина с кнопкой

// (buttonPin), состоянием до проверки (wasUp) и градацией

// яркости при клике на кнопку (delta). Функция возвращает

// (англ. return) обратно новое, текущее состояние кнопки boolean handleClick(int buttonPin, boolean wasUp, int delta)

{

boolean isUp = digitalRead(buttonPin); if (wasUp && !isUp) {

delay(10);

isUp = digitalRead(buttonPin);

// если был клик, меняем яркость в пределах от 0 до 255 if (!isUp)

brightness = constrain(brightness + delta, 0, 255);

}

return isUp; // возвращаем значение обратно, в вызывающий код

}

Пояснения к коду

Мы можем пользоваться не только встроенными функциями, но и создавать собственные. Это обоснованно, когда нам нужно повторять одни и те же действия в разных местах кода или, например, нужно выполнять одни и те же действия над разными данными, как в данном случае: обработать сигнал с цифровых портов 2 и 3.

Определять собственные функции можно в любом месте кода вне кода других функций. В нашем примере, мы определили функцию после loop.

Чтобы определить собственную функцию, нам нужно:

oОбъявить, какой тип данных она будет возвращать. В нашем случае это boolean. Если функция только выполняет какие-то действия и не возвращает никакого значения, используйте ключевое слово void

oНазначить функции имя — идентификатор. Здесь действуют те же правила, что при именовании переменных и констант. Называть функции принято в том же стиле какПеременные.

oВ круглых скобках перечислить передаваемые в функцию параметры, указав тип каждого. Это является объявлением переменных, видимых внутри вновь создаваемой функции, и только внутри нее. Например, если в данном эксперименте мы попробуем обратиться к wasUp или isUp изloop() получим от компилятора сообщение об ошибке.

Точно так же, переменные, объявленные вloop, другим функциям не видны, но их

значения можно передать в качестве параметров.

o Между парой фигурных скобой написать код, выполняемый функцией

oЕсли функция должна вернуть какое-то значение, с помощью ключевого

слова return указать, какое значение возвращать. Это значение должно быть того типа, который мы объявили

Так называемые глобальные переменные, т.е. переменные, к которым можно обратиться из любой функции, обычно объявляются в начале программы. В нашем случае —

это brightness.

Внутри созданной нами функции handleClick происходит всё то же самое, что в эксперименте«Кнопочный переключатель».

Поскольку при шаге прироста яркости 35 не более чем через восемь нажатий подряд на одну из кнопок значение выражения brightness + delta выйдет за пределы интервала [0, 255].

Спомощью функцииconstrain мы ограничиваем допустимые значения для

переменной brightness указанными границами интервала.

 В выражении plusUp = handleClick(PLUS_BUTTON_PIN, plusUp, +35) мы обращаемся к переменнойplusUp дважды. Поскольку = помещает значение правого операнда в левый,

сначала вычисляется, что вернет handleClick. Поэтому когда мы передаем ей plusUp в качестве параметра, она имеет еще старое значение, вычисленное при прошлом

вызове handleClick.

Внутри handleClick мы вычисляем новое значение яркости светодиода и записываем его в глобальную переменную brightness, которая на каждой итерации loop просто передается в analogWrite.

Вопросы для проверки себя

1.Что необходимо для определения собственной функции?

2.Что означает ключевое слово void?

3.Как ведет себя программа при упоминании одной переменной с разных сторон от оператора присваивания =?

Задания для самостоятельного решения

1.Доработайте код таким образом, чтобы шаг изменения яркости настраивался в одном месте.

2.Создайте еще одну функцию и переделайте код так, чтобы одна функция отвечала за отслеживание нажатий, а другая — за вычисление яркости светодиода и возвращала его в analogWrite.

Эксперимент 12. Кнопочные ковбои

Список деталей для эксперимента

1 плата Arduino Uno

1 беспаечная макетная плата

2 тактовых кнопки

2 резистора номиналом 220 Ом

2 светодиода

1 пьезопищалка

10 проводов «папа-папа»

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

Схема на макетке

Скетч

#define

BUZZER_PIN

12 //

пин с пищалкой

 

 

 

 

 

#define

PLAYER_COUNT

2

//

количество игроков-ковбоев

//

вместо перечисления

всех

пинов

по-одному, мы объявляем пару

//

списков: один с номерами

пинов

с кнопками, другой — со

 

 

 

 

 

 

 

// светодиодами. Списки также называют массивами (англ. array) int buttonPins[PLAYER_COUNT] = {3, 13};

int ledPins[PLAYER_COUNT] = {9, 11};

void setup()

{

pinMode(BUZZER_PIN, OUTPUT);

for (int player = 0; player < PLAYER_COUNT; ++player) {

// при помощи квадратных скобок получают значение в массиве

// под указанным в них номером. Нумерация начинается с нуля pinMode(ledPins[player], OUTPUT); pinMode(buttonPins[player], INPUT_PULLUP);

}

}

void loop()

{

// даём сигнал «пли!», выждав случайное время от 2 до 7 сек delay(random(2000, 7000));

tone(BUZZER_PIN, 3000, 250); // 3 килогерца, 250 миллисекунд

for (int player = 0; ; player = (player+1) % PLAYER_COUNT) {

// если игрок номер «player» нажал кнопку…

if (!digitalRead(buttonPins[player])) {

// …включаем его светодиод и сигнал победы на 1 сек digitalWrite(ledPins[player], HIGH); tone(BUZZER_PIN, 4000, 1000);

delay(1000); digitalWrite(ledPins[player], LOW);

break; // Есть победитель! Выходим (англ. break) из цикла

}

}

}

Пояснения к коду

Массив состоит из элементов одного типа, в нашем случае int.

Объявить массив можно следующими способами:

int firstArray[6]; // 6 целых чисел с неопределёнными начальными значениями

int pwmPins[] = {3, 5, 6, 9, 10, 11}; // 6 целых чисел, длина вычисляется автоматом

boolean buttonState[3] = {false, true, false}; // можно использовать элементы любого

типа

Когда мы объявляем массив с указанием количества его элементов n, это число всегда на 1 больше, чем номер последнего элемента (n-1), т.к. индекс первого элемента — 0.

Считать или записать значение элемента массива можно, обратившись к нему по индексу,

напримерfirstArray[2] или buttonState[counter], где counter — переменная, такая как счетчик цикла

В переменных типа long можно хранить значения до 2 147 483 647. unsigned int в этом случае нам будет недостаточно, потому что 65 535 миллисекунд пройдут чуть больше чем за минуту!

Функция random(min, max) возвращает целое псевдослучайное число в интервале [min, max]. Для драматичности каждая игра начинается с паузы случайной длины.

Благодаря массивам в этом эксперименте мы настраиваем порты, считываем кнопки и включаем светодиоды в циклах со счетчиком, который используется как индекс элемента.

Мы используем цикл for без условия его завершения, поэтому пока мы явно того не потребуем, цикл будет крутиться до бесконечности.

Мы использовали выражение player = (player+1) % PLAYER_COUNT для счётчика цикла, чтобы не только увеличивать его на единицу каждый раз, но и обнулять при достижении последнего игрока.

Инструкция break прекращает работу цикла и выполнение программы продолжается с инструкции после его конца.

Вопросы для проверки себя

1.Можно ли поместить в один массив элементы типа boolean и int?

2.Обязательно ли при объявлении массива заполнять его значениями?

3.Чем удобно использование массива?

4.Как обратиться к элементу массива, чтобы прочитать его значение?

5.Почему для хранения времени прошлого сигнала мы используем переменную типа long?

6.Чем отличаются инструкции continue и break?

Задания для самостоятельного решения

1.Сделайте напряженный вариант игры: пусть интервал между сигналами будет в диапазоне от 10 до 15 секунд.

2.В игре есть лазейка: кнопку можно зажать до сигнала «пли!» и таким образом сразу же выиграть. Дополните программу так, чтобы так выиграть было нельзя.

3.Добавьте в игру еще двух ковбоев!

Эксперимент 13. Секундомер

Список деталей для эксперимента

1 плата Arduino Uno

1 беспаечная макетная плата

1 семисегментный индикатор

7 резисторов номиналом 220 Ом

9 проводов «папа-папа»

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

Схема на макетке

Обратите внимание

Выводы 3 и 8 семисегментного индикатора оба являются катодами, к земле можете подключать любой из них.

Внимательно рассмотрите схему, сопоставьте сегменты индикатора с номерами его ножек, а те, в свою очередь, с пинами Arduino, к которым мы их подключаем.

Вывод 5 индикатора — это точка. Мы не используем её в этом эксперименте

Сегменты индикатора — просто светодиоды, поэтому мы используем резистор с каждым из них.

Скетч

#define

FIRST_SEGMENT_PIN

2

 

 

 

#define

SEGMENT_COUNT

7

 

 

 

 

 

 

// префикс «0b» означает, что целое число за ним записано в

// в двоичном коде. Единицами мы обозначим номера сегментов

// индикатора, которые должны быть включены для отображения

// арабской цифры. Всего цифр 10, поэтому в массиве 10 чисел.

// Нам достаточно всего байта (англ. byte, 8 бит) для хранения

// комбинации сегментов для каждой из цифр. byte numberSegments[10] = {

0b00111111, 0b00001010, 0b01011101, 0b01011110, 0b01101010, 0b01110110, 0b01110111, 0b00011010, 0b01111111, 0b01111110,

};

void setup()

{

for (int i = 0; i < SEGMENT_COUNT; ++i) pinMode(i + FIRST_SEGMENT_PIN, OUTPUT);

}

void loop()

{

// определяем число, которое собираемся отображать. Пусть им

// будет номер текущей секунды, зацикленный на десятке int number = (millis() / 1000) % 10;

// получаем код, в котором зашифрована арабская цифра int mask = numberSegments[number];

// для каждого из 7 сегментов индикатора…

for (int i = 0; i < SEGMENT_COUNT; ++i) {

// …определяем: должен ли он быть включён. Для этого

// считываем бит (англ. read bit), соответствующий текущему

// сегменту «i». Истина — он установлен (1), ложь — нет (0) boolean enableSegment = bitRead(mask, i);

// включаем/выключаем сегмент на основе полученного значения digitalWrite(i + FIRST_SEGMENT_PIN, enableSegment);

}

}

Пояснения к коду

Мы создали массив типа byte: каждый его элемент это 1 байт, 8 бит, может принимать значения от 0 до 255.

Символы арабских цифр закодированы состоянием пинов, которые соединены с выводами соответствующих сегментов: 0, если сегмент должен быть выключен, и 1, если включен.

В переменную mask мы помещаем тот элемент массива numberSegments, который соответствует текущей секунде, вычисленной в предыдущей инструкции.

В цикле for мы пробегаем по всем сегментам, извлекая с помощью встроенной функции bitReadнужное состояние для текущего пина, в которое его и приводим с помощью digitalWrite и переменнойenableSegment

bitRead(x, n) возвращает boolean значение: n-ный бит справа в байте x

Вопросы для проверки себя

1.К которой ножке нашего семисегментного индикатора нужно подключать землю?

2.Как мы храним закодированные символы цифр?

3.Каким образом мы выводим символ на индикатор?

Задания для самостоятельного решения

1.Измените код, чтобы индикатор отсчитывал десятые секунды.

2.Поменяйте программу так, чтобы вместо символа «0» отображался символ «А».

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

Конспект хакера Эксперименты — Стр 8

pinMode(LED_PIN, OUTPUT); Serial.begin(9600);

}

void loop()

{

// передаваемые с компьютера данные поставляются байт за

// байтом, в виде отдельных символов (англ. character). Нам

// нужно последовательно их обрабатывать пока (англ. while) // в порту доступны (англ. available) новые данные

while (Serial.available()) {

// считываем (англ. read) пришедший символ в переменную char incomingChar = Serial.read();

// не стоит путать целые числа и символы. Они соотносятся

// друг с другом по таблице, называемой кодировкой. Например

// ‘0’ — это 48, ‘9’ — 57, ‘A’ — 65, ‘B’ — 66 и т.п. Символы

// в программе записываются в одинарных кавычках if (incomingChar >= ‘0’ && incomingChar <= ‘9’) {

// если пришёл символ-цифра, добавляем его к сообщению message += incomingChar;

} else if (incomingChar == ‘\n’) {

// если пришёл символ новой строки, т.е. enter, переводим

// накопленное сообщение в целое число (англ. to integer). // Так последовательность символов ‘1’, ‘2’, ‘3’ станет

// числом 123. Результат выводим на светодиод analogWrite(LED_PIN, message.toInt());

// обнуляем накопленное сообщение, чтобы начать всё заново message = «»;

}

}

// посылайте сообщения-числа с компьютера через Serial Monitor

}

Пояснения к коду

В этой программе мы создаем объект класса String. Это встроенный класс, предназначенный для работы со строками, т.е. с текстом.

Не путайте его с типом данных string, который является просто массивом

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

Мы знакомимся с новым видом циклов: цикл с условием while. В отличие от цикла со счетчиком for, цикл while(expression) выполняется до тех пор, пока логическое выражение expression истинно.

Метод available() объекта Serial возвращает количество байт, полученных через последовательный порт.

В данном эксперименте цикл while работает до тех пор, пока available() возвращает ненулевое значение, любое из которых приводится к true.

Переменные типа char могут хранить один символ.

В этом примере символ мы получаем методом Serial.read(), который возвращает первый байт, пришедший на последовательный порт, или -1, если ничего не пришло.

Обратите внимание, что в if мы сравниваем не пришедший символ с 0 и 9, но их коды. Если пришел какой-то символ, который не является цифрой, мы не будем его добавлять к нашей строке message.

Объекты типа String позволяют производить конкатенацию, т.е. объединение строк. Это

можно сделать так: message = message + incomingChar, но можно записать в

сокращенной форме: message += incomingChar.

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

Напомним, что последовательностью \n кодируется символ переноса строки. Если он был передан устройству, мы передаем полученные ранее символы как параметр

для analogWrite(), которая включает светодиод.

Мы используем один из методов String, toInt(), который заставляет считать строку не набором цифр, но числом. Он возвращает значение типа long, при этом, если строка начинается с символа, не являющегося цифрой, будет возвращен 0. Если после цифр, идущих в начале строки, будут символы не-цифры, на них конверсия остновится.

Обратите внимание на выпадающее меню внизу монитора порта: чтобы наше устройство получало символ перевода строки, там должно быть выбрано «Новая строка (NL)»

Пустая строка обозначается так: «». Опустошив ее, мы готовы собирать новую последовательность символов.

Вопросы для проверки себя

1.Какие объекты позволяют легко манипулировать текстовыми данными?

2.Что возвращают методы Serial.available() и Serial.read()?

3.Чем отличаются конструкции for и while?

4.Каким образом можно организовать более сложное ветвление, чем if … else?

5.Как можно объединить текстовые строки?

6.Как можно привести текстовую строку, содержащую цифры, к числовому типу?

Задания для самостоятельного решения

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

2.Переделайте программу так, чтобы устройство распознавало текстовые команды, например, «on» и «off», и соответственно включало и выключало светодиод.

Вам может пригодиться один из

методов String: toLowerCase(yourString) илиtoUpperCase(yourString), которые возвращают переданную строку yourString, приведенную к нижнему или верхнему регистру соответственно.

Эксперимент 20. Перетягивание каната

Список деталей для эксперимента

1 плата Arduino Uno

1 беспаечная макетная плата

1 светодиодная шкала

10 резисторов номиналом 220 Ом

4 резисторов номиналом 100 кОм

2 тактовых кнопки

2 керамических конденсатора номиналом 100 нФ

1 пьезопищалка

1 инвертирующий триггер Шмитта

24 провода «папа-папа» Для дополнительного задания

1 сервопривод

1 конденсатор 220 мкФ

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

Схема на макетке

Обратите внимание

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

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

Скетч

#define BUZZER_PIN

0

 

 

#define FIRST_BAR_PIN

4

#define

BAR_COUNT

10

#define

MAX_SCORE

20

 

 

 

// глобальные переменные, используемые в прерываниях (см. далее)

// должны быть отмечены как нестабильные (англ. volatile) volatile int score = 0;

void setup()

{

for (int i = 0; i < BAR_COUNT; ++i) pinMode(i + FIRST_BAR_PIN, OUTPUT);

pinMode(BUZZER_PIN, OUTPUT);

// Прерывание (англ. interrupt) приостанавливает основную

// программу, выполняет заданную функцию, а затем возобновляет

// основную программу. Нам нужно прерывание на нажатие кнопки,

// т.е. при смене сигнала с высокого на низкий, т.е. на

// нисходящем (англ. falling)

фронте

 

 

attachInterrupt(INT1, pushP1,

FALLING); // INT1 — это 3-й пин

attachInterrupt(INT0, pushP2,

FALLING); // INT0 — это 2-й пин

 

 

}

void pushP1() { ++score; } // функция-прерывание 1-го игрока void pushP2() { —score; } // функция-прерывание 2-го игрока void loop()

{

tone(BUZZER_PIN, 2000, 1000); // даём

сигнал к старту.

// пока никто из игроков не выиграл, обновляем «канат»

while

(abs(score) < MAX_SCORE) {

 

int

bound = map(score, -MAX_SCORE, MAX_SCORE, 0, BAR_COUNT);

 

 

 

int

left = min(bound, BAR_COUNT / 2

— 1);

int

right = max(bound, BAR_COUNT / 2);

for (int i = 0; i < BAR_COUNT; ++i)

 

digitalWrite(i + FIRST_BAR_PIN, i

>= left && i <= right);

}

 

 

 

 

 

tone(BUZZER_PIN, 4000, 1000); // даём сигнал победы while (true) {} // «подвешиваем» плату до перезагрузки

}

Пояснения к коду

Код нашей обычной программы исполняется инструкция за инструкцией и если мы, например, проверяем состояние датчика, мы к нему обратимся только в те моменты, когда очередь дойдет до соответствующей инструкции. Однако мы можем использовать прерывания:

o по наступлении определенного события

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

была приостановлена.

Arduino Uno позволяет делать прерывания на портах 2 и 3.

В setup() прописывается инструкция attachInterrupt(interrupt, action, event),

где

o interrupt может принимать значения INT0 или INT1 для портов 2 и 3 соответственно

o action — имя функции, которая будет вызываться при наступлении события

oevent — событие, которое мы отслеживаем. Может принимать

значение RISING (изменение от низкого уровня сигнала к высокому, от 0 к

1), FALLING (от высокого уровня к низкому, от 1 к 0),CHANGE (от 0 к 1 или от 1 к

0), LOW (при низком уровне сигнала).

Глобальные переменные, к которым мы обращаемся из функции, обрабатывающей прерывания, должны объявляться с использованием ключевого слова volatile, как в

данном эксперименте volatile int score = 0.

Внутри функции, вызываемой по прерыванию, нельзя использовать delay().

Функция abs(value) возвращает абсолютное значение value (значение по модулю). Обратите внимание, что функция может сработать некорректно, если передавать ей выражение, которое еще не вычислено, например abs(++a), лучше передавать ей просто переменную.

Функция min(val1, val2) вернет меньшее из val1 и val2.

Функция max(val1, val2) вернет большее из val1 и val2.

В данном эксперименте мы вычисляем значение, которое записывается на светодиоды, прямо вdigitalWrite()

Мы уже знакомы с логическим «и» (&&). Нередко нужен оператор «логическое «или»: ||. Он

возвращает «истину», если хотя бы один из операндов имеет значение «истина». false ||

falseвернет false, а true || true, true || false и false || true вернут true.

Мы использовали while(true){} для того, чтобы loop() остановился после того, как кто-

то выиграл: уwhile всегда истинное условие и он бесконечно ничего не выполняет!

Вопросы для проверки себя

1.Каким образом мы подавляем дребезг аппаратно?

2.Для чего используются прерывания?

3.Каким образом можно включить обработку внешних прерываний?

4.О каких нюансах работы с уже известными нам вещами следует помнить при работе с прерываниями?

5.Как выбрать максимальное из двух значений? Минимальное?

6.Как получить абсолютное значение переменной? Чего следует избегать при использовании этой функции?

7.Когда оператор логическое «или» возвращает «ложь»?

Задания для самостоятельного решения

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

alexxlab

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *