Занятие № 2. Аналоговые сигналы. Фоторезистор. Пьезодинамик. Потенциометр. Сервомотор.

По окончании занятия учащиеся смогут…

Задание № 1. Измерение освещённости. Фоторезистор

Соберите схему с фоторезистором для измерения уровня освещённости. Полученные значения выводите на экран.

Схема для сборки

и резистор на 10 кОм образуют делитель напряжения. Напряжение считывается из точки между двумя сопротивлениями и подаётся на аналоговый пин A0. Аналогово-цифровой преобразователь поможет привести показания с датчика к целым значениям в диапазоне от 0 до 1023.

Выходное напряжение можно измерить по следующей формуле:

\[ U_{out}= U_{in}\cdot \frac{R_2}{R_1 + R_2} \]

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

Значение измеренного напряжения - величина непрерывная. Микроконтроллер может обрабатывать лишь дискретные значения. Для преобразования аналогового сигнала в цифровой используется аналогово-цифровой преобразователь (АЦП).

Опорное напряжение \(U_{ref}\) влияет на максимально возможное напряжение на входе АЦП, которое будет корректно преобразовано в цифровое значение.

Цифровое значение на выходе АЦП определяется по следующей формуле: \[ A=\frac{U_{in}}{U_{ref}}\cdot (2^n-1) \]

Программа

Переменная val хранит сырые показания датчика, полученные напрямую с пина A0. В переменной normalVal сохраним значение с датчика приведённое к диапазону 0..100.

// Чтение аналоговых датчиков

// информационный пин фоторезистора назовём LDR_PIN
// и будем ссылаться на аналоговый пин A0
#define LDR_PIN A0

int val; // хранение сырых показаний с датчика 0..1023
int normalVal; // хранение показаний приведённых к 0..100

void setup()
{
    // Начинаем связь через последовательный порт
    Serial.begin(9600);
}

void loop()
{
    // сохраняем показания с аналогового пина A0
    val = analogRead(LDR_PIN);

    /*
      С помощью функции map приводим показания с фоторезистора
      val из диапазона 0..1023 к диапазону 0..100 и сохраняем
      результат в переменную normalVal
    */
    normalVal = map(val, 0, 1023, 0, 100);

    /*
      Выводим информацию в монитор последовательного порта
      print - выводит в текущую строку
      println - вывод и перенос на новую строку
      Ответ выводим в формате:
      val, normalVal
    */
    Serial.print(val);
    Serial.print(", ");
    Serial.println(normalVal);
}

Для обмена информацией между Arduino-скетчем и компьютером используем библиотеку Serial. Чтобы посмотреть сообщения в Arduino IDE, выберите пункт меню Инструменты - Монитор порта ⌃Ctrl + ⇧Shift + M Плата должна быть подключена к компьютеру. При моделировании в TinkerCad, откройте вкладку Код и нажмите по кнопке Монитор последовательного интерфейса внизу окна.

Чтобы преобразовать один диапазон значений в другой, используем функцию map(значение, текущий_минимум, текущий_максимум, новый_минимум, новый_максимум).

Чтобы преобразовать значение с пина к новому диапазону используем следующую формулу: \[ normalVal=[\frac{100\cdot val}{1023}] \]

Задание № 2. Терменвокс. Пьезодинамик

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

Схема для сборки

Сборка схемы

Схема этого задания основана на предыдущем. Можете добавить пьезодинамик к уже собранной схеме.

Программа

// Терменвокс

// Пин управления пьезодинамиком
#define BUZZER_PIN  3
// Пин фоторезистора
#define LDR_PIN     A0

void setup()
{
    // Пин пьезодинамика настраиваем на выход
    // При этом пин должен поддерживать ШИМ
    pinMode(BUZZER_PIN, OUTPUT);
}

void loop()
{
    // val - хранение показаний с фоторезистора
    // freq - вычисленная частота звука
    int val, freq;

    // считываем уровень освещённости - 0..1023
    val = analogRead(LDR_PIN);

    // Расчитываем частоту звука. Преобразуем диапазон
    // 0..1023 в диапазон частот от 250 до 500 Гц.
    freq = map(val, 0, 1023, 250, 500);

    // Воспроизводим звук с частотой freq в течении 20 миллисекунд
    tone(BUZZER_PIN, freq, 20);
}

Создайте переменные val - значение с аналогового входа, note - номер воспроизводимой ноты, minL и maxL для хранения минимального и максимального значения освещённости соответственно.

Чтобы привести значение с пина A0 к номеру ноты от 0 до 83, используем следующую формулу: \[ freq=[\frac{(val - minL)\cdot 83}{(maxL - minL)}] \]

