Во многих случаях мини-компьютеры, такие как: 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?
Здравствуйте! Спасибо за статью! Управление вентилятором работает (с помощью биполярного 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.
In urban areas, fighting dogs can often be seen from a public vantage point and dogfighting paraphernalia is often kept in plain view in yards, garages and homes, such that the items are often easily encountered when officers are on the premises for unrelated business, such as drug raids, domestic violence complaints or execution of arrest warrants otc clomiphene citrate McCormick, Carol Bishopric and Richard Chang Danny LauogxiOAw 6 18 2022