Во многих случаях мини-компьютеры, такие как: Raspberry Pi, Orange Pi, Banana Pi и т.п., поставляется с небольшим вентилятором на 5 В, чтобы можно было охлаждать процессор (вернее — СнК/SoC) компьютера. Тем не менее, эти вентиляторы обычно довольно шумные, и многие подключают его к выводу на 3.3 В, чтобы уменьшить шум. Вентиляторы обычно рассчитаны на 200 мА, что довольно много для регулятора на 3.3 В на Raspberry Pi.
Этот проект научит вас, как регулировать скорость вращения вентилятора в зависимости от температуры процессора. В отличие от большинства руководств, охватывающих эту тему, мы не только включим или выключим вентилятор, но и будем контролировать его скорость с помощью ШИМ, как это делается на обычном ПК.
- 1 Что такое ШИМ?
- 2 Управление вентилятором с помощью биполярного NPN-транзистора
- 3 Управление вентилятором с помощью МОП транзистора
- 4 Как получить температуру процессора
- 5 Включение вентилятора при заданной температуре
- 6 ШИМ управление: Пример 1
- 7 ШИМ управление: Пример 2
- 8 Как поместить скрипт в автозагрузку
- 9 Как проверить?
- 10 Удаление скрипта из автозагрузки
- 11 Материалы
- 12 Похожие записи
Что такое ШИМ?
Широтно-импульсная модуляция (ШИМ, англ. pulse-width modulation (PWM)) — процесс управления мощности методом пульсирующёго включения и выключения прибора. Различают аналоговую ШИМ и цифровую ШИМ, двоичную (двухуровневую) ШИМ и троичную (трёхуровневую) ШИМ. Основной причиной применения ШИМ является стремление к повышению КПД при построении вторичных источников питания электронной аппаратуры и в других узлах, например, ШИМ используется для регулировки яркости подсветки LCD-мониторов и дисплеев в телефонах, КПК и т.п..
Управление вентилятором с помощью биполярного NPN-транзистора
Первое что приходит на ум — поставить биполярный NPN-транзистор. Вентилятору требуется 200мА, поэтому ищем транзистор с коллекторным током более 200мА, лучше раза в 2-3. В импортных даташитах этот параметр называется Ic, в наших Iк. Подойдут транзисторы: 2N5550, 2N5551, 2N2222A и т.д.. У транзистора, в первую очередь, надо определить назначение выводов. Где у него коллектор, где база, а где эмиттер. Сделать это лучше всего по даташиту или справочнику.
Схема подключения вентилятора
Берем транзистор и подключаем его по такой схеме:
Таким образом, при подаче «1» на вход нашей схемы ток от источника питания потечёт через резистор R1, базу и эмиттер на землю. При этом транзистор откроется и ток сможет идти через переход коллектор-эмиттер, а значит и через нагрузку (вентилятор).
Резистор R1 играет важную роль — он ограничивает ток через переход база-эмиттер. Если бы его не было, ток не был бы ничем ограничен и просто испортил бы управляющую микросхему (ведь именно она связывает линию питания с транзистором).
Кроме того, нужно помнить, что нагрузка индуктивная и нужен защитный диод D1. Дело в том, что энергия, запасённая магнитным полем, не даёт мгновенно уменьшить ток до нуля при отключении ключа. А значит, на контактах нагрузки возникнет напряжение обратной полярности, которое легко может нарушить работу контроллера или даже повредить его.
Управление вентилятором с помощью МОП транзистора
Вместо биполярного можно использовать полевой транзистор — MOSFET, то есть полевые транзисторы с изолированным затвором (они же МОП, они же МДП). Они удобны тем, что управляются исключительно напряжением: если напряжение на затворе больше порогового, то транзистор открывается. При этом управляющий ток через транзистор пока он открыт или закрыт не течёт. Это значительное преимущество перед биполярными транзисторами, у которых ток течёт всё время, пока открыт транзистор.
В дальнейшем мы будем использовать только n-канальные MOSFET. Это связано с тем, что n-канальные транзисторы дешевле, имеют лучшие характеристики и для управления N-канальным полевиком необходимо приложить положительное напряжение на затвор относительно истока.
Схема подключения вентилятора
Нагрузка подключена к стоку («сверху»). Если подключить её «снизу», то схема работать не будет. Дело в том, что транзистор открывается, если напряжение между затвором и истоком превышает пороговое. При подключении «снизу» нагрузка будет давать дополнительное падение напряжения, и транзистор может не открыться или открыться не полностью.
Резистор R1 на 100 Ом ограничивает ток заряда-разряда, а резистор R2 на 10 кОм — это стягивающий резистор, что в неопределенном состоянии «стягивает» потенциал к земле.
Кроме того, нужно помнить, что нагрузка индуктивная и нужен защитный диод D1.
N-канальные MOSFET с логическим уровнем управления
Один из минусов МОП транзисторов — это высокое пороговое напряжение затвора, больше 3.3 В. Тем не менее, существуют N-канальные транзисторы с логическим уровнем управления, например: IRL2505, FDN337N, ZVN4306A, 2N7000, PMV16XNR, NTZD3155C, IRLZ24NPBF, IRL520NPBF и т.п.
Как получить температуру процессора
Существует несколько способов получить текущую температуру процессора.
Если вы используйте Armbian, вы можете использовать команду:
armbianmonitor -m
эта команда будет давать вам время работы, частоту и текущую температуру процессора каждые 6 секунд.
Есть еще одна команда, которая просто возвращает температуру процессора:
cat /sys/devices/virtual/thermal/thermal_zone1/temp
или
cat /sys/devices/virtual/thermal/thermal_zone0/temp
или
cat /sys/class/thermal/thermal_zone0/temp
Внутри SoC Allwinner есть два датчика, вы можете взять оба значения, чтобы получить среднюю температуру. На Raspberry Pi температура измеряется в миллиградусах, для перевода в градусы Цельсия нужно разделить полученное число на 1000:
В Raspberry Pi можно узнать температуру процессора при помощи ввода консольной команды:
vcgencmd measure_temp
Включение вентилятора при заданной температуре
Ниже приведённые примеры используют WiringPi и, если библиотека у вас не установлена, установите её, инструкции тут: WiringPi, WiringOP или BPI-WiringPi.
Самый простой пример управления вентилятором — это его включение, при достижении критичной температуры, и выключение, если температура ниже. Если шум вентилятора не мешает, тогда можно использовать такой вариант.
#include <iostream> #include <fstream> #include <wiringPi.h> #include <unistd.h> #define PIN 7 #define TEMPERATURE_MIN 55 using namespace std; static int getTemperature() { static fstream myfile; int temperature = 0; myfile.open("/sys/devices/virtual/thermal/thermal_zone0/temp", ios_base::in); myfile >> temperature; myfile.close(); return temperature; } int main() { int temperature; int pinState = 0; try { if (wiringPiSetup() == 0) { pinMode(PIN, OUTPUT); while (1) { temperature = getTemperature(); if (temperature >= TEMPERATURE_MIN && pinState == 0) { digitalWrite(PIN, HIGH); pinState = 1; } else if (temperature < (TEMPERATURE_MIN - 10) && pinState == 1) { digitalWrite(PIN, LOW); pinState = 0; } usleep(1000 * 1000); } } } catch (exception& e) { cerr << e.what() << endl; } return 0; }
Программа работает следующим образом — при достижении заданной температуры (более 55°С) вентилятор включается, и отключается только когда температура снизится более чем на 10°С от максимального порога (менее 45°С).
Температуру получаем с помощью функции static int getTemperature()
. На Raspberry Pi температура измеряется в миллиградусах, для перевода в градусы Цельсия нужно разделить полученное число на 1000 и необходимо будет внести несколько изменений,
вместо:
static int getTemperature() { static fstream myfile; int temperature = 0; myfile.open("/sys/devices/virtual/thermal/thermal_zone0/temp", ios_base::in); myfile >> temperature; myfile.close(); return temperature; }
использовать:
static int getTemperature() { static fstream myfile; int temperature = 0; myfile.open("/sys/devices/virtual/thermal/thermal_zone0/temp", ios_base::in); myfile >> temperature; myfile.close(); return temperature / 1000; }
Компиляция, сборка и запуск программы
Сознаём файл FanPiOnOff.cpp
и вставляем вышеприведённый код:
nano FanPiOnOff.cpp
Компилируем и собираем программу:
g++ -Ofast -Wall FanPiOnOff.cpp -lwiringPi -lpthread -o FanPiOnOff
Запускаем:
./FanPiOnOff
если хотим запустить программу в фоновом режиме:
nohup ./FanPiOnOff &
ШИМ управление: Пример 1
Логика программы такова — при достижении заданных температур вентилятор включается с определённым коэффициентом заполнения, а отключается только тогда, когда температура ниже минимального порога:
- 45 °C -> 35 %
- 50 °C -> 50 %
- 60 °C -> 75 %
- 75 °C -> 100 %
#include <iostream> #include <fstream> #include <wiringPi.h> #include <softPwm.h> #include <unistd.h> #define PIN 7 #define RANGE 100 #define PWM_VALUE1 35 #define PWM_VALUE2 50 #define PWM_VALUE3 75 #define PWM_VALUE4 100 #define TEMPERATURE_1 45 #define TEMPERATURE_2 50 #define TEMPERATURE_3 60 #define TEMPERATURE_4 70 using namespace std; static int getTemperature() { static fstream myfile; int temperature = 0; myfile.open("/sys/devices/virtual/thermal/thermal_zone0/temp", ios_base::in); myfile >> temperature; myfile.close(); return temperature; } int main() { int temperature; bool pwmStopped = true; try { if (wiringPiSetup() == 0) { while (1) { temperature = getTemperature(); if (temperature > TEMPERATURE_4) { if (pwmStopped) { softPwmCreate(PIN, ((PWM_VALUE4 * RANGE) / 100), RANGE); pwmStopped = false; } else { softPwmWrite(PIN, ((PWM_VALUE4 * RANGE) / 100)); } } else if (temperature > TEMPERATURE_3) { if (pwmStopped) { softPwmCreate(PIN, ((PWM_VALUE3 * RANGE) / 100), RANGE); pwmStopped = false; } else { softPwmWrite(PIN, ((PWM_VALUE3 * RANGE) / 100)); } } else if (temperature > TEMPERATURE_2) { if (pwmStopped) { softPwmCreate(PIN, ((PWM_VALUE2 * RANGE) / 100), RANGE); pwmStopped = false; } else { softPwmWrite(PIN, ((PWM_VALUE2 * RANGE) / 100)); } } else if (temperature > TEMPERATURE_1) { if (pwmStopped) { softPwmCreate(PIN, ((PWM_VALUE1 * RANGE) / 100), RANGE); pwmStopped = false; } else { softPwmWrite(PIN, ((PWM_VALUE1 * RANGE) / 100)); } } else { softPwmStop(PIN); pwmStopped = true; } usleep(1000 * 1000); } } } catch (exception& e) { cerr << e.what() << endl; } return 0; }
Компиляция, сборка и запуск программы
Сознаём файл FanPiPWM.cpp
и вставляем вышеприведённый код:
nano FanPiPWM.cpp
Компилируем и собираем программу:
g++ -Ofast -Wall FanPiPWM.cpp -lwiringPi -lpthread -o FanPiPWM
Запускаем:
./FanPiPWM
если хотим запустить программу в фоновом режиме:
nohup ./FanPiPWM &
ШИМ управление: Пример 2
Также можно менять коэффициент заполнения линейно. В таком случае программе нужно задать минимальную температуру срабатывания и минимальный коэффициент заполнения, к примеру 45°C и 35% соответственно, а на максимальную температуру (к примеру 70°C) — коэффициент в 100%. Рассчитывается коэффициент заполнения с помощью функции static int map(int x, int inMin, int inMax, int outMin, int outMax);
.
#include <iostream> #include <fstream> #include <wiringPi.h> #include <softPwm.h> #include <unistd.h> #define PIN 7U #define RANGE_MAX 100 #define RANGE_MIN 35 #define TEMPERATURE_MAX 70 #define TEMPERATURE_MIN 45 using namespace std; static int getTemperature() { static fstream myfile; int temperature = 0; myfile.open("/sys/devices/virtual/thermal/thermal_zone0/temp", ios_base::in); myfile >> temperature; myfile.close(); return temperature; } static int map(int x, int inMin, int inMax, int outMin, int outMax) { if (x < inMin) { return outMin; } else if (x > inMax) { return outMax; } return (x - inMin) * (outMax - outMin) / (inMax - inMin) + outMin; } int main() { int temperature; int pwmValue; bool pwmStopped = true; try { if (wiringPiSetup() == 0) { while (1) { temperature = getTemperature(); pwmValue = map(temperature, TEMPERATURE_MIN, TEMPERATURE_MAX, RANGE_MIN, RANGE_MAX); if (temperature >= TEMPERATURE_MIN && pwmStopped) { softPwmCreate(PIN, pwmValue, RANGE_MAX); pwmStopped = false; } else if (temperature >= (TEMPERATURE_MIN - 5) && !pwmStopped) { softPwmWrite(PIN, pwmValue); } else { if (!pwmStopped) { softPwmStop(PIN); } pwmStopped = true; } usleep(1000 * 1000); } } } catch (exception& e) { cerr << e.what() << endl; } return 0; }
Компиляция, сборка и запуск программы
Сознаём файл FanPiPwmLinear.cpp
и вставляем вышеприведённый код:
nano FanPiPwmLinear.cpp
Компилируем и собираем программу:
g++ -Ofast -Wall FanPiPwmLinear.cpp -lwiringPi -lpthread -o FanPiPwmLinear
Запускаем:
./FanPiPwmLinear
если хотим запустить программу в фоновом режиме:
nohup ./FanPiPwmLinear &
Как поместить скрипт в автозагрузку
Остается сделать так, чтобы скрипт, контролирующий работу вентилятора охлаждения, автоматически запускался каждый раз при загрузке системы.
Для этого, в конец файла /etc/rc.local
:
sudo nano /etc/rc.local
Нужно поместить команду запуска скрипта перед строкой exit 0
:
sudo ./home/pi/FanPiPwmLinear &
После перезагрузки скрипт будет автоматически запущен и вентилятор будет включаться при наступлении заданных условий.
Чтобы проверить факт запуска, после перезагрузки, нужно переключиться в терминал и проверить наличие процесса:
ps aux | grep -i FanPiPwmLinear
Как проверить?
Для проверки работоспособности скрипта нужно «разогреть» процессор до нужной температуры и посмотреть, как на это будет реагировать система охлаждения. «Нагревать» процессор можно с помощью утилит sysbench
или stress
. Вы можете установить эти утилиты с aptitude
:
sudo apt-get install sysbench
или
sudo apt-get install stress
Запуск утилиты с задействованием 4 ядер:
sysbench --num-threads=4 --test=cpu --cpu-max-prime=20000 --validate run
или
sudo stress --cpu 4 --timeout 30s
Температура процессора сразу начнет повышаться.
Принудительно завершить, как выполнение теста утилитой sysbench
, так и stress
можно сочетанием клавиш Ctrl+C
.
Удаление скрипта из автозагрузки
Для удаления скрипта из автозагрузки нужно просто удалить строку с запуском скрипта из файла /etc/rc.local
.
Материалы
Управление мощной нагрузкой постоянного тока. Часть 1
Управление мощной нагрузкой постоянного тока. Часть 3.
Raspberry Pi 3: GPIO (#3) — умное управление собственным активным охлаждением
Управление мощной нагрузкой
Широтно-импульсная модуляция
Здравствуйте.
У меня BPI M2Ultra с чипом A40i. Установил Armbian последний с оф.сайта.
К сожалению температура процессора не доступна, ни одно приложение не находит сенсоров. Возможно потому, что A40i начали недавно устанавливать в эту плату.
Есть желание подключить DS18B20 и используя ваши примеры, организовать мониторинг и smart-охлаждение.
Есть ли возможность заменить транзистор и резисторы одним транзистором типа MOSFET K3919?
Gate Cut-off Voltage VGS(off) от 2.0 до 3.0 V, так что подойдёт для 3,3В
Можете подсказать как в схему его включить? Спасибо)
Тут найдёте документацию:
http://www.radioradar.net/datasheet_search/K/3/9/K3919_NEC.pdf.html
http://www.radioradar.net/files.html?fid=614262
На седьмой странице найдёте распиновку вашего экземпляра.
А подключайте так, как указанно в статье или на второй странице документа:
Source —- GND
Drain —- Минус (-) мотора
Gate —- Управляющий (ШИМ)
Здравствуйте! Спасибо за статью! Управление вентилятором работает (с помощью биполярного NPN-транзистора) но вот столкнулся я такими нюансами.
1) Если использовать простой пример управления, то при понижении температуры «TEMPERATURE_MIN» на 1 градус (а мож и меньше), то вентилятор сразу включается, т.е. получается что идёт включение / выключение чуть ли не каждую секунду. Я программист ещё тот, так знаю как «Hello World» вывести, попробовал исправить ситуацию через do … while..
int main() {
int temperature;
int pinState = 0;
try {
if (wiringPiSetup() == 0) {
pinMode(PIN, OUTPUT);
while (1) {
temperature = getTemperature();
if (temperature >= TEMPERATURE_MIN && pinState == 0) {
digitalWrite(PIN, HIGH);
do{
// digitalWrite(PIN, HIGH);
pinState = 1;
temperature = getTemperature();
usleep(1000 * 5000);
}
while (temperature > TEMPERATURE_END);
}
else if (temperature < TEMPERATURE_END && pinState == 1) {
digitalWrite(PIN, LOW);
pinState = 0;
}
usleep(1000 * 5000);
}
}
} catch (exception& e) {
cerr << e.what() << endl;
}
return 0;
}
2) С управлением ШИМ непонятности — при понижении коэффициента вентилятор начинает жутко звучать, ещё громче чем при полных оборотах. Это так и должно быть? Или какой-то спецвентилятор надо?
Можно ли как-то использовать аппаратный ШИМ? У чипа H3 он вроде бы есть.
Link vao fun88 cung cấp cho người dùng một trải nghiệm cá cược tuyệt vời với nhiều trò chơi hấp dẫn.