Энкодер и прерывание

Мужик из полиуретана
Offline
Зарегистрирован: 12.09.2015

Итак, к ардуине (китайская nano) подключено:

1)две штуки DHT22

2)один DS18B20

3) DS3231

4)LCD 1602

5)Энкодер, на 2 и 3 цифровые пины, притянутые через 10 кОм к земле, средний контакт - +5В

Что есть: дефолтом показываем время, влажность и две температуры (засекал - луп со всеми опросами датчиков выполняется за 1260 мс, все нужные данные на один экран не влазят, поэтому делаем без дилея, просто чередуя вывод нужных значений на экран (1.2 секунды показывает температуру внутри, 1.2 секунды - температуру снаружи).

Что нужно - чтобы по энкодеру считывались данные с еепром, выводились на экран, в течении какого-то времени (секунд 30-60) висели на экране, ожидаясь дальнейшего кручения энкодера, если этого не произошло - возвращалось к лупу.

Есть скетч, который просто выводит данные на 1602(кстати,буду рад любым советам по улучшению читаемости кода):

// подключаем все библиотеки
#include <OneWire.h>
#include "DHT.h"                
#include <DallasTemperature.h>
#include <Time.h>
#include <Wire.h>
#include <DS1307RTC.h>
#include <EEPROM.h>
#include <LiquidCrystal.h>

#define ONE_WIRE_BUS 13           //номер пина ds18b20
#define DHTPINa 8                // номер пина первого dht22
#define DHTPINb 9               // номер пина второго dht22

OneWire oneWire(ONE_WIRE_BUS);   //создаем обьект для ds18b20

DHT dhta(DHTPINa, DHT22);        // и для dht22
DHT dhtb(DHTPINb, DHT22); 

LiquidCrystal lcd(12, 11, 10, 5, 4, 6, 7);  //подключаем экран

DallasTemperature sensors(&oneWire);  //подключаем ds18b20
DeviceAddress Thermometer1 = { 0x28, 0xFF, 0xEE, 0xBB, 0x62, 0x15, 0x01, 0x92 }; //адрес термометра

int addressWrite = 0;            // переменная для записи
int addressRead = 0;             // переменная для чтения
byte value;                      // переменная значения ячейки
boolean counter_temp = true;
int val;
unsigned long current_time;

byte L_kr_lit[8] =               //рисуем нужную кириллицу, буква л
 {
   B00000,
   B00000,
   B01111,
   B00101,
   B00101,
   B10101,
   B01001,
   B00000,
 };
 
byte J_kr_lit[8] =               //рисуем нужную кириллицу, буква ж
 {
   B00000,
   B00000,
   B10101,
   B10101,
   B01110,
   B10101,
   B10101,
   B00000,
 };
 
byte N_kr_lit[8] =               //рисуем нужную кириллицу, буква н
 {
   B00000,
   B00000,
   B10001,
   B10001,
   B11111,
   B10001,
   B10001,
   B00000,
 }; 
 
byte P_kr_lit[8] =               //рисуем нужную кириллицу, буква п
 {
   B00000,
   B00000,
   B11111,
   B10001,
   B10001,
   B10001,
   B10001,
   B00000,
 }; 
 
byte M_kr_lit[8] =               //рисуем нужную кириллицу, буква м
 {
   B00000,
   B00000,
   B10001,
   B11011,
   B10101,
   B10001,
   B10001,
   B00000,
 }; 

byte U_kr_lit[8] =               //рисуем нужную кириллицу, буква У
 {
   B10001,
   B10001,
   B10001,
   B01010,
   B00100,
   B01000,
   B10000,
   B00000,
 }; 
 
byte Cels_kr_lit[8] =            //рисуем значок градуса и С
 {
   B11000,
   B11000,
   B00010,
   B00101,
   B00101,
   B00100,
   B00101,
   B00010,
 }; 

void setup() 
{
  lcd.createChar(2, L_kr_lit);  // создаем чары для наших нарисованных букв и символов
  lcd.createChar(3, J_kr_lit);
  lcd.createChar(4, N_kr_lit);
  lcd.createChar(5, P_kr_lit);
  lcd.createChar(6, M_kr_lit);
  lcd.createChar(7, Cels_kr_lit);
  lcd.createChar(1, U_kr_lit);
  
  lcd.begin(16, 2);             // инициализируем экран

  sensors.begin();              // запускаем датчики
  sensors.setResolution(Thermometer1, 10); // и задаем разрешение датчика(от 8 до 12(бит),при 12 лагает)
  
  dhta.begin();                 // запускаем оба DHT
  dhtb.begin();

  setSyncProvider(RTC.get);     // и модуль часов
}

void loop() 
{
  sensors.requestTemperatures();   // запрашиваем данные с датчиков, пишем в переменные
  float h1 = dhta.readHumidity();
  float h2 = dhtb.readHumidity();
  float t3 = sensors.getTempC(Thermometer1);                                                          
  float t1 = dhta.readTemperature();
  float t2 = dhtb.readTemperature();

  if (isnan(h1) || isnan(t1) || isnan(h2) || isnan(t2) || isnan (t3) ) 
  // на случай если не удалось считать данные с датчика - выдадим моргающее 10 раз сообщение о ошибке
  {
    for (int i=0; i < 10; i++)
    {
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print( "Sensor Error" );
      delay(200);
      lcd.clear();
      delay(200);
    }
  return;
  }

  byte humydity;                    // переменная для средней влажности
  humydity = ((h1+h2)/2);           // получаем и записываем среднюю влажность
 
  int temp;                         // переменная для средней температуры
  temp = ((t1+t2)/2);

  lcd.clear();                      // очистим для начала экран
  lcd.setCursor(0, 0);              // зададим координаты 
  lcd.print( "B\2a\3\4.:" );        // пишем "Влаж.:", самое значение влажности и процент
  lcd.print(humydity);                                         
  lcd.print("%");                                                             
    
  lcd.setCursor(11, 0);             // переходим на вторую строку
  if (hour() < 10)     // для красивого отображения часов и минут меньше 10 (например, не 2:5, а 02:05)
  {lcd.print("0");}
  lcd.print( hour() );              // пишем часы и минуты
  lcd.print( ":" );
  if (minute() < 10)
  {lcd.print("0");}
  lcd.print( minute() );

  if (counter_temp)
  // в зависимости от счетчика показываем либо температуру внутри и меняем счетчик, либо уличную и меняем счетчик
  {
    counter_temp = false;
    lcd.setCursor(0, 1);
    lcd.print( "Te\6\5.:" );        // пишем "Темп.:"
    lcd.print(temp);
    lcd.print( "\7" );              // и наш значок градусов
   
  }
  else
  {
    counter_temp = true;
    lcd.setCursor(0, 1);           // аналогично для уличной температуры, только пишем "Темп.Ул.:"
    lcd.print( "Te\6\5.\1\2.:" );                                            
    lcd.print(t3);
    lcd.print("\7");
  }  
  
  
}

Наработки по записи\чтению из еепром тоже наличествуют:

  while (buttonState == HIGH) // если нажата кнопка
    {
    value = EEPROM.read(addressWrite);// то выводим в ком-порт данные
    Serial.print("Archive of temperature and humidity: ");
    Serial.print(value, DEC);                                   // первая ячейка - число
    Serial.print(".");
    addressWrite = addressWrite + 1;

    value = EEPROM.read(addressWrite);
    Serial.print(value, DEC);
    Serial.print(".");                                         // вторая - месяц
    addressWrite = addressWrite + 1;

    value = EEPROM.read(addressWrite);
    Serial.print(value + 2000, DEC);                           // третья - год, чтобы влезло в один байт, при записи отнимаем 2000, при чтении добавляем
    addressWrite = addressWrite + 1;
    Serial.print("\t");

    value = EEPROM.read(addressWrite);
    Serial.print(value, DEC);                                  // четвертая - час записи.
    addressWrite = addressWrite + 1;
    Serial.print(":00\n");
  
    value = EEPROM.read(addressWrite);
    Serial.print("The temperature at a height of 1.5 meters: ");
    Serial.print(value-127, DEC);                                 // пятая - температура с первого DHT22, -127 - чтобы иметь возможность писать отрицательные температуры, при записи 
    Serial.print(" Celsius");                                     // берем значение 127 за 0 градусов.
    addressWrite = addressWrite + 1;
    Serial.print("\n");
  
    value = EEPROM.read(addressWrite);
    Serial.print("The temperature at a height of 6 meters: ");
    Serial.print(value-127, DEC);                                 // шестая - температура с второго DHT22
    Serial.print(" Celsius");
    addressWrite = addressWrite + 1;
    Serial.print("\n");

    value = EEPROM.read(addressWrite);
    Serial.print("The temperature at a height of 9 meters: ");
    Serial.print(value-127, DEC);
    Serial.print(" Celsius");                                 // седьмая - температура с ds18b20
    addressWrite = addressWrite + 1;
    Serial.print("\n");

    value = EEPROM.read(addressWrite);
    Serial.print("Average humidity: ");
    Serial.print(value, DEC);                                 // восьмая - средняя влажность
    Serial.print(" %");
    addressWrite = addressWrite + 1;
    Serial.print("\n");
    Serial.print("\n");

    if(addressWrite == EEPROM.length())                        // если достигли конца EEPROM - начинаем сначала
    addressWrite = 0; 
    }
 


  if (x == 0 && hour() == 8 && minute() == 0 )                              // условия для записи, одна запись в нужную минуту
  {
   digitalWrite(13, HIGH);                                                  //моргнем светодиодом пока пишем, для визуального контроля
   EEPROM.write(addressWrite, day());
   addressWrite = addressWrite + 1;                                        // переход на следующий адрес
   if (addressWrite == 1024)                                               // если заполнилось - начинаем сначала
    addressWrite = 0;
   delay(50);                                                              // на всякий случай
   
   EEPROM.write(addressWrite, month());
   addressWrite = addressWrite + 1;
   if (addressWrite == 1024)
    addressWrite = 0;
   delay(50);

   EEPROM.write(addressWrite,(byte) year() - 2000 );
   addressWrite = addressWrite + 1;
   if (addressWrite == 1024)
    addressWrite = 0;
   delay(50);
   
   EEPROM.write(addressWrite, hour());
   addressWrite = addressWrite + 1;
   if (addressWrite == 1024)
    addressWrite = 0;
   delay(50);
                                                       
   EEPROM.write(addressWrite, (byte) t1 + 127);
   addressWrite = addressWrite + 1;
   if (addressWrite == 1024)
    addressWrite = 0;
   delay(50);
   
   EEPROM.write(addressWrite, (byte) t2 + 127);
   addressWrite = addressWrite + 1;
   if (addressWrite == 1024)
    addressWrite = 0;
   delay(50);

   EEPROM.write(addressWrite, (byte) t3 + 127);
   addressWrite = addressWrite + 1;
   if (addressWrite == 1024)
    addressWrite = 0;
   delay(50);
   
   EEPROM.write(addressWrite, (byte) humydity);
   addressWrite = addressWrite + 1;
   if (addressWrite == 1024)
    addressWrite = 0;
   delay(50);
   x++;
   digitalWrite(13, LOW);                                                     // выключаем светодиод
  }
  if ( x > 0 && hour() == 8 && minute() == 1 )                                // когда прошла первая минута - обнуляем счетчик, не сделали это сразу чтобы не было несколько записей                  
  x =0;                                                                       // в одну и ту же минуту
  delay(100);
}

Есть скетч, на котором добился стабильной работы энкодера:

enum { ENC_PIN1 = 2, ENC_PIN2 = 3 };
#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 10, 5, 4, 6, 7);

volatile int val= 0;
volatile int val_prev = 0;

void setup()
{
 pinMode(ENC_PIN1, INPUT);
 pinMode(ENC_PIN2, INPUT);
 lcd.begin(16, 2);      
}

/* Функция декодирования кода Грея, взятая с Википедии.
* Принимает число в коде Грея, возвращает обычное его представление.
*/
unsigned graydecode(unsigned gray)
{
 unsigned bin;

 for (bin = 0; gray; gray >>= 1)
    bin ^= gray;

 return bin;
}

void loop()
{
 static uint8_t previous_code = 0; // предыдущий считанный код
 
 /* gray_code - считанное с энкодера значение
  * code - декодированное значение
  */
 uint8_t gray_code = digitalRead(ENC_PIN1) | (digitalRead(ENC_PIN2) << 1),
         code = graydecode(gray_code);
 
 /* Если считался нуль, значит был произведён щелчок ручкой энкодера */
 if (code == 0)
 {
   /* Если переход к нулю был из состояния 3 - ручка вращалась
    * по часовой стрелке, если из 1 - против.
    */
   if (previous_code == 3)
     val = val +1;
   else if (previous_code == 1)
      val = val -1;
 }
 
 /* Сохраняем код и ждём 1 мс - вполне достаточно опрашивать энкодер
  * не более 1000 раз в секунду.
  */
 previous_code = code;
 

 
  if (val != val_prev)
    {
     lcd.clear();
     lcd.print(val);
     val_prev = val;
    }
 
 delay(1);
}

Теперь вопрос - при добавлении в первый скетч прерывания (attachInterrupt(0, encoder, RISING);) отображение температуры начинает работать нестабильно, функция энкодера как нужно тоже не срабатывает.

Подскажите, как это вообще по-человечески делается? %)

 

Valera19701
Valera19701 аватар
Offline
Зарегистрирован: 18.10.2015

вот здесь я выкладывал код работы энкодера без прерывания, работает до 500КГц

http://arduino.ru/forum/apparatnye-voprosy/opticheskie-enkodery#comment-144045

Мужик из полиуретана
Offline
Зарегистрирован: 12.09.2015

Valera19701 пишет:

вот здесь я выкладывал код работы энкодера без прерывания, работает до 500КГц

http://arduino.ru/forum/apparatnye-voprosy/opticheskie-enkodery#comment-144045

Ну, если я правильно понимаю, то без прерывания здесь мне все равно не обойтись

Клапауций 777
Offline
Зарегистрирован: 21.11.2015

библиотека http://www.pjrc.com/teensy/td_libs_Encoder.html

параметры ползания прерываний:

ENCODER_USE_INTERRUPTS
ENCODER_OPTIMIZE_INTERRUPTS
ENCODER_DO_NOT_USE_INTERRUPTS
Мужик из полиуретана
Offline
Зарегистрирован: 12.09.2015

Клапауций 777 пишет:

библиотека http://www.pjrc.com/teensy/td_libs_Encoder.html

параметры ползания прерываний:

ENCODER_USE_INTERRUPTS
ENCODER_OPTIMIZE_INTERRUPTS
ENCODER_DO_NOT_USE_INTERRUPTS

Премного благодарствую!

Теперь же вопрос такой, как в этот код прикрутить чтобы данные на экране оставались,допустим, 10 секунд ?

void loop() 
{
long newPosition = myEnc.read();
  if (newPosition != oldPosition) {
    if(newPosition < oldPosition )
    {
    value = EEPROM.read(addressRead);// то выводим в ком-порт данные
    lcd.clear();
    lcd.print(value, DEC);                                   // первая ячейка - число
    lcd.print(".");
    addressRead = addressRead + 1;

    value = EEPROM.read(addressRead);
    lcd.print(value, DEC);
    lcd.print(".");                                         // вторая - месяц
    addressRead = addressRead + 1;

    value = EEPROM.read(addressRead);
    lcd.print(value, DEC);                           // третья - год, чтобы влезло в один байт, при записи отнимаем 2000, при чтении добавляем
    addressRead = addressRead + 1;
    lcd.print(" ");

    value = EEPROM.read(addressRead);
    lcd.print(value, DEC);                                  // четвертая - час записи.
    addressRead = addressRead + 1;
    lcd.print(" ");
  
    value = EEPROM.read(addressRead);
    lcd.print("B");
    lcd.print(value, DEC);                                 // влажность
    lcd.print("%");                                     // 
    addressRead = addressRead + 1;
    
    lcd.setCursor(0, 1);
    lcd.print(addressRead);
    value = EEPROM.read(addressRead);
    lcd.print("\x5e");
    lcd.print(value-127, DEC);
    lcd.print( "\7" );                // шестая - температура с первого DHT22
    lcd.print(" ");
   addressRead = addressRead + 1;

    value = EEPROM.read(newPosition);
    lcd.print("v");
    lcd.print(value-127, DEC);
    lcd.print( "\7" ); 
    lcd.print(" ");                                 // седьмая - температура с второго DHT22
    addressRead = addressRead + 1;

    value = EEPROM.read(newPosition);
    lcd.print("\x7e");
    lcd.print(value-127, DEC);
    lcd.print( "\7" ); // восьмая - температура с ds18b20
    addressRead = addressRead + 1;


    if(addressRead == EEPROM.length())                        // если достигли конца EEPROM - начинаем сначала
    addressRead = 0; 
    oldPosition = newPosition;
    }
    else
    {
     value = EEPROM.read(addressRead);// то выводим в ком-порт данные
    lcd.clear();
    lcd.print(value, DEC);                                   // первая ячейка - число
    lcd.print(".");
    addressRead = addressRead - 1;

    value = EEPROM.read(addressRead);
    lcd.print(value, DEC);
    lcd.print(".");                                         // вторая - месяц
    addressRead = addressRead - 1;

    value = EEPROM.read(addressRead);
    lcd.print(value, DEC);                           // третья - год, чтобы влезло в один байт, при записи отнимаем 2000, при чтении добавляем
    addressRead = addressRead - 1;
    lcd.print(" ");

    value = EEPROM.read(addressRead);
    lcd.print(value, DEC);                                  // четвертая - час записи.
    addressRead = addressRead - 1;
    lcd.print(" ");
  
    value = EEPROM.read(addressRead);
    lcd.print("B");
    lcd.print(value, DEC);                                 // влажность
    lcd.print("%");                                     // 
    addressRead = addressRead - 1;
    
    lcd.setCursor(0, 1);
    lcd.print(addressRead);
    value = EEPROM.read(addressRead);
    lcd.print("\x5e");
    lcd.print(value-127, DEC);
    lcd.print( "\7" );                // шестая - температура с первого DHT22
    lcd.print(" ");
   addressRead = addressRead - 1;

    value = EEPROM.read(newPosition);
    lcd.print("v");
    lcd.print(value-127, DEC);
    lcd.print( "\7" ); 
    lcd.print(" ");                                 // седьмая - температура с второго DHT22
    addressRead = addressRead - 1;

    value = EEPROM.read(newPosition);
    lcd.print("\x7e");
    lcd.print(value-127, DEC);
    lcd.print( "\7" ); // восьмая - температура с ds18b20
    addressRead = addressRead - 1;


    if(addressRead == EEPROM.length())                        // если достигли конца EEPROM - начинаем сначала
    addressRead = 0; 
    
    oldPosition = newPosition;
    }
  }
  

Пробовал весь код по отображению засовывать в while ((Millis() - current_time) < interval)

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

Какие еще могут быть варианты, чтобы и на экране показывалось, и листалось, если положение энкодера изменилось?

Клапауций 777
Offline
Зарегистрирован: 21.11.2015

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

и затираться в указанном месте через время печатью пробелов

lcd.clear(); вообще использовать не обязательно, если ты печатаешь по разным событиям в разные месте экрана.

Мужик из полиуретана
Offline
Зарегистрирован: 12.09.2015

  Вот весь код целиком, правда пока что в дико нечитаемом виде:

// подключаем все библиотеки
#include <OneWire.h>
#include "DHT.h"                
#include <DallasTemperature.h>
#include <Time.h>
#include <Wire.h>
#include <DS1307RTC.h>
#include <EEPROM.h>
#include <LiquidCrystal.h>
#include <Encoder.h>

#define ENCODER_USE_INTERRUPTS

#define ONE_WIRE_BUS 13        //номер пина ds18b20
#define DHTPINa 8                // номер пина первого dht22
#define DHTPINb 9           // номер пина второго dht22

OneWire oneWire(ONE_WIRE_BUS);   //создаем обьект для ds18b20

DHT dhta(DHTPINa, DHT22);        // и для dht22
DHT dhtb(DHTPINb, DHT22); 

LiquidCrystal lcd(12, 11, 10, 5, 4, 6, 7);  //подключаем экран
Encoder myEnc(2, 3);
DallasTemperature sensors(&oneWire);  //подключаем ds18b20
DeviceAddress Thermometer1 = { 0x28, 0xFF, 0xEE, 0xBB, 0x62, 0x15, 0x01, 0x92 }; //адрес термометра

int addressWrite = 0;            // переменная для записи       
int addressRead = 0; // переменная для чтения
int x = 0;
byte value;                      // переменная значения ячейки
boolean counter_temp = true;
long oldPosition  = -999;

byte L_kr_lit[8] =               //рисуем нужную кириллицу, буква л
 {
   B00000,
   B00000,
   B01111,
   B00101,
   B00101,
   B10101,
   B01001,
   B00000,
 };
 
byte J_kr_lit[8] =               //рисуем нужную кириллицу, буква ж
 {
   B00000,
   B00000,
   B10101,
   B10101,
   B01110,
   B10101,
   B10101,
   B00000,
 };
 
byte N_kr_lit[8] =               //рисуем нужную кириллицу, буква н
 {
   B00000,
   B00000,
   B10001,
   B10001,
   B11111,
   B10001,
   B10001,
   B00000,
 }; 
 
byte P_kr_lit[8] =               //рисуем нужную кириллицу, буква п
 {
   B00000,
   B00000,
   B11111,
   B10001,
   B10001,
   B10001,
   B10001,
   B00000,
 }; 
 
byte M_kr_lit[8] =               //рисуем нужную кириллицу, буква м
 {
   B00000,
   B00000,
   B10001,
   B11011,
   B10101,
   B10001,
   B10001,
   B00000,
 }; 

byte U_kr_lit[8] =               //рисуем нужную кириллицу, буква У
 {
   B10001,
   B10001,
   B10001,
   B01010,
   B00100,
   B01000,
   B10000,
   B00000,
 }; 
 
byte Cels_kr_lit[8] =            //рисуем значок градуса и С
 {
   B11000,
   B11000,
   B00010,
   B00101,
   B00101,
   B00100,
   B00101,
   B00010,
 }; 
 
void setup() 
{
  lcd.createChar(2, L_kr_lit);  // создаем чары для наших нарисованных букв и символов
  lcd.createChar(3, J_kr_lit);
  lcd.createChar(4, N_kr_lit);
  lcd.createChar(5, P_kr_lit);
  lcd.createChar(6, M_kr_lit);
  lcd.createChar(7, Cels_kr_lit);
  lcd.createChar(1, U_kr_lit);
  
  lcd.begin(16, 2);             // инициализируем экран
               // при включении обнуляем счетчик записи 

  sensors.begin();              // запускаем датчики
  sensors.setResolution(Thermometer1, 10); // и задаем разрешение датчика(от 8 до 12(бит),при 12 лагает)
  
  dhta.begin();                 // запускаем оба DHT
  dhtb.begin();

  setSyncProvider(RTC.get);     // и модуль часов
}

void loop() 
{
long newPosition = myEnc.read();
  if (newPosition != oldPosition) {
    
    if(newPosition < oldPosition )
    {
  
    value = EEPROM.read(addressRead);// то выводим в ком-порт данные
    lcd.clear();
    lcd.print(value, DEC);                                   // первая ячейка - число
    lcd.print(".");
    addressRead = addressRead + 1;

    value = EEPROM.read(addressRead);
    lcd.print(value, DEC);
    lcd.print(".");                                         // вторая - месяц
    addressRead = addressRead + 1;

    value = EEPROM.read(addressRead);
    lcd.print(value, DEC);                           // третья - год, чтобы влезло в один байт, при записи отнимаем 2000, при чтении добавляем
    addressRead = addressRead + 1;
    lcd.print(" ");

    value = EEPROM.read(addressRead);
    lcd.print(value, DEC);                                  // четвертая - час записи.
    addressRead = addressRead + 1;
    lcd.print(" ");
  
    value = EEPROM.read(addressRead);
    lcd.print("B");
    lcd.print(value, DEC);                                 // влажность
    lcd.print("%");                                     // 
    addressRead = addressRead + 1;
    
    lcd.setCursor(0, 1);
    lcd.print(addressRead);
    value = EEPROM.read(addressRead);
    lcd.print("\x5e");
    lcd.print(value-127, DEC);
    lcd.print( "\7" );                // шестая - температура с первого DHT22
    lcd.print(" ");
   addressRead = addressRead + 1;

    value = EEPROM.read(newPosition);
    lcd.print("v");
    lcd.print(value-127, DEC);
    lcd.print( "\7" ); 
    lcd.print(" ");                                 // седьмая - температура с второго DHT22
    addressRead = addressRead + 1;

    value = EEPROM.read(newPosition);
    lcd.print("\x7e");
    lcd.print(value-127, DEC);
    lcd.print( "\7" ); // восьмая - температура с ds18b20
    addressRead = addressRead + 1;


    if(addressRead == EEPROM.length())                        // если достигли конца EEPROM - начинаем сначала
    addressRead = 0; 
    oldPosition = newPosition;
    }
    else
    {
    value = EEPROM.read(addressRead);// то выводим в ком-порт данные
    lcd.clear();
    lcd.print(value, DEC);                                   // первая ячейка - число
    lcd.print(".");
    addressRead = addressRead - 1;

    value = EEPROM.read(addressRead);
    lcd.print(value, DEC);
    lcd.print(".");                                         // вторая - месяц
    addressRead = addressRead - 1;

    value = EEPROM.read(addressRead);
    lcd.print(value, DEC);                           // третья - год, чтобы влезло в один байт, при записи отнимаем 2000, при чтении добавляем
    addressRead = addressRead - 1;
    lcd.print(" ");

    value = EEPROM.read(addressRead);
    lcd.print(value, DEC);                                  // четвертая - час записи.
    addressRead = addressRead - 1;
    lcd.print(" ");
  
    value = EEPROM.read(addressRead);
    lcd.print("B");
    lcd.print(value, DEC);                                 // влажность
    lcd.print("%");                                     // 
    addressRead = addressRead - 1;
    
    lcd.setCursor(0, 1);
    lcd.print(addressRead);
    value = EEPROM.read(addressRead);
    lcd.print("\x5e");
    lcd.print(value-127, DEC);
    lcd.print( "\7" );                // шестая - температура с первого DHT22
    lcd.print(" ");
   addressRead = addressRead - 1;

    value = EEPROM.read(newPosition);
    lcd.print("v");
    lcd.print(value-127, DEC);
    lcd.print( "\7" ); 
    lcd.print(" ");                                 // седьмая - температура с второго DHT22
    addressRead = addressRead - 1;

    value = EEPROM.read(newPosition);
    lcd.print("\x7e");
    lcd.print(value-127, DEC);
    lcd.print( "\7" ); // восьмая - температура с ds18b20
    addressRead = addressRead - 1;


    if(addressRead == EEPROM.length())                        // если достигли конца EEPROM - начинаем сначала
    addressRead = 0; 
    
    oldPosition = newPosition;
    }
  }
  
  sensors.requestTemperatures();   // запрашиваем данные с датчиков, пишем в переменные
  float h1 = dhta.readHumidity();
  float h2 = dhtb.readHumidity();
  float t3 = sensors.getTempC(Thermometer1);                                                          
  float t1 = dhta.readTemperature();
  float t2 = dhtb.readTemperature();

  if (isnan(h1) || isnan(t1) || isnan(h2) || isnan(t2) || isnan (t3) ) 
  // на случай если не удалось считать данные с датчика - выдадим моргающее 10 раз сообщение о ошибке
  {
    for (int i=0; i < 10; i++)
    {
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print( "Sensor Error" );
      delay(200);
      lcd.clear();
      delay(200);
    }
  return;
  }

  byte humydity;                    // переменная для средней влажности
  humydity = ((h1+h2)/2);           // получаем и записываем среднюю влажность
 
  int temp;                         // переменная для средней температуры
  temp = ((t1+t2)/2);

  lcd.clear();                      // очистим для начала экран
  lcd.setCursor(0, 0);              // зададим координаты 
  lcd.print( "B\2a\3\4.:" );        // пишем "Влаж.:", самое значение влажности и процент
  lcd.print(humydity);                                         
  lcd.print("%");                                                             
    
  lcd.setCursor(11, 0);             // переходим на вторую строку
  if (hour() < 10)     // для красивого отображения часов и минут меньше 10 (например, не 2:5, а 02:05)
    {lcd.print("0");}
  lcd.print( hour() );              // пишем часы и минуты
  lcd.print( ":" );
  if (minute() < 10)
    {lcd.print("0");}
  lcd.print( minute() );

  if (counter_temp)
  // в зависимости от счетчика показываем либо температуру внутри и меняем счетчик, либо уличную и меняем счетчик
  {
    counter_temp = false;
    lcd.setCursor(0, 1);
    lcd.print( "Te\6\5.:" );        // пишем "Темп.:"
    lcd.print(temp);
    lcd.print( "\7" );              // и наш значок градусов
   
  }
  else
  {
    counter_temp = true;
    lcd.setCursor(0, 1);           // аналогично для уличной температуры, только пишем "Темп.Ул.:"
    lcd.print( "Te\6\5.\1\2.:" );                                            
    lcd.print(t3);
    lcd.print("\7");
  }  

  if (x == 0 && minute() == 0 )                              // условия для записи, одна запись в нужную минуту
  {
   lcd.clear();
   lcd.print("Data write");
   EEPROM.write(addressWrite, day());
   addressWrite = addressWrite + 1;                                        // переход на следующий адрес
   if (addressWrite == 1024)                                               // если заполнилось - начинаем сначала
    addressWrite = 0;
   delay(50);                                                              // на всякий случай
   
   EEPROM.write(addressWrite, month());
   addressWrite = addressWrite + 1;
   if (addressWrite == 1024)
    addressWrite = 0;
   delay(50);

   EEPROM.write(addressWrite,(byte) year() - 2000 );
   addressWrite = addressWrite + 1;
   if (addressWrite == 1024)
    addressWrite = 0;
   delay(50);
   
   EEPROM.write(addressWrite, hour());
   addressWrite = addressWrite + 1;
   if (addressWrite == 1024)
    addressWrite = 0;
   delay(50);
   
   EEPROM.write(addressWrite, (byte) humydity);
   addressWrite = addressWrite + 1;
   if (addressWrite == 1024)
    addressWrite = 0;
   delay(50);
                                                      
   EEPROM.write(addressWrite, (byte) t1 + 127);
   addressWrite = addressWrite + 1;
   if (addressWrite == 1024)
    addressWrite = 0;
   delay(50);
   
   EEPROM.write(addressWrite, (byte) t2 + 127);
   addressWrite = addressWrite + 1;
   if (addressWrite == 1024)
    addressWrite = 0;
   delay(50);

   EEPROM.write(addressWrite, (byte) t3 + 127);
   addressWrite = addressWrite + 1;
   if (addressWrite == 1024)
    addressWrite = 0;
   delay(50);
   
   x++;
   }
   
   if ( x > 0 && minute() == 1 )                                // когда прошла первая минута - обнуляем счетчик, не сделали это сразу чтобы не было несколько записей                  
   x =0;                                                                       // в одну и ту же минуту

  
  }

 

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

Клапауций 777
Offline
Зарегистрирован: 21.11.2015

Мужик из полиуретана пишет:

  Вот весь код целиком, правда пока что в дико нечитаемом виде:

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

не нужно мне код давать, что ты там наворотил, сам разбирайся - я тебе объясняю общий принцип: печатай с lcd.setCursor();, стирай пробелами с lcd.setCursor(); всё.

и, всё будет работать.

Мужик из полиуретана
Offline
Зарегистрирован: 12.09.2015

Клапауций 777 пишет:

не нужно мне код давать, что ты там наворотил, сам разбирайся - я тебе объясняю общий принцип: печатай с lcd.setCursor();, стирай пробелами с lcd.setCursor(); всё.

и, всё будет работать.

А чем это принципиально лучше, чем lcd.clear, если, допустим, в режиме реал-тайм отображения ин-фы с датчиков обе строки полностью заняты и в режиме считывания записанных данных тоже ? clear же в таком случае даже удобнее использовать, чем две строки пробелами забивать.

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

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

В покое отображают реал-тайм данные с датчиков, крутанул энкодером - отображаются данные из еепром за прошлые числа, если 10 секунд энкодером не крутишь - возврат обратно к реал-тайм данным, если крутишь - листаются записи. 

Logik
Offline
Зарегистрирован: 05.08.2014

Мужик из полиуретана пишет:

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

 

Смотрите http://arduino.ru/tutorials/BlinkWithoutDelay и этот подход используйте для определения нужного времени.

Клапауций 777
Offline
Зарегистрирован: 21.11.2015

Мужик из полиуретана пишет:

А чем это принципиально лучше, чем lcd.clear, если, допустим, в режиме реал-тайм отображения ин-фы с датчиков обе строки полностью заняты и в режиме считывания записанных данных тоже ? clear же в таком случае даже удобнее использовать, чем две строки пробелами забивать.

начнём с факта того, что твой алгоритм кода не работает, а мой - работает.

тебе этого достаточно?

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

вот тебе шаблон печати в дисплей одной переменной без затирания всего дисплея:

печать четырёхзначного значения энкодера в экран

static int a; 
int na = Enc_a.read();
if (na != a) {a = na;
lcd.setCursor(4, 1); 
if (a < 10) {lcd.print(" ");}
if (a < 100) {lcd.print(" ");}
if (a < 1000) {lcd.print(" ");}
lcd.print(a);
}
Мужик из полиуретана
Offline
Зарегистрирован: 12.09.2015

Logik пишет:

Мужик из полиуретана пишет:

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

 

Смотрите http://arduino.ru/tutorials/BlinkWithoutDelay и этот подход используйте для определения нужного времени.

Премного благодарен 

В итоге все-таки додумал решение

void loop() 
  {
   long newPosition = myEnc.read();  // берем значение с энкодера
  
   if (newPosition != oldPosition)  // если оно изменилось
   {
    unsigned long currentMillis = millis(); // запоминаем время
    if(newPosition < oldPosition ) // и смотрим в какую сторону его крутили, если по часовой
      {
  
      *Выводим нужные данные*

      oldPosition = newPosition;  //запоминаем положение энкодера
      while( (currentMillis - previousMillis < interval) && (newPosition == oldPosition) ) 
      {                  // создаем цикл, который будет слушать энкодер и считать секунды пока не прошло 10 сек или пока не изменилось положение энкодера
       currentMillis = millis();
       newPosition = myEnc.read();
       }

       previousMillis = currentMillis   //запоминаем время
;
      }

    else        //если же крутили против часовой, то тоже самое, только уходим на минус 16 ячеек и делаем тоже самое
    {
      addressRead = addressRead - 16;
  *выводим нужные данные*

      oldPosition = newPosition;  
      while( (currentMillis - previousMillis < interval) && (newPosition == oldPosition) ) 
      {
       currentMillis = millis();
       newPosition = myEnc.read();
       }
       previousMillis = currentMillis;
      }
    } 
  
  *считываем датчики, показываем их рил-тайм*