Не понятно... как одно от другого зависит

Alex67Z
Offline
Зарегистрирован: 23.01.2013

Всем привет. 

Не могу понять в чем проблема. Железо простое, все работает. понимаю, что-то в программе, а вот что....???

Итак имеется - UNO, LCD 16x2, шилд на 4 реле на 5 В, кнопка с фиксатором на анлоговом входе A1 (земля при нажатии, +5В через 2 кОм), 2 датчика температуры, часы, датчик влажности DHT22. 

Все работает. На экран все выводится, что хотел. От одного датчика температуры, при срабатывании порога,  включается реле.

Пр нажатии на кнопку - включается второе реле. 

Вот сам скетч:

// Подключение необходимых библиотеки
#include <Wire.h>
#include "RTClib.h"
#include <OneWire.h>
#include <DallasTemperature.h>
#include <DHT.h>

// Датчик (или датчики) температуры подключается к пину "3" Ардуины
#define ONE_WIRE_BUS 3

// Датчик влажности подключають к пину 2 Ардуины
#define DHTPIN 2 
#define DHTTYPE DHT22  
DHT dht(DHTPIN, DHTTYPE);

// настройка «onewire» для работы с любыми другими девайсами (не только Dallas датчиками температуры)
OneWire oneWire(ONE_WIRE_BUS);

// подключаем Dallas Temperature.
DallasTemperature sensors(&oneWire);

#include <LiquidCrystal.h>
LiquidCrystal lcd(9, 8, 7, 6, 5, 4);

int reading;      // назначение переменной
int Temp_1=LOW;
int u=0;      // назначение 2-й переменной для датчика уровня
int v=0;      // назначение 3-й переменной для охлаждения воды

int Relay1 = 11;     // вентилятор охлаждения назначаем 11-й выход
int Relay2 = 10;     // кнопка, назначаем 10-й выход

RTC_DS1307 RTC;



void setup () 
{
    lcd.begin(16, 2);
    Wire.begin();
    RTC.begin();
    sensors.begin();
    dht.begin();               // инициализация датчика 
//    pinMode(A0, INPUT);      // настраиваем аналоговый вход A0
    pinMode(A1, INPUT);        // настраиваем аналоговый вход A1
 
// назначаем на 10-м и 11-м пинах (пины реле) низкий уровень  
    pinMode(Relay1, OUTPUT);
    digitalWrite(Relay1, LOW);
    pinMode(Relay2, OUTPUT);
    digitalWrite(Relay2, LOW);
 
         if (! RTC.isrunning()) 
       {
 lcd.setCursor(0, 0);
 lcd.print("RTC no time");
       //RTC.adjust(DateTime(__DATE__, __TIME__));
       }

}

// Вывод на экран текущего времени и температуры

void LCD_Time()
{
   DateTime now = RTC.now();
   sensors.requestTemperatures();   // запрос показаний температуры
   float h = dht.readHumidity();    // запрос показаний влажности
//  float t = dht.readTemperature();
 

   // управление исполнительным реле
{
  u=analogRead(A1);                     // значение «u» равно аналоговому входу A1
  if (u<5)                              // при срабатывании датчика уровня, на выходе 4 устанавливается высокий уровень
        { 
    digitalWrite(Relay2, HIGH);
        }  
    else if (u>=30)                     // при срабатывании датчика уровня, на выходе 4 устанавливается низкий уровень
        {
    digitalWrite(Relay2, LOW);
         }    
}

// управление вентилятором охлаждения по температуре   
{
 v=sensors.getTempCByIndex(1);           // переменной "v" присваивается темп. 1-го датчика (Т воды)
 reading = digitalRead(Relay1);
 Temp_1 = reading;
 
 if (v>=28)                              // если температура поднимается до 28 градусов, срабатывает реле на вентилятор охлаждения
      {
 digitalWrite(Relay1, HIGH);
      } 
  
 else if ((Temp_1 == HIGH) && (v < 27))   // если температура опускается до 27 градусов, вентилятор выключается
    {
 digitalWrite(Relay1, LOW);
     } 
}     
     
{
 lcd.setCursor(0, 0);
 if(now.hour()<10){lcd.print("0");}
 lcd.print(now.hour(), DEC);
 lcd.print(":");
 if(now.minute()<10){lcd.print("0");}
 lcd.print(now.minute(), DEC);
// lcd.print(":");
// if(now.second()<10){lcd.print("0");}
// lcd.print(now.second(), DEC);
// lcd.print(" "); 
 lcd.setCursor(9, 0);
 lcd.print("T=");                                             
 lcd.print(sensors.getTempCByIndex(0),1);     // получение данных температуры от 1-го датчика
 lcd.print("C");
 //lcd.setCursor(0, 1);
 //lcd.print("Arina"); 
 lcd.setCursor(0, 1);
 lcd.print("H="); 
 lcd.setCursor(3, 1);
 lcd.print(h,1);
 lcd.print("%\t");
 //lcd.print("%");
 lcd.setCursor(8, 1);
 lcd.print(" "); 
 lcd.setCursor(9, 1);
 lcd.print("A=");                                              
 lcd.setCursor(11, 1);
 lcd.print(sensors.getTempCByIndex(1),1);    // получение данных температуры от 2-го датчика
 lcd.print("C");
}

}

void loop () 
{
  
if ( ( millis() % 2000 ) == 0 )                   //вызов функции раз в 2 сек.
      {
         LCD_Time();
       }
}

А вот проблема в следующем:

Когда температура больше 28 град. срабатывает реле, а также температура в пределах от 27 до 28 град. - т.е. на на 11 выходе высокий уровень - на кнопку UNO не реагирует(( На кнопку начинает реагировать, т.е. на 10 вых. HIGH - только тогда, когда температура ниже 27 гр. и на 11 вых. - LOW/

Я просто не понимаю...

 

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

Мне кажется, что ищите соплю. А вот компота в коде много, начиная от переменных, таящих в себе грабли (присваивать типу int бинарное значение LOW).
Непонятны строки 88-89 и последующее использование Temp_1. Если температура ниже 27, то и так запишется LOW, если оно уже там записано при повторной записи ничего не изменится, что вы спокойно используете в строках 91-94.
И уж если взялись выносить код в отдельные функции, не лепите все в одну. Считывание и отображение времени это одно, температура и ее обработка другое. Сам бы выделил отдельно и кнопку с влажностью, с вызовом либо последовательно, либо из другой функции. Для отладки много легче.

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

bwn, присваивать int переменной значение LOW не наказуемо, всё нормально, а вот использовать int для такой переменной - пустой расход ресурсов. 88, 89 - тоже пустая трата ресурсов (места).

А вот сравнение в loop: ((millis() % 2000) == 0) можно легко пропустить вызов LCD_Time. Дались вам всем эти %. Считайте дельту и не парьтесь. Будет точно надежней и точно не пропустите вызовы LC_Time.

analogRead(A1), почему бы не использовать digitalRead(A1)? К тому же зачем такое значение 5 (после чтения analogRead(A1)) для сравнения, если тупо посчитать 1024 - 5В, то 5 - это примерно 24мВ (вроде правильно посчитал :), для чего так жестко 0 зажимать? Не, ну дело Ваше, конечно. Да вроде у Вас есть еще цифровые пины, если есть сомнения. Хотя бы для отладки перекиньте кнопку на цифровой пин, вместо Ваших уровней 5 и 30 (это 24мВ и 146мВ). Зачем такой узкий коридор? Дребезг не страшит?

Короче, сначала разобраться с millis, чтобы срабатывало четко, потом с кнопкой, вот тогда можно будет остальное посмотреть.

PS Форматируйте исходники в ArduinoIDE, нажмите просто Ctrl-T и всё будет намного читабельней.

 

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

kisoft пишет:

bwn, присваивать int переменной значение LOW не наказуемо, всё нормально, а вот использовать int для такой переменной - пустой расход ресурсов. 88, 89 - тоже пустая трата ресурсов (места).

kisoft, я ведь и не сказал, что так нельзя. Мне кажется, что столь вольное обращение с числовыми переменными в начале пути, способствует дополнительной каше в голове. ИМХО.

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

bwm, ну не знаю, я проблемы в этом не вижу. Было бы правильней описать byte Temp_1 = LOW;, а не int.

Ок, какие другие варианты? byte Temp_1 = true? (ужас) byte Temp_1 = 1; (еще ужасней). Переменная Temp_1 используется для хранения значения, полученного из digitalRead, а он возвращает что? HIGH или LOW и никаких других значений. Значит переменная должна быть беззнаковым байтом, т.е. byte или uint8_t (и никаких unsigned char).

 

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

kisoft, убедили )))) То, что не пользуешь сам, не значит неправильно. Как то ни разу не требовалось таким образом присвоить значение, а в сравнении всегда применял x!=0 или x==0.
Не пинайте, сам учусь))).

Tomasina
Tomasina аватар
Offline
Зарегистрирован: 09.03.2013

kisoft пишет:
Переменная Temp_1 используется для хранения значения, полученного из digitalRead, а он возвращает что? HIGH или LOW и никаких других значений. Значит переменная должна быть беззнаковым байтом, т.е. byte или uint8_t (и никаких unsigned char).
а почему не boolean? Как раз только два состояния.

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

bwn, а я попинаю ;) Шучу.

Давайте рассмотрим исходник digitalRead

int digitalRead(uint8_t pin)
{
	uint8_t timer = digitalPinToTimer(pin);
	uint8_t bit = digitalPinToBitMask(pin);
	uint8_t port = digitalPinToPort(pin);

	if (port == NOT_A_PIN) return LOW;

	// If the pin that support PWM output, we need to turn it off
	// before getting a digital reading.
	if (timer != NOT_ON_TIMER) turnOffPWM(timer);

	if (*portInputRegister(port) & bit) return HIGH;
	return LOW;
}

Здесь видно, что возвращается int (приплыли, видно по каким то религиозным причинам, либо по историческим, хватило бы и uint8_t, впрочем, может быть это для камней не 8 битных тоже) и возвращаться могут всего два значения LOW или HIGH и никак иначе. Что такое LOW & HIGH, это можно найти в Arduino.h, а именно:

#define HIGH 0x1
#define LOW  0x0

Да, формально можно использовать 0 и 1, однако правильней использовать именно те константы, которые возвращает функция digitalRead, т.е. LOW & HIGH. И в сравнениях использовать тоже только эти два значения LOW или HIGH.

Вообще это вопрос философии каждого программиста и каждый решает эти вопросы сам, исходя из опыта и граблей, по которым он ходил.

Разумеется я сам иногда косячу, отклоняясь от своего убеждения, так что..

PS А вообще я не идеален и проповедую здесь всего лишь свою философию, делюсь своим опытом и ни в коем случае не навязываю :)

PPS А еще, при сравнении пишите сначала константу, потом переменную, как я уже говорил, будет меньше ошибок типа if(var = 0) вместо правильного if(val == 0), а есть напишешь if(0 = val), то компилятор выругается, что позволит исправить эту ошибку, а не удивляться, почему это у меня сранение работает неправильно?!

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

 

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

kisoft, спасибо за разъяснения, по исходникам - так глубоко еще не влез, нынче уровень офортранненного бейсика в переложении на С++, буду потихоньку разбираться. )))