Arduino + сенсор DHT11 + шаговый двигатель (биполярный)

DrLOR
Offline
Зарегистрирован: 14.04.2012
  •  Доброго времени суток! Есть Arduino + сенсор DHT11 (температура и влажность) + шаговый двигатель (биполярный).  Хочу сделать конролируемое по температуре открытие/закрытие форточки в доме. Например, при достижении t > 24 C, форточка открылась и не закрывалась. При t < 24 C форточка закрылась. При работе моего кода ШД, если t>24 или t<24, постоянно срабатывает. Знаю, чо где-то  что-то делаю не правильно при цеплянии ШД. Помогите пожалуйста...
  • P.S. да, ламер и чайник
#include <Stepper.h>
#define DHT11_PIN 0     // цепляю сенсор
#define STEPS 200
Stepper stepper(STEPS, 8, 9, 10, 11); 
byte read_dht11_dat()
{
  byte i = 0;
  byte result=0;
  for(i=0; i< 8; i++){

    while(!(PINC & _BV(DHT11_PIN)));  
    delayMicroseconds(30);

    if(PINC & _BV(DHT11_PIN)) 
      result |=(1<<(7-i));
    while((PINC & _BV(DHT11_PIN))); 

 }
  return result;
}

void setup()
{
  DDRC |= _BV(DHT11_PIN);
  PORTC |= _BV(DHT11_PIN);

  Serial.begin(9600);
  stepper.setSpeed(10);

  Serial.println("Ready");
}

void loop()
{
  byte dht11_dat[5];
  byte dht11_in;
  byte i;
   PORTC &= ~_BV(DHT11_PIN);
  delay(18);
  PORTC |= _BV(DHT11_PIN);
  delayMicroseconds(40);

  DDRC &= ~_BV(DHT11_PIN);
  delayMicroseconds(40);

  dht11_in = PINC & _BV(DHT11_PIN);

  if(dht11_in){
    Serial.println("dht11 start condition 1 not met");
    return;
  }
  delayMicroseconds(80);

  dht11_in = PINC & _BV(DHT11_PIN);

  if(!dht11_in){
    Serial.println("dht11 start condition 2 not met");
    return;
  }
  delayMicroseconds(80);
  for (i=0; i<5; i++)
    dht11_dat[i] = read_dht11_dat();

  DDRC |= _BV(DHT11_PIN);
  PORTC |= _BV(DHT11_PIN);

  byte dht11_check_sum = dht11_dat[0]+dht11_dat[1]+dht11_dat[2]+dht11_dat[3];
  if(dht11_dat[4]!= dht11_check_sum)
  {
    Serial.println("DHT11 checksum error");
  }

  Serial.print("Current humdity = ");
  Serial.print(dht11_dat[0], DEC);
  Serial.print(".");
  Serial.print(dht11_dat[1], DEC);
  Serial.print("%  ");
  Serial.print("temperature = ");
  Serial.print(dht11_dat[2], DEC);
  Serial.print(".");
  Serial.print(dht11_dat[3], DEC);
  Serial.println("C  ");

  delay(2000);
  
   if (dht11_dat[2] > 24) // начало работы ШД
 {
    stepper.step(100);
 }
  if (dht11_dat[2] < 22)
  {
    stepper.step(-100); 
  }    
}

спасибо

 

step962
Offline
Зарегистрирован: 23.05.2011

 Решение называется RTFM - Read The Fucking Manual.

Если открыть даташит и посмотреть раздел тех. характеристик, то можно выяснить, что

"Temperature Accuracy ±2℃"

то есть, при одном считывании вы можете получить 20 градусов Цельсиуса, а при следующем за ним - 24. Или лучше так - при одном 25 (и срочно откроете свою форточку), а при следующем - 21 (и "побежите" задраивать все щели).

Пути решения? Их есть у меня:

либо расширяйте гистерезис, скажем с ">24 откр, <22 закр" перейдите на ">25 откр, <21 закр"

либо находите среднее арифметическое по последни 5-6-10-100 замерам.

 

ЗЫ: И еще: вот вы чексум проверяете и даже истошное сообщение в случае чего выводите.

Оч. хор.

Только, выполнив эту проверку, почему-то успокаиваитесь и бесстрашно используете полученные неправильные данные в своем алгоритме. Правильнее было бы заключить все инструкции, стоящие ниже проверки контрольной суммы, в конструкцию "else {...}" и выполнять их ТОЛЬКО в том случае, если проверка успешна.

DrLOR
Offline
Зарегистрирован: 14.04.2012

Спасибо step962.  значения температуры поменял.. однако остается следующая проблема - при t>25 двигатель срабатывает постоянно (т.е форточка открывается, затем еще и еще).  <21  происходит закрытие, +закрытие, + закрытие и т.д.

Как сделать так, чтоб открытие/закрытие осуществлялось однократно (т.е. 24, 25, 26(открытие),27 (форточка продолжает оставаться открытой, а не "открывается еще разок")?

P.S. как посчитать "среднее арифметическое по последни 5-6-10-100 замерам" 

 

step962
Offline
Зарегистрирован: 23.05.2011

DrLOR пишет:

 

Как сделать так, чтоб открытие/закрытие осуществлялось однократно (т.е. 24, 25, 26(открытие),27 (форточка продолжает оставаться открытой, а не "открывается еще разок")?

Ну, это можно реализовать разными способами.

Например, ввести константы

#define UNDEFINED 0
#define OPENED 1
#define CLOSED 2

и переменную состояния (обозвав ее, например, State)

В setup():

State = UNDEFINED;

В loop():

if (dht11_dat[2]>25 && State != OPENED) {
  stepper.step(100); // открываем форточку
  State = OPENED;    // запоминаем текущее состояние
}

Проверка на закрывание - в том же духе. 

Цитата:

P.S. как посчитать "среднее арифметическое по последни 5-6-10-100 замерам" 

Это уже разбиралось в одной из тем, посвященных борьбе с дребезгом кнопок или чему-то там еще:

mean = 4/5 * mean + 1/5 * val; // скользящее среднее по 5 последним значениям
mean = 99/100 * mean + 1/100 * val; // скользящее среднее по 100 последним значениям

 

При расчете среднего не следует забывать об особенностях целочисленной математики, иначе очень легко накопить непереносимо большую погрешность. (например, в выражении, в котором участвуют исключительно целочисленные переменные результат действия 4/5 и даже 99/100 равен нулю)

DrLOR
Offline
Зарегистрирован: 14.04.2012

 Step962 спасибо вам ОГРОМНОЕ! Все работает! Думаю, тема закрыта)