Конфликт двух процессов - помогите разобраться

Dinosaur
Dinosaur аватар
Offline
Зарегистрирован: 01.01.2018

Добрый день, корифеи

Опять я со своим увлажнителем - теперь засел за подключение электродвигателя вентилятора к нему. Когда работает только код управления двигателем, то все прекрасно работает и регулируется (сейчас подключена лампа накаливания в качестве нагрузки) - лампочка светит ровно, яркость меняется, мерцания не видно. По осцилограмме тоже все в порядке - ширина полуволны регулируется, переход через ноль определяется корректно.

Но вот когда начинаем опрашивать датчик влажности - имеем моргание лампочки с частотой опроса датчика (по осциллограмме пропуски периодов идут). Если закомментировать опрос датчика и просто присваивать значение переменной - тоже глюков нет. Остальной код, влияния на этот глюк не оказывает, поэтому я его убрал. Глюк происходит именно в момент опроса датчика (и видимо ожидания ответа от него).

Вопрос - как побороть этот эффект? И показания от датчика нужно получать, и напряжение на мотор должно подаваться без пропусков.

 

#define DEBUG 0 // включение отладки

const byte SensorLevel = 0;   //присваиваем имена выводам
const byte LedMedSpeed = 3;
const byte LedDio = 4;
const byte LedClk = 5;
const byte MotorOsc = 6;
const byte LedAutoSpeed = 7;
const byte LedLowSpeed = 8;
const byte FanMotor = 9;
const byte Buzzer = 10;
const byte LedHighSpeed = 11;
const byte PumpWater = 12;
const byte LedPower = 13;
const byte LedOsc = 14;
const byte SensorDht = 15;
const byte ButtonPower = 16;
const byte ButtonSpeed = 17;
const byte ButtonOsc = 18;
const byte ButtonHum = 19;

#include "stDHT.h"                   //подключаем библиотеку датчика влажности
DHT sens(DHT22);                     //указать датчик DHT11, DHT21, DHT22
unsigned long DHTpreviousMillis = 0; // время, когда датчик влажности опрашивался в последний раз

const int DHTinterval = 2000;       // интервал опроса датчика влажности - 2 секунды
const int FanInterval = 20000;      // интервал между расчетами разницы между расчетной и усредненной влажностью для изменения скорости мотора - 20 сек

byte HumTarget = 50;                 // Влажность, которую нужно поддерживать
byte HumCurrent;                     // Влажность, которую измерили датчиком
const int HumNumReadings = 10;       // Количество измерений для усреднения показаний DHT
int HumReadings[HumNumReadings];     // данные, считанные с входного аналогового контакта

volatile int FanLowSpeedDelay = 80;        //Время задержки для низкой скорости мотора
volatile unsigned long ZeroCrossTime;      // время в микросекундах срабатывания датчика нуля
unsigned long ZeroCrossTims;               // переменная показаний времени

void setup() {
  //устанавливаем PIN A1-A5 в режим входа и включаем подтяжку
  for (byte pin = 15; pin <= 19; ++pin) {
    pinMode(pin, INPUT);
    digitalWrite(pin, HIGH);
  }
  pinMode(SensorLevel, INPUT);
  digitalWrite(SensorLevel, HIGH);

  // устанавливаем PIN D3-D13 в режим выхода
  for (byte pin = 3; pin <= 14; ++pin) {
    pinMode(pin, OUTPUT);
    digitalWrite(pin, LOW);

    attachInterrupt(0, zero_crosss_int, RISING);  // Choose the zero cross interrupt # from the table above

  }
  if (DEBUG == 1) {
    Serial.begin(9600);
  }

  byte HumCurrent = sens.readHumidity(SensorDht);            // измеряем однократно влажность, чтобы HumCurrent не была пустой
  if (isnan(HumCurrent)) {                                   // проверяем, были ли ошибки при считывании:
    if (DEBUG == 1) {
      Serial.println("Не удается считать показания");
    }
    return;                                                  // если были - начинаем заново,
  }

  for (int HumThisReading = 0; HumThisReading < HumNumReadings; HumThisReading++)
    HumReadings[HumThisReading] = 0;

  if (DEBUG == 1) {
    Serial.print("Starting, target humidity set to: ");
    Serial.print(HumTarget);
    Serial.println("%.");
    Serial.print("Current humidity: ");
    Serial.print(HumCurrent);
    Serial.println("%.");
  }
}