Задание № 3. Управление яркостью светодиода

Составьте программу, которая при нажатии на кнопку, будет увеличивать яркость светодиода.

Схема для сборки

Резистор на 10 кОм в схеме называется стягивающим. Он тянет значение на 8 пине к земле, пока кнопка не нажата.

Подтягивающий резистор

Если нужно, чтобы в не нажатом состоянии на пине с кнопкой была логическая единица (5 В), то кнопку подключают к питанию через подтягивающий резистор, который подтягивает значение на пине к напряжению 5 В.

Программа

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

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

// Яркость светодиода

/* объявляем переменную и сразу инициализируем
    начальным значением, равным 0
    в переменной храним текущее значение яркости */
int brightness = 0;

void setup()
{
    // пин светодиода 9 настраиваем на выход
    pinMode(9, OUTPUT);

    // режим INPUT для пина кнопки не указываем
    // по умолчанию пины настроены на этот режим
}

void loop()
{
    // если кнопка нажата ...
    if (digitalRead(8) == HIGH) {

        // увеличиваем текущую яркость на 15
        brightness = brightness + 15;

        // небольшая задержка, чтобы убрать
        // ложное повторное срабатывание
        delay(100);
    }

    // подаём ШИМ-сигнал на пин светодиода
    analogWrite(9, brightness);
}

Чтобы подать ШИМ-сигнал на выбранный пин используется функция analogWrite(пин, заполнение). Коэффициент заполнения может находится в диапазоне от 0 (всегда выключен) до 255 (всегда включён).

Дополнительное задание

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

Задание № 4. Управление сервомотором

Составьте программу, которая будет управлять вращение сервомотора. Последовательно поверните на 45, 90 и 180 градусов. Затем верните в начальное положение - 0 градусов.

Схема для сборки

Подключение сервомотора

При подключении можно ориентироваться на цвет проводов:

GND - земля (чаще всего чёрный), VCC - плюс питания (чаще всего красный), CTR - управляющий пин.

Программа

// Управление серводвигателем

// подключение библиотеки Servo
#include <Servo.h>

// управляющий пин серводвигателя
#define SERVO_PIN 9

/*
    создаём объект класса Servo
    с помощью этого объекта сможем
    управлять двигателем 
    */
Servo motor;

void setup()
{
    // с помощью метода attach() указываем
    // номер управляющиего пина серводвигателя
    motor.attach(SERVO_PIN);
}

void loop(){
    motor.write(45); // поворачиваем в положение 45 градусов
    delay(1000);
    motor.write(90); // поворачиваем в положение 90 градусов
    delay(1000);
    motor.write(180); // поворачиваем в положение 180 градусов
    delay(1000);
    motor.write(0); // поворачиваем в положение 0 градусов
    delay(2000);
}

Чтобы управлять сервоприводом используем готовую библиотеку Servo. Чтобы импортировать библиотеки используется директива #include.

Задание № 5. Пантограф

Соберите схему с сервомотором и потенциометр. Вращение ручки потенциометра должно управлять положением сервомотора. Получится своеобразный пантограф.

Схема для сборки

Сборка схемы

Схема этого задания основана на предыдущем. Можете добавить потенциометр к уже собранной схеме.

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

Программа

// Пантограф

// импортируем библиотеку Servo
#include <Servo.h>

#define SERVO_PIN 9 // управляющий пин сервомотора
#define POT_PIN A0 // аналоговый пин для потенциометра

int angle; // положение сервомотора (угол) 0..180
int pot; // значение с потенциометра 0..1023

Servo motor;

void setup()
{
    // Аналоговые пины по умолчанию настроены на
    // вход. Поэтому не нужно писать команду
    // pinMode(POT_PIN, INPUT);
    motor.attach(SERVO_PIN);
}

void loop()
{
    // Получаем значение с потенциомера 0..1023
    pot = analogRead(POT_PIN);

    // Преобразуем значение с потенциометра
    // в угол для сервомотора
    angle = map(pot, 0, 1023, 0, 180);

    // поворачиваем сервомотор на вычисленный угол
    motor.write(angle);
}

Чтобы преобразовать значение с потенциометра (0..1023) к углу поворота сервомотора (0..180), используем следующую формулу: \[ angle=[\frac{180\cdot pot}{1023}] \]

Задание № 6 Умный светильник

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

Соберите схему, состоящую из трёх контуров:

  1. с фоторезистором;
  2. с потенциометром;
  3. со светодиодом.

После сборки схемы составьте программу по следующему алгоритму: