Чтение и эмуляция датчиков Oregon Scientific (433Mhz)

gulin176
Offline
Зарегистрирован: 03.09.2016

Ну не знаю неделю дождь льёт рядом с датчиком. Показания влажности в такой период 98-99%. Считаю идеальным калибром. В другие периоды очень сложно найти от чего мерять влажность. Хотя в летние месяцы при полностью открытых окнах домашние показания и уличные условно одинаковые. Сама станция стоит близко к открытому окну за которым датчик

gulin176
Offline
Зарегистрирован: 03.09.2016

А откуда инфа что должно что-то покрывать поверхность электродов. Не видел не разу не окислов не другого налёта. Возможно я живу в довольно таки чистом месте. Думаю что датчику в районе МКАДа действительно несладко. Но внутри датчика всё таки замкнутая система

snickser
Offline
Зарегистрирован: 02.07.2016

Притом что большинство орегоновских датчиков имеют заявленный диапазон измеренией как 25%...95%, 98 это странное число )

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

http://pokupandex.ru/aliexpress/1287/kalibrovka-izmeriteley-vlazhnosti-s-datchikom-hr202l.html

XOR
Offline
Зарегистрирован: 25.04.2015

в этом диапазоне погрешность не превышает заявленной, а амс понимает 2-98%

датчик резистивный

Sprite
Offline
Зарегистрирован: 30.10.2016

Перестал передавать показания датчик Oregon RTGN318.

Подумал, что батарейка села, заменил, безрезультатно.

Мало того, с других датчиков сигнал стал плохо приходить, подумал что помехи посторонние какие то.

Вынул батарейку из этого не работающего датчика и с остальтных датчиков стали данные приходить хорошо.

Получается датчик умер, да ещё и эфир засорять стал. 

4ishops
Offline
Зарегистрирован: 06.10.2012

Porosenok пишет:

KVadik пишет:

Ну про "у всех" это вы загнули, это у тех что за $0.5-$1 нет. У всяких Si4432, CC1101 она, насколько я помню, есть.

И кстати ещё. Подскажите, где почитать на тему исправления показаний влажности орегоновских датчиков? У меня все три из разных серий, все сейчас за бортом и при -9С все показывают 40-50%, что явно враньё.

 

Орегоновские датчики это те еще поделки, да))) на датчик влажности я бы вообще внимания не обращал, врет он безбожно!

 

Недавно сравнивал показания с цифровым и довольно точным SHT21 (Typ. Humidity Accuracy %RH ±2, Typ. Temperature °C ±0.3), орегон внутри показывал 18%, SHT 30%, снаружи 45%, SHT 68%

 

snickser
Offline
Зарегистрирован: 02.07.2016

4ishops,

и не надейтесь, разброс показаний влажности у SHT21 тоже весьма велик порой бывает. ;) у меня их несколько, и сравнивал с экземпляром у коллеги, лежащие рядом иной раз до 10% разницу показывают.

4ishops
Offline
Зарегистрирован: 06.10.2012

snickser пишет:

4ishops,

и не надейтесь, разброс показаний влажности у SHT21 тоже весьма велик порой бывает. ;) у меня их несколько, и сравнивал с экземпляром у коллеги, лежащие рядом иной раз до 10% разницу показывают.

 

10% это не в полтора раза как сейчас, уже жить можно :) 

в любом случае SHT21 это цифра и более точен по определению, дальше уже только профессиональные решения идут типа Honeywell и подобных, но там ценник уже другой будет...

snickser
Offline
Зарегистрирован: 02.07.2016

Работал у меня датчик работал, а потом с него приехало вот такое... )

Wed Nov 30 15:12:57 2016 - :1A:2D:10:CE:90:07:18:06:4A: 1 206 -7.9 61.0 0
Wed Nov 30 15:13:36 2016 - :1A:2D:10:DE:F0:CF:F3:6B:79: 1 222 136.5 125.0 0

И ведь контрольная сумма совпала... Кто-то мне в эфир нагадил, или датчик с ума сошёл?... ))

gulin176
Offline
Зарегистрирован: 03.09.2016

спасибо, классно работает а для отладки можно вывести на экран количество потерянных "периодов приёма данных". чтобы понять там ли стоит приемник. ещё с вашим кодом работает thgn800.

snickser
Offline
Зарегистрирован: 02.07.2016

Вот только код канала не универсален получается, надо его как-то допилить... )

 

byte channel(const byte* data)
{
   byte channel;
   switch (data[2]>>4)
   {
      case 0x1:
         channel = 1;
         break;
      case 0x2:
         channel = 2;
         break;
      case 0x3:
         channel = 3;
         break;
      case 0x4:
         if((data[2]&0xF)>0){
          channel = 4;
         } else {
          channel = 3;
         } 
         break;
      case 0x5:
         channel = 5;
         break;
      case 0x6:
         channel = 6;
         break;
      case 0x7:
         channel = 7;
         break;
   }
 return channel;
} 

 

gulin176
Offline
Зарегистрирован: 03.09.2016

а на 1602 пишет: канал.22

snickser
Offline
Зарегистрирован: 02.07.2016

22 это 0x34 в HEX, канал третий, используете код функции что я выше привел.

 

gulin176
Offline
Зарегистрирован: 03.09.2016

получилось вот так

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

а можно при допустим 5 пропущеных периодах выводить звёздочку(допустим), при десяти пропущеных писать данные устарели. и ещё на экране 1602 вполне можно уместить данные с 2 датчиков ещё и место останется. чтобы показания не скакали надо для каждого датчика свой (data) иметь? тут можно подсказать что исправить

Porosenok
Offline
Зарегистрирован: 06.11.2016

snickser пишет:

И ведь контрольная сумма совпала... Кто-то мне в эфир нагадил, или датчик с ума сошёл?... ))

Ну так там метод расчёта контрольной суммы не выдерживает никакой критики. Вероятность ошибки достаточно высока. Неоднократно подобные пакеты ловил.

Porosenok
Offline
Зарегистрирован: 06.11.2016

Кстати, мой вопрос по поводу использования si4432 для ловли сигналов от датчиков Oregon был проигнорирован. Я что-то неприличное спросил?

Sprite
Offline
Зарегистрирован: 30.10.2016

Подскажите, почему компилятор ругается на эту строчку?

if ((channel(data))==2 || (сhannel(data))==4 || (сhannel(data))==6)

 

snickser
Offline
Зарегистрирован: 02.07.2016

у вас там буква 'с' русская ;)

snickser
Offline
Зарегистрирован: 02.07.2016

Porosenok пишет:

почему для приёма сигнала от орегоновских датчиков мы используем всякие китайские супергетородины и прочую муть?

В смысле этот вопрос?...

Потому что Si4432 по умолчанию не умеет принимать ничего ) его надо для этого программировать, а простые приёмники вроде тех что на первой странице - питание подключил и они сразу начинают данные выдавать.

 

Sprite
Offline
Зарегистрирован: 30.10.2016

snickser пишет:

у вас там буква 'с' русская ;)

Вот блин, спасибо!!

Porosenok
Offline
Зарегистрирован: 06.11.2016

snickser пишет:

Потому что Si4432 по умолчанию не умеет принимать ничего ) его надо для этого программировать, а простые приёмники вроде тех что на первой странице - питание подключил и они сразу начинают данные выдавать.

Они же выдают не данные, а сырой шум. А si4432 способен сам поймать, распотрошить посылку, посчитать CRC и выдать уже приготовленные данные с гарниром. Цена-то у всех приёмников копеечная.

snickser
Offline
Зарегистрирован: 02.07.2016

gulin176 пишет:

получилось вот так

а можно при допустим 5 пропущеных периодах выводить звёздочку(допустим), при десяти пропущеных писать данные устарели. и ещё на экране 1602 вполне можно уместить данные с 2 датчиков ещё и место останется. чтобы показания не скакали надо для каждого датчика свой (data) иметь? тут можно подсказать что исправить

Всё можно сделать, было бы желание )

Я бы сделал массивы для каждого параметра, и хранил данные там, типа:

float t[5]; // температура
byte h[5]; // влажность
byte b[5]; // батарейка
unsigned long upd[5]; // время
byte ch=0; // счётчик

В качестве индекса использовал бы номер канала  channel(data), а в upd[] сохранял бы время последнего прихода пакета

t[channel(data)]=temperature(data);
h[channel(data)]=humidity(data);
b[channel(data)]=battery(data);
upd[channel(data)]=millis();

 Организовал бы в loop() показ всех датчиков по очереди, каждую третью секунду, вроде:

if(millis()%3000==0){
// увеличиваем счётчик 
 ch++;
 if(ch<=4){
// вывод параметров
// print(t[ch]);
// print(h[ch]);
// print(b[ch]);
  if(millis()-upd[ch] > 500000){
// проверка десяти обновлений (500сек)
// print("Данные устарели");
  } else if (millis()-upd[ch] > 250000){
// проверка пяти обновлений (250сек)
// print("*");
  }
 } else {
  ch=0;
 }
}

 

 

Porosenok пишет:

А si4432 способен сам поймать, распотрошить посылку, посчитать CRC и выдать уже приготовленные данные с гарниром.

Тогда бы это была бы тема программирования si4432, а не Arduino ;)

 

gulin176
Offline
Зарегистрирован: 03.09.2016

спасибо попытаюсь, код для меня очень длинный смогу ли осилить... в посту#180 у меня уличный датчик работает почти без пропусков. в вашем же коде мне кажется присутствует ошибка. сначала принимает показания обеих датчиков, однако спустя пару часов уличный датчик пропадает из сериал, появляется 1 раз на 20(примерно) показаний "комнатного" и даже реже. возможно чтото с эфиром, но живу в довольно таки чистом месте(электромагнитном)

snickser
Offline
Зарегистрирован: 02.07.2016

Дело в том, что это не мой код )

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

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

Орегоны передают данные с разной задержкой, именно по этой причине, на первом канале каждые 39 секунд, на втором канале 41 секунду, на третьем канале 43 секунды. Мне кажется это сделано чтоб если вдруг они все вместе захотят передать данные в один и тот же момент времени, на следующий раз у них бы это не получилось ))

Так же вполне допускаю, что на этой частоте в эфире вещается что-то, что мешает приёму. Или у вас там просто датчик неисправен, как у меня номер два.

Вот график обновлений данных моих Орегон датчиков, второй (зелёный) часто глючит сам по себе. Иногда может сам по себе часами ничего якобы не слать... Хотя первый и третий стабильны. 4-й это передатчик собранный на Ардуино, на 5-й не обращайте внимания, это тестовый.

На графике это время от millis()%10000.

 

 

Porosenok
Offline
Зарегистрирован: 06.11.2016

snickser пишет:

Тогда бы это была бы тема программирования si4432, а не Arduino ;)

Там не программирование, а конфигурирование. Один раз забил данные в регистры и всё. Нельзя же, например, назвать программированием LCD2004 забивку туда пользовательских символов.

4ishops
Offline
Зарегистрирован: 06.10.2012

Porosenok пишет:

snickser пишет:

Тогда бы это была бы тема программирования si4432, а не Arduino ;)

Там не программирование, а конфигурирование. Один раз забил данные в регистры и всё. Нельзя же, например, назвать программированием LCD2004 забивку туда пользовательских символов.

 

Все так, но скетч явно сложнее будет, пока не видел проектов где есть связка SI4432 и Oregon или RCSwitch.

В целом конечно чип более навороченный и недорогой.

 

 

Sprite
Offline
Зарегистрирован: 30.10.2016

На данный момент реализовал одновременный вывод информации с двух датчиков.

На первую строку выводятся данные с датчиков, чьи каналы 1,3,5, а на вторую соответственно 2,4,6.

Выводятся только текущие полученные значения, на матрицу и накопление данных моих знаний не достаточно.

// ATmega 2560
// Приёмник подключается к PWM(2)
// LCD подключается SCL -> SCL(21); SDA -> SDA(20)


#define PORT 2
#define printByte(args) write(args);

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3f,16,2);  // Адрес LCD 0x3f, может быть 0x27

uint8_t cels[8]  = {0x2,0x5,0x5,0x2}; // Значёк цельсия
uint8_t batlow[8]  = {0xE,0x1f,0x11,0x11,0x11,0x11,0x1f,0x1f}; // Значок пустой батарейки
uint8_t batok[8] = {0xE,0x1f,0x11,0x15,0x15,0x15,0x11,0x1f};  // Значок полной батарейки
uint8_t termom[8] = {0x4,0xA,0xA,0xE,0xE,0x1f,0x1f,0xE};  // Значок термометра
uint8_t kapla[8] = {0x4,0x4,0xA,0xA,0x11,0x11,0x11,0xE};  // Значок капли

class DecodeOOK {
protected:
    byte total_bits, bits, flip, state, pos, data[25];

    virtual char decode (word width) =0;
    
public:

    enum { UNKNOWN, T0, T1, T2, T3, OK, DONE };

    DecodeOOK () { resetDecoder(); }

    bool nextPulse (word width) {
        if (state != DONE)
        
            switch (decode(width)) {
                case -1: resetDecoder(); break;
                case 1:  done(); break;
            }
        return isDone();
    }
    
    bool isDone () const { return state == DONE; }

    const byte* getData (byte& count) const {
        count = pos;
        return data; 
    }
    
    void resetDecoder () {
        total_bits = bits = pos = flip = 0;
        state = UNKNOWN;
    }
    
    // add one bit to the packet data buffer
    
    virtual void gotBit (char value) {
        total_bits++;
        byte *ptr = data + pos;
        *ptr = (*ptr >> 1) | (value << 7);

        if (++bits >= 8) {
            bits = 0;
            if (++pos >= sizeof data) {
                resetDecoder();
                return;
            }
        }
        state = OK;
    }
    
    // store a bit using Manchester encoding
    void manchester (char value) {
        flip ^= value; // manchester code, long pulse flips the bit
        gotBit(flip);
    }
    
    // move bits to the front so that all the bits are aligned to the end
    void alignTail (byte max =0) {
        // align bits
        if (bits != 0) {
            data[pos] >>= 8 - bits;
            for (byte i = 0; i < pos; ++i)
                data[i] = (data[i] >> bits) | (data[i+1] << (8 - bits));
            bits = 0;
        }
        // optionally shift bytes down if there are too many of 'em
        if (max > 0 && pos > max) {
            byte n = pos - max;
            pos = max;
            for (byte i = 0; i < pos; ++i)
                data[i] = data[i+n];
        }
    }
    
    void reverseBits () {
        for (byte i = 0; i < pos; ++i) {
            byte b = data[i];
            for (byte j = 0; j < 8; ++j) {
                data[i] = (data[i] << 1) | (b & 1);
                b >>= 1;
            }
        }
    }
    
    void reverseNibbles () {
        for (byte i = 0; i < pos; ++i)
            data[i] = (data[i] << 4) | (data[i] >> 4);
    }
    
    void done () {
        while (bits)
            gotBit(0); // padding
        state = DONE;
    }
};

// 433 MHz decoders



class OregonDecoderV2 : public DecodeOOK 
{
   public:  
  OregonDecoderV2() {}

      // add one bit to the packet data buffer
  virtual void gotBit (char value) 
      {
         if(!(total_bits & 0x01))
         {
            data[pos] = (data[pos] >> 1) | (value ? 0x80 : 00);
         }

         total_bits++;
         pos = total_bits >> 4;

         if (pos >= sizeof data) 
         {
            resetDecoder();
            return;
         }
         state = OK;
      }

  virtual char decode(word width) 
      {
         if (200 <= width && width < 1200) 
         {
            byte w = width >= 700;

            switch (state) 
            {
               case UNKNOWN:
                  if (w != 0) 
                  {
                     // Long pulse
                     ++flip;
                  } 
                  else if (w == 0 && 24 <= flip) 
                  {
                     // Short pulse, start bit
                     flip = 0;
                     state = T0;
                  } 
                  else 
                  {
                     // Reset decoder
                     return -1;
                  }
                  break;
               case OK:
                  if (w == 0) 
                  {
                     // Short pulse
                     state = T0;
                  }
                  else 
                  {
                     // Long pulse
                     manchester(1);
                  }
                  break;
               case T0:
                  if (w == 0) 
                  {
                     // Second short pulse
                     manchester(0);
                  } 
                  else 
                  {
                     // Reset decoder
                     return -1;
                  }
               break;
            }
         } 
         else if (width >= 2500  && pos >= 8) 
         {
            return 1;
         } 
         else 
         {
            return -1;
         }
         return 0;
      }

};


class OregonDecoderV3 : public DecodeOOK {
public:
    OregonDecoderV3() {}
    
    // add one bit to the packet data buffer
    virtual void gotBit (char value) {
        data[pos] = (data[pos] >> 1) | (value ? 0x80 : 00);
        total_bits++;
        pos = total_bits >> 3;
        if (pos >= sizeof data) {
            resetDecoder();
            return;
        }
        state = OK;
    }
    
    virtual char decode (word width) {
        if (200 <= width && width < 1200) {
            byte w = width >= 700;
            switch (state) {
                case UNKNOWN:
                    if (w == 0)
                        ++flip;
                    else if (32 <= flip) {
                        flip = 1;
                        manchester(1);
                    } else
                        return -1;
                    break;
                case OK:
                    if (w == 0)
                        state = T0;
                    else
                        manchester(1);
                    break;
                case T0:
                    if (w == 0)
                        manchester(0);
                    else
                        return -1;
                    break;
            }
        } else {
            return -1;
        }
        return  total_bits == 80 ? 1: 0;
    }
};


OregonDecoderV2 orscV2;
OregonDecoderV3 orscV3;

volatile word pulse;

void ext_int_1(void) {
    static word last;
    // determine the pulse length in microseconds, for either polarity
    pulse = micros() - last;
    last += pulse;
}

//
// Oregon packet decoder
//

float temperature(const byte* data)
{
   int sign = (data[6]&0x8) ? -1 : 1;
   float temp = ((data[5]&0xF0) >> 4)*10 + (data[5]&0xF) + (float)(((data[4]&0xF0) >> 4) / 10.0);
   return sign * temp;
}

byte humidity(const byte* data)
{
   return (data[7]&0xF) * 10 + ((data[6]&0xF0) >> 4) ;
}

float humi_ext(const byte* data)
{
   return  humidity(data) + ((data[7]&0xF0)>>4)/10.0 ;
}

byte battery(const byte* data)
{
   return (data[4] & 0xF) ;
}

byte serial(const byte* data)
{
   return (data[3]);
}

byte channel(const byte* data)
{
   byte channel;
   switch (data[2]>>4)
   {
      case 0x1:
         channel = 1;
         break;
      case 0x2:
         channel = 2;
         break;
      case 0x3:
         channel = 3;
         break;
      case 0x4:
         if((data[2]&0xF)>0){
          channel = 4;
         } else {
          channel = 3;
         } 
         break;
      case 0x5:
         channel = 5;
         break;
      case 0x6:
         channel = 6;
         break;
      case 0x7:
         channel = 7;
         break;
   }
 return channel;
} 

int Sum(byte count, const byte* data)
{
  int s = 0;
 
  for(byte i = 0; i<count;i++)
  {
    s += (data[i]&0xF0) >> 4;
    s += (data[i]&0xF);
  }
 
  if(int(count) != count)
    s += (data[count]&0xF0) >> 4;
 
  return s;
}

////////////////////////////////////////////////////
////////////////////////////////////////////////////
/////////// Вывод результата в Serial  /////////////
////////////////////////////////////////////////////
////////////////////////////////////////////////////

void reportSerial (const char* s, class DecodeOOK& decoder)
{
    byte pos;
    const byte* data = decoder.getData(pos);
    Serial.print(millis()/1000.,3);
    Serial.print(" ");
    Serial.print(s);
    Serial.print(' ');
    for (byte i = 0; i < pos; ++i) {
        Serial.print(data[i] >> 4, HEX);
        Serial.print(data[i] & 0x0F, HEX);
    }

    if( data[8] == (Sum(8,data)-0xa)&0xFF )
    {
      Serial.print(" Bat.: "+String(battery(data)));
      Serial.print(" ID: "+String(serial(data),HEX));
      Serial.println();
      Serial.print("Ch."+String(channel(data)));
      Serial.println();
      Serial.print("T="+String(temperature(data),1)+"C"+" H="+String(humidity(data))+"%");
      Serial.println();
          if(battery(data) == 0xC){
          Serial.print("Bat: LOW");
          Serial.println();}
          else {
          Serial.print("Bat: OK");
          Serial.println();}

      }
      else
      {
      int sum = ((Sum(6, data) + (data[6]&0xF) - 0xa) & 0xff);
      if( (sum&0xF) == (data[6]>>4) && (sum>>4) == (data[7]&0xF) ){
      Serial.print(" Bat: "+String(battery(data)));
      Serial.print(" ID: "+String(serial(data),HEX));
      Serial.println();
      Serial.print("Ch."+String(channel(data)));
      Serial.println();
      Serial.print("T="+String(temperature(data),1)+"C");
      Serial.println();
          if (battery(data) == 0xC){
          Serial.print("Bat: LOW");
          Serial.println();
          }
          else {
          Serial.print("Bat: OK");
          Serial.println();
          }
        }
        else
        {
        Serial.print(" Checksum error");
        }
     Serial.println(); 
    }

////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
///////////////////  Вывод результата на LCD   /////////////////////
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////

/// Датчик с влажностью

 if( data[8] == (Sum(8,data)-0xa)&0xFF )
 {
  if ((channel(data))==1|(channel(data))==3|(channel(data))==5)
  {
   lcd.setCursor(0,0); lcd.print("                ");
   lcd.setCursor(0,0);
   lcd.print (String(channel(data),HEX));
   lcd.print(" "); lcd.printByte(3); lcd.print(String(temperature(data),1)); lcd.printByte(0); lcd.print("C");
   lcd.setCursor(10,0);
   lcd.printByte(4); lcd.print(String(humidity(data))+"%");
   if( (battery(data)) == 0xC)
   {
    lcd.setCursor(15,0);
    lcd.printByte(1)
   }
   else
   {
    lcd.setCursor(15,0);
    lcd.printByte(2);
   }
  }
  if ((channel(data))==2|(channel(data))==4|(channel(data))==6)
  {
   lcd.setCursor(0,1); lcd.print("                ");
   lcd.setCursor(0,1);
   lcd.print (String(channel(data),HEX));
   lcd.print(" "); lcd.printByte(3); lcd.print(String(temperature(data),1)); lcd.printByte(0); lcd.print("C");
   lcd.setCursor(10,1);
   lcd.printByte(4); lcd.print(String(humidity(data))+"%");
   if( (battery(data)) == 0xC)
   {
    lcd.setCursor(15,1);
    lcd.printByte(1)
   }
   else
   {
    lcd.setCursor(15,1);
    lcd.printByte(2);
   }
  }
 }
/// Датчик без влажности      
 else
 {
  int sum = ((Sum(6, data) + (data[6]&0xF) - 0xa) & 0xff);
  if( (sum&0xF) == (data[6]>>4) && (sum>>4) == (data[7]&0xF) )
  {
   if ((channel(data))==1|(channel(data))==3|(channel(data))==5)
   {
    lcd.setCursor(0,0); lcd.print("                ");
    lcd.setCursor(0,0);
    lcd.print (String(channel(data),HEX));
    lcd.print(" "); lcd.printByte(3); lcd.print(String(temperature(data),1)); lcd.printByte(0); lcd.print("C");
    if( (battery(data)) == 0xC)
    {
     lcd.setCursor(15,0);
     lcd.printByte(1)
    }
    else
    {
     lcd.setCursor(15,0);
     lcd.printByte(2);
    }
   }
   if ((channel(data))==2 | (channel(data))==4 | (channel(data))==6)
   {
    lcd.setCursor(0,1); lcd.print("                ");
    lcd.setCursor(0,1);
    lcd.print (String(channel(data),HEX));
    lcd.print(" "); lcd.printByte(3); lcd.print(String(temperature(data),1)); lcd.printByte(0); lcd.print("C");
    if( (battery(data)) == 0xC)
    {
     lcd.setCursor(15,1);
     lcd.printByte(1)}
    else
    {
     lcd.setCursor(15,1);
     lcd.printByte(2);
    }
   }
  }
 }   
 

////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
////////////////  Конец вывод результата на LCD   //////////////////
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////





 decoder.resetDecoder();
}




void setup () {
  lcd.init();
   lcd.backlight();
    lcd.createChar(0, cels);
    lcd.createChar(1, batlow);
    lcd.createChar(2, batok);
    lcd.createChar(3, termom);
    lcd.createChar(4, kapla);
    
    Serial.begin(9600);
    Serial.println("\n[ookDecoder]");
     
    
    pinMode(PORT, INPUT);  // use the AIO pin

   attachInterrupt(digitalPinToInterrupt(PORT), ext_int_1, CHANGE);



}

void loop () {

  
    static int i = 0;
    
    cli();
    word p = pulse;
    pulse = 0;
    sei();

    //if (p != 0){ Serial.print(++i); Serial.print('\n');}
    
    if (p != 0) {
        if (orscV2.nextPulse(p))
            reportSerial("OSV2", orscV2);  
        if (orscV3.nextPulse(p))
            reportSerial("OSV3", orscV3);        
      }
}

 

gulin176
Offline
Зарегистрирован: 03.09.2016

Хочется предупредить желающих повторить конструкцию что схема из ардуино и датчика rf-5v(у меня) очень требовательна к питанию. сначала думал что помехи в эфире мешают принимать датчику сигналы, однако выяснилось, что если питать ардуино напряжением с компьютера, то наблюдается интересная картина. если компьютер в простое то не наблюдается ничего ненормального, если же запустить игру, то видимо возникает большое количество помех в кабеле юсб и данные в ардуино перестают приходить. само расположение всех элементов конструкции не менясь. просадок в питании не наблюдается бп с запасом стоит

Belka
Offline
Зарегистрирован: 09.12.2016

snickser пишет:

В общем код из шапки поста неполный, надо его чуток дохачивать...

1) Кроме чексуммы восьмого байта ещё и CRC считать в девятом байте пакета.

void checkSumAndCRC(byte * data, const uint8_t len)
{
#define mByte(i) (data[i])
#define NIBBLE(i) ((mByte(i>>1) >> (((i)&1)<<2))&0xf)
uint8_t i,j,c,CRC,SUM;

CRC =0x3C;
SUM =0x00;
uint8_t CCIT_POLY = 0x07;
for (j=1; j<2*len; j++)
{
c = NIBBLE(j);
SUM += c;
if ( j != 6 && j != 7){ // place for ID
CRC ^= c;
for(i = 0; i<4; i++)
if(CRC & 0x80 )
CRC = (CRC << 1) ^ CCIT_POLY;
else
CRC <<= 1;
CRC &= 0xff;
}
}
for(i = 0; i<4; i++)
if(CRC & 0x80 )
CRC = (CRC << 1) ^ CCIT_POLY;
else
CRC <<= 1;
data[len] = (SUM & 0xFF);
data[len+1] = CRC;
}

Заменив старую функцию новой

// Calculate the checksum
// calculateAndSetChecksum(OregonMessageBuffer);
checkSumAndCRC(OregonMessageBuffer, 8);

2) Увеличить размер буфера с 9 на 10 из-за CRC.

3) Увеличить размер тишины между посылками  delayMicroseconds(TWOTIME*10); хотя это и не обязательно, обычно база читает только первый посыл.

4) защитить код передатчика от прерываний

void sendOregon(byte *data, byte size)
{
  cli(); //off
    sendPreamble();
    //sendSync();
    sendData(data, size);
    //sendPostamble();
  sei(); //on
}

5) И самое главное - найти осциллографом или методом научного тыка временные интервалы для "TIME = 482". У меня три ардуины и у всех этот параметр пришлось подбирать индивидуально, из-за различий в работе внутреннего таймера. Приём на базе работает только если это время +/- 1-3 микросекунды от стандарта. Выключение прерываний сильно влияет на этот параметр, если их не выключать ардуина растягивает пакеты во времени на произвольное число и они не всегда понимаются базой. Если нет осциллографа можно попробовать перебрать по очереди все значения от 480-490... ;)

А не могли бы вы рабочий код целиком привести?

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

Соответственно, оригинальная погодная станция его не видит.

snickser
Offline
Зарегистрирован: 02.07.2016

Belka пишет:

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

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

 

#include <Wire.h>  // must be incuded here so that Arduino library object file references work

#include <Adafruit_SleepyDog.h>

// HTU21
#include "Adafruit_HTU21DF.h"
Adafruit_HTU21DF htu = Adafruit_HTU21DF();
byte HT;

char params[255];

long sleepMS;

#define V_PIN   A0
#define TX_PIN  4

const unsigned long TIME = 482;
const unsigned long TWOTIME = TIME*2;
 
#define SEND_HIGH() digitalWrite(TX_PIN, HIGH)
#define SEND_LOW() digitalWrite(TX_PIN, LOW)
 
byte OregonMessageBuffer[10];
 
/**
 * \brief    Send logical "0" over RF
 * \details  azero bit be represented by an off-to-on transition
 * \         of the RF signal at the middle of a clock period.
 * \         Remenber, the Oregon v2.1 protocol add an inverted bit first
 */
inline void sendZero(void)
{
  SEND_HIGH();
  delayMicroseconds(TIME);
  SEND_LOW();
  delayMicroseconds(TWOTIME);
  SEND_HIGH();
  delayMicroseconds(TIME);
}
 
/**
 * \brief    Send logical "1" over RF
 * \details  a one bit be represented by an on-to-off transition
 * \         of the RF signal at the middle of a clock period.
 * \         Remenber, the Oregon v2.1 protocol add an inverted bit first
 */
inline void sendOne(void)
{
   SEND_LOW();
   delayMicroseconds(TIME);
   SEND_HIGH();
   delayMicroseconds(TWOTIME);
   SEND_LOW();
   delayMicroseconds(TIME);
}
 
/**
* Send a bits quarter (4 bits = MSB from 8 bits value) over RF
*
* @param data Source data to process and sent
*/
 
/**
 * \brief    Send a bits quarter (4 bits = MSB from 8 bits value) over RF
 * \param    data   Data to send
 */
inline void sendQuarterMSB(const byte data)
{
  (bitRead(data, 4)) ? sendOne() : sendZero();
  (bitRead(data, 5)) ? sendOne() : sendZero();
  (bitRead(data, 6)) ? sendOne() : sendZero();
  (bitRead(data, 7)) ? sendOne() : sendZero();
}
 
/**
 * \brief    Send a bits quarter (4 bits = LSB from 8 bits value) over RF
 * \param    data   Data to send
 */
inline void sendQuarterLSB(const byte data)
{
  (bitRead(data, 0)) ? sendOne() : sendZero();
  (bitRead(data, 1)) ? sendOne() : sendZero();
  (bitRead(data, 2)) ? sendOne() : sendZero();
  (bitRead(data, 3)) ? sendOne() : sendZero();
}
 
/******************************************************************/
/******************************************************************/
/******************************************************************/
 
/**
 * \brief    Send a buffer over RF
 * \param    data   Data to send
 * \param    size   size of data to send
 */
void sendData(byte *data, byte size)
{
  for(byte i = 0; i < size; ++i)
  {
    sendQuarterLSB(data[i]);
    sendQuarterMSB(data[i]);
  }
}
 
/**
 * \brief    Send an Oregon message
 * \param    data   The Oregon message
 */
void sendOregon(byte *data, byte size)
{
   cli();
    sendPreamble();
    //sendOne();
    //sendSync();
    sendData(data, size);
    //sendPostamble();
   sei();
}
 
/**
 * \brief    Send preamble
 * \details  The preamble consists of 16 "1" bits
 */
inline void sendPreamble(void)
{
  byte PREAMBLE[]={0xFF,0xFF};
  sendData(PREAMBLE, 2);
}
 
/**
 * \brief    Send postamble
 * \details  The postamble consists of 8 "0" bits
 */
inline void sendPostamble(void)
{
#ifdef THN132N
  sendQuarterLSB(0x00);
#else
  byte POSTAMBLE[]={0x00};
  sendData(POSTAMBLE, 1); 
#endif
}
 
/**
 * \brief    Send sync nibble
 * \details  The sync is 0xA. It is not use in this version since the sync nibble
 * \         is include in the Oregon message to send.
 */
inline void sendSync(void)
{
  sendQuarterLSB(0xA);
}
 
/******************************************************************/
/******************************************************************/
/******************************************************************/
 
/**
 * \brief    Set the sensor type
 * \param    data       Oregon message
 * \param    type       Sensor type
 */
inline void setType(byte *data, byte* type)
{
  data[0] = type[0];
  data[1] = type[1];
}
 
/**
 * \brief    Set the sensor channel
 * \param    data       Oregon message
 * \param    channel    Sensor channel (0x10, 0x20, 0x30)
 */
inline void setChannel(byte *data, byte channel)
{
    data[2] = channel;
}
 
/**
 * \brief    Set the sensor ID
 * \param    data       Oregon message
 * \param    ID         Sensor unique ID
 */
inline void setId(byte *data, byte ID)
{
  data[3] = ID;
}
 
/**
 * \brief    Set the sensor battery level
 * \param    data       Oregon message
 * \param    level      Battery level (0 = low, 1 = high)
 */
void setBatteryLevel(byte *data, byte level)
{
  if(!level) data[4] = 0x0C;
  else data[4] = level;
}
 
/**
 * \brief    Set the sensor temperature
 * \param    data       Oregon message
 * \param    temp       the temperature
 */
void setTemperature(byte *data, float temp)
{
  // Set temperature sign
  if(temp < 0)
  {
    data[6] = 0x08;
    temp *= -1; 
  }
  else
  {
    data[6] = 0x00;
  }
 
  int td = (int)temp / 10;

  int tf = (int)temp % 10;

  int tempFloat = (int)((temp * 10)) % 10;

  // Set temperature decimal part
  data[5] = (td << 4);
  data[5] |= tf;
 
  // Set temperature float part
  data[4] |= (tempFloat << 4);
 
}
 
/**
 * \brief    Set the sensor humidity
 * \param    data       Oregon message
 * \param    hum        the humidity
 */
void setHumidity(byte* data, float hum)
{
  int hd = (int)hum / 10;
  int hf = (int)hum % 10;
  int humFloat = (int)((hum * 10)) % 10;

    data[7] = (humFloat<<4);
    data[7] |= hd;
    data[6] = (hf<<4);
    
}
 
/**
 * \brief    Sum data for checksum
 * \param    count      number of bit to sum
 * \param    data       Oregon message
 */
int Sum(byte count, const byte* data)
{
  int s = 0;
 
  for(byte i = 0; i<count;i++)
  {
    s += (data[i]&0xF0) >> 4;
    s += (data[i]&0xF);
  }
 
  if(int(count) != count)
    s += (data[count]&0xF0) >> 4;
 
  return s;
}
 
/**
 * \brief    Calculate checksum
 * \param    data       Oregon message
 */
void calculateAndSetChecksum(byte* data)
{
#ifdef THN132N
    int s = ((Sum(6, data) + (data[6]&0xF) - 0xa) & 0xff);
    data[6] |=  (s&0x0F) << 4;     data[7] =  (s&0xF0) >> 4;
#else
    data[8] = ((Sum(8, data) - 0xa) & 0xFF);
#endif
}

void checkSumAndCRC(byte * data, const uint8_t len)
{
#define mByte(i) (data[i])
#define NIBBLE(i) ((mByte(i>>1) >> (((i)&1)<<2))&0xf)
uint8_t i,j,c,CRC,SUM;

CRC =0x3C;
SUM =0x00;

uint8_t CCIT_POLY = 0x07;

for (j=1; j<2*len; j++)
{
c = NIBBLE(j);
SUM += c;
if ( j != 6 && j != 7){ // place for ID
 CRC ^= c;
for(i = 0; i<4; i++)
if(CRC & 0x80 )
 CRC = (CRC << 1) ^ CCIT_POLY;
else
 CRC <<= 1;
 CRC &= 0xff;
}
}
for(i = 0; i<4; i++)
if(CRC & 0x80 )
 CRC = (CRC << 1) ^ CCIT_POLY;
else
 CRC <<= 1;

data[len] = (SUM & 0xFF);
data[len+1] = CRC;

}
/******************************************************************/


////////////////////////////////////////////////////////////
void setup ()
{
   Serial.begin(9600);

   pinMode(V_PIN, INPUT);
   pinMode(13, OUTPUT);
   pinMode(TX_PIN, OUTPUT);

   // randomSeed(analogRead(A0));

   HT = htu.begin();

  // Create the Oregon message for a temperature/humidity sensor
  byte ID[] = {0x1A,0x2D};
  setType(OregonMessageBuffer, ID);
  setChannel(OregonMessageBuffer, 0x43);
  setId(OregonMessageBuffer, 0xBB);

Serial.println("Start");

}

void loop() 
{

  while(millis()%1000!=500);

  unsigned int val = analogRead(V_PIN);

  float voltage = 5.0 / 1024 * val; 

  float htu_t = 0;
  float htu_h = 0;

  // Get temperature and humidity level from sensors
  if(HT){
      htu_t = htu.readTemperature();
//      htu_h = htu.readHumidity();
      htu_h = htu.readHumidity() + (25 - htu_t) * -0.15;
  }
    
  // Get battery
  byte bt = ( voltage - 3.2) * 100 ;

  setBatteryLevel(OregonMessageBuffer, round(bt/10.0) );
  setTemperature(OregonMessageBuffer, (round(htu_t*10)/10.0) );
  setHumidity(OregonMessageBuffer, (round(htu_h*10)/10.0) );

  // Calculate the checksum
  //calculateAndSetChecksum(OregonMessageBuffer);
  checkSumAndCRC(OregonMessageBuffer,8);

  Serial.print(millis()/1000.,3);
  Serial.print(" ");
  // Show the Oregon Message
  for (byte i = 0; i < sizeof(OregonMessageBuffer); ++i)   {     
    Serial.print(OregonMessageBuffer[i] >> 4, HEX);
    Serial.print(OregonMessageBuffer[i] & 0x0F, HEX);
  }
  Serial.println();
  
  digitalWrite(13,HIGH);
 
  // Send the Message over RF
  sendOregon(OregonMessageBuffer, sizeof(OregonMessageBuffer));
  SEND_LOW();
  delayMicroseconds(TWOTIME*10);
  sendOregon(OregonMessageBuffer, sizeof(OregonMessageBuffer));
  SEND_LOW();

  digitalWrite(13,LOW);

  Serial.print(htu_t,2);
  Serial.print(",");
  Serial.print(htu_h,2);
  Serial.print(",");
  Serial.print(voltage,3);
  Serial.print(",");
  Serial.println(bt);
 
/*  Wire.begin();
  Wire.beginTransmission(HTU21DF_I2CADDR);
  Wire.write(HTU21DF_WRITEREG);
  Wire.write(0x3);
  Wire.endTransmission();
*/

  delay(100);

  // power save mode
  sleepMS = Watchdog.sleep(8000);
  sleepMS += Watchdog.sleep(8000);
  sleepMS += Watchdog.sleep(8000);
  sleepMS += Watchdog.sleep(8000);
  sleepMS += Watchdog.sleep(8000);
  sleepMS += Watchdog.sleep(4000);
  
}

Arduino nano с передатчиком и термо-гигро сенсором HTU21. Запитано от двух литиевых аккумуляторов 18650, с которых через делитель на резисторах считывается уровень напряжения. К сожалению, даже используя powesave-mode аккумуляторы приходится заряжать каждые две недели. Ардуина в sleep-mode потребляет ~7мА (наверное из-за светодиода, надо бы его отпаять...)

Sprite
Offline
Зарегистрирован: 30.10.2016

Подскажите пожалуйста, как можно реализовать вывод на LCD так, чтобы при любых значениях температуры, Цельсий всегда был в одном месте, и лишь отступ после "=" увеличивался или уменьшался.

T=-25.5*C

T=   5.3*C

T= 25.2*C

Сейчас у меня так, "пляшет" от знака "=":

lcd.print("T="); lcd.print(String(temperature(data),1)); lcd.print("*C");

 

gulin176
Offline
Зарегистрирован: 03.09.2016

типа так надо 

lcd.setCursor(6, 1); 
    if (temperature  < 10) lcd.print(0);
    lcd.print(temperature);

взято из другого места

gulin176
Offline
Зарегистрирован: 03.09.2016

https://www.youtube.com/watch?v=SbM9l1gNmB4 спрашивали про si4432. может поможет. кстати блогер Дмитрий Осипов просто отличный учитель в теме ардуино. классные обзоры

Porosenok
Offline
Зарегистрирован: 06.11.2016

Ничего нового для себя я в этом ролике не открыл. Как с помощью модуля передавать СВОИ данные - и так понятно. Мне пока не до конца ясно, как приспособить si4432 под протокол Орегона, возложив на чип всю обработку пакета. Может надо не вино с сыром, а водку с солёным огурцом попробовать в поисках ответа?

gulin176
Offline
Зарегистрирован: 03.09.2016

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

Porosenok
Offline
Зарегистрирован: 06.11.2016

gulin176 пишет:

 а зачем на si4432 перекладывать обработку

Хотя бы затем, что он это может. Пусть сам отлавливает преамбулу, синхропоследовательность и считает CRC. А уж чем нагрузить ардуино - найти можно. Тому же esp8266 это бы сильно облегчило жизнь.

Sprite
Offline
Зарегистрирован: 30.10.2016

gulin176 пишет:

типа так надо 

lcd.setCursor(6, 1); 
    if (temperature  < 10) lcd.print(0);
    lcd.print(temperature);

взято из другого места