void zero_crosss_int()        // function to be fired at the zero crossing to dim the light
{
  ZeroCrossTime = micros();   //запоминаем время перехода напряжения через ноль
}

void loop() {

// управление мотором
  int dimtime = (75 * FanLowSpeedDelay);                              // For 60Hz =>65
  ZeroCrossTims = micros();                                           // считываем время, прошедшее с момента запуска программы
  if (ZeroCrossTims >= (ZeroCrossTime + dimtime)) {                   //если время больше или равно времени срабатывания нуля + время задержки
    digitalWrite(FanMotor, HIGH);                                     // открываем симистор
    if (ZeroCrossTims >= (ZeroCrossTime + dimtime + 10)) {
    }
    digitalWrite(FanMotor, LOW);                                      // выключаем сигнал на симистор.
  }
// конец управления мотором

  unsigned long CurrentMillis = millis();                             // запоминаем текущее время для разных таймеров

// Опрос датчика влажности
  if (CurrentMillis - DHTpreviousMillis > DHTinterval) {              // проверяем не прошел ли заданный интервал между измерениями, и если прошел, то
    DHTpreviousMillis = CurrentMillis;                                // сохраняем время последнего измерения
//    byte HumCurrent = 56;                                                     //когда просто присваиваем значение переменной - пропусков нет
    byte HumCurrent = sens.readHumidity(SensorDht);                 // измеряем однократно влажность, чтобы HumCurrent не была пустой
    if (isnan(HumCurrent)) {                                        // проверяем, были ли ошибки при считывании
      return;                                                       // если были, начинаем заново
    }
  }
// Конец опроса датчика влажности
}

 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

мошт, дело в библиотеке для DHT?

bwn
Offline
Зарегистрирован: 25.08.2014

Там библиотека вроде прерывания запрещает на время опроса. А чем это на двигатель повлияет?

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

bwn пишет:

Там библиотека вроде прерывания запрещает на время опроса. А чем это на двигатель повлияет?

А зачем в Вашем коде zero_crosss_int()?

bwn
Offline
Зарегистрирован: 25.08.2014

andriano пишет:

bwn пишет:

Там библиотека вроде прерывания запрещает на время опроса. А чем это на двигатель повлияет?

А зачем в Вашем коде zero_crosss_int()?

В моем нет, у меня вообще кода нет.))))

nik182
Offline
Зарегистрирован: 04.05.2015

В этом коде для диммера уже заложена не стабильность фазы. Пока нет ничего другого в цикле ещё как то работает. Любые дополнения в loop будут приводить к морганию. Ничего сделать нельзя. Надо диммер на прерывании таймера делать.

Datak
Offline
Зарегистрирован: 09.10.2014

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

Я бы предложил выдавать импульс аппаратным таймером, установив период счёта приблизительно равным полупериоду сетевого напряжения, и длину импульса - те же 10мкс, или сколько там требуется для надёжного срабатывания.

А вот положение импульса относительно момента пересечения нуля - это уже действительно можно подстраивать программмно, причём достаточно плавно, изменяя в небольших пределах значение, загружаемое в счётчик таймера.

Получится конечно посложней, чем сейчас, но зато красиво, и пригодно для использования в других проектах.

 

Ну а если лень с этим всем возиться  - можно просто поставить на управление мотором отдельный контроллер.

Dinosaur
Dinosaur аватар
Offline
Зарегистрирован: 01.01.2018

bwn пишет:
Там библиотека вроде прерывания запрещает на время опроса.

Как это посмотреть и корректно поправить? Прошу прощения если вопрос чайниковский - я и есть чайник :)

bwn пишет:
А чем это на двигатель повлияет?

Двигатель работает рывками, что не есть гуд.

Dinosaur
Dinosaur аватар
Offline
Зарегистрирован: 01.01.2018

andriano пишет:

А зачем в Вашем коде zero_crosss_int()?

Поймать момент перехода напряжения через ноль, чтобы открыть симистор и отсчитать ширину имульса. Не?

