Урок 1.7. Транзистор. Управление скоростью вращения мотора
Базовый курс "Программирование микроконтроллеров"
Модуль 1. Введение в Arduino. Работа с цифровым и аналоговым сигналом
Транзистор
Каждый начинающий робототехник сталкивается с проблемой подключения двигателя к микроконтроллеру. Пройдя урок по управлению светодиодом кажется, что с двигателем можно поступить точно также: подключить его к цифровым выводам Arduino, а затем включать и выключать по программе.
Но не тут-то было. Даже небольшой двигатель, часто используемый в разного рода игрушках, для своей работы требует ток силой от 200 мА до 1 Ампера. А цифровой выход Arduino может дать нам только 20мА. Большинству мощных двигателей требуется напряжение более 5 Вольт, привычных для Arduino. Распространены двигатели на 12, на 24 и на 48 Вольт. Другими словами, Arduino очень слаба для прямого управления двигателями. Нужен какой-то мощный посредник! Самый простой посредник — это транзистор.
Транзистор — это электронный компонент из полупроводникового материала, способный небольшим входным сигналом управлять значительным током в выходной цепи.
Подойдут и полевые транзисторы, и биполярные, работающие в режиме ключа. Давайте рассмотрим схемы таких цепей.
Схема управления двигателем при помощи биполярного NPN-транзистора
Как видим, схема очень простая. Подаем на базу транзистора слабый сигнал от Arduino через резистор 1кОм, вследствие чего транзистор открывает мощный канал, по которому ток проходит от плюса к минусу, через двигатель. По сути, мы получили примитивный драйвер двигателя!
Обратите внимание: в цепи обязательно нужно поставить защитный диод, например 1N4001 или 1N4007. Этот диод не даст сгореть транзистору и контроллеру в момент остановки двигателя, когда ЭДС самоиндукции создаст на обмотках скачок напряжения.
Схема управления мотором через полевой транзистор
В этой схеме можно использовать NPN транзистор КТ850А с током коллектор-эмиттер 2 Ампера. Мотор F130, который мы используем в этом уроке, при пуске может потреблять ток до 1 А, так что транзистор должен иметь некоторый запас по току.
В этой схеме можно использовать NPN транзистор КТ850А с током коллектор-эмиттер 2 Ампера. Мотор F130, который мы используем в этом уроке, при пуске может потреблять ток до 1 А, так что транзистор должен иметь некоторый запас по току.
Зачем нужны резисторы?
Резистор на 100 Ом (можно ставить в диапазоне 100-500 Ом, мощность любая) выполняет защитную функцию: затвор полевика представляет собой конденсатор, в момент открытия затвора конденсатор начнёт заряжаться и в цепи пойдёт большой ток (практически короткое замыкание), который может повредить пин Arduino. Резистор просто ограничивает ток в цепи пин-затвор и спасает пин от скачков тока. В целом можно его не ставить, но когда-нибудь оно обязательно сломается, увы.
Резистор на 10 кОм (можно ставить в диапазоне 5-50 кОм, мощность любая) выполняет подтягивающую функцию для затвора. Если случится так, что плата Arduino выключена или сигнальный провод от неё отвалился – на затвор будут приходить случайные наводки и он может случайно открыться. Если в этот момент будет подключен источник питания – нагрузка тоже включится! Восстание машин начнётся именно с этого момента. Подтягивающий к GND резистор позволяет “прижать” затвор, чтобы он не открылся сам по себе.
Обратите внимание: с помощью одного транзистора мы можем включать и выключать двигатель постоянного тока в одном направлении.
Схема подключения и программа управления мотором через полевой транзистор
Соберем схему управления электродвигателем с помощью потенциометра на одном полевом транзисторе. Внимательно ознакомьтесь с распиновкой транзистора.
Принцип управление нагрузкой через транзистор точно такой же, как и управление светодиодом. Напишем простую программу для проверки работы мотора. В итоге мы должны увидеть как мотор включается и выключается каждую секунду.
const int motor = 3;
void setup() {
Serial.begin(9600);
pinMode(motor, OUTPUT);
}
void loop() {
digitalWrite(motor, HIGH);
delay(1000);
digitalWrite(motor, LOW);
delay(1000);
}
Добавим уже знакомые нам строчки когда, для управления вращением мотора с помощью потенциометра:
const int motor = 3;
const byte pot = A0;
int val = 0;
void setup() {
Serial.begin(9600);
pinMode(motor, OUTPUT);
pinMode(pot, INPUT);
}
void loop() {
val = analogRead(pot);
val = map(val,0,1023,0,255);
Serial.println(val);
analogWrite(motor, val);
}
Теперь с помощью одного транзистора мы можем включать и выключать двигатель постоянного тока, но только в одном направлении. Но что делать, если мы хотим вращать мотором в разные стороны? Нужна более сложная схема, а именно драйвер двигателя!
Драйвер двигателя L293D. Н-мост
Составив транзисторы определенным образом, мы получим устройство для управления вращением двигателя в обе стороны. Такое устройство называется H-мост. Вот так выглядит H-мост на биполярных PNP и NPN транзисторах:
IN1 и IN2 на рисунке — это вход слабых управляющих сигналов. В случае Ардуино, на них необходимо подавать либо 0 (земля) либо +5В;
VCC — это питание двигателей, оно может быть во много раз выше напряжения управляющего сигнала;
GND — это земля, общая для Ардуино и H-моста.
В зависимости от того, на какой из входов мы подаем положительный сигнал, двигатель будет крутиться в одну или в другу сторону. Как правило, в схему драйвера двигателя постоянного тока помимо самого H-моста, добавляют защитные диоды, фильтры, опторазвязки и прочие улучшения.
Разумеется, необязательно собирать драйвер двигателя вручную из отдельных транзисторов. Существует множество готовых микросхем, которые позволяют управлять разными типами двигателей. Мы рассмотри распространенный драйвер L293D.
Микросхема представляет собой два H-моста, а значит можно управлять сразу двумя двигателями. Каждый мост снабжен четырьмя защитными диодами и защитой от перегрева. Максимальный ток, который может передать L293D на двигатель — 1.2А. Рабочий ток — 600мА. Максимальное напряжение — 36 В.
Микросхема L293D имеет DIP корпус с 16-ю выводами. Схема выводов представлена ниже.
Наглядно представить управление мотором с помощью драйвера можно следующим образом: ножки IN1 и IN2 являются цифровыми входами, а в зависимости от их положения изменяется направление или состояния вращения мотора:
IN1 – высокий уровень, IN2 – низкий уровень и EN1 скорость вращения → мотор вращается вправо;
IN1 – низкий уровень, IN2 – высокий уровень и EN1 скорость вращения → мотор вращается влево;
IN1 – низкий уровень, IN2 – низкий уровень и EN1 максимальное значение 255 → мотор заблокирован;
IN1 – высокий уровень, IN2 – высокий уровень и EN1 максимальное значение 255 → мотор заблокирован;
IN1 – низкий уровень, IN2 – низкий уровень и EN1 значение 0 → мотор не двигается.
Соберем схему управления мотором с помощью драйвера двигателя:
Программа движения мотора в разные стороны
const int motor = 3;
const byte pot = A0;
const byte EN1 = 5;
const byte IN1 = 3;
const byte IN2 = 2;
int val = 0;
void setup() {
Serial.begin(9600);
pinMode(EN1, OUTPUT);
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(pot, INPUT);
}
void loop() {
// включаем мотор на движение вперед
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
analogWrite(EN1, 255);
delay(2000);
// останавливаем мотор
digitalWrite(IN1, HIGH);
digitalWrite(IN2, HIGH);
analogWrite(EN1, 255);
delay(2000);
// включаем мотор на движение назад
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
analogWrite(EN1, 255);
delay(2000);
// останавливаем мотор
digitalWrite(IN1, HIGH);
digitalWrite(IN2, HIGH);
analogWrite(EN1, 255);
delay(2000);
}
Для удобства управления мотором напишем специальную функцию.
Функции — это блоки кода, выполняющие определенные операции. Если требуется, функция может определять входные параметры, позволяющие вызывающим объектам передавать ей аргументы. При необходимости функция также может возвращать значение как выходное.
На самом деле setup и loop это тоже функции, внутри которых мы пишем свой код, создавать свою функцию необходимо за в любом месте пределами этих функций.
Создадим такую функцию, например, после функции void loop().
const int motor = 3;
const byte pot = A0;
const byte EN1 = 5;
const byte IN1 = 3;
const byte IN2 = 2;
int val = 0;
void setup() {
Serial.begin(9600);
pinMode(EN1, OUTPUT);
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(pot, INPUT);
}
void loop() {
// включаем мотор на движение вперед
drive(255);
delay(2000);
// останавливаем мотор
drive(0);
delay(2000);
// включаем мотор на движение назад
drive(-255);
delay(2000);
// останавливаем мотор
drive(0);
delay(2000);
}
// описание функции для управления мотором
void drive(int power) {
// обрезаем число, которое будет передано в функцию в качестве параметра power
power = constrain(power, -255, 255);
// если введенная мощность больше или равна нулю то вращаем мотор вперед
if (power > 0) {
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
} else // если введенная мощность меньше нуля то вращаем мотор назад
{
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
}
// передаем в команду ШИМ управления скоростью модуль числа power
analogWrite(EN1, abs(power));
}
Теперь управлять мотором гораздо удобнее!
Программа плавного изменения скорости вращения мотора
Следующая программа будет плавно изменять скорость мотора в одну и другую сторону:
const int motor = 3;
const byte pot = A0;
const byte EN1 = 5;
const byte IN1 = 3;
const byte IN2 = 2;
int val = 0;
void setup() {
Serial.begin(9600);
pinMode(EN1, OUTPUT);
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(pot, INPUT);
}
void loop() {
// мотор разгоняется от 0 до 255
for (int i = 0; i < 255; i++) {
drive(i);
delay(20);
}
// мотор замедляется от 255 до 0
for (int i = 255; i > 0; i--) {
drive(i);
delay(20);
}
}
// описание функции для управления мотором
void drive(int power) {
// обрезаем число, которое будет передано в функцию в качесте параметра power
power = constrain(power, -255, 255);
// если введенная мощность больше или равна нулю то вращаем мотор вперед
if (power > 0) {
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
} else // если введенная мощность меньше нуля то вращаем мотор назад
{
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
}
// передаем в команду ШИМ управления скоростью модуль числа power
analogWrite(EN1, abs(power));
}
Программа управления мотором с потенциометра
Ну и на последок настроим управление мотором ручкой потенциометра. Обратите внимание на масштабирование, которое мы будем применять к показаниям потенциометра:
Среднее положение ручки потенциометра определяет остановку мотора;
Поворот ручки вправо будет масштабироваться в скорость движение мотора вперед;
Поворот ручки влево будет масштабироваться в скорость движения мотора назад.
const int motor = 3;
const byte pot = A0;
const byte EN1 = 5;
const byte IN1 = 3;
const byte IN2 = 2;
int val = 0;
void setup() {
Serial.begin(9600);
pinMode(EN1, OUTPUT);
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(pot, INPUT);
}
void loop() {
val = analogRead(pot);
int power = map(val, 0, 1023, -255, 255);
Serial.println(power);
drive(power);
}
// описание функции для управления мотором
void drive(int power) {
// обрезаем число, которое будет передано в функцию в качесте параметра power
power = constrain(power, -255, 255);
// если введенная мощность больше или равна нулю то вращаем мотор вперед
if (power > 0) {
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
} else // если введенная мощность меньше нуля то вращаем мотор назад
{
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
}
// передаем в команду ШИМ управления скоростью модуль числа power
analogWrite(EN1, abs(power));
}