Реобас на Ардуино (часть 2)
реклама
Прежде чем браться за подключение датчиков посмотрим, на плату Arduino повнимательней.
Плата может запитываться от нестабилизированных источников постоянного тока с напряжением от 6 до 20 Вольт (это экстремальные значения, рекомендованный диапазон от 7 до 12 Вольт) и имеет встроенный стабилизатор питания. Встроенный стабилизатор выдаёт 5В. При входном напряжении на стабилизаторе менее 7 Вольт его работа может быть неустойчивой (в зависимости от экземпляра), а более 12 Вольт приведут к черезмерному нагреву встроенного стабилизатора. Есть платы с переключателем напряжения 3.3В/5В. Если у вас такая, переключите на 5В (3.3В в нашем случае пока не понадобятся). Так же можно подключить питание от стабилизированного источника питания 5В непосредственно в цепь после стабилизатора.
Назначение выводов колодки Power (стандартное для всех полноразмерных плат Arduino):
Vin - "входное" напряжение, вход внешнего источника питания, соединяется напрямую с разъёмом питания;
GND - "минус", "масса", "земля" (от ground), "ноль", "корпус", "общий" и т.п. - названий масса, используйте название к которому привыкли. Для систем где нет отрицательных напряжений и/или множества фаз (с отрицательными относительно этого контакта напряжениями) они все являются верными (в обиходном общении, разумеется). Лично я привык к названиям "общий" и "масса", кои у буду использовать далее.
5V - соединяется с выходом стабилизатора на плате. Максимальный ток до 2.2А, однако я бы не советовал бы "выжимать все соки" из него и ориентироваться на максимальный ток в 1А. Силовые ключи конечно же разумней запитывать от внешних источников. На этот же контакт можно запитать плату от внешнего стабилизированного источника питания +5В. Однако такой вариант не приветсвуется разработчиком ввиду его небезопасности (видимо разработчик не доверяет нашим многокиловаттным и суперстабильным источникам питания). Тем не менее, я бы посоветовал запитывать плату ардуино через Vin от +12В и избегать ситуаций одновременной запитки на Vin и +5V (это просто неграмотно). Помимо этих двух вариантов подключения питания существует и третий - от USB. Подключение внешнего источника питания Vin отключает питание платы от USB, тут всё грамотно. Питания от USB вполне достаточно для отладочных работ с датчиками и индикаторами, однако не более того. Редко какой кабель USB способен прокачать ток в 2А, для большинства из них (особенно китайских noname) ток в 700mA является предельным.
3.3V (на некоторых версиях обозначается как 3V3) - выход от ещё одного стабилизатора. Максимальный ток 50мА. Используется в основном в качестве опорного напряжения для датчиков.
IOREF - выход опорного напряжения для датчиков (input/output reference), соединяется напрямую с 5-ти вольтовым стабилизатором на плате;
RESET - замыкание это контакта на массу приведёт к сбросу состояния контроллера и перезапуску программы.
В дальнейшем, чтобы не создавать путаницы, единицы измерения тока и напряжения буду указывать латиницей.
Плата Arduino Nano точно такие же контакты (кроме IOREF, смысла нём в малом формате просто нет).
Чудесно! Теперь мы знаем как правильно включить ардуину при этом не спалив её.
Теперь, прежде чем мы перейдём к повторению закона Ома, обратим внимание на аналоговые входы Arduino. Именно к ним мы будем подключать аналоговые датчики, а ортодоксальные моддеры могут подключить к нему переменный резистор для ручной регулировки оборотов или яркости подсветки (лично мне вариант с управлением от шаттла куда более симпатичней несмотря на его несколько большую сложность).
Итак. Аналоговые входы.
|
У Arduino Nano их 8: A0-A7 |
|
У Arduino Uno их всего 6: A0-A5 |
|
У Arduino Mega их аж 16: A0-A15 |
При опросе соответсвующего контакта (описание операторов ниже) контроллер возвращает значение напряжения на нём. Но так как входное напряжение раскладывается 10 битным АЦП (аналого-цифровым преобразователем) возвращаемое значение будет целым числом от 0 до 1023, где значение 0 равно 0V, а 1023 равняется опорному напряжению (по умолчанию это 5V). Таким образом можно напрямую померить напряжение от 0 до 5V с шагом 5mV (0.004883V, если быть точным). Правда при этом придётся прибегнуть к дополнительному преобразованию значения, чтобы получить реальное напряжение, а не его код. В некоторых случаях может понадобится другое опорное напряжение (соответственно изменится шаг измерения). Для установки другого опорного напряжения (в его качестве можно использовать, например 3.3V от всторого встроенного стабилизатора) его надо будет подать на контакт AREF и в процедуре setup() указать соответвующую команду (синтаксис и описание ниже).
Теперь вспомним, что нам завещал старина Ом. Особенно нас интересует приложение его закона к делителям напряжения. Именно это самый простой способ подключить аналоговый датчик.
Ток в цепи из двух последовательно соединённых резисторов:
При подборе компонентов (сопротивлений резисторов) при таком подключении следует учитывать два взаимоисключающих обстоятельства. С одной стороны - пассивное сопротивление должно быть как можно меньше с целью обеспечить как можно больший диапазон изменения напряжения. С другой - уменьшение номинала пассивного резистора приведёт к росту тока через датчик, что в конечном итоге после приведёт к его саморазогреву (при увеличении температуры сопротивление терморезистора падает, ток через него увеличивается).
Датчик включим в "нижнее плечо". Настоятельно рекомендую датчики и органы управления всегда включать в нижнее (относительно сигнального провода) плечо. Так как случайное замыкание любого из проводов датчика (или кнопки) на корпус устройства при таком подключении не вызовет фатальных последствий. При включении датчика в верхнее плечо на одном из выводов устройства будет напряжение питания без каких-либо токоограничивающих резисторов и замыкание его на корпус может повредить здоровью вашей ардуины. И хотя все нормальные стабилизаторы имеют защиту по току, испытывать её лишний раз всё же не стоит.
Напряжение на датчике (подаваемое на аналоговый вход Arduino):
Сделав несложную подстановку из предыдущей формулы получим:
Теперь попробуем расчитать схему подключения термодатчика на основе терморезистора. В моём случае это датчик приобретённый под торговой маркой Scythe. Марка не имеет значения. Имеет значение характеристика сопротивления от температуры.
Наиболее распространённый тип датчиков - NTC (такой же как и мой) имеет сопротивление 10kOm при температуре +25C и 0.7kOm при температуре +100C. Сразу предупреждаю, что разброс сопротивлений датчиков может быть весьма значительным. 2-3 градуса погрешности для датчиков такого класса - норма, меньшее - удача (добавьте сюда погрешности вносимые креплением датчика и поймёте, что большинство холиваров "на полградуса холоднее" просто не имеют смысла). С такой погрешностью можно вполне успешно бороться проводя калибровку датчиков, но сейчас нам особая точность пока не нужна. Пока вполне будет достаточно демонстрации принципа управления "горячее - больше оборотов".
За напряжение подаваемое на делитель возьмём +5V со стабилизатора. Сопротивление пассивного (или как его ещё называют, притягивающего) возьмём равным 1kOm. Сразу скажу, что получится далеко не самый широкий диапазон. Если у вас есть коробка с резисторами, то можно будет поиграться с диапазоном. Помимо этого, есть ещё один трюк с опорным напряжением о котором чуть ниже. Сейчас нам более важно продемонстрировать сам принцип работы.
Так как с аналогового входа Arduino мы можем считать только код аналогово-цифрового преобразователя соответсвующий входному напряжению, а не само напряжение приведу ещё и формулу для расчёта кода по напряжению:
1024 - количество отсчётов при измерении напряжения. 2 в 10-ой степени. Как уже было сказано ранее, АЦП у нас 10-ти битный.
Usens - входное напряжение
Ureference - величина опорного напряжения. По умолчанию для АЦП Arduino оно равно напряжению питания, т.е. 5V.
При комнатной температуре:
При +100С:
Не самый широкий диапазон, но на первое время сойдёт.
Собираем схему.
В цепь управления вентилятором добавили токоограничивающий резистор. В принципе можно и без него, но в случае если с вентилятором случится какая бяка и на этот вывод попадёт +12, то ардуине может непоздоровится. Поэтому, если собирается схема для долговременной эксплуатации, токоограничивающий резистор обязателен. Во время экспериментов можно обойтись и без него.
Теперь загрузим в Ардуино код (описание команд и ньюансы чуть ниже, после видео):
// начало
// описание глобальных переменных
int fanCtrlPin = 3; // выход D3 на драйвер вентилятора
int thermoPin = 1; // аналоговый вход термодатчика
int tempADC = 0; // температура (ADCcode считываемый с анлогового входа)
int rpmCtrl = 0; // управляющее значение оборотов вентиялтора (PWM код)
void setup() {
// установка частоты PWM
//для нужного типа платы убрать "//" в начале строки
// это для плат типа Arduino Nano и Uno:
// TCCR2B = (TCCR2B & 0xF8) | 0x01; // timer 2 (pins 11,3)
// это для плат типа Arduino Mega:
// TCCR3B = (TCCR3B & 0xF8) | 0x01; // timer 3 (pins 2,3,5)
analogReference(DEFAULT); // утановка опорного напряжения
pinMode(fanCtrlPin, OUTPUT); // назначаем контакт D3 как выход
}
void loop() {
// считываем ADCcode с анлогового входа)
tempADC = analogRead(thermoPin);
// устанавливаем границы допустимых значений
tempADC = constrain(tempADC, 421, 930);
// проецируем температуру на управление оборотами
rpmCtrl = map(tempADC, 421, 930, 255, 0);
// отсылаем управляющее значенние оборотов на вентилятор
analogWrite(fanCtrlPin, rpmCtrl);
// задержка в 1с, в принципе, можно уменьшить или вообще убрать
// введена в демонстрационных целях
delay(1000);
}
// конец
Должно получится примерно следующее
Частота вращения вентилятора меняется в зависимости от температуры на датчике. Изменение происходит с некоторой задержкой (до 1 секунды). Задержка была введена для того чтобы изменение оборотов было отчётливо слышно на видео. В принципе, задержку можно убрать совсем, но я бы посоветовал в данном конкретном случае оставить некоторое значение. Одна десятая секунды или delay(100); подойдёт идеально.
Теперь немного подробнее собственно о коде и новых для некоторых из нас командах и функциях.
Про установку частоты PWM я уже кратенько писал впервой части. Более подробно про частоту, таймеры и прерывания в одной из последующих частей.
С глобальными переменными всё понятно, единственное о чём важно помнить, что переменные
tempADC
и
rpmCtrl
отражают не конкретные значения температуры и оборотов, а некий код.
tempADC
может принимать значения от 0 до 1023 в зависимости от параметров подобранного делителя напряжения, напряжения питания датчика и температуры. Причём зависимость от температуры при подключении по нашей схеме обратная! Чем выше температура на датчике, тем меньшее значение будет принимать
tempADC
.
rpmCtrl
- код широтно импульсной модуляции. В данном конкретном случае значение 0 будет означать минимальные обороты вентилятора (мой PWM вентилятор от кулера Intel уменьшает частоту вращения до минимальной при уменьшении этого значения до 32, после чего обороты остаются неизменными даже при PWM = 0), а значение 255 будет означать максимальные обороты.
Далее в процедуре setup() мы указываем какое напряжение надо использовать в качестве референсного для АЦП. Если в качестве референсного напряжения используется напряжение питания, то команда будет иметь вид
analogReference(DEFAULT);
Если потребуется по каким-то причинам использовать другое напряжение (например генерируемое платой 3.3V), то его необходимо подать на контакт AREF и прописать команду использовать опорное напряжение с контакта AREF
analogReference(EXTERNAL);
Помимо этого на разных платах есть ещё и внутренние источники опорного напряжения и прописываются они параметрами содержащими фразу INTERNAL (более подробно параметры и типы плат можно посмотреть здесь, а так же в спецификации к вашей ардуине).
Для использования иного опорного напряжения надо будет пересчитывать делитель, чтобы максимальное напряжение на входе не превышало референсное. Это один из простейших трюков по расширению рабочего диапазона датчика температры, оставить питание делителя +5V, а в качестве референсного использовать меньшее напряжение. Но с технической точки зрения это не есть правильно. Правильней было бы подключить датчик через схему на операционном усилителе, но это неприемлемо усложнит схему для новичка. Поэтому пока довольствуемся тем что есть. Тем более что даже урезанный диапазон всё равно обеспечивает вполне приемлемую точность.
Идём дальше.
После установки референсного напряжения идёт команда по установке контакта
D3
в режим вывода. Надо заметить, что в программе используется только цифровое обозначение контактов. Разделение аналоговый вход или цифровой вход-выход следует из применяемых команд. На аналоговые входы нельзя ничего записать, можно только считывать (поэтому для аналоговых входов не применяются команды установки режима ввод/вывод
pinmode() ). А с цифрового контакта установленного в режим ввода нельза произвести аналоговое чтение (а вот аналоговую запись, под которое подразумевается запись PWM кода, можно). Использование понятных имен переменных вместо прямой адресации в команде позволит вам избежать путаницы.
Всё, больше в процедуре установки у нас ничего нет.
В процедуре loop() мы первым делом считаем значение на аналоговом входе (естественно не само значение, а его АЦП-код). Функция чтения имеет вид:
analogRead(Pin)
где Pin - порядковый номер аналогового входа, а возвращаяемое функцией значение находится в диапазоне от 0 до 1023
Далее идёт функция, которая проверяет, не лежит ли указанное значение вне допусимых пределов и обрезает его до ближайшего в случае необходимости. Функция имеет вид:
constrain(var, min, max)
где var - проверяемое значение, min - минимальное значение допустимого диапазона, max - максимальное значение допустимого диапазона. Функция возвращает уже проверенное на превышение пределов значение. Указанную функцию можно было бы заменить строкой:
if (tempADC < 421) tempADC = 421; else if (tempADC > 930) tempADC = 930;
Что более понятно, но менее элегантно.
После проверки диапазона значений у нас идёт такое же элегантное преобразование температуры в обороты с помощью функции map()
map(var, a1, a2, b1, b2)
где var - преобразуемое значение, функция возвращает значение из диапазона b1-b2, причём если значение var будет равно a1 функция возвратит значение b1 и b2 для a2 соответсвенно. Все остальные промежуточные значения из диапазона a1-a2 будут линейно рапределены по диапазону b1-b2. Очень удобная и понятная функция по приведению одного диапазона к другому без какой-либо необходимости сочинять кучу формул. Применять только если величина var находится в диапазоне a1-a2 (для чего нам ранее и понадобился constrain), в противном случае результат будет непредсказуем.
После преобразования значение оборотов (PWM код) записываем уже известным способом на контакт управления вентилятором.
Надо заметить, что расчитанный диапазон ADC может оказаться неоптимальным. Например для видео, чтобы точно видно было где холодная вода, мне пришлось взять стакан со льдом. После многократных попыток угомонить детей, чтобы на видео не было слышно их радостных воплей, вода остыла до примерно +75C. Пришлось откорректировать диапазон в constrain и следующей функции map. В итоге эти две строчки выглядели следующим образом:
tempADC = constrain(tempADC, 200, 720)
rpmCtrl = map(tempADC, 200, 720, 255, 0);
На сегодня это всё. В следующий раз рассмотрим подключение ЖК индикатора и получение данных по USB (если не планируете портить стильную морду своего компа). Это нам понадобится в четвёртой части, где рассмотрим вычисление и отображение оборотов вентилятора и температуры.
Продолжение следует...
первая часть здесь
Обсуждение, предложение по темам, вопросы и т.п. можно обсудить на форуме.
реклама
Лента материалов
Соблюдение Правил конференции строго обязательно!
Флуд, флейм и оффтоп преследуются по всей строгости закона!
Комментарии, содержащие оскорбления, нецензурные выражения (в т.ч. замаскированный мат), экстремистские высказывания, рекламу и спам, удаляются независимо от содержимого, а к их авторам могут применяться меры вплоть до запрета написания комментариев и, в случае написания комментария через социальные сети, жалобы в администрацию данной сети.
Сейчас обсуждают