Dinosaur
Dinosaur аватар
Offline
Зарегистрирован: 01.01.2018

nik182 пишет:
В этом коде для диммера уже заложена не стабильность фазы. Пока нет ничего другого в цикле ещё как то работает. Любые дополнения в loop будут приводить к морганию. Ничего сделать нельзя. Надо диммер на прерывании таймера делать.

На самом деле только опрос датчика влажности вызывает указанный эффект, если датчик не опрашивать, то остальной код не вызывает проблем (ту там собственно кода то кот наплакал - опрос кнопок и вывод показаний влажности на дисплей. А где почитать про "надо диммер на прерывании таймера" можно?

Dinosaur
Dinosaur аватар
Offline
Зарегистрирован: 01.01.2018

Datak пишет:
Управлять импульсом на симистор программно - это значит всегда рисковать выдать его не вовремя. В коде, тем более при использовании сторонних библиотек, всегда могут возникнуть задержки, которые предвидеть и учесть очень трудно.

Согласен, по видимому на этом момент я и напоролся.

Datak пишет:
Я бы предложил выдавать импульс аппаратным таймером, установив период счёта приблизительно равным полупериоду сетевого напряжения, и длину импульса - те же 10мкс, или сколько там требуется для надёжного срабатывания.

Ткните пожалуйста носом где про это почитать можно?

Datak
Offline
Зарегистрирован: 09.10.2014

nik182 пишет:
Надо диммер на прерывании таймера делать.

Да, тоже вариант. Во всяком случае, лучше чем просто в цикле.

Но если библиотека DHT, или ещё кто-то, действительно надолго запрещает прерывания, такой способ не сильно поможет.

Datak
Offline
Зарегистрирован: 09.10.2014

Dinosaur пишет:

Datak пишет:
Я бы предложил выдавать импульс аппаратным таймером, установив период счёта приблизительно равным полупериоду сетевого напряжения, и длину импульса - те же 10мкс, или сколько там требуется для надёжного срабатывания.

Ткните пожалуйста носом где про это почитать можно?

Да  сам только что придумал. :)
Но вообще-то, подозреваю что не я первый, поэтому можно попробовать погуглить.

А читать, конечно же, даташит на контроллер - программирование таймеров.
Думаю, если чётко понимать, что требуется - вполне можно осилить. Осциллограф есть - это уже хорошо, с ним намного проще. 

bwn
Offline
Зарегистрирован: 25.08.2014

Dinosaur пишет:

Как это посмотреть и корректно поправить? Прошу прощения если вопрос чайниковский - я и есть чайник :)

Двигатель работает рывками, что не есть гуд.

Посмотрите в сторону Ciber-lib, там на таймере, но этот эффект тоже присутствует. У меня на лампе (нагреватель) немного видно, думал на движке, за счет инерции, будет незаметно.

P/S следующий вариант - самописный опрос датчика, это мне не по зубам.((((

nik182
Offline
Зарегистрирован: 04.05.2015

Проитайте тему http://arduino.ru/forum/programmirovanie/attiny85-i-preryvanie . Там всё разжёвано. А тема не совместимости программного диммера и DHT22 ещё в 16 году обсуждалась на форуме. Поиск рулит.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Управление импульсом нужно организовать при помощи флагов, а не так как в программе.

/**/
//---------------------------------------
const byte FanMotor = 9;
bool fON = false, fOFF = false;
unsigned long past = 0;
const unsigned long intrevalON = 10;
const unsigned long intrevalOFF = 10;

void ZCR() {
  past = micros();
  fON = true;
}
//---ьmain()-----------------------------
void setup() {
  attachInterrupt(0, ZCR, RISING);

}

void loop() {
  unsigned long mic = micros();
  if (fON && mic - past >= intrevalON) {
    fON = false;
    fOFF = true ;
    past = mic;
    digitalWrite(FanMotor, HIGH);
  }
  if (fOFF && mic - past >= intrevalOFF) {
    fOFF = false;
    digitalWrite(FanMotor, LOW);
  }
}
/**/

 

Dinosaur
Dinosaur аватар
Offline
Зарегистрирован: 01.01.2018

qwone пишет:
Управление импульсом нужно организовать при помощи флагов, а не так как в программе.

Что то не работает... :(