24.08.2010

Термоконтроллер на Arduino

Уважаемые читатели!

Эта статья написана не мной, посему - прошу любить и жаловать: сегодня Vergellan поделится с вами опытом создания умного регулятора вращения вентиляторов, с участием термодатчика, LCD-дисплея и, конечно же, Arduino.

Несколько месяцев назад я прочел ряд статей об Arduino и весьма заинтересовался данным девайсом, а вскоре решил приобрести. Надо отметить, что я далек от микроэлектроники, поэтому плата расположила к себе прежде всего относительной простотой в освоении. Набаловавшись с LED-ами и «Hello world»-ами, захотелось сделать что-нибудь практичное, заодно более детально ознакомиться с возможностями Arduino. Памятуя об аномально жарком лете 2010 года, возникла идея собрать регулятор оборотов кулера в зависимости от температуры с выводом всех сопутствующих характеристик на LCD. Надеюсь, что кому-нибудь данная схема или ее вариации смогут пригодиться, поэтому решил выложить свои наброски.


Для данной схемы нам понадобится:
  • Собственно сама плата Arduino или аналог;
  • Макетная плата для сборки компонентов схемы;
  • Дисплей WH1601A-NGG-CT с подстроечным резистором на 20 кОм или аналогичный;
  • Резисторы – 220 Ом, 10 кОм, 4.7 кОм;
  • Биполярный транзистор SS8050D или аналогичный ему;
  • Цифровой температурный датчик DS18B20;
  • Диод 1N4148 или аналог;
  • Вентилятор осевой трехпроводной (на 12В), например - компьютерный;
  • Разъем гнезда питания 2,1/5,5 мм.
Компьютерный кулер имеет три провода, два из которых - красный (+12V) и черный (GND) используются для питания, а третий  (желтый) связан с таходатчиком, построенном на элементе Холла. К сожалению,  5V с платы нам явно недостаточно, но 6 цифровых выходов Arduino могут работать в режиме ШИМ (они отмечены на самой плате белыми квадратиками, либо буквами PWM), поэтому мы можем регулировать подачу сигнала с платы на реле, которое будет отвечать за изменение напряжения, подаваемого на вентилятор.


Получать информацию об оборотах мы будем с третьего провода от таходатчика, воспользовавшись модифицированным способом, основанным на реализации прерываний, которые у большинства Arduino могут приходить на цифровые pin 2 (прерывание 0) и 3 (прерывание  1). Кстати, у Arduino Mega наличествует еще 4 дополнительных пина с возможностью получения прерываний.

Теперь необходимо расположить цифровой датчик температуры, данные которого мы будем использовать для регулирования напряжения, подаваемого на цифровой выход с ШИМ, а следовательно для «открытия» канала напряжения  вентилятора. Для датчиков фирмы Dallas существует собственная библиотека Arduino – DallasTemperature, которую впоследствии мы и будем подключать в скетче. Библиотеку необходимо распаковать в каталог arduino-0018/libraries/.

Осталось последнее – подключить LCD, где у нас будет отображаться вся текущая информация о температуре и скорости вентилятора. Поскольку я использовал для сборки экран WH1601A, могут иметь место известные проблемы с отображением строк. Для их устранения мы воспользуемся библиотекой LiquidCrystalRus, которую необходимо также распаковать  в каталог arduino-0018/libraries/.

//Подключаем библиотеку для термодатчика 
#include <dallastemperature.h>
//Подключаем библиотеку для LCD
#include <LiquidCrystalRus.h> 

#define PowerPin 9    // pin для контроля питания вентилятора
#define HallSensor 2  // pin для датчика оборотов вентилятора (прерывание)
#define TempPin 7 // pin для датчика температуры

LiquidCrystalRus lcd(12, 11, 10, 6, 5, 4, 3); //Подключение LCD
DallasTemperature tempSensor;                            

int NbTopsFan, Calc, fadeValue;  //целочисленные переменные для расчетов
float temper;  //вещественная переменная для хранения температуры

