Плавное изменение оборотов асинхронного вентилятора переменного тока с помощью Arduino.
- Войдите на сайт для отправки комментариев
Здравствуйте уважаемые форумчане.Обращаюсь с такой проблемой:
Недавно решил своими силами сделать устройство позволяющее плавно менять скорость вентилятора(асинхронного 220 V) в зависимости от температуры.
Для начала решил подключить датчик температуры DS18B20 и прописать логику, для проверки использовал стандартный ШИМ arduino + двигатель постоянного тока через MOSFET. Результат меня более чем устроил, все завелось с пол пинка и олично выполняло свои функции.
Датчик температуры DS18B20 , использовал стандартные библиотеки.
Первый потенциометр VAR_REZ задаёт температуру включения вентиляции (на наименьших оборотах) , второй потенциометр VAR_REZ2 задает температуру на которой вентилятор выйдет на максимальные обороты. Соотношением этих двух резисторов можно довольно тонко настроить соотношение эффективности охлаждения к уровню шума.
вот код: (сильно не ругайте он первый у меня:)
#include <OneWire.h>
#include <DallasTemperature.h>
#define VAR_REZ A0
#define VAR_REZ2 A1
#define ONE_WIRE_BUS 10//назначение термодатчика на пин 10
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
int led = 13;
int pwm = 9;
void setup(void)
{
pinMode(led, OUTPUT);
pinMode(pwm, OUTPUT);
Serial.begin(9600);
Serial.println("Start");
analogWrite(pwm, 255);
delay(2000);
sensors.begin();
}
void loop(void)
{
int valrez = analogRead(VAR_REZ);
int valrez2 = analogRead(VAR_REZ2);
int tempmin = map(valrez,147,1023,2000,5000) ;
int tempmax = map(valrez2,135,1023,2000,5000) ;
Serial.print(" Requesting temperatures...");
sensors.requestTemperatures(); // Send the command to get temperatures
Serial.println("DONE");
Serial.print("min temp-");
Serial.println(tempmin);
Serial.print("max temp-");
Serial.println(tempmax);
Serial.println(valrez);
Serial.println(valrez2);
int pwmval = map(sensors.getTempCByIndex(0)*100,tempmin,tempmax,10,255);
Serial.print("pwm-");
Serial.println(pwmval);
if (sensors.getTempCByIndex(0)*100<tempmin)
{analogWrite(pwm, 0);}
else if (sensors.getTempCByIndex(0)*100>tempmax)
{analogWrite(pwm, 255);}
else if (sensors.getTempCByIndex(0)*100>tempmin)
{analogWrite(pwm, pwmval);}
Serial.print("Temperature: ");
Serial.print(sensors.getTempCByIndex(0));
if (sensors.getTempCByIndex(0)*100>tempmin) digitalWrite(led, HIGH);
if (sensors.getTempCByIndex(0)*100<tempmin) digitalWrite(led, LOW);
}
Вдохновлённый первым успехом решил начинать с 220v... И тут начались настоящие траблы))Первым ударом было то что придётся отказаться от любимой функции analogWrite,вторым-то что придётся мутить обратную связь и.т.д.
Короче в какой то момент начал понимать что задачу не по зубам взял...Но в какой то момент натолкнулся на статью, собрал устройство (пришлось немного изменить номиналы резисторов ) залил скетч из первого поста ,протестировал и понял что данный диммер полностью подходит для моих целей. И с разбегу переписал свой скетч добавив туда код и библиотеки диммера. И всё как будто заработало- логика выполняется , скорость вращения меняется....но вентилятор вращается с прерываниями которое задаёт опрос датчика температуры !!! (видно когда порт мониториш)
В варианте с стандартным ШИМом такого не наблюдалось.Всю голову сломал то ли значение Dimmer1 сбрасывается почему то, при опросе датчика температуры, или конфликт библиотек.( может <DallasTemperature.h> тоже timer 1 использует )
но это всё лиш догадки...
В общем даже не знаю в какую сторону смотреть т.к. это первый проэкт на МК.
Буду рад любым предложениям, советам, критике , примерам)
Всем заранее спасибо)
Вот код переделаный:
Здесь все библиотеки использованые в проэкте.
#include "nanopins.h" //быстрое управление пинами
#include <TimerOne.h> //использует Timer1
#include <OneWire.h>
#include <DallasTemperature.h>
#define VAR_REZ A0
#define VAR_REZ2 A1
#define ONE_WIRE_BUS 10//назначение термодатчика на пин 10
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
int led = 13;
volatile uint8_t tic, Dimmer1, Dimmer2, Dimmer3;
void setup()
{
D4_Out; //Настраиваем порт на выход Dimmer1
D5_Out; //Настраиваем порт на выход Dimmer2
D6_Out; //Настраиваем порт на выход Dimmer3
D4_Low; D5_Low; D6_Low; //установить на выходах низкий уровень сигнала
D2_In; //настраиваем порт на вход для отслеживания прохождения сигнала через ноль
pinMode(led, OUTPUT);
Serial.begin(9600);
Serial.println("Start");
sensors.begin();
attachInterrupt(0, detect_up, FALLING); // настроить срабатывание прерывания int0 на pin 2
Timer1.initialize(40); // Интервал срабатывания таймера в мкс
Timer1.attachInterrupt(halfcycle); //будет вызыватся каждый раз при отсчете заданого времени
Timer1.stop();
}
//********************обработчики прерываний*******************************
void halfcycle() //прерывания таймера
{
tic++; //счетчик
if(Dimmer1 < tic ) D4_High; //управляем выходом
if(Dimmer2 < tic ) D5_High; //управляем выходом
if(Dimmer3 < tic ) D6_High; //управляем выходом
}
void detect_up() // обработка внешнего прерывания. Сработает по переднему фронту синусоиды
{
tic=0; //обнулить счетчик
Timer1.resume(); //запустить таймер
attachInterrupt(0, detect_down, RISING); //перепрограммировать прерывание на другой обработчик
}
void detect_down() // обработка внешнего прерывания. Сработает по заднему фронту синусоиды
{
Timer1.stop(); //остановить таймер
D4_Low; D5_Low; D6_Low; //логический ноль на выходы
tic=0; //обнулить счетчик
attachInterrupt(0, detect_up, FALLING); //перепрограммировать прерывание на другой обработчик
}
//*************************************************************************
void loop()
{
int valrez = analogRead(VAR_REZ);
int valrez2 = analogRead(VAR_REZ2);
int tempmin = map(valrez,147,1023,2000,5000) ;
int tempmax = map(valrez2,135,1023,2000,5000) ;
Serial.print(" Requesting temperatures...");
sensors.requestTemperatures(); // Send the command to get temperatures
Serial.println("DONE");
Serial.print("min temp-");
Serial.println(tempmin);
Serial.print("max temp-");
Serial.println(tempmax);
Serial.println(valrez);
Serial.println(valrez2);
int pwmval = map(sensors.getTempCByIndex(0)*100,tempmin,tempmax,150,0);
Serial.print("pwm-");
Serial.println(pwmval);
if (sensors.getTempCByIndex(0)*100<tempmin)
{Dimmer1=255;}
else if (sensors.getTempCByIndex(0)*100>tempmax)
{Dimmer1=0;}
else if (sensors.getTempCByIndex(0)*100>tempmin)
{Dimmer1=pwmval;}
Serial.print("Temperature: ");
Serial.print(sensors.getTempCByIndex(0));
if (sensors.getTempCByIndex(0)*100>tempmin) digitalWrite(led, HIGH);
if (sensors.getTempCByIndex(0)*100<tempmin) digitalWrite(led, LOW);
}
Открываете файл OneWire.cpp и все строки содержащие noInterrupts(); комментируете:
uint8_t OneWire::reset(void) { IO_REG_TYPE mask = bitmask; volatile IO_REG_TYPE *reg IO_REG_ASM = baseReg; uint8_t r; uint8_t retries = 125; //noInterrupts(); DIRECT_MODE_INPUT(reg, mask); interrupts(); // wait until the wire is high... just in case do { if (--retries == 0) return 0; delayMicroseconds(2); } while ( !DIRECT_READ(reg, mask)); //noInterrupts(); DIRECT_WRITE_LOW(reg, mask); DIRECT_MODE_OUTPUT(reg, mask); // drive output low interrupts(); delayMicroseconds(500); //noInterrupts(); DIRECT_MODE_INPUT(reg, mask); // allow it to float delayMicroseconds(80); r = !DIRECT_READ(reg, mask); interrupts(); delayMicroseconds(420); return r; } и т.д.И так по всему файлу. Сохраняете файл. Перезапускаете IDE. Компилируете.
Но учтите датчик температуры начнет лагать и температура будет с ошибками, которые прийдется фильтровать.
Большое спасибо, буду пробовать :)
Опробовал Ваш рецепт, есть провижения некоторые ) прерывание по опросу датчика действительно исчезли. Но вентилятор стал жить своей жизнью- хаотично прибавляет и снижает скорость и.т.д
Причем дело не в лагах датчика , они появились конечно но проскакивают довольно редко-раз в 20 секунд примерно появляется значение -127, в промежутке между лагами пока температура адекватная посылается вентик успевает несколько раз сбросить и набрать скорость))
Как думаете может легче датчик сменить на DTH11 например? он вроде по другому протоколу работает.
Так может тогда дело не в датчике, а в алгоритме регулирования? DTH11 тоже работает по асинхронному протоколу.
Может быть , но первый скетч в первом посте абсолютно рабочий, и тестовый код диммера тоже нареканий не вызывает , но совместить их никак не выходит :( короче надо мне матчасть учить прежде чем за такие проэкты браться))
код диммера:
#define VAR_REZ A0 #include "nanopins.h" //быстрое управление пинами #include <TimerOne.h> //использует Timer1 volatile uint8_t tic, Dimmer1, Dimmer2, Dimmer3; void setup() { Serial.begin(9600); D4_Out; //Настраиваем порт на выход Dimmer1 D5_Out; //Настраиваем порт на выход Dimmer2 D6_Out; //Настраиваем порт на выход Dimmer3 D4_Low; D5_Low; D6_Low; //установить на выходах низкий уровень сигнала D2_In; //настраиваем порт на вход для отслеживания прохождения сигнала через ноль attachInterrupt(0, detect_up, FALLING); // настроить срабатывание прерывания int0 на pin 2 Timer1.initialize(40); // Интервал срабатывания таймера в мкс Timer1.attachInterrupt(halfcycle); //будет вызыватся каждый раз при отсчете заданого времени Timer1.stop(); } //********************обработчики прерываний******************************* void halfcycle() //прерывания таймера { tic++; //счетчик if(Dimmer1 < tic ) D4_High; //управляем выходом if(Dimmer2 < tic ) D5_High; //управляем выходом if(Dimmer3 < tic ) D6_High; //управляем выходом } void detect_up() // обработка внешнего прерывания. Сработает по переднему фронту синусоиды { tic=0; //обнулить счетчик Timer1.resume(); //запустить таймер attachInterrupt(0, detect_down, RISING); //перепрограммировать прерывание на другой обработчик } void detect_down() // обработка внешнего прерывания. Сработает по заднему фронту синусоиды { Timer1.stop(); //остановить таймер D4_Low; D5_Low; D6_Low; //логический ноль на выходы tic=0; //обнулить счетчик attachInterrupt(0, detect_up, FALLING); //перепрограммировать прерывание на другой обработчик } //************************************************************************* void loop() { int valrez = analogRead(VAR_REZ); int tempmin = map(valrez,147,1023,200,0) ; Dimmer1=tempmin; Serial.println(tempmin); }Я бы предложил сделать некоторое сглаживание результата измерения температуры, измерение ее раз в 20 - 30 секунд, а не в каждом цикле, ну и, для обеспечения плавности регулирования, на вход оптопары - воткнул бы конденсатор, который обеспечил бы 1 - 3 - 5 секунд задержки после снятия сигнала с ножки D4.
Вы ошибаетесь, нельзя сглаживать управляющий сигнал при фазовом управлении. Это не аналоговый диммер.
По поводу того что двигатель не стабильно работает, не в одном из примеров кода нет ни фильтрации, ни усреднения, ни нормального регулирования.
Во-от это забавно. Регулировать обороты асинхронника с помощью ШИМа! ????
На практике однофазные асинхронники позволяют в небольших пределах регулировать мощность. Но обороты.... ?????
Спасибо за ответы)
Совершенно согласен , это только наброски , но повторюсь что по отдельности эти скетчи меня полностью устраивают. Если бы удалось их совместить , то продолжил бы работу над устранением мелких багов.
Если у кого есть свой взгляд на решение задачи (Плавное изменение оборотов асинхронного вентилятора переменного тока с помощью Arduino) , будет очень интересно услышать мнения. Не в коем случае не считаю своё решение верным, просто эксперементирую и смотрю на результаты.
На практике однофазные асинхронники позволяют в небольших пределах регулировать мощность. Но обороты.... ?????
Обороты за счет "скольжения" получатся... А вообще надо автору второй термометр, благо по 1-wire их можно цеплять пачками, поставить непосредственно на корпус двигателя, чтобы по перегреву включать его на полную мощность без искривления синусоиды питания...
Заработало ! Спасибо всем за помощь )
Пришлось датчик температуры по другому подключить(в коде все изменения видно). подсказали добрые люди с форума где димер брал.
Код конечно еще в порядок приводить, но в целом всё работает .
Предложения по оптимизации и улучшению приветствуются))
#include <MsTimer2.h> #include <OneWire.h> #include <DallasTemperature.h> #include "nanopins.h" //быстрое управление пинами #include <TimerOne.h> //использует Timer1 #define VAR_REZ A0 #define VAR_REZ2 A1 #define LM_35 A5 #define ONE_WIRE_BUS 10 // датчик DS1820 DATA подкл. на pin 10 #define RES_TEMP 12 // разрешение (точность) темп. датчика в битах volatile uint8_t tic, Dimmer1, Dimmer2, Dimmer3; OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire); DeviceAddress Thermometer; // адрес устройства float TempC=0; int led = 13; void setup() { Serial.begin(9600); sensors.begin(); // Start up the library sensors.getAddress(Thermometer, 0); // получить адрес DS18B20 (0 - 1 датчик) sensors.setResolution(Thermometer, RES_TEMP); // установить разрешение (точность) sensors.setWaitForConversion(false); // отключить ожидание при изм.темп. // время на изм. должно быть > 750ms sensors.requestTemperatures(); // Команда на измерение температуры, // выборка произойдет по прерыванию таймера через 2 сек (первый раз) MsTimer2::set(2000, Tizm); // установка таймера на 2 сек. для изм. температуры MsTimer2::start(); // запустить таймер D4_Out; //Настраиваем порт на выход Dimmer1 D5_Out; //Настраиваем порт на выход Dimmer2 D6_Out; //Настраиваем порт на выход Dimmer3 D4_Low; D5_Low; D6_Low; //установить на выходах низкий уровень сигнала D2_In; //настраиваем порт на вход для отслеживания прохождения сигнала через ноль pinMode(led, OUTPUT); Serial.begin(9600); Serial.println("Start"); attachInterrupt(0, detect_up, FALLING); // настроить срабатывание прерывания int0 на pin 2 Timer1.initialize(40); // Интервал срабатывания таймера в мкс Timer1.attachInterrupt(halfcycle); //будет вызыватся каждый раз при отсчете заданого времени Timer1.stop(); } //********************обработчики прерываний******************************* void halfcycle() //прерывания таймера { tic++; //счетчик if(Dimmer1 < tic ) D4_High; //управляем выходом if(Dimmer2 < tic ) D5_High; //управляем выходом if(Dimmer3 < tic ) D6_High; //управляем выходом } void detect_up() // обработка внешнего прерывания. Сработает по переднему фронту синусоиды { tic=0; //обнулить счетчик Timer1.resume(); //запустить таймер attachInterrupt(0, detect_down, RISING); //перепрограммировать прерывание на другой обработчик } void detect_down() // обработка внешнего прерывания. Сработает по заднему фронту синусоиды { Timer1.stop(); //остановить таймер D4_Low; D5_Low; D6_Low; //логический ноль на выходы tic=0; //обнулить счетчик attachInterrupt(0, detect_up, FALLING); //перепрограммировать прерывание на другой обработчик } void Tizm() //обработка прерывания таймера - изм температуры { TempC = sensors.getTempC(Thermometer); // Получить температуру в градусах sensors.requestTemperatures(); // Команда на измерение температуры для следующего раза } //************************************************************************* void loop() { int valrez = analogRead(VAR_REZ); int valrez2 = analogRead(VAR_REZ2); int tempmin = map(valrez,147,1023,2000,5000) ; int tempmax = map(valrez2,135,1023,2000,5000) ; Serial.print(" Requesting temperatures..."); Serial.println("DONE"); Serial.print("min temp-"); Serial.println(tempmin); Serial.print("max temp-"); Serial.println(tempmax); Serial.println(valrez); Serial.println(valrez2); int pwmval = map(TempC*100,tempmin,tempmax,110,60); Serial.print("pwm-"); Serial.println(pwmval); if (TempC*100<tempmin) {Dimmer1=255;} else if (TempC*100>tempmax) {Dimmer1=0;} else if (TempC*100>tempmin) {Dimmer1=pwmval;} Serial.print("Temperature: "); Serial.print(TempC); if (TempC*100>tempmin) digitalWrite(led, HIGH); if (TempC*100<tempmin) digitalWrite(led, LOW); delay(200); }Обороты асинхронного двигателя регулируются изменением частоты. zsm@nxt.ru, у Вас может быть коллекторный двигатель?