Спасибо за совет.

Всё получилось.

if (temperature(data) < -9)
   {
    lcd.setCursor(3,0);
    lcd.print(String(temperature(data),1)); lcd.printByte(0); lcd.print("C");
   }
   if (((temperature(data) >= -9) & (temperature(data)<= -1)) | (temperature(data) >= 10))
   {
    lcd.setCursor(4,0);
    lcd.print(String(temperature(data),1)); lcd.printByte(0); lcd.print("C");
   }
   if ((temperature(data) >= 0) & (temperature(data) <= 9))
   {
    lcd.setCursor(5,0);
    lcd.print(String(temperature(data),1)); lcd.printByte(0); lcd.print("C");
   }

 

Porosenok
Offline
Зарегистрирован: 06.11.2016

gulin176 пишет:

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

Да задел за очень больное место. Сыр российский для него нормальный! Уж два года как за нормальным сыром в Финляндию ездить приходится. Извиняюсь за оффтоп :)

udavst
udavst аватар
Offline
Зарегистрирован: 29.11.2013

snickser пишет:

К сожалению, даже используя powesave-mode аккумуляторы приходится заряжать каждые две недели. Ардуина в sleep-mode потребляет ~7мА (наверное из-за светодиода, надо бы его отпаять...)

Когда мне надо было экономить, я тоже голову ломал, потом, оказалось, что стабилизатор на плате ест, и светодиод - было всё удалено, перешиты фьюзы для работы до 2.8v, и всё наладилось, и потребляла она во сне какие-то микроамперы.

snickser
Offline
Зарегистрирован: 02.07.2016

"перешиты фьюзы" - а это как?

udavst
udavst аватар
Offline
Зарегистрирован: 29.11.2013

Прошил лоадер optiboot, и выставил фьюзы. 

Тут частота 8MHz (вместо 16) и не используется кварц (думал ещё сэкономить, но во сне роли не играет), и напряжение до 0v (т.е. при любом напряжении 0-5v будет работать, ну пока питания хватит):

low_fuses=0xe2
high_fuses=0xda
extended_fuses=0x07

Тут 2.7v нижнее напряжение, с частотой 16MHz (остальные шил так, ниже 2.7 нет смысла работать, неустойчиво становится)

low_fuses=0xFF
high_fuses=0xDA
extended_fuses=0x05

Тут обсуждалось, либо поищите тему про optiboot и сон.

 
Sprite
Offline
Зарегистрирован: 30.10.2016

Прошу помощи, совсем запутался.

Как мне реализовать вывод на экран LCD 2004, часов с DS3231 и значение давления с BMP280.

В какое место в скетче мне нужно "вставить" вывод на LCD эти данные?

lcd.setCursor(0,0);

lcd.print(time.gettime("H:i")); // выводим время

lcd.setCursor(10,0);
 
lcd.print(bme.readPressure()/133.3," mmHg"); // выводим давление
 
Если я их добавляю в "void loop ()" то перестают работать датчики Oregon
 
Если я добавляю там же, где и вывод информации с датчиков Oregon, то соответственно часы и давление обновляется на экране только тогда, когда приходят показания с датчиков Oregon.
// ATmega 2560
// Приёмник подключается к PWM(2)
// "LCD 2004", "DS3231", "BMP280" подключаются: SCL -> SCL(21); SDA -> SDA(20)


#define PORT 2
#define printByte(args) write(args);
#define BMP_SCK 13
#define BMP_MISO 12
#define BMP_MOSI 11 
#define BMP_CS 10

#include <iarduino_RTC.h>
#include <Adafruit_BMP280.h>
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

iarduino_RTC time(RTC_DS3231);
LiquidCrystal_I2C lcd(0x27,20,4);  // Адрес моего "LCD 2004" 0x27, "LCD 1602" 0x3f
Adafruit_BMP280 bme; //  работаем по шине I2C

uint8_t cels[8]  = {0x2,0x5,0x5,0x2}; // Значёк цельсия
uint8_t batlow[8]  = {0xE,0x1f,0x0,0x11,0x0,0x11,0x0,0x1f}; // Значок пустой батарейки
uint8_t batok[8] = {0xE,0x1f,0x11,0x15,0x15,0x15,0x11,0x1f};  // Значок полной батарейки
uint8_t termom1[8] = {0x4,0xA,0xE,0xE,0xE,0x1f,0x1f,0xE};  // Значок термометра больше 0
uint8_t termom0[8] = {0x4,0xA,0xA,0xA,0xE,0x1f,0x1f,0xE};  // Значок термометра меньше 0
uint8_t kapla[8] = {0x4,0x4,0xA,0xA,0x11,0x11,0x11,0xE};  // Значок капли

class DecodeOOK {
protected:
    byte total_bits, bits, flip, state, pos, data[25];

    virtual char decode (word width) =0;
    
public:

    enum { UNKNOWN, T0, T1, T2, T3, OK, DONE };

    DecodeOOK () { resetDecoder(); }

    bool nextPulse (word width) {
        if (state != DONE)
        
            switch (decode(width)) {
                case -1: resetDecoder(); break;
                case 1:  done(); break;
            }
        return isDone();
    }
    
    bool isDone () const { return state == DONE; }

    const byte* getData (byte& count) const {
        count = pos;
        return data; 
    }
    
    void resetDecoder () {
        total_bits = bits = pos = flip = 0;
        state = UNKNOWN;
    }
    
    // add one bit to the packet data buffer
    
    virtual void gotBit (char value) {
        total_bits++;
        byte *ptr = data + pos;
        *ptr = (*ptr >> 1) | (value << 7);

        if (++bits >= 8) {
            bits = 0;
            if (++pos >= sizeof data) {
                resetDecoder();
                return;
            }
        }
        state = OK;
    }
    
    // store a bit using Manchester encoding
    void manchester (char value) {
        flip ^= value; // manchester code, long pulse flips the bit
        gotBit(flip);
    }
    
    // move bits to the front so that all the bits are aligned to the end
    void alignTail (byte max =0) {
        // align bits
        if (bits != 0) {
            data[pos] >>= 8 - bits;
            for (byte i = 0; i < pos; ++i)
                data[i] = (data[i] >> bits) | (data[i+1] << (8 - bits));
            bits = 0;
        }
        // optionally shift bytes down if there are too many of 'em
        if (max > 0 && pos > max) {
            byte n = pos - max;
            pos = max;
            for (byte i = 0; i < pos; ++i)
                data[i] = data[i+n];
        }
    }
    
    void reverseBits () {
        for (byte i = 0; i < pos; ++i) {
            byte b = data[i];
            for (byte j = 0; j < 8; ++j) {
                data[i] = (data[i] << 1) | (b & 1);
                b >>= 1;
            }
        }
    }
    
    void reverseNibbles () {
        for (byte i = 0; i < pos; ++i)
            data[i] = (data[i] << 4) | (data[i] >> 4);
    }
    
    void done () {
        while (bits)
            gotBit(0); // padding
        state = DONE;
    }
};

// 433 MHz decoders



class OregonDecoderV2 : public DecodeOOK 
{
   public:  
  OregonDecoderV2() {}

      // add one bit to the packet data buffer
  virtual void gotBit (char value) 
      {
         if(!(total_bits & 0x01))
         {
            data[pos] = (data[pos] >> 1) | (value ? 0x80 : 00);
         }

         total_bits++;
         pos = total_bits >> 4;

         if (pos >= sizeof data) 
         {
            resetDecoder();
            return;
         }
         state = OK;
      }

  virtual char decode(word width) 
      {
         if (200 <= width && width < 1200) 
         {
            byte w = width >= 700;

            switch (state) 
            {
               case UNKNOWN:
                  if (w != 0) 
                  {
                     // Long pulse
                     ++flip;
                  } 
                  else if (w == 0 && 24 <= flip) 
                  {
                     // Short pulse, start bit
                     flip = 0;
                     state = T0;
                  } 
                  else 
                  {
                     // Reset decoder
                     return -1;
                  }
                  break;
               case OK:
                  if (w == 0) 
                  {
                     // Short pulse
                     state = T0;
                  }
                  else 
                  {
                     // Long pulse
                     manchester(1);
                  }
                  break;
               case T0:
                  if (w == 0) 
                  {
                     // Second short pulse
                     manchester(0);
                  } 
                  else 
                  {
                     // Reset decoder
                     return -1;
                  }
               break;
            }
         } 
         else if (width >= 2500  && pos >= 8) 
         {
            return 1;
         } 
         else 
         {
            return -1;
         }
         return 0;
      }

};


class OregonDecoderV3 : public DecodeOOK {
public:
    OregonDecoderV3() {}
    
    // add one bit to the packet data buffer
    virtual void gotBit (char value) {
        data[pos] = (data[pos] >> 1) | (value ? 0x80 : 00);
        total_bits++;
        pos = total_bits >> 3;
        if (pos >= sizeof data) {
            resetDecoder();
            return;
        }
        state = OK;
    }
    
    virtual char decode (word width) {
        if (200 <= width && width < 1200) {
            byte w = width >= 700;
            switch (state) {
                case UNKNOWN:
                    if (w == 0)
                        ++flip;
                    else if (32 <= flip) {
                        flip = 1;
                        manchester(1);
                    } else
                        return -1;
                    break;
                case OK:
                    if (w == 0)
                        state = T0;
                    else
                        manchester(1);
                    break;
                case T0:
                    if (w == 0)
                        manchester(0);
                    else
                        return -1;
                    break;
            }
        } else {
            return -1;
        }
        return  total_bits == 80 ? 1: 0;
    }
};


OregonDecoderV2 orscV2;
OregonDecoderV3 orscV3;

volatile word pulse;

void ext_int_1(void) {
    static word last;
    // determine the pulse length in microseconds, for either polarity
    pulse = micros() - last;
    last += pulse;
}

//
// Oregon packet decoder
//

float temperature(const byte* data)
{
   int sign = (data[6]&0x8) ? -1 : 1;
   float temp = ((data[5]&0xF0) >> 4)*10 + (data[5]&0xF) + (float)(((data[4]&0xF0) >> 4) / 10.0);
   return sign * temp;
}

byte humidity(const byte* data)
{
   return (data[7]&0xF) * 10 + ((data[6]&0xF0) >> 4) ;
}

float humi_ext(const byte* data)
{
   return  humidity(data) + ((data[7]&0xF0)>>4)/10.0 ;
}

byte battery(const byte* data)
{
   return (data[4] & 0xF) ;
}

byte serial(const byte* data)
{
   return (data[3]);
}