typedef struct{ // Вводим новый тип переменных для вентиляторов 
  char fantype;
  unsigned int fandiv;
}fanspec;

//Массив переменных нового типа
fanspec fanspace[3]={{0,1},{1,2},{2,8}};

//Переменная, отвечающая за выбор типа датчика вентилятора (1 – униполярный датчик Холла, 2 –биполярный датчик Холла)
char fan = 2;   

//Эта функция у нас будет вызываться при каждом прерывании
void rpm () 
{
  NbTopsFan++; 
}

// Функция расчета подаваемого напряжения на цифровой pin с ШИМ
void temp ()   
{
  fadeValue = min(int(temper*7),255);  // Умножаем температуру на коэффициент, 
                                       // берем от произведения целое число
}  // Т.к. максимальное значение ШИМ составляет 255, то подавать больше не имеет смысла – берем минимум из двух

void setup()
{
    tempSensor.begin(TempPin);  //Запускаем температурный датчик
    lcd.begin(16, 2); //Задаем характеристики LCD
    lcd.setDRAMModel(LCD_DRAM_WH1601); //И тип дисплея
    pinMode(HallSensor, INPUT);  // Настраиваем pin на получение прерываний
    attachInterrupt(0, rpm, RISING);  //Привязываем прерывание по номеру 0 к нашей функции, причем высчитываться она будет каждый раз при смене сигнала
}

void loop ()
{
   temper = tempSensor.getTemperature(); // Получаем температуру
   temp(); // Высчитываем подаваемое напряжение на ШИМ
   analogWrite(PowerPin, fadeValue); // Подаем его
   NbTopsFan = 0; // Обнуляем переменную, содержащую обороты
   delay (1000); //Ждем 1 секунду
   Calc = ((NbTopsFan * 60)/fanspace[fan].fandiv);   //Рассчитываем величину оборотов за 60 секунд, поделенную на множитель вентилятора
   lcd.print (Calc, DEC); //Выводим рассчитанную величину в десятичном виде
   lcd.print (" rpm - "); 
   lcd.print(temper); //Выводим температуру
   lcd.home(); 
}


У меня финальная схемка выглядит так (часть компонентов перенес с макетки на дополнительную плату, т.к. планирую сделать уже готовый регулятор в нормальном корпусе):


В завершение хотел бы выразить огромную благодарность Илье Данилову (idanilov) за «привитый» интерес к Arduino и за помощь в освоении данной платформы.

UPD: Последняя версия LiquidCrystalRus доступна на github.

19.08.2010

Уроки Wiring (6)

Урок 6. Что за ШИМ?

(продолжение, начало см. Урок 5. Нажми на кнопку!)

Пожалуй, самая загадочная для новичка надпись на плате Arduino - PWM. На самом деле, это сокращение от Pulse Width Modulation, по-русски "Широтно Импульсная Модуляция" или ШИМ.

Что такое PWM?

На секунду вернемся к картинке из предыдущего урока:



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

Собственно, именно эту ширину и предполагается модулировать - то есть изменять определенным образом. Зачем все это может понадобиться? Да вот - хотя бы для изменения яркости свечения светодиодов.

Так выглядит график зависимости свечения от тока для самого ординарного светодиода:


Получается, что чем больше ток через светодиод, тем ярче он будет светиться. Логично, если вспомнить, что светодиод - это полупроводниковый прибор, управляемый током. Так что всего-то остается - понять, как изменять величину тока в цепи питания светодиода.

Возьмем для примера  светодиод L, присутствующий на всех современных Arduino-совместимых платах:


Светодиод загорится только в том случае, когда к его выводам будет приложена достаточная разность потенциалов. В данном случае одна ножка подключена к земле, а к другой - через токоограничительный резистор 1 кОм - вывод digital13. Следовательно, светодиод будет загораться по команде digitalWrite(13, HIGH).

Резистор включен последовательно со светодиодом с единственной целью - ограничить ток, протекающий в цепи. Обычно его значение прикидывают следующим образом: берут напряжение во всей цепи (для Arduino это 5 Вольт) и вычитают из него рабочее падение напряжения на светодиоде (указано в технических характеристиках светодиода, в простейшем случае зависит от цвета - для красного около 2 Вольт), получая падение напряжение на резисторе (в данном случае 5-2=3В). И далее, по закону Ома: R = U/I, где вместо I подставляется ток в цепи - который мы и хотим ограничить, скажем 3 мА. Получаем R = 3В/0.003А = 1000 Ом. При таком раскладе светодиод будет светиться, хоть и немного тускло, но вполне приемлемо. Чтобы добиться максимума яркости, можно увеличить ток до 30 мА - изменив номинал резистора R2 на 100 Ом.

Что же получается? Если мы хотим изменить яркость свечения светодиода, надо менять значение токоограничительного резистора. В принципе, нет ничего невозможного - существуют специальные резисторы с цифровым управлением, которые управляются через шину SPI или I2C, получают от микроконтроллера значение и меняют свое сопротивление в соответствии с ним. Но едва ли это оправдано с точки зрения стоимости и удобства (пойди еще найди и купи такой компонент, не пользующийся широким спросом). Другой вариант - это простейший ЦАП на основе R-2R цепочки, но он требует использования дополнительных выходов Arduino и тоже выглядит чересчур внушительным решением для такой простой задачи. Вот тут-то, как вы уже догадались, и приходит на помощь ШИМ.

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


Вот так выглядит скетч, который плавно гасит и зажигает светодиод L:

void setup() {
  pinMode(13, OUTPUT);
}

word cycle = 300;
byte stepdelay = 20;
byte zazor = 5;

void loop() {
  for (word intensity=zazor;intensity<(cycle-zazor);intensity++) {
    for (byte k=0;k<stepdelay;k++) {
      digitalWrite(13,HIGH);
      delayMicroseconds(intensity);
      digitalWrite(13,LOW);
      delayMicroseconds(cycle-intensity);
    }
  }
  for (word intensity=(cycle-zazor);intensity>zazor;intensity--) {
    for (word k=0;k<stepdelay;k++) {
      digitalWrite(13,HIGH);
      delayMicroseconds(intensity);
      digitalWrite(13,LOW);
      delayMicroseconds(cycle-intensity);
    }
  }
}

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

Ура, мы изобрели диммер! (именно этот скетч я заливаю готовые платы перед отправкой, в качестве одного из элементов ОТК ;)

Торжество разума омрачает только одно - наш Ардуино оказался загруженным исключительно одной задачей. А если надо заставить скетч выполнять и другие операции? Как сделать генерацию PWM-сигнала фоновой и незаметной задачей?

Вот именно в этом случае нужно воспользоваться функцией аппаратного ШИМ в Arduino. Правда, работает она лишь на избранных пинах (они помечены звездочкой или надписью pwm), зато можно один раз выполнить analogWrite(pin, value), и спокойно заниматься другими делами. Вот так можно переписать скетч с использованием новой функции:

/*
 Fading
 
 This example shows how to fade an LED using the analogWrite() function.
 
 The circuit:
 * LED attached from digital pin 9 to ground.
 
 Created 1 Nov 2008
 By David A. Mellis
 Modified 17 June 2009
 By Tom Igoe
 
 http://arduino.cc/en/Tutorial/Fading
 
 */


int ledPin = 9;    // LED connected to digital pin 9

void setup()  { 
  // nothing happens in setup void loop()  { 
  // fade in from min to max in increments of 5 points:
  for(int fadeValue = 0 ; fadeValue <= 255; fadeValue +=5) { 
    // sets the value (range from 0 to 255):
    analogWrite(ledPin, fadeValue);         
    // wait for 30 milliseconds to see the dimming effect    
    delay(30);                            
  } 

  // fade out from max to min in increments of 5 points:
  for(int fadeValue = 255 ; fadeValue >= 0; fadeValue -=5) { 
    // sets the value (range from 0 to 255):
    analogWrite(ledPin, fadeValue);         
    // wait for 30 milliseconds to see the dimming effect    
    delay(30);                            
  } 
}

(на самом деле это скетч из примеров к ArduinoIDE - Analog|Fading).

