Программа тахометра
Если двигатель вращается достаточно медленно, мы можем обойтись подходом, который обычно используют для считывания сигнала кнопки. Например, так:
...
int rot = 0; // переменная для хранения количества оборотов
void loop(){
if( digitalRead(2) ){ // если датчик сработал
rot++; // прибавляем единичку к счетчику
Serial.println(rot);
}
}
Эта программа будет сносно считать количество оборотов и выводить их в последовательный порт. Но у такого решения есть большой недостаток. Если кроме подсчета оборотов в суперцикле loop будут другие операции, и не дай бог вызовы функции delay, то мы можем легко пропустить очередное срабатывание датчика! То есть в момент, когда щель на диске будет очередной раз пролетать мимо луча, контроллер будет занят какими-то другими делами и пропустит срабатывание.
Даже если в loop не будет ничего кроме digitalRead, мы всё равно рискуем пропустить срабатывание датчика при измерении скорости быстрых двигателей. Процедура digitalRead медленная. Что же делать?
Прерывания
Прерывания — это специальная аппаратная функция микроконтроллеров, которая позволяет прерывать выполнение основной программы по сигналу на определенных входах. Например, у Ардуино Уно есть два прерывания №0 и №1 на соответствующих выводах D2 и D3 (обычные цифровые ноги 2 и 3). 0 и 1 — это номера самих прерываний! Не путать с нумерацией ног Ардуино.
Если прерывание активировано, то при появлении на соответствующем контакте высокого уровня, программа мгновенно останавливается, и запускается так называемый обработчик прерывания. После выполнения кода обработчика, управление передается основной программе ровно в том же месте, где она была прервана.
Важное замечание. Код обработчика не должен выполняться слишком долго, иначе есть риск нарушить работу других прерываний и основной программы. А еще прерывание не должно вызываться слишком часто, иначе микроконтроллер только и будет, что висеть непрерывно в функции обработчика. В общем при работе с прерываниями есть много тонкостей, но мы не будем в них сильно углубляться на этом уроке.
Напишем программу для подсчета количества оборотов при помощи прерывания №0.
const byte interruptPin = 2; // контакт к которому подключен датчик
long int rot = 0; // переменная для хранения количества оборотов
// функция-обработчик, которая вызывается во время прерывания
void detect() {
rot++;
}
void setup() {
Serial.begin(9600);
// настроим контакт D2 на вход, да ещё с подтяжкой к питанию
pinMode(interruptPin, INPUT_PULLUP);
// активируем прерывание и свяжем его с функцией detect
attachInterrupt(digitalPinToInterrupt(interruptPin), detect, RISING);
}
void loop() {
Serial.println(rot);
delay(100);
}
Функция digitalPinToInterrupt преобразует номер контакта Ардуино в номер прерывания. Вызов digitalPinToInterrupt(2) вернёт 0. Можно было явно написать:
attachInterrupt(0, detect, RISING);
Загрузим эту программу на Ардуино и откроем монитор последовательного порта.

Увидим вереницу чисел — это и есть количество оборотов. Каждые 100мс в порт вываливается текущее число оборотов, которое пока для нас бесполезно. Вот если бы у нас вращалось колесо робота, то умножив количество оборотов на длину окружности колеса мы бы получили пройденное расстояние! Обязательно попробуем это сделать в уроке про контроль движения робота.
А пока перейдем к скорости вращения.
Расчёт скорости
Изменим программу. Каждые 100мс будем считать скорость по формуле:
V = rot/dt
где rot — количество оборотов, dt — время, пройденное с последнего расчёта.
const byte interruptPin = 2;
unsigned int rot = 0;
unsigned long int tm;
unsigned long int spd = 0;
unsigned int dt = 0;
void detect() {
rot++; // прибавляем единичку к счётчику обротов
dt = millis() - tm; // вычисляем время с последнего расчёта
if( dt >= 100 ){ // если прошло 100мс или более, то начинаем расчёт
spd = rot*60000/dt;
rot = 0; // обнуляем счётчик
tm = millis(); // запоминаем время расчёта
}
}
void setup() {
Serial.begin(9600);
pinMode(interruptPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin), detect, RISING);
tm = millis();
}
void loop() {
Serial.println(spd);
delay(100);
}
Откуда взялось 60000? Дело в том, что формула V = rot/dt даст нам скорость в единицах об/мс. Ведь dt у нас в миллисекундах. Чтобы превратить миллисекунды в секунды нужно dt поделить на 1000. А чтобы секунды в минуты — еще поделить на 60. Вот и получается: V = rot * 60000/dt.
Загрузим программу и откроем плоттер для изображения наших данных в виде графика. Если мотор подключен к лабораторному источнику питания, можно менять напряжение и смотреть как меняется скорость вращения.

Также на графике виден шум — это колебания скорости вращения. К сожалению, коллекторный двигатель постоянного тока — машина не совершенная и его скорость имеет свойство «плавать». Но это тема совсем другого разбирательства.
Здравствуйте, спасибо за статью. Можете рассказать поподробнее: почему скорость вращения якоря колеблеться?