byte channel(const byte* data)
{
   byte channel;
   switch (data[2])
   {
      case 0x10:
         channel = 1;
         break;
      case 0x20:
         channel = 2;
         break;
      case 0x40:
         channel = 3;
         break;
      case 0x13:
         channel = 1;
         break;
      case 0x23:
         channel = 2;
         break;
      case 0x33:
         channel = 3;
         break;
      case 0x43:
         channel = 4;
         break;
      case 0x53:
         channel = 5;
         break;
   }
 return channel;
} 


int Sum(byte count, const byte* data)
{
  int s = 0;
 
  for(byte i = 0; i<count;i++)
  {
    s += (data[i]&0xF0) >> 4;
    s += (data[i]&0xF);
  }
 
  if(int(count) != count)
    s += (data[count]&0xF0) >> 4;
 
  return s;
}


    
////////////////////////////////////////////////////
////////////////////////////////////////////////////
/////////// Вывод результата в Serial  /////////////
////////////////////////////////////////////////////
////////////////////////////////////////////////////

void reportSerial (const char* s, class DecodeOOK& decoder){
    byte pos;
    const byte* data = decoder.getData(pos);
    Serial.print(millis()/1000.,3);
    Serial.print(" ");
    Serial.print(s);
    Serial.print(' ');
    for (byte i = 0; i < pos; ++i) {
        Serial.print(data[i] >> 4, HEX);
        Serial.print(data[i] & 0x0F, HEX);
    }

    if( data[8] == (Sum(8,data)-0xa)&0xFF )
    {
      Serial.print(" Bat.: "+String(battery(data)));
      Serial.print(" ID: "+String(serial(data),HEX));
      Serial.println();
      Serial.print("Ch."+String(channel(data)));
      Serial.println();
      Serial.print("T="+String(temperature(data),1)+"C"+" H="+String(humidity(data))+"%");
      Serial.println();
          if(battery(data) == 0xC){
          Serial.print("Bat: LOW");
          Serial.println();}
          else {
          Serial.print("Bat: OK");
          Serial.println();}

      }
      else
      {
      int sum = ((Sum(6, data) + (data[6]&0xF) - 0xa) & 0xff);
      if( (sum&0xF) == (data[6]>>4) && (sum>>4) == (data[7]&0xF) ){
      Serial.print(" Bat: "+String(battery(data)));
      Serial.print(" ID: "+String(serial(data),HEX));
      Serial.println();
      Serial.print("Ch."+String(channel(data)));
      Serial.println();
      Serial.print("T="+String(temperature(data),1)+"C");
      Serial.println();
          if (battery(data) == 0xC){
          Serial.print("Bat: LOW");
          Serial.println();
          }
          else {
          Serial.print("Bat: OK");
          Serial.println();
          }
        }
        else
        {
        Serial.print(" Checksum error");
        }
     Serial.println(); 
    }

////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
///////////////////  Вывод результата на LCD   /////////////////////
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
       

/// Датчик с влажностью

 if( data[8] == (Sum(8,data)-0xa)&0xFF )
 {
  if ((channel(data))==1|(channel(data))==3|(channel(data))==5)    // Канал датчика 1, 3, 5
  {
   lcd.setCursor(0,1); lcd.print("                ");
   lcd.setCursor(0,1);
   lcd.print (channel(data));
   lcd.print(" ");
   if (temperature(data) < -9)
   {
    lcd.printByte(4);
    lcd.setCursor(3,1);
    lcd.print(String(temperature(data),1)); lcd.printByte(0); lcd.print("C");
   }
   if ((temperature(data) >= -9) & (temperature(data) < 0))
   {
    lcd.printByte(4);
    lcd.setCursor(4,1);
    lcd.print(String(temperature(data),1)); lcd.printByte(0); lcd.print("C");
   }
   if ((temperature(data) >= 0) & (temperature(data) <= 9))
   {
    lcd.printByte(3);
    lcd.setCursor(5,1);
    lcd.print(String(temperature(data),1)); lcd.printByte(0); lcd.print("C");
   }
   if (temperature(data) >= 10)
   {
    lcd.printByte(3);
    lcd.setCursor(4,1);
    lcd.print(String(temperature(data),1)); lcd.printByte(0); lcd.print("C");
   }
   lcd.setCursor(11,1);
   lcd.printByte(5); lcd.print(String(humidity(data))+"%");
   if( (battery(data)) == 0xC)
   {
    lcd.setCursor(16,1);
    lcd.printByte(1);
   }
   else
   {
    lcd.setCursor(16,1);
    lcd.printByte(2);
   }
   
  }
  else   // Канал датчика отличны от 1, 3, 5                                               
  {
   lcd.setCursor(0,2); lcd.print("                ");
   lcd.setCursor(0,2);
   lcd.print (channel(data));
   lcd.print(" ");
     if (temperature(data) < -9)
   {
    lcd.printByte(4);
    lcd.setCursor(3,2);
    lcd.print(String(temperature(data),1)); lcd.printByte(0); lcd.print("C");
   }
   if ((temperature(data) >= -9) & (temperature(data) < 0))
   {
    lcd.printByte(4);
    lcd.setCursor(4,2);
    lcd.print(String(temperature(data),1)); lcd.printByte(0); lcd.print("C");
   }
   if ((temperature(data) >= 0) & (temperature(data) <= 9))
   {
    lcd.printByte(3);
    lcd.setCursor(5,2);
    lcd.print(String(temperature(data),1)); lcd.printByte(0); lcd.print("C");
   }
   if (temperature(data) >= 10)
   {
    lcd.printByte(3);
    lcd.setCursor(4,2);
    lcd.print(String(temperature(data),1)); lcd.printByte(0); lcd.print("C");
   }
   lcd.setCursor(11,2);
   lcd.printByte(5); lcd.print(String(humidity(data))+"%");
   if( (battery(data)) == 0xC)
   {
    lcd.setCursor(16,2);
    lcd.printByte(1);
   }
   else
   {
    lcd.setCursor(16,2);
    lcd.printByte(2);
   }
   
  }
 }
/// Датчик без влажности      
 else
 {
  int sum = ((Sum(6, data) + (data[6]&0xF) - 0xa) & 0xff);
  if( (sum&0xF) == (data[6]>>4) && (sum>>4) == (data[7]&0xF) )
  {
   if ((channel(data))==1|(channel(data))==3|(channel(data))==5)    // Канал датчика 1, 3, 5
   {
    lcd.setCursor(0,1); lcd.print("                ");
    lcd.setCursor(0,1);
    lcd.print (channel(data));
    lcd.print(" ");
    if (temperature(data) < -9)
    {
     lcd.printByte(4);
     lcd.setCursor(3,1);
     lcd.print(String(temperature(data),1)); lcd.printByte(0); lcd.print("C");
    }
    if ((temperature(data) >= -9) & (temperature(data) < 0))
    {
     lcd.printByte(4);
     lcd.setCursor(4,1);
     lcd.print(String(temperature(data),1)); lcd.printByte(0); lcd.print("C");
    }
    if ((temperature(data) >= 0) & (temperature(data) <= 9))
    {
     lcd.printByte(3);
     lcd.setCursor(5,1);
     lcd.print(String(temperature(data),1)); lcd.printByte(0); lcd.print("C");
    }
    if (temperature(data) >= 10)
    {
     lcd.printByte(3);
     lcd.setCursor(4,0);
     lcd.print(String(temperature(data),1)); lcd.printByte(0); lcd.print("C");
    }
    if( (battery(data)) == 0xC)
    {
     lcd.setCursor(16,1);
     lcd.printByte(1)
    }
    else
    {
     lcd.setCursor(16,1);
     lcd.printByte(2);
    }
    
   }
   else        // Канал датчика отличны от 1, 3, 5
   {
    lcd.setCursor(0,2); lcd.print("                ");
    lcd.setCursor(0,2);
    lcd.print (channel(data));
    lcd.print(" ");
    if (temperature(data) < -9)
    {
     lcd.printByte(4);
     lcd.setCursor(3,2);
     lcd.print(String(temperature(data),1)); lcd.printByte(0); lcd.print("C");
    }
    if ((temperature(data) >= -9) & (temperature(data) < 0))
    {
     lcd.printByte(4);
     lcd.setCursor(4,2);
     lcd.print(String(temperature(data),1)); lcd.printByte(0); lcd.print("C");
    }
    if ((temperature(data) >= 0) & (temperature(data) <= 9))
    {
     lcd.printByte(3);
     lcd.setCursor(5,2);
     lcd.print(String(temperature(data),1)); lcd.printByte(0); lcd.print("C");
    }
    if (temperature(data) >= 10)
    {
     lcd.printByte(3);
     lcd.setCursor(4,2);
     lcd.print(String(temperature(data),1)); lcd.printByte(0); lcd.print("C");
    }
    if( (battery(data)) == 0xC)
    {
     lcd.setCursor(16,2);
     lcd.printByte(1)}
    else
    {
     lcd.setCursor(16,2);
     lcd.printByte(2);
    }
    
   }
  }
 }   
 

////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
////////////////  Конец вывод результата на LCD   //////////////////
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////





 decoder.resetDecoder();
}




void setup () {
  lcd.init();
   lcd.backlight();
    lcd.createChar(0, cels);
    lcd.createChar(1, batlow);
    lcd.createChar(2, batok);
    lcd.createChar(3, termom1);
    lcd.createChar(4, termom0);
    lcd.createChar(5, kapla);
    
    
    Serial.begin(9600);
    time.begin();
    Serial.println("\n[ookDecoder]");
    if (!bme.begin()) {  
    Serial.println("Could not find a valid BMP280 sensor, check wiring!");
    while (1);
  }
     
    
    pinMode(PORT, INPUT);  // use the AIO pin

   attachInterrupt(digitalPinToInterrupt(PORT), ext_int_1, CHANGE);



}

void loop () {
   
    static int i = 0;
    
    cli();
    word p = pulse;
    pulse = 0;
    sei();

    //if (p != 0){ Serial.print(++i); Serial.print('\n');}
    
    if (p != 0) {
        if (orscV2.nextPulse(p))
            reportSerial("OSV2", orscV2);  
        if (orscV3.nextPulse(p))
            reportSerial("OSV3", orscV3);        
      }
    
       
           
    }

 

 

Porosenok
Offline
Зарегистрирован: 06.11.2016

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



unsigned long pora_vivodit = 0, time_interval = 10000;
//......
void loop(){
//......
if (pora_vivodit > millis()) { 
// Вывод на экран
 pora_vivodit = millis() + time_interval; 
}
Sprite
Offline
Зарегистрирован: 30.10.2016

Porosenok пишет:

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



unsigned long pora_vivodit = 0, time_interval = 10000;
//......
void loop(){
//......
if (pora_vivodit > millis()) { 
// Вывод на экран
 pora_vivodit = millis() + time_interval; 
}

Спасибо за ответ, но что то у меня не работает.

#include <iarduino_RTC.h>
iarduino_RTC time(RTC_DS3231);
unsigned long pora_vivodit = 0, time_interval = 1000;


void setup()
   {
    Serial.begin(9600);
    time.begin();
    Serial.println(time.gettime("H:i"));
   }

void loop()
  {
  if (pora_vivodit > millis())
   { 
   Serial.println(time.gettime("H:i:s")); // Вывод на экран
   pora_vivodit = millis() + time_interval; 
   }

  }   

 

А вот так всё работает:

void loop () {
if(millis()%10000==0){ // если прошло 10 секунд    
      lcd.setCursor(0,0);
      lcd.print (time.gettime("H:i")); // выводим время 

 

Sprite
Offline
Зарегистрирован: 30.10.2016

Получилось так.

Код.

// ATmega 2560
// Приёмник подключается к PWM(2)
// "LCD 2004", "DS3231": SCL -> SCL(21); SDA -> SDA(20)


#define PORT 2
#define printByte(args) write(args);
/*#define BMP_SCK 13
#define BMP_MISO 12
#define BMP_MOSI 11 
#define BMP_CS 10*/

#include <iarduino_RTC.h>
/*#include <Adafruit_BMP280.h>*/
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

iarduino_RTC time(RTC_DS3231);
LiquidCrystal_I2C lcd(0x27,20,4);  // Адрес моего "LCD 2004" 0x27, "LCD 1602" 0x3f
/*Adafruit_BMP280 bme; //  работаем по шине I2C*/

uint8_t cels[8]  = {0x2,0x5,0x5,0x2}; // Значёк цельсия
uint8_t batlow[8]  = {0xE,0x1f,0x0,0x11,0x0,0x11,0x0,0x1f}; // Значок пустой батарейки
uint8_t ygol[8] = {0x0,0x8,0x4,0x2,0x4,0x8,0x0,0x0};  // Значок >
uint8_t termom[8] = {0x4,0xA,0xA,0xE,0xE,0x1f,0x1f,0xE};  // Значок термометра больше
uint8_t kapla[8] = {0x4,0x4,0xA,0xA,0x11,0x11,0x11,0xE};  // Значок капли
uint8_t pe[8] = {0x1f,0x11,0x11,0x11,0x11,0x11,0x11,0x0};  // Буква П
uint8_t che[8] = {0x11,0x11,0x11,0x11,0xf,0x1,0x1,0x0};  // Буква Ч
uint8_t be[8] = {0x1f,0x10,0x10,0x1E,0x11,0x11,0x1E,0x0};  // Буква Б

class DecodeOOK {
protected:
    byte total_bits, bits, flip, state, pos, data[25];

    virtual char decode (word width) =0;
    
public:

    enum { UNKNOWN, T0, T1, T2, T3, OK, DONE };

    DecodeOOK () { resetDecoder(); }

    bool nextPulse (word width) {
        if (state != DONE)
        
            switch (decode(width)) {
                case -1: resetDecoder(); break;
                case 1:  done(); break;
            }
        return isDone();
    }
    
    bool isDone () const { return state == DONE; }

    const byte* getData (byte& count) const {
        count = pos;
        return data; 
    }
    
    void resetDecoder () {
        total_bits = bits = pos = flip = 0;
        state = UNKNOWN;
    }
    
    // add one bit to the packet data buffer
    
    virtual void gotBit (char value) {
        total_bits++;
        byte *ptr = data + pos;
        *ptr = (*ptr >> 1) | (value << 7);

        if (++bits >= 8) {
            bits = 0;
            if (++pos >= sizeof data) {
                resetDecoder();
                return;
            }
        }
        state = OK;
    }
    
    // store a bit using Manchester encoding
    void manchester (char value) {
        flip ^= value; // manchester code, long pulse flips the bit
        gotBit(flip);
    }
    
    // move bits to the front so that all the bits are aligned to the end
    void alignTail (byte max =0) {
        // align bits
        if (bits != 0) {
            data[pos] >>= 8 - bits;
            for (byte i = 0; i < pos; ++i)
                data[i] = (data[i] >> bits) | (data[i+1] << (8 - bits));
            bits = 0;
        }
        // optionally shift bytes down if there are too many of 'em
        if (max > 0 && pos > max) {
            byte n = pos - max;
            pos = max;
            for (byte i = 0; i < pos; ++i)
                data[i] = data[i+n];
        }
    }
    
    void reverseBits () {
        for (byte i = 0; i < pos; ++i) {
            byte b = data[i];
            for (byte j = 0; j < 8; ++j) {
                data[i] = (data[i] << 1) | (b & 1);
                b >>= 1;
            }
        }
    }
    
    void reverseNibbles () {
        for (byte i = 0; i < pos; ++i)
            data[i] = (data[i] << 4) | (data[i] >> 4);
    }
    
    void done () {
        while (bits)
            gotBit(0); // padding
        state = DONE;
    }
};

// 433 MHz decoders



class OregonDecoderV2 : public DecodeOOK 
{
   public:  
  OregonDecoderV2() {}

      // add one bit to the packet data buffer
  virtual void gotBit (char value) 
      {
         if(!(total_bits & 0x01))
         {
            data[pos] = (data[pos] >> 1) | (value ? 0x80 : 00);
         }

         total_bits++;
         pos = total_bits >> 4;

         if (pos >= sizeof data) 
         {
            resetDecoder();
            return;
         }
         state = OK;
      }

  virtual char decode(word width) 
      {
         if (200 <= width && width < 1200) 
         {
            byte w = width >= 700;

            switch (state) 
            {
               case UNKNOWN:
                  if (w != 0) 
                  {
                     // Long pulse
                     ++flip;
                  } 
                  else if (w == 0 && 24 <= flip) 
                  {
                     // Short pulse, start bit
                     flip = 0;
                     state = T0;
                  } 
                  else 
                  {
                     // Reset decoder
                     return -1;
                  }
                  break;
               case OK:
                  if (w == 0) 
                  {
                     // Short pulse
                     state = T0;
                  }
                  else 
                  {
                     // Long pulse
                     manchester(1);
                  }
                  break;
               case T0:
                  if (w == 0) 
                  {
                     // Second short pulse
                     manchester(0);
                  } 
                  else 
                  {
                     // Reset decoder
                     return -1;
                  }
               break;
            }
         } 
         else if (width >= 2500  && pos >= 8) 
         {
            return 1;
         } 
         else 
         {
            return -1;
         }
         return 0;
      }

};


class OregonDecoderV3 : public DecodeOOK {
public:
    OregonDecoderV3() {}
    
    // add one bit to the packet data buffer
    virtual void gotBit (char value) {
        data[pos] = (data[pos] >> 1) | (value ? 0x80 : 00);
        total_bits++;
        pos = total_bits >> 3;
        if (pos >= sizeof data) {
            resetDecoder();
            return;
        }
        state = OK;
    }
    
    virtual char decode (word width) {
        if (200 <= width && width < 1200) {
            byte w = width >= 700;
            switch (state) {
                case UNKNOWN:
                    if (w == 0)
                        ++flip;
                    else if (32 <= flip) {
                        flip = 1;
                        manchester(1);
                    } else
                        return -1;
                    break;
                case OK:
                    if (w == 0)
                        state = T0;
                    else
                        manchester(1);
                    break;
                case T0:
                    if (w == 0)
                        manchester(0);
                    else
                        return -1;
                    break;
            }
        } else {
            return -1;
        }
        return  total_bits == 80 ? 1: 0;
    }
};


OregonDecoderV2 orscV2;
OregonDecoderV3 orscV3;

volatile word pulse;

void ext_int_1(void) {
    static word last;
    // determine the pulse length in microseconds, for either polarity
    pulse = micros() - last;
    last += pulse;
}

//
// Oregon packet decoder
//

float temperature(const byte* data)
{
   int sign = (data[6]&0x8) ? -1 : 1;
   float temp = ((data[5]&0xF0) >> 4)*10 + (data[5]&0xF) + (float)(((data[4]&0xF0) >> 4) / 10.0);
   return sign * temp;
}

byte humidity(const byte* data)
{
   return (data[7]&0xF) * 10 + ((data[6]&0xF0) >> 4) ;
}

float humi_ext(const byte* data)
{
   return  humidity(data) + ((data[7]&0xF0)>>4)/10.0 ;
}

byte battery(const byte* data)
{
   return (data[4] & 0xF) ;
}

byte serial(const byte* data)
{
   return (data[3]);
}

byte channel(const byte* data)
{
   byte channel;
   switch (data[2])
   {
      case 0x10:
         channel = 1;
         break;
      case 0x20:
         channel = 2;
         break;
      case 0x40:
         channel = 3;
         break;
      case 0x13:
         channel = 1;
         break;
      case 0x23:
         channel = 2;
         break;
      case 0x33:
         channel = 3;
         break;
      case 0x43:
         channel = 4;
         break;
      case 0x53:
         channel = 5;
         break;
   }
 return channel;
} 


int Sum(byte count, const byte* data)
{
  int s = 0;
 
  for(byte i = 0; i<count;i++)
  {
    s += (data[i]&0xF0) >> 4;
    s += (data[i]&0xF);
  }
 
  if(int(count) != count)
    s += (data[count]&0xF0) >> 4;
 
  return s;
}


    
////////////////////////////////////////////////////
////////////////////////////////////////////////////
/////////// Вывод результата в Serial  /////////////
////////////////////////////////////////////////////
////////////////////////////////////////////////////

void reportSerial (const char* s, class DecodeOOK& decoder){
    byte pos;
    const byte* data = decoder.getData(pos);
    Serial.print(millis()/1000.,3);
    Serial.print(" ");
    Serial.print(s);
    Serial.print(' ');
    for (byte i = 0; i < pos; ++i) {
        Serial.print(data[i] >> 4, HEX);
        Serial.print(data[i] & 0x0F, HEX);
    }

    if( data[8] == (Sum(8,data)-0xa)&0xFF )
    {
      Serial.print(" Bat.: "+String(battery(data)));
      Serial.print(" ID: "+String(serial(data),HEX));
      Serial.println();
      Serial.print("Ch."+String(channel(data)));
      Serial.println();
      Serial.print("T="+String(temperature(data),1)+"C"+" H="+String(humidity(data))+"%");
      Serial.println();
          if(battery(data) == 0xC){
          Serial.print("Bat: LOW");
          Serial.println();}
          else {
          Serial.print("Bat: OK");
          Serial.println();}

      }
      else
      {
      int sum = ((Sum(6, data) + (data[6]&0xF) - 0xa) & 0xff);
      if( (sum&0xF) == (data[6]>>4) && (sum>>4) == (data[7]&0xF) ){
      Serial.print(" Bat: "+String(battery(data)));
      Serial.print(" ID: "+String(serial(data),HEX));
      Serial.println();
      Serial.print("Ch."+String(channel(data)));
      Serial.println();
      Serial.print("T="+String(temperature(data),1)+"C");
      Serial.println();
          if (battery(data) == 0xC){
          Serial.print("Bat: LOW");
          Serial.println();
          }
          else {
          Serial.print("Bat: OK");
          Serial.println();
          }
        }
        else
        {
        Serial.print(" Checksum error");
        }
     Serial.println(); 
    }

////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
///////////////////  Вывод результата на LCD   /////////////////////
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
 
/// Датчик с влажностью

 if( data[8] == (Sum(8,data)-0xa)&0xFF )
 {
 if ((channel(data))==1|(channel(data))==3|(channel(data))==5)    // Канал датчика 1, 3, 5
  {
   lcd.setCursor(0,1); lcd.print("          ");
   lcd.setCursor(0,2); lcd.print("          ");
   lcd.setCursor(0,3); lcd.print("          ");
   lcd.setCursor(0,1); lcd.print("Ch"); lcd.print (channel(data)); 
   lcd.setCursor(0,2); lcd.printByte(3); 
   if (temperature(data) < 0)
   {
   lcd.setCursor(1,2); lcd.print(String(temperature(data),1)); lcd.printByte(0); lcd.print("C");
   }
   else
   { 
   lcd.setCursor(2,2); lcd.print(String(temperature(data),1)); lcd.printByte(0); lcd.print("C");
   }
   lcd.setCursor(0,3); lcd.printByte(4); lcd.print(" "); lcd.print(String(humidity(data))); lcd.print(" %");
   if( (battery(data)) == 0xC)
   {
    lcd.setCursor(8,3); lcd.printByte(1);
   }
   lcd.setCursor(3,1); lcd.printByte(2); lcd.print(time.gettime("H:i")); // выводим время
  }
  else   // Канал датчика 2, 4, 6                                               
 {
   lcd.setCursor(10,1); lcd.print("          ");
   lcd.setCursor(10,2); lcd.print("          ");
   lcd.setCursor(10,3); lcd.print("          ");
   lcd.setCursor(11,1); lcd.print("Ch"); lcd.print (channel(data));
   lcd.setCursor(11,2); lcd.printByte(3); 
   if (temperature(data) < 0)
   {
   lcd.setCursor(12,2); lcd.print(String(temperature(data),1)); lcd.printByte(0); lcd.print("C");
   }
   else
   { 
   lcd.setCursor(13,2); lcd.print(String(temperature(data),1)); lcd.printByte(0); lcd.print("C");
   }
   lcd.setCursor(11,3); lcd.printByte(4); lcd.print(" "); lcd.print(String(humidity(data))); lcd.print(" %");
   if( (battery(data)) == 0xC)
   {
    lcd.setCursor(18,3); lcd.printByte(1);
   }
   lcd.setCursor(14,1); lcd.printByte(2); lcd.print(time.gettime("H:i")); // выводим время
 }
 }
/// Датчик без влажности      
 else
 {
  int sum = ((Sum(6, data) + (data[6]&0xF) - 0xa) & 0xff);
  if( (sum&0xF) == (data[6]>>4) && (sum>>4) == (data[7]&0xF) )
  {
 if ((channel(data))==1|(channel(data))==3|(channel(data))==5)    // Канал датчика 1, 3, 5
  {
   lcd.setCursor(0,1); lcd.print("          ");
   lcd.setCursor(0,2); lcd.print("          ");
   lcd.setCursor(0,3); lcd.print("          ");
   lcd.setCursor(0,1); lcd.print("Ch"); lcd.print (channel(data)); 
   lcd.setCursor(0,2); lcd.printByte(3); 
   if (temperature(data) < 0)
   {
   lcd.setCursor(1,2); lcd.print(String(temperature(data),1)); lcd.printByte(0); lcd.print("C");
   }
   else
   { 
   lcd.setCursor(2,2); lcd.print(String(temperature(data),1)); lcd.printByte(0); lcd.print("C");
   }
   if( (battery(data)) == 0xC)
   {
    lcd.setCursor(8,3); lcd.printByte(1);
   }
   lcd.setCursor(3,1); lcd.printByte(2); lcd.print (time.gettime("H:i")); // выводим время
  }
  else   // Канал датчика 2, 4, 6                                               
 {
   lcd.setCursor(10,1); lcd.print("          ");
   lcd.setCursor(10,2); lcd.print("          ");
   lcd.setCursor(10,3); lcd.print("          ");
   lcd.setCursor(11,1); lcd.print("Ch"); lcd.print (channel(data));
   lcd.setCursor(11,2); lcd.printByte(3); 
   if (temperature(data) < 0)
   {
   lcd.setCursor(12,2); lcd.print(String(temperature(data),1)); lcd.printByte(0); lcd.print("C");
   }
   else
   { 
   lcd.setCursor(13,2); lcd.print(String(temperature(data),1)); lcd.printByte(0); lcd.print("C");
   }
   if( (battery(data)) == 0xC)
   {
    lcd.setCursor(18,3); lcd.printByte(1);
   }
   lcd.setCursor(14,1); lcd.printByte(2); lcd.print(time.gettime("H:i")); // выводим время
 }
  }
 }   
 

////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
////////////////  Конец вывод результата на LCD   //////////////////
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////





 decoder.resetDecoder();
}





void setup () {
  lcd.init();
   lcd.backlight();
    lcd.createChar(0, cels);
    lcd.createChar(1, batlow);
    lcd.createChar(2, ygol);
    lcd.createChar(3, termom);
    lcd.createChar(4, kapla);
    lcd.createChar(5, pe);
    lcd.createChar(6, che);
    lcd.createChar(7, be);
    
    Serial.begin(9600);
    time.begin();
    Serial.println("\n[ookDecoder]");
      
    lcd.setCursor(10,0);
    lcd.print (time.gettime("d/m/Y")); // выводим дату
     if (time.weekday==1) // ПН
      {
      lcd.setCursor(7,0);
      lcd.printByte(5); lcd.print ("H");
      }
       if (time.weekday==2) // ВТ
      {
      lcd.setCursor(7,0); lcd.print ("BT");
      }
       if (time.weekday==3) // СР
      {
      lcd.setCursor(7,0); lcd.print ("CP");
      }
       if (time.weekday==4) // ЧТ
      {
      lcd.setCursor(7,0);
      lcd.printByte(6); lcd.print ("T");
      }
      if (time.weekday==5) // ПТ
      {
      lcd.setCursor(7,0);
      lcd.printByte(5); lcd.print ("T");
      }
      if (time.weekday==6) // СБ
      {
      lcd.setCursor(7,0);
      lcd.print ("C"); lcd.printByte(7);
      }
      if (time.weekday==0) // ВС
      {
      lcd.setCursor(7,0);
      lcd.print ("BC");
      }
      
      lcd.setCursor(0,0);
      lcd.print (time.gettime("H:i")); // выводим время 
      /*lcd.setCursor(0,1);
      lcd.print ("<<< Wait  OREGON >>>"); 
      lcd.setCursor(0,2);
      lcd.print ("<<< Wait  OREGON >>>");*/ 
      
    pinMode(PORT, INPUT);  // use the AIO pin

   attachInterrupt(digitalPinToInterrupt(PORT), ext_int_1, CHANGE);



}

void loop () {

  
    static int i = 0;
    
    cli();
    word p = pulse;
    pulse = 0;
    sei();

    //if (p != 0){ Serial.print(++i); Serial.print('\n');}
    
    if (p != 0) {
        if (orscV2.nextPulse(p))
            reportSerial("OSV2", orscV2);  
        if (orscV3.nextPulse(p))
            reportSerial("OSV3", orscV3);        
      }
if (millis()%10000==0){ // если прошло 10 секунд    
      lcd.setCursor(0,0);
      lcd.print(time.gettime("H:i")); // выводим время 
      

if (time.Hours==0){ // Полночь
      lcd.setCursor(10,0);
      lcd.print (time.gettime("d/m/Y")); // выводим дату
            
      if (time.weekday==1) // ПН
      {
      lcd.setCursor(7,0);
      lcd.printByte(5); lcd.print ("H");
      }
       if (time.weekday==2) // ВТ
      {
      lcd.setCursor(7,0); lcd.print ("BT");
      }
       if (time.weekday==3) // СР
      {
      lcd.setCursor(7,0); lcd.print ("CP");
      }
       if (time.weekday==4) // ЧТ
      {
      lcd.setCursor(7,0);
      lcd.printByte(6); lcd.print ("T");
      }
      if (time.weekday==5) // ПТ
      {
      lcd.setCursor(7,0);
      lcd.printByte(5); lcd.print ("T");
      }
      if (time.weekday==6) // СБ
      {
      lcd.setCursor(7,0);
      lcd.print ("C"); lcd.printByte(7);
      }
      if (time.weekday==0) // ВС
      {
      lcd.setCursor(7,0);
      lcd.print ("BC");
      }
      
      }    
}
}        
    

 

gulin176
Offline
Зарегистрирован: 03.09.2016

а вторая строчка что выводит?

Sprite
Offline
Зарегистрирован: 30.10.2016

gulin176 пишет:

а вторая строчка что выводит?

Номер канала>Время прихода данных

Porosenok
Offline
Зарегистрирован: 06.11.2016

Sprite пишет:

Спасибо за ответ, но что то у меня не работает.

 

Естественно не работает, была ночь и я жестоко ошибся. Надо было не

pora_vivodit > millis()

а

millis() > pora_vivodit

 

 

Sprite
Offline
Зарегистрирован: 30.10.2016

Porosenok пишет:

Sprite пишет:

Спасибо за ответ, но что то у меня не работает.

 

Естественно не работает, была ночь и я жестоко ошибся. Надо было не

pora_vivodit > millis()

а

millis() > pora_vivodit

 

 


Вас понял.
Но по сути, у меня работает похожее условие.

Porosenok
Offline
Зарегистрирован: 06.11.2016

В вашем случае условие не выполнится, если в момент сравнения millis() вернёт не 10000, а например 10004.