Espruino:Примеры/Измерение и управление скоростью вентилятора

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

Перевод: Максим Кузьмин (Cubewriter) Контакты:</br>* Skype: cubewriter</br>* E-mail: cubewriter@gmail.com</br>* Максим Кузьмин на freelance.ru
Проверка/Оформление/Редактирование: Мякишев Е.А.


Измерение и управление скоростью вентилятора[1]

Это руководство подразумевает, что вы уже умеете загружать код на Espruino. Если вы этого делать не умеете, пройдите сначала вот это руководство.

Введение

В этом руководстве мы измерим скорость вращения 4-проводного CPU-вентилятора Intel, а потом сами зададим ему скорость вращения. Измерения будут делаться при помощи функции setWatch() – с её помощью мы зададим прерывание на нужном контакте, в результате чего при изменении состояния этого контакта будет запущена нужная нам функция.

Ниже – видеоверсия этого руководства:

Control Fan Speed with Espruino JavaScript for ARM Microcontrollers

Подсоединение

4-проводные вентиляторы Intel – это 12-вольтовые вентиляторы, совместимые с более ранними 2- и 3-проводными моделями. Они оснащены одним цифровым вводом для управления скоростью и одним цифровым выводом для её измерения. Его контакты отвечают за следующее:

Контакт вентилятора Цвет провода За что отвечает
1 Чёрный Земля
2 Жёлтый 12-вольтовое питание
3 Зелёный Датчик для измерения скорости, притянутый к «0» (притягивается дважды за оборот)
4 Синий Управление скоростью

Хотя в таблице выше написано, что вентилятору нужно 12 вольт (и это на 100% верно), но мы в целях упрощения это проигнорируем и вместо 12 вольт будем питать вентилятор от 5 вольт – именно столько Espruino получает через USB-соединение.

Итак:

  • Подключите чёрный (1) провод к контакту GND на плате Espruino.
  • Подключите жёлтый (2) провод к 5 вольтам на плате Espruino.
  • Подключите зелёный (3) провод к любому свободному контакту на плате Espruino (я в этом примере решил воспользоваться B9).
  • Подключите синий (4) провод к любому аналоговому контакту, умеющему генерировать ШИМ. Чтобы узнать, какие контакты умеют это делать, напечатайте analogWrite(), но если рядом с контактом говорится DAC, не используйте его. Я для этого примера решил воспользоваться контактом B8.
  • Наконец, найдите резистор на 10 кОм, а затем подключите одну его ножку к зелёному (3) проводу вентилятора, а другую – к 3.3 вольтам на плате Espruino. Это притянет датчик скорости к значению «1». Если вам лень это делать, просто подключите 2 и 3 провода вентилятора друг к другу при помощи резистора.
  • После включения питания вентилятор должен начать вращаться (но медленно – потому что по-хорошему его нужно питать от 12 вольт).

Код

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

var FAN_SPEED_OUT = B8;
var FAN_SPEED_IN = B9;

Теперь давайте быстренько проверим, всё ли работает нормально:

setWatch(function (e) { 
  digitalWrite(LED1, e.state); 
}, FAN_SPEED_IN, { repeat: true });

Это заставит светодиод моргнуть после того, как индикатор скорости вентилятора отправит сигнал. При каждом изменении сигнала этот код будет вызывать функцию, задающую светодиоду новое состояние, которое было прислано в сигнале.

В результате светодиод будет то включаться, то выключаться, а если вентилятор замедлится, светодиод будет включаться и выключаться ещё медленнее.

digitalWrite(FAN_SPEED_OUT, 0);

Теперь вентилятор (и светодиод) должны работать очень медленно.

digitalWrite(FAN_SPEED_OUT, 1);

Теперь вентилятор (и светодиод) снова должны начать работать быстро.

Давайте удалим прерывание (что прекратит мигание светодиода) и попробуем кое-что новенькое.

clearWatch()

Ниже – функция, измеряющая время между сигналами от вентилятора. С её помощью мы рассчитаем количество оборотов вентилятора в минуту (переменная RPM).

function onFanMovement(e) { 
  var d = e.time-lastTime;
  lastTime = e.time;  
  RPM = 60 / (d*2);
}
setWatch(onFanMovement, FAN_SPEED_IN, { repeat: true, edge: 'falling' });

Обратите внимание, что в свойстве edge задано значение falling. Это нужно, чтобы наша функция вызывалась, только если состояние сигнала сменится с «1» на «0» (т.е. «упадёт»). Дело в том, что сигналы могут быть несимметричными (то есть переключение с «1» на «0» и с «0» на «1» занимает разное время). Но мы замеряем только «падение» сигнала, и поэтому нам об этой проблеме беспокоиться не нужно.

В коде выше мы рассчитываем количество оборотов в минуту (переменная RPM), а в одной минуте, как известно, 60 секунд. Кроме того, на каждый оборот приходится по 2 импульса, так что нам нужно удвоить продолжительность импульса, чтобы измерить его. В итоге получаем вот такую формулу:

RPM = 60 / (d*2);

Итак, загрузите функцию onFanMovement(e), показанную выше, на Espruino. После её загрузки ничего не произойдёт, потому что Espruino будет просто в фоновом режиме обновлять переменную RPM.

Поэтому просто напечатайте:

RPM

В результате в консоли будет напечатано количество оборотов в минуту.

Теперь давайте замедлим вентилятор:

digitalWrite(FAN_SPEED_OUT, 0);

А потом снова узнаем количество оборотов в минуту. Оно должно уменьшиться.

RPM

А что если нам нужно сделать значение в переменной RPM постоянным?

Для этого мы можем отредактировать функцию onFanMovement(), чтобы включать и выключать вентилятор в зависимости от нужной нам скорости. Мы также будем включать и выключать светодиод, чтобы видеть, что происходит:

var targetRPM = 200;
function onFanMovement(e) { 
  var d = e.time-lastTime;
  lastTime = e.time;
  RPM = 60 / (d*2);
  var fanOn = RPM < targetRPM;
  digitalWrite(LED1, fanOn);
  digitalWrite(FAN_SPEED_OUT, fanOn);
}

Теперь мы можем задать в переменной targetRPM нужное нам количество оборотов в минуту, а Espruino воспользуется им для изменения скорости вращения вентилятора (вы увидите это по светодиоду).

var targetRPM = 300;

Если задать здесь слишком большое значение (например, 10000), вентилятор никогда не разовьёт такую скорость, а светодиод останется включенным. А если задать слишком низкое значение, светодиод останется выключенным.

Обратите внимание, что если задать значение где-то посередине, скорость вращения будет постоянно колебаться. Исправить это можно при помощи использования широтно-импульсной модуляции – с её помощью мы будем очень быстро менять скорость вращения вентилятора.

Вместо использования переменной fanOn (с помощью которой задаётся либо включение, либо выключение вентилятора) мы создадим и запомним новую переменную. В ней будет храниться значение между «0» и «1», определяющее то, с какой силой работает вентилятор. Вместо того, чтобы просто задавать его, мы будем увеличивать и уменьшать его на маленькое значение в зависимости от того, быстрее ли или медленнее ли нужного нам значения крутится вентилятор.

var fanDrive = 0.5;
function onFanMovement(e) { 
  var d = e.time-lastTime;
  lastTime = e.time;
  RPM = 60 / (d*2);
  if (RPM < targetRPM) {
    if (fanDrive<1) fanDrive += 0.01;
  } else {
    if (fanDrive>0) fanDrive -= 0.01;
  }
  digitalWrite(LED1, fanDrive>0.5);
  analogWrite(FAN_SPEED_OUT, fanDrive);
}

Но значение в переменной fanDrive не должно выходить за пределы диапазона 0-1. Если задать в targetRPM какое-то недостижимое число, значение в fanDrive будет постоянно увеличиваться, а когда вы снова решите задать в targetRPM значение поменьше, у Espruino уйдёт бездна времени на то, чтобы снова сделать значение в fanDrive меньше «1».

Если вы попробуете задать значение targetRPM сейчас, вентилятор достигнет нужной скорости вращения за несколько секунд. Чтобы узнать, какое именно значение было задано для вентилятора, напечатайте следующее:

fanDrive

Если вы будете какое-то время вызывать эту переменную, то увидите, что её значение постоянно меняется, чтобы достичь значения, заданного в targetRPM.

Теперь давайте попробуем резко увеличить скорость вращения вентилятора и посмотрим, что получится!

fanDrive=1;

В результате вентилятор закрутится с максимальной скоростью, а затем Espruino начнёт потихоньку её замедлять, пока не достигнет нужного значения.

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

Это решается очень просто!

Во-первых, мы больше не будем менять скорость вентилятора при изменении сигнала от вентилятора. Мы будем делать это 10 раз в секунду независимо от его текущей скорости:

function onFanMovement(e) { 
  var d = e.time-lastTime;
  lastTime = e.time;
  RPM = 60 / (d*2);
}
function onTimer() {
  if (RPM < targetRPM) {
    if (fanDrive<1) fanDrive += 0.01;
  } else {
    if (fanDrive>0) fanDrive -= 0.01;
  }
  digitalWrite(LED1, fanDrive>0.5);
  analogWrite(FAN_SPEED_OUT, fanDrive);
}
setInterval(onTimer, 100);

Итак, теперь вентилятор будет подстраивать скорость вращения одинаково – независимо от того, медленнее нужной скорости он крутится или быстрее. Кроме того, нужная скорость будет гарантированно достигнута в течение не более 10 секунд.

Есть другие способы управления устройствами, с помощью которых нужной скорости можно достичь гораздо быстрее... Например, рекомендуем ознакомиться с этой статьёй о ПИД-регуляторах на «Википедии».

См.также

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