Полюбоваться на его работу можно, если воткнуть светодиод длинной плюсовой ножкой в digital9, а короткой минусовой - в GND. Для счастливых владельцев Arduino Mega можно просто исправить значение константы ledPin в самом начале скетча с 9 на 13, поскольку в отличие от Duemilanova, Mega поддерживает аппаратный ШИМ на digital13.

Как видите - проще некуда. В данном случае используется аппаратная возможность atmega, связанная с работой таймеров. Но производится она внутри ядра, поэтому снаружи все выглядит так просто. И это хорошо, особенно для начинающих ;)

13.08.2010

Arduino USB ID

Свежие слухи гласят, что для Arduino будет зарегистрирован собственной уникальный USB Vendor ID.

По большому счету - бантик, но приблизительно в одном случае из 20 у пользователя оказывается уже установлен драйвер устройства, использующий дефолтные VID от FTDI (какой-то другой "вендор", не удосужившийся получить собственный VID), и начинается мучительный поиск причины неработоспособности Arduino...

Ну что же - что не делается, все к лучшему! ;)

12.08.2010

MicroSD shield (1)

Попытки интегрировать в Arduino поддержку SD-карт начались достаточно давно, и давно же увенчались успехом. Пусть вас не смущает обилие элементов на новой Ethernet Shield - ничего сложного в этом нет.

Я решил разобрать технологию доступа к SD на примере изделия libellium-а - известной испанской фирмы, занимающейся разработками в области мониторинга состояния окружающей среды. К счастью, одной из побочных ветвей их деятельности является Arduino и все с ним связанное. Их microSD шилд выглядит так:



Как видите, ничего хитроумного в этом шилде - нет. При подключении SD-карты к Arduino надо помнить пару моментов:
  1. Питание карты - 3.3В;
  2. Обмен происходит по шине SPI, требуется согласование сигналов по уровням.
Поддержка SPI в контроллерах ATmega совпадает по пинам с разъемом внутрисхемного программирования, так что можно подключаться к digital 10-12. Теоретически, питание +3.3В можно брать с питающей колодки Arduino Duemilanova, но тут, на мой взгляд, сложилась парадоксальная ситуация - хотя во многих платах и клонах Arduino пин трехвольтового питания присутствует, все шилды в обязательном порядке забивают игнорируют эту возможность и используют свой собственный регулятор +3.3В. 

Для работы надо соединить две линии сигналов данных (MISO/MOSI), тактовые (SCK) и выбор приемника (SS). Правда, тут нас ждет небольшая проблема согласования сигналов по уровням. 

Как известно, в Arduino мы имеем дело с КМОП-логикой, управляемой напряжением - один уровень соответствует логическому нулю, другой - логической единице. Реально же, при определении состояния входа КМОП, логические уровни зависят от напряжения питания, граница проходит по Vcc/2. И действительно, если мы обратимся к документации, то увидим, что логической единицей для ATmega будет напряжение более 2,5 В, а нулем - менее 2,5 В (естественно, при Vcc=5В). И в то же время, при работе в качестве выхода, КМОП будет формировать для логической единицы напряжение близкое к Vcc, а для нуля - к GND.

У работающего в SD-карте трехвольтового КМОП-а на выходе формируется логическая единица с уровнем = Vcc = 3,3В, что больше 2,5В и будет правильно восприниматься пятивольтовым входом. Но пятивольтовая единица на трехвольтовом входе крайне нежелательна, поэтому надо изыскать способ преобразовать ее в диапазон 1,65..3,3 В. Конечно, на эту тему существует обширнейшее семейство чипов, которые "в лучшем виде" организуют такие преобразования, но они в данном случае не потребуются. Для относительно невысоких скоростей обмена, можно прибегнуть к тривиальному делителю напряжения на резисторах

Я взял на себя смелость перерисовать схему устройства, тем более, что там всё просто:



Увы, я не смог идентифицировать чип в корпусе SOT23-5, хотя это явно регулятор напряжения. На нем написано "PHUI", и ни один из справочников по SMD о такой комбинации не знал. Пришлось его заменить на близкий по смыслу и корпусу NCP1400 (чип IC1 по схеме).

Updated: чип этот все-таки удалось идентифицировать - это LP2985-33BVR! Более подробно - здесь.

Делители напряжений на плате представляют пары SMD-резисторов 10K/15K - R3/R4, R5/R6 и R2/R7. Кроме сигналов SPI, слот SD-карты умеет сообщать о наличии в нем карты (сигнал CD), и этот дополнительный сигнал притянут к Vcc через R1, поскольку представляет из себя простой механический контакт, разрываемый во время вставки карты. Конденсаторы C1 и C2 выступают в качестве фильтров по питанию.

Само питание на плату подается двумя разными способами:
  1. С цифрового пина digital8 (не так уж много microSD надо для работы)
  2. C гребенки ICSP



Переключение осуществляется джампером JP4, в позиции 1-2 он подает на вход IC1 напряжение с digital8, в позиции 2-3 - со 2-го контакта разъема IСSP-6:



Дополнительная колодка JP5 (сигналы CD и SS) нужна в двух случаях:
  1. При подключении через ISP-6 (место SS занял необходимый для программирования RESET, а места для сигнала CD уже и вовсе нет);
  2. При подключении к Arduino Mega (там пин SS находится в другом месте).
При этом, линии +5В, +3.3В и GND выводятся на JP2 - просто так, на всякий случай.

Картинки вариантов подключения:





Можно использовать пин-экстендер:



В этом случае можно подключаться игнорируя шилд, у которого не заняты колодки digital 13-8, типичный пример - Arduino Motor Shield:



10.08.2010

Новая Arduino Ethernet shield

Готовится к выходу новая версия оригинальной Arduino Ethernet Shield:


Самое значимое изменение вы уже наверное заметили - добавлен слот microSD. И если раньше это был всего лишь декоративный элемент, то в грядущей версии ArduinoIDE 0019 он станет поддерживаться специальной sdfatlib, которая сейчас пока умеет только читать существующие файлы. Но, как говориться, лиха беда - начало!

Кроме этого, при подключении через ISCP-гребенку шилд будет совместим с Arduino MEGA, а также будет содержать дополнительный контроллер сброса, снимающий некоторые проблемы с работой Arduino+Shield сразу после подачи питания.

Кстати, ArduinoIDE 0019 выходит в конце недели. Редакция будет следить за развитием событий ;)

06.08.2010

Металлоискатели


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

Вот что пишет автор этой книги, Андрей Щедрин, в неопубликованном фрагменте предисловия к 3-му изданию:

Эпоха, в которую мы живем - это эпоха сплошных суррогатов. Наука подменяется ремеслом, творчество – плагиатом, товары - китайским ширпотребом, культура – телевидением (перечислять можно долго). Человек эпохи суррогатов, не прилагающий никаких усилий, обречен на деградацию. Добродушный Иванушка-дурачок из старых сказок давно превратился в слабоумного Лёню Голубкова. А лень, наряду с дорогами и дураками – одна из бед нашей страны. Ведь “троечник”, списывающий у соседа контрольную и даже не пытающийся потрудиться над собой, превратится, в лучшем случае, в бездарного инженера, бездарного журналиста, бездарного политика… Тридцать лет назад в книжке “Занимательная математика” Перельман рассказывал школьникам о финансовых “пирамидах”. Но видимо, и творцы ГКО, и жертвы “МММ” - не читали в детстве книжек!..

Снимаю шляпу, подписываюсь под всеми словами и горячо благодарю за потраченный труд!

03.08.2010

Набор USBasp

Честно говоря, никогда бы не подумал, что будет столько желающих собрать USBasp самостоятельно... Но без печатной платы - сами понимаете - сборка превращается в муторное занятие, раза в 2-3 скучнее вышивания - чем сложнее схема, тем меньше получающийся в финале рисунок из проводков и деталек похож на бумажный эквивалент. То ли дело, когда есть печатная плата - уже просверленная и залуженная! 


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