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

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

Несколькими постами выше ссылка на проект

RogerRU
RogerRU аватар
Offline
Зарегистрирован: 08.11.2016

Да, в сериал валится какая то абракадабра. Скорость порта???

RogerRU
RogerRU аватар
Offline
Зарегистрирован: 08.11.2016

Вот что в сереале при передаче датчика:

1)     IOOIIOOIOOOIOOOOOOOII.IIOOIOIOoo.iiiiiiiiiiiii.ooooooooooooooooooooooooooooooooooooooooooo VAL:81 SIZE:60 SHIFT:0 
2)     Ioiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii.ooooooooooooooooooooooooooooooooooooooooooo VAL:0 SIZE:1 SHIFT:1 COR: 0
RESULT IOOIIOOIOOOIOOOOOOOII.IIOOIOIOoo.iiiiiiiiiiiii.ooooooooooooooooooooooooooooooooooooooooooo 
PERIOD: 1  WRONG
Porosenok
Offline
Зарегистрирован: 06.11.2016

Это повторяется одинаково с каждой посылкой? или по разному?

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

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

RogerRU
RogerRU аватар
Offline
Зарегистрирован: 08.11.2016
 
Иногда проходит норм и опледеляет тип датчика и очень иногда температуру 1 раз из 30. Может с питанием что то не так. 
UPD:
Да, при подключении внешнего питания все вроде заработало, тьфу-тьфу.
Огромное спасибо.
PS
А есть данный код в виде либы, без всех приблуд с часами и дисплеями?
Porosenok
Offline
Зарегистрирован: 06.11.2016

"Но я не знаю трогательных маршей" (с).

Либы делать пока не умею, да боюсь и не выйдет. Код завязан на работу с прерыванием и loop().

А так, выпилить из программы дисплей и часы - вопрос получаса . Думаете стоить плодить код и перенести его сюда в базовом варианте?

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

Ну, если ваш код лучше чем тот что в #113 комментарии - то почему бы и нет )

 

 

RogerRU
RogerRU аватар
Offline
Зарегистрирован: 08.11.2016

Библиотеку сделать не сложно, попробую на досуге и пришлю.

Что до кода, то ваш код самый удачный, что я видел на просторах инета.

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

Доброго времени суток.

Есть датчики Oregon RTGN318.

Как определить, какая версия протокола исползуется?

RogerRU
RogerRU аватар
Offline
Зарегистрирован: 08.11.2016

v 2.2 имхо

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

RogerRU пишет:

v 2.2 имхо

Ясно. Меня смутило наличие RF Clock.

Пытаюсь освоить Ардуино, только для одной цели, приём и отображение/отправка данных с датчиков Oregon.

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

А чем 2.2 отличается от 2.1?

PAV
Offline
Зарегистрирован: 29.10.2012

Простите меня за оффтоп, но я так долго мучался с получением данных от датчиков орегон, что когда случайно наткнулся на сайт Narodmon просто вздохнул. Да, понимаю, не мое, чужое, но какая разница, если датчики вон, в соседнем доме, да еще и с барометром :) Так что забил на свое, пользуюсь чужими данными.

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

PAV пишет:

Простите меня за оффтоп, но я так долго мучался с получением данных от датчиков орегон, что когда случайно наткнулся на сайт Narodmon просто вздохнул. Да, понимаю, не мое, чужое, но какая разница, если датчики вон, в соседнем доме, да еще и с барометром :) Так что забил на свое, пользуюсь чужими данными.


Неизвестно где висит датчик у соседа и что он показывает.
Свой надёжнее)) ИМХО

re3lex
Offline
Зарегистрирован: 02.06.2015

PAV пишет:

Простите меня за оффтоп, но я так долго мучался с получением данных от датчиков орегон, что когда случайно наткнулся на сайт Narodmon просто вздохнул. Да, понимаю, не мое, чужое, но какая разница, если датчики вон, в соседнем доме, да еще и с барометром :) Так что забил на свое, пользуюсь чужими данными.

Ну вообще-то, люди данные не из Великого Рандома берут, а часто с тех же погодных датчиков Oregon. А как собрать данные с них? - Правильно: Ардуино собирает и шлет на Narodmon.ru

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

Ну вот, дошли руки. Выкладываю чистый код приёмника.

#define THGN132 0x1D20      //Типы известных датчиков
#define THN132  0xEC40

#define MHZ 2               //Приёмник подключается к D2

#define FIND_PACKET   1     
#define ANALIZE_PACKETS 3

#define PER_LENGTH 976      // Период в мкс
#define THR_LENGTH 615     //Порог периода 0 или 1
#define LENGTH_TOLERANCE 20 //Допуск на период

#define READ_BITS 90        //Размер битовой посылки
#define READ_BITS2 180      //Двойной размер битовой посылки
#define PACKET_LENGTH 20    //Размер пакета данных
#define DEBUG_INFO 1        //Выводить ли диагностическую информацию

bool  reciever_ctrl = true; //Флаг контроля ресивера (выставляется при приходе импулься, сбрасывается в таймере)
bool  reciever_status = false; // Результат проверки состояния ресивера

//Массивы для хранения полученных данных:
float r_tmp[3];         //Температура
byte  r_hmdty[3];       //Влажность. Если = 101 - значит нет данных
bool  r_bat[3];         //Флаг батареи
bool  r_isreceived[3];  //Флаг о том, что по данному каналу приходил хоть один правильный пакет
word  r_type[3];        //Тип датчика
unsigned long rcv_time[3]; // времена прихода пакетов

byte _chnl;              

byte receive_status, packet_number;
byte start_pulse_cnt;

unsigned long pulse_length, work_time,  timer_marklong;  
unsigned long pulse_marker, right_pulse_marker, last_premarker;
unsigned long pre_marker[4]; // Для хранения временных меток преамбулы ()
unsigned long first_packet_end;

bool crc_c;             //Результат проверки CRC
word sens_type;         //Тип сенсора
bool pulse_type;        //Пустое

byte data_length, data_length2; //Длины пакетов
int data_val, data_val2;        // Качество пакетов

//Массивы данных для записи данных с канала и полученных битов
byte collect_data[READ_BITS2], collect_data2[READ_BITS2];
//А когда становится массивом полученных битов, то значения такие:
//                          0 - неизвестен
//                          >0 - единица
//                          <0 - ноль
byte decode_tacts[READ_BITS2]; //Массив тактов. значения
//                          0=ноль
//                          1=единица
//                          2=неизвестен
//                          3=переход+
//                          4=переход-

/////////    ПРЕРЫВАНИЕ   ///////////////////////////////////////////////////////////////////////////////////////////

volatile unsigned long pm;
volatile unsigned long pl, timer_mark;  

void int_0(void) {  
  if(digitalRead(MHZ)){
  //Начало импульса
    pl = 0;
    pm = micros();  
  }
  else{
    //Конец импульса
    //Вычисляется время окончания и длина
    pl = micros() - pm;  
    pm += pl;
  }
}  
//////////////// УСТАНОВКИ  ///////////////////////////////////////
void setup ()
{
  Serial.begin(57600);
   
  //Прерывание по сигналу от приёмника
  pinMode(MHZ,INPUT);   
  attachInterrupt(0, int_0, CHANGE);  
  
  receive_status = FIND_PACKET;
  start_pulse_cnt = 0;
  packet_number = 0;
  for (int i = 0; i < 3; i++){
    rcv_time[i] = 7000000;
    r_isreceived[i] = 0;
  }
  pinMode(13, OUTPUT);        //Будем мигать светодиодом
  digitalWrite(13, LOW);
}

//////////////// ГЛАВНЫЙ ЦИКЛ  ///////////////////////////////////////
void loop() 
{
  noInterrupts();
  pulse_length = pl;
  pl = 0;
  pulse_marker = pm;
  interrupts();
//////////////////////////////////////////////////////////////////////
//Получен некий импульс,//////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
  if (pulse_length != 0 && receive_status == FIND_PACKET){  
    reciever_ctrl = 1;
    //Режим поиска пакета в эфире
    if (start_pulse_cnt == 0){
    //Найдена первый "правильный" импульс - длинная единица!
      if (pulse_length < (PER_LENGTH) && pulse_length > (THR_LENGTH) ) {
        start_pulse_cnt = 1;
        pre_marker[start_pulse_cnt] = pulse_marker;
        pulse_length = 0;
      }
    }
    //Ищем следующие импульсы
    else{
    //Найден импуль правильной длины
      if (pulse_length <= (PER_LENGTH) && pulse_length >= (THR_LENGTH)) {
        //Если импульс в правильном месте, то добавляем счётчик найденых стартовых импульсов
        if(pulse_marker - pre_marker[start_pulse_cnt] > (PER_LENGTH*2-LENGTH_TOLERANCE) && pulse_marker - pre_marker[start_pulse_cnt] < (PER_LENGTH * 2 + LENGTH_TOLERANCE)){
          start_pulse_cnt++;
          pre_marker[start_pulse_cnt] = pulse_marker;
          pulse_length = 0;
        }
        ///...если  в неправильном месте то назначаем его первым
        else{
          start_pulse_cnt = 1;
          pre_marker[start_pulse_cnt] = pulse_marker;
          pulse_length = 0;
        }
      }
      else{
        //Если импульс неправильной длины, то стоит проверить, а не вышло ли время ожидания правильного импульса
        if(pulse_marker - pre_marker[start_pulse_cnt] < (PER_LENGTH * 2 + LENGTH_TOLERANCE)){
          //Время ещё не вышло, скорее всего это помеха. Пропускаем...
          pulse_length = 0;
        }
        else{
          //Время вышло, начинаем искать заново
            start_pulse_cnt = 0;
            pulse_length = 0;
          }
        }
      }
    }
    if(packet_number == 1 && (millis() - first_packet_end) > 200){ // Если найден первый пакет и вышло вермя ожидания второго
                                                               // Не ждём второго, а переходм в режим анализа
    receive_status = ANALIZE_PACKETS;
    }
//////////////////////////////////////////////////////////////////////
// Сбор данных////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

  //Если Найдены три длинных единицы и два длинных нуля. Возможно это начало посылки...
    if (start_pulse_cnt == 3 && receive_status == FIND_PACKET){
      work_time = millis();
      last_premarker = pre_marker[3];
      start_pulse_cnt = 0;
        if (packet_number == 0){
          collect(collect_data, &data_length);
          first_packet_end = millis();
          packet_number = 1;
        }
        else{
          collect(collect_data2, &data_length2);
          packet_number = 2;
          receive_status = ANALIZE_PACKETS;
        }
      }
      if  (receive_status == ANALIZE_PACKETS){     
        digitalWrite(13, HIGH);
  //////////////////////////////////////////////////////////////////////
  // Анализ данных////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////      
        bool halfshift;
  //Дамп собранных данных        
/*        if (DEBUG_INFO){
          for(int bt = 0; bt < 180; bt++){
            Serial.print(collect_data[bt], HEX);
            Serial.print(' ');
          }
          Serial.println(" ");

          for(int bt = 0; bt < 180; bt++){
            Serial.print(collect_data2[bt],HEX);
            Serial.print(' ');
          }
          Serial.println(" ");
        }
*/
        
        get_bits(collect_data);
        if (get_data(0, collect_data) > get_data(1, collect_data)){
          data_val = get_data(0, collect_data);
          halfshift = 0;
        }
        else {
          data_val = get_data(1, collect_data);
         halfshift = 0;
        }
        if (DEBUG_INFO){
          Serial.print("1)     ");
          for(int bt = 0; bt < READ_BITS; bt++){
            if (collect_data[bt] > 128 + 1) Serial.print('I');
            if (collect_data[bt] < 128 - 1) Serial.print('O');
            if (collect_data[bt] == 128 + 1) Serial.print('i');
            if (collect_data[bt] == 128 - 1) Serial.print('o');
            if (collect_data[bt] == 128) Serial.print('.');
          }
          Serial.print(" VAL:");
          Serial.print(data_val);
          //Serial.print(" SIZE:");
          //Serial.print(data_length);
          Serial.print(" SHIFT:");
          Serial.print(halfshift);
        }
        if (packet_number == 2){
          get_bits(collect_data2);
          if (get_data(0, collect_data2) > get_data(1, collect_data2)) {
            data_val2 = get_data(0, collect_data2);
            halfshift = 0;
          }
          else {
            data_val2 = get_data(1, collect_data2);
            halfshift = 1;
          }
          if (DEBUG_INFO){
          Serial.println(" ");  
          Serial.print("2)     ");
          for(int bt = 0; bt < READ_BITS; bt++){
            if (collect_data2[bt] > 128 + 1) Serial.print('I');
            if (collect_data2[bt] < 128 - 1) Serial.print('O');
            if (collect_data2[bt] == 128 + 1) Serial.print('i');
            if (collect_data2[bt] == 128 - 1) Serial.print('o');
            if (collect_data2[bt] == 128) Serial.print('.');
          }
          Serial.print(" VAL:");
          Serial.print(data_val2);
          //Serial.print(" SIZE:");
          //Serial.print(data_length2);
          Serial.print(" SHIFT:");
          Serial.print(halfshift);
        }
      }
      int correlation = correlate_data(collect_data, collect_data2);
        if (DEBUG_INFO){
          Serial.print(" COR: ");
          Serial.println(correlation);
        }
        byte* result_data, result_data_start, aux_data;
        if (packet_number == 1){
          result_data = collect_data;     
        }
        else{
          if (correlation > 0){
            result_data = collect_data2;
            assemble_data(collect_data2,collect_data, &correlation);
        }
        else{
          result_data = collect_data;
          correlation = -correlation;
          assemble_data(collect_data, collect_data2, &correlation);
        }
        //Вывод готовой посылки
      }
      if (DEBUG_INFO){
        Serial.print("RESULT ");
        byte* rdt = result_data;
        for(int bt = 0; bt < READ_BITS; bt++){
          if (*rdt > 128 + 1) Serial.print('I');
          if (*rdt < 128 - 1) Serial.print('O');
          if (*rdt == 128 + 1) Serial.print('i');
          if (*rdt == 128 - 1) Serial.print('o');
          if (*rdt == 128) Serial.print('.');
          rdt++;
        }
        Serial.println(" ");
      }
        //Обработка посылки
      Serial.print("PERIOD: ");
      Serial.print(millis()/40000);
      Serial.print(" ");
      byte packet[PACKET_LENGTH], valid_p[PACKET_LENGTH];
      if (get_info_data(result_data, packet, valid_p)){
        sens_type = get_sensor(packet); //Определяем тип пакета по типу датчика
        restore_data(packet, sens_type); // Восстанавливаем данные по типу датчика
        crc_c = check_CRC(packet, sens_type); // Проверяем CRC, если оно верно, то все сомнительные биты делаем уверенными
        
        if (crc_c) for (byte www = 0; www < PACKET_LENGTH; www++) valid_p[www] = 0x0f;
        Serial.print(" PACKET: ");
        for (int q = 0;q < PACKET_LENGTH; q++) Serial.print(packet[q], HEX);
        Serial.print(" VALIDITY: ");
          for (int q = 0; q < PACKET_LENGTH; q++) Serial.print(valid_p[q], HEX);
      }
      if (sens_type == THGN132 || sens_type == THN132){
        Serial.print(" TYPE: ");
        if (sens_type == THGN132) Serial.print("THGN132N ");
        if (sens_type == THN132) Serial.print("THN132N  ");
        Serial.print("ID: ");
        Serial.print(get_id(packet), HEX);
        Serial.print(" CHNL: ");
        _chnl=get_channel(packet)-1;
        Serial.print(_chnl+1);
        r_type[_chnl] = sens_type;
        if (crc_c) r_isreceived[_chnl] = 1;
        
        //......Если получен правильный пакет, сбрасываем таймер
        if(crc_c) rcv_time[_chnl] = millis();  //         
        
        Serial.print(" BAT: ");
        if(crc_c) r_bat[_chnl] = get_battery(packet);
        if (r_bat[_chnl]) Serial.print("F "); else Serial.print("e ");
       
        Serial.print("TMP: ");
        if(get_temperature_mask(valid_p)){
          if(crc_c) r_tmp[_chnl] = get_temperature(packet);
          Serial.print(r_tmp[_chnl], 1);
        }
        else {
          Serial.print("----");
        }
        Serial.print("C ");
        if (sens_type == THGN132) {
          Serial.print("HUM: ");
          if (get_humidity_mask(valid_p)) {
            if(crc_c) r_hmdty[_chnl] = get_humidity(packet);
            Serial.print(r_hmdty[_chnl], 1);
        }
        else{
          Serial.print("--");
          r_hmdty[_chnl] = 101;
        }
        Serial.print("%");
      }
      else Serial.print("        ");
      Serial.print(" CRC: ");
      if (crc_c) Serial.print("OK ");
      else Serial.print("-- ");
      
          
      Serial.print(" PROC. TIME: ");
      Serial.print(millis() - work_time);
      Serial.println("ms ");
    }
    else Serial.println(" WRONG  ");
    // Возвращаемся к исходному состоянию
    receive_status = FIND_PACKET;
    packet_number = 0;
    start_pulse_cnt = 0;
    sens_type = 0;
    _chnl = 0;
    digitalWrite(13, LOW);
  }

//////////////////////////////////////////////////////////////////////      
//Здесь записываются остальные  процедуры, например те, которые выполняются ежесекундно
//////////////////////////////////////////////////////////////////////      
  if ((millis() - timer_mark) > 1000) {
    {
      if (!reciever_status) Serial.println("RECEIVING...");
      reciever_status = 1;
    }
    reciever_ctrl = 0;
  }
//////////////////////////////////////////////////////////////////////      
//////////////////////////////////////////////////////////////////////      
//////////////////////////////////////////////////////////////////////      
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Извлекает из тактовой последовательности - битовую
//Параметры: cdptr - указатель на записанную тактовую последовательность
////////////////////////////////////////////////////////////////////////////////////////////////////
void get_bits(byte* cdptr){
  
//Сброс массивов
  byte* cdp=cdptr;
  for(int bt=0 ; bt<READ_BITS*2; bt++) decode_tacts[bt]=2;
      
        
  for(int bt=0 ; bt<READ_BITS*2; bt++){
        
    if ((*cdp&0xf0)>0x20 && (*cdp&0x0f)>0x04) decode_tacts[bt]=1;
    if ((*cdp&0xf0)<0x30 && (*cdp&0x0f)<0x05) decode_tacts[bt]=0;
    if ((*cdp&0xf0)<0x20 && (*cdp&0x0f)>0x04) decode_tacts[bt]=4;
    if ((*cdp&0xf0)>0x40 && (*cdp&0x0f)<0x02) decode_tacts[bt]=3;
    *cdp++;
  }
  return;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Извлекает из записи канала тактовую последовательность
//Параметры: cdptr - указатель на записанные данные
// btt - смещение в тактах. Смещение на такт при анализе может поммочь восстановить пакет, у которого разрушено начало
// Функция вовзращает качество или "годность" расшифровки - количесвто уверенно узнаных тактов.
// Сравнивая годность с btt=0 и btt=1 выбираем лучшую
////////////////////////////////////////////////////////////////////////////////////////////////////
int get_data(int btt, byte* cdptr){ //btt - смещение на такт при анализе может поммочь восстановить пакет, у которого разрушено начало
  
  byte* cdp=cdptr;
  for(int bt=0 ; bt<READ_BITS; bt++){
    *cdp=128;
    cdp++;
  }
  cdp=cdptr;
  *cdp=(128+2);
  cdp++;
  int packet_validity=0;
  for(int bt=1 ; bt<READ_BITS; bt++){
    if(decode_tacts[bt*2-btt]==0) *cdp-=1;
    if(decode_tacts[bt*2-btt]==1) *cdp+=1;
    if(decode_tacts[bt*2-2-btt]==1 && decode_tacts[bt*2-1-btt]==4) *cdp-=1;
    if(decode_tacts[bt*2-2-btt]==0 && decode_tacts[bt*2-1-btt]==3) *cdp+=1;
    if(decode_tacts[bt*2-2-btt]==0 && decode_tacts[bt*2-1-btt]==1) *cdp-=1;
    if(decode_tacts[bt*2-2-btt]==1 && decode_tacts[bt*2-1-btt]==0) *cdp+=1;

    if(decode_tacts[bt*2+2-btt]==1 && decode_tacts[bt*2+1-btt]==3) *cdp-=1;
    if(decode_tacts[bt*2+2-btt]==0 && decode_tacts[bt*2+1-btt]==4) *cdp+=1;
    if(decode_tacts[bt*2+2-btt]==0 && decode_tacts[bt*2+1-btt]==1) *cdp-=1;
    if(decode_tacts[bt*2+2-btt]==1 && decode_tacts[bt*2+1-btt]==0) *cdp+=1;

        //Подсчитываем кол-во достоверных бит в пакете
    if (*cdp>(128+1) )  packet_validity+=*cdp-128;
    if (*cdp<(128-1)) packet_validity+=128-*cdp;
    cdp++;
  }
  return packet_validity;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Прослушивание канала с частотой дискретизации 16384Гц
////////////////////////////////////////////////////////////////////////////////////////////////////
void collect(byte* cdptr, byte* dtl){
  
  // В функцию передаётся уазатель на область памяти, куда сливать данные.
  *dtl=0;
  bool cdp_prev_null;
  byte* cdp=cdptr;
  byte nulls_found=0;
  unsigned long tmp_marker=last_premarker+PER_LENGTH/32; //
  byte bt2=0;
  *cdp=0x88; //Первые два такта - единицы. Мы же поймали импульс!
  cdp++;
  //Ждём момента наступления первого считывания (конец последнего импулься зацепки + 1/16 такта)
  while (micros() <= tmp_marker);
  //Начинаем читать данные в память!
  for(int bt=1 ; bt<READ_BITS*2; bt++){// чИТАЕМ максимум ПО 90 БИТ (ПОСЫЛКА thgn - 96БИТ, THN - 76 бИТ + как минимум 3 бита 111, которые мы уже нашли)
    *cdp=0;
    for(byte ckl=0; ckl<8; ckl++){      // Читаем 8 раз за полутакт
      if (digitalRead(MHZ)) *cdp+=0x10; // Измерения запиываем в старший полубайт
      tmp_marker+=PER_LENGTH/16;
      while (micros() < tmp_marker);
    }
    last_premarker+=PER_LENGTH/2;
    tmp_marker=last_premarker+PER_LENGTH/32;
    
    for(byte ckl=0; ckl<8; ckl++){
      if (digitalRead(MHZ)) *cdp+=1;    // В следующий полутакт измерения запиываем в младший  полубайт. Это экономит память.
      tmp_marker+=PER_LENGTH/16;
      while (micros() < tmp_marker);
    }
    last_premarker+=PER_LENGTH/2;
    bt2++;
    //  Каждые 8 тактов добавлять 5мкс для выравнивания периода с 976мкс до 976.56мкс
    if (bt2==8){ 
      last_premarker+=5;
      bt2=0;
    }
    tmp_marker=last_premarker+PER_LENGTH/32;

    while (micros() < last_premarker);//Ждём прихода времени следующего полутакта
    if (*cdp==0 && cdp_prev_null==1) nulls_found++;                    
    //if (*cdp==0 && (*(cdp-1)==0)) nulls_found++;
    else nulls_found=0;
    
    if (nulls_found>1) return; //Если найдено более 7 нулевых тактов подряд, значит либо жёсткая помеха, убившая пакет
                                  //Либо конец посылки. Дальше читать нет смысла.

    cdp_prev_null= (*cdp==0) ? 1 : 0;
    cdp++;                              
    *dtl+=1;
  }
  return;
} 
////////////////////////////////////////////////////////////////////////////////////////////////////
//Определение смещения пакетов друг относительно друга
//В качестве параметров передаются указатели на массивы данных
// Возваращаяется смещение
// >0 - второй пакет начался раньше, <0 - Первый пакет начался раньше
////////////////////////////////////////////////////////////////////////////////////////////////////
int correlate_data(byte* ser1, byte* ser2){
  
  byte best_correl=0;
  int best_shift=0;
  byte best_correl_back=0;
  int best_shift_back=0;
  byte shift_score[READ_BITS];
  byte* s1;
  byte* s2;
  byte* s2t=ser2;
  //смещаем первый пакет относительно второго
  for( byte sht=0; sht<READ_BITS; sht++){
    s1=ser1;
    s2=s2t;
    shift_score[sht]=0;
    for(byte sp=0; sp<READ_BITS-sht; sp++){
      if ((*s1 >(128+1) && *s2 >(128+1))||(*s1 <(128-1) && *s2 <(128-1)) ) shift_score[sht]++;
      s2++;
      s1++;
    }
    s2t++;
  }

  for (int i=0; i<READ_BITS; i++){
    if (shift_score[i]>best_correl){
      best_correl=shift_score[i];
      best_shift=i;
    }
  }
 
//Теперь наоборот -втрой пакет относительно первого
  
  byte* s1t=ser1;
  for( byte sht=0; sht<READ_BITS; sht++){
    s2=ser2;
    s1=s1t;
    shift_score[sht]=0;
    for(byte sp=0; sp<READ_BITS-sht; sp++){
      if ((*s1 >(128+1) && *s2 >(128+1))||(*s1 <(128-1) && *s2 <(128-1)) ) shift_score[sht]++;
      s2++;
      s1++;
    }
    s1t++;
  }
// Ищем наилучшее совпадение для обоих вариантов 
  
  
  for (int i=0; i<READ_BITS; i++){
    if (shift_score[i]>best_correl_back){
      best_correl_back=shift_score[i];
      best_shift_back=i;
    }
  }
  //И возвращаем самое лучшее из двух
  if (best_correl_back > best_correl) return -best_shift_back;
  else return best_shift;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Сборка из двух пакетов
//В качестве параметров передаются указатели на массивы данных
// Причём первым должен идти результирующий пакет, т.е. тот который имеет более длинную преамбулу.
//shift - смещение втрого пакета относительного первого
////////////////////////////////////////////////////////////////////////////////////////////////////
void assemble_data(byte* s1, byte* s2, int* shift){
  
  for (int g=0; g<=*shift-1; g++) s1++;
  for (int i=0; i<(READ_BITS-*shift); i++){
      if(*s1 < (128+2) && *s1 > (128-2) && (*s2>(128+1) || *s2<(128-1))) {
      *s1=*s2;
    }
    s1++;
    s2++;
  }
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Создаёт кодовую посылку
//code - указатель на расшифрованную битовую последовательность
//result - указатель на кодовую посылку
//valid - указатель на карту достоверности кодовой посылки
////////////////////////////////////////////////////////////////////////////////////////////////////
byte get_info_data(byte* code, byte* result, byte* valid){
  
  byte* rd=result;
  byte* vd=valid;
  //Чистим массивы
  for (int l=0; l<PACKET_LENGTH; l++){
    *vd=0;
    *rd=0;
    vd++;
    rd++;
  }
  int csm;
  for (csm=0; csm<30;csm++){
    if (*code<128 && *(code+1)>128 && *(code+2)<128 && *(code+3)>128) break;//Найдена последовательность 0101 
    code++;
  }
  if (csm>22) return 0;// Стартовая последовательность в первых 20 битах не найдена, такой пакет этим методом не расшифруешь
  
  code+=4;//Переходим на начало считывания
  int ii=0;
  for (int i=0; i<READ_BITS-csm; i++) 
  {
    byte multipl;
    switch (ii){
      case 0: {multipl=0x01; break;}
      case 1: {multipl=0x02; break;}
      case 2: {multipl=0x04; break;}
      case 3: {multipl=0x08; break;}
    }
    if (*code==129 ) *result+=multipl;
    if (*code>129 ) {
      *result+=multipl;
      *valid+=multipl;
    }
    if (*code<127 ) *valid+=multipl;
    code++;
    ii++;
    if (ii==4) {
      ii=0;
      valid++;
      result++;
    }
  }
  return 1;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Возвращает значение температуры
//oregon_data - указатель на кодовую посылку
////////////////////////////////////////////////////////////////////////////////////////////////////
float get_temperature(byte* oregon_data){
  
  float tmprt;
  oregon_data+=8;
  //исправляем возможные ошибки:
  for (int g=0;g<4; g++)  if (*(oregon_data+g)>9) *(oregon_data+g)=*(oregon_data+g)-8;
  tmprt+=*(oregon_data)*0.1;
  tmprt+=*(oregon_data+1);
  tmprt+=*(oregon_data+2)*10;
  return (*(oregon_data+3)) ? -tmprt : tmprt;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Возвращает значение маски годности
//validity_data - указатель на карту достоверности кодовой посылки
////////////////////////////////////////////////////////////////////////////////////////////////////
byte get_temperature_mask(byte* validity_data){
  
    return (*(validity_data+8)==0x0f && *(validity_data+9)==0x0f && *(validity_data+10)==0x0f && *(validity_data+11)==0x0f) ? 1 : 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Возвращает тип сенсора
//oregon_data - указатель на кодовую посылку
////////////////////////////////////////////////////////////////////////////////////////////////////
word get_sensor(byte* oregon_data){
  
    return (word)(*(oregon_data))*0x1000 + (*(oregon_data+1))*0x0100 + (*(oregon_data+2))*0x10 + *(oregon_data+3);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Возвращает значение канала
//oregon_data - указатель на кодовую посылку
////////////////////////////////////////////////////////////////////////////////////////////////////
byte get_channel(byte* oregon_data){
  
  byte channel;  
  switch (*(oregon_data+4))  
  {  
  case 1:  
    channel = 1;  
    break;  
  case 2:  
    channel = 2;  
    break;  
  case 4:  
    channel = 3;  
    break;  
  }  
  return channel;  
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
byte get_battery(byte* oregon_data){

  return (*(oregon_data+7) & 0x4) ? 0 : 1;  
  
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Возвращает значение влажности
//oregon_data - указатель на кодовую посылку
////////////////////////////////////////////////////////////////////////////////////////////////////
byte get_humidity(byte* oregon_data){
  
  byte tmprt;
  oregon_data+=12;
  //исправляем возможные ошибки:
  for (int g=0;g<2; g++)  if (*(oregon_data+g)>9) *(oregon_data+g)=*(oregon_data+g)-8;
  tmprt=*(oregon_data);
  tmprt+=*(oregon_data+1)*10;
  return tmprt;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Возвращает значение маски годности влажности 4 бита, старший - знак, младший -  десятые доли градуса
//validity_data - указатель на карту достоверности кодовой посылки
////////////////////////////////////////////////////////////////////////////////////////////////////
byte get_humidity_mask(byte* validity_data){
  
 return (*(validity_data+13)==0x0f && *(validity_data+14)==0x0f) ? 1 : 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Возвращает id датчика
//oregon_data - указатель на кодовую посылку
////////////////////////////////////////////////////////////////////////////////////////////////////
byte get_id(byte* oregon_data){
  
  byte tmprt;
  oregon_data+=5;
  tmprt=*(oregon_data)*0x10;
  tmprt+=*(oregon_data+1);
  return tmprt;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
//Проверка CRC
//oregon_data - указатель на кодовую посылку
////////////////////////////////////////////////////////////////////////////////////////////////////
bool check_CRC(byte* oregon_data, word sensor_type){
  
  byte* pp=oregon_data;
  byte crc, resived_crc;
  crc=0;
  if (sensor_type==THGN132){
    for(int x=0; x<15; x++){
      crc+=*pp;
      pp++;  
    }
    resived_crc=(*(oregon_data+15))+(*(oregon_data+16))*0x10;
   return (resived_crc==crc)? 1 : 0;
  }

  if (sensor_type==THN132){
    for(int x=0; x<12; x++){
      crc+=*pp;
      pp++;  
    }
    resived_crc=(*(oregon_data+12))+(*(oregon_data+13))*0x10;
    return (resived_crc==crc)? 1 : 0;
  }
  return 0;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
//Востановление данных по типу датчика
////////////////////////////////////////////////////////////////////////////////////////////////////
void restore_data(byte* oregon_data, word sensor_type){
  
  byte* pp=oregon_data;
  if (sensor_type==THGN132){
    pp+=8;
    for(int x=0; x<6; x++){
      if(*pp>9 && x!=3) *pp-=8;
      pp++;  
    }
  }
  if (sensor_type==THN132){
    pp+=8;
    for(int x=0; x<3; x++){
      if(*pp>9) *pp-=8;
      pp++;  
    }
  }
  return;
}

 

gulin176
Offline
Зарегистрирован: 03.09.2016
Arduino: 1.6.11 (Windows 10), Плата:"Arduino/Genuino Uno"

C:\Users\Администратор\Documents\Arduino\UNORF-5V\UNORF-5V.ino: In function 'void loop()':

UNORF-5V:164: error: 'collect' was not declared in this scope

UNORF-5V:169: error: 'collect' was not declared in this scope

UNORF-5V:196: error: 'get_bits' was not declared in this scope

UNORF-5V:197: error: 'get_data' was not declared in this scope

UNORF-5V:223: error: 'get_data' was not declared in this scope

UNORF-5V:249: error: 'correlate_data' was not declared in this scope

UNORF-5V:261: error: 'assemble_data' was not declared in this scope

UNORF-5V:266: error: 'assemble_data' was not declared in this scope

UNORF-5V:288: error: 'get_info_data' was not declared in this scope

UNORF-5V:289: error: 'get_sensor' was not declared in this scope

UNORF-5V:290: error: 'restore_data' was not declared in this scope

UNORF-5V:291: error: 'check_CRC' was not declared in this scope

UNORF-5V:304: error: 'get_id' was not declared in this scope

UNORF-5V:306: error: 'get_channel' was not declared in this scope

UNORF-5V:315: error: 'get_battery' was not declared in this scope

UNORF-5V:319: error: 'get_temperature_mask' was not declared in this scope

UNORF-5V:320: error: 'get_temperature' was not declared in this scope

UNORF-5V:329: error: 'get_humidity_mask' was not declared in this scope

UNORF-5V:330: error: 'get_humidity' was not declared in this scope

exit status 1
'collect' was not declared in this scope

Этот отчёт будет иметь больше информации с
включенной опцией Файл -> Настройки ->
"Показать подробный вывод во время компиляции"

посмотрите код ошибки почему то. 

и что значит #define MHZ 2               //Приёмник подключается к D2

что значит D2?

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

Porosenok пишет:

Ну вот, дошли руки. Выкладываю чистый код приёмника.

С вашим кодом что-то не так... ;)

RECEIVING...
1)     IIIIIOIOIIOOOIOIIOIOOOOOOIOOOIIOIIIOIOOOOOOOOIOIOOOOOOOOiOOioiOOiOOOOiOOOOO.o.OOIIiOO.oooo VAL:204 SHIFT:0 
2)     IOOOIOOOIIOIIIOIOOOOOOOOIOIOOOOOOOOIOOIOIOOIOOOOiOOOOOioiOOIIIOO.ooooooooooooooooooooooooo VAL:164 SHIFT:1 COR: -21
RESULT IIIIIOIOIIOOOIOIIOIOOOOOOIOOOIIOIIIOIOOOOOOOOIOIOOOOOOOOIOOIOIOOIOOOOiOOOOO.o.OOIIIOO.oooo 
PERIOD: 0  PACKET: 1D201BB0050849010830 VALIDITY: FFFFFFFFFFFFFFFE3EF0 TYPE: THGN132N ID: BB CHNL: 1 BAT: e TMP: 0.0C HUM: 0% CRC: --  PROC. TIME: 567ms 
1)     IIIIIIIIIIIIOIOIIOOOIOIIOIOOOOOOOOIOIOIOIOOOOOOOOOOIOOIOOIOOOOOOOOOOIIIOOOIOIIOOIIOOOOOOOO VAL:266 SHIFT:0 
2)     IIIIIIIIIIIIIOIOIIOOOIOIIOIOOOOO.ioo.iiiiiiiiIIiiIIIIi..ii.OO.iioooooooooooooooooooooooooo VAL:110 SHIFT:0 COR: 1
RESULT IIIIIIIIIIIIIOIOIIOOOIOIIOIOOOOOOOOIOIOIOIOOOIIOOIIIIOOIOOIOOOOOOOOOOIIIOOOIOIIOOIIOOOOOOO 
PERIOD: 0  PACKET: 1D2045137420074330A0 VALIDITY: FFFFFFFFFFFFFFFFFFF1 TYPE: THGN132N ID: 51 CHNL: 3 BAT: e TMP: 0.0C HUM: 0% CRC: --  PROC. TIME: 508ms 
1)     IIIIIIIIIIIIIOIOIIOOOIOIIOIOOOOOOIoOOOIIIOOIIoOOOOOOOIOIOOOOOOOOIoOI.ioOOOIOIIOOIIOOOOOOOO VAL:243 SHIFT:0 
2)     IIIIIOIOIIOOOIOIIOIoOOOOOIoOOOIIIoOIIOOOOOOOOIOIOOOOOOOOIOOIoIOOIOOIIIOOOIOIOIOIIIOOOooooo VAL:223 SHIFT:0 COR: -8
RESULT IIIIIIIIIIIIIOIOIIOOOIOIIOIOOOOOOIoOOOIIIOOIIOOOOOOOOIOIOOOOOOOOIOOI.IOOOOIOIIOOIIOOOOOOOO 
PERIOD: 0  PACKET: 1D201EC0050841A91000 VALIDITY: FFFFDFFFFFFF7FFFFFF1 TYPE: THGN132N ID: EC CHNL: 1 BAT: e TMP: 0.0C HUM: 0% CRC: --  PROC. TIME: 606ms 
1)     IIIIIIIIOIOIIOOOIOIIOIOOOOOOIOOOIIOIIIOIOOOOOOOOioiOOOOOOOOiOOioiOOiOOOO.OOOOO.o.OOIIiOO.o VAL:206 SHIFT:0 
2)     IIIIIIIIOIOIIOOOIOIIOIOOOOOOIOOOIIOIIIOIOOOOOOOOiioOOOOOIOOIoIOOIOOIIIOOOIOIOIOIIIOOOooooo VAL:230 SHIFT:0 COR: 0
RESULT IIIIIIIIOIOIIOOOIOIIOIOOOOOOIOOOIIOIIIOIOOOOOOOOioiOOOOOOOOIOOOOIOOIOOOOOOOOOOOIIOOIIiOO.o 
PERIOD: 0  PACKET: 1D201BB0050809008938 VALIDITY: FFFFFFFFF8FFFFFFFFDC TYPE: THGN132N ID: BB CHNL: 1 BAT: e TMP: ----C HUM: 0% CRC: --  PROC. TIME: 539ms 
1)     IIIIIIIIIIIIIIOIOIIOOOIOIIOIOOOOO.oIOOIIIIOOIOOOOOOOOIIIOOOIOOOOOOOOIOIIOOOOOIIOOOOOIOIIOI VAL:258 SHIFT:0 COR: -6
RESULT IIIIIIIIIIIIIIOIOIIOOOIOIIOIOOOOO.oIOOIIIIOOIOOOOOOOOIIIOOOIOOOOOOOOIOIIOOOOOIIOOOOOIOIIOI 
PERIOD: 0  PACKET: 1D202F40832043814BA0 VALIDITY: FFFFFFFFFFFFFFFFFFFF TYPE: THGN132N ID: F4 CHNL: 2 BAT: F TMP: 23.8C HUM: 34% CRC: OK  PROC. TIME: 695ms 
1)     IIIIIIIIIIIIIIOIOIIOOOIOIIOIOOOOOOOOIOIOIOIOOOOOOOOOOIOOIO..oOOOOOOOIOIIOOOOOIIOOOOOIOIIOI VAL:255 SHIFT:0 
2)     IIIIIIIIIIIIOIOIIOOOIOIIOIOOOOOOOOIOIOIOIOOOOOOOOOOIOOIOOIOOOOOOIOOOIIIOOOIIOOIIIIOOIOIIOI VAL:266 SHIFT:0 COR: -2
RESULT IIIIIIIIIIIIIIOIOIIOOOIOIIOIOOOOOOOOIOIOIOIOOOOOOOOOOIOOIOOIOOOOOOOOIOIIOOOOOIIOOOOOIOIIOI 
PERIOD: 1  PACKET: 1D204510842043814B00 VALIDITY: FFFFFFFFFFFFFFFFFFF0 TYPE: THGN132N ID: 51 CHNL: 3 BAT: e TMP: 0.0C HUM: 0% CRC: --  PROC. TIME: 616ms 
1)     IIIIIIIIIIIIOIOIIOOOIOIIOIOOOOOOIOOOOIIIOOIIOOOOOOOOioIOOOOOOOOIoOIOIOOIOOIIIOOOIOIOIOIIIO VAL:253 SHIFT:0 
2)     IIIIIIIIIIIOIOIIOO.ioo.iiii.iiii.i..i.i..i..iOOOOOOIOOIOOIOOOOOOIOOOIIIOOOIIOOIIIIOOIOIIOI VAL:183 SHIFT:0 COR: -1
RESULT IIIIIIIIIIIIOIOIIOOOIOIIOIOOOOOOIOOOOIIIOOIIOOOOOOOOIOIOOOOOOOOIOOIOIOOIOOIIIOOOIOIOIOIIIO 
PERIOD: 1  PACKET: 1D201EC0050849C15D10 VALIDITY: FFFFFFFFFFFFFFFFFFFF TYPE: THGN132N ID: EC CHNL: 1 BAT: F TMP: -5.0C HUM: 94% CRC: OK  PROC. TIME: 482ms 
1)     IIIIIIIIIOIOIIOOOIOIIOIOOOOOOIOOOIIOIIIOIOOOOOOOOIOIOOOOOOOOiOOioiOOiOOOO.OOOOOio.OOIIiOO. VAL:218 SHIFT:0 
2)     IIIIIIIIOIOIIOOOIO..o..iiii.iiii.i..i.i..i..iOOOOOOIOOIOOIOOOOOOIOOOIIIOOOIIOOIIIIOOIOIIOI VAL:183 SHIFT:0 COR: -1
RESULT IIIIIIIIIOIOIIOOOIOIIOIOOOOOOIOOOIIOIIIOIOOOOOOOOIOIOOOOOOOOOOOOOIOOOOOOOOOOOOOIIIOOIIOOOO 
PERIOD: 1  PACKET: 1D201BB005000100C914 VALIDITY: FFFFFFFFFFFFFFFFFFFF TYPE: THGN132N ID: BB CHNL: 1 BAT: F TMP: -5.0C HUM: 94% CRC: --  PROC. TIME: 481ms 
1)     IIIIIIIIIIIOIOIIOOOIOIIOIOOOOOOOOIOIOIOIOOOIOOOIOOIOOIOOIOOOOOOIIOOIIIOIOIIIOOOOOIOIOOOIIO VAL:266 SHIFT:0 
2)     IIIIioo..oi............iiii.iiii.i..i.i..i..iOOOOOOIOOIOOIOOOOOOIOOOIIIOOOIIOOIIIIOOIOIIOI VAL:141 SHIFT:0 COR: 1
RESULT IIIIIIIIIIIIOIOIIOOOIOIIOIOOOOOOOOIOIOIOIOOOIOOOOOOIOOIOOIOOOOOOIOOOIIIOOOIIOOIIIIOOIOIIOI 
PERIOD: 2  PACKET: 1D204511842017CC3D20 VALIDITY: FFFFFFFFFFFFFFFFFFF3 TYPE: THGN132N ID: 51 CHNL: 3 BAT: e TMP: 0.0C HUM: 0% CRC: --  PROC. TIME: 450ms 
1)     IIIiiIIIIioooiiiiiiiiiiii.ii.iii.i.ii.iiiiiioOOIOOIOOIOOIOOOOOOIIOOIIIOIOIIIOOOOOIOIOOOIIO VAL:148 SHIFT:0 
2)     IIIIIIII.IOIIOOOIOIIoIOOOOOOIOOOOIIIOOIIOOOOOOOOIOIOOOOOOOOIoOIoIoOIOOIIIoOOIOIoIOIIIOOOOI VAL:225 SHIFT:0 COR: -5

 

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

snickser пишет:

Porosenok пишет:

Ну вот, дошли руки. Выкладываю чистый код приёмника.

С вашим кодом что-то не так... ;)

посмотрите пожалуйста ошибку и куда подключать DATA на UNO

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

gulin176 пишет:

что значит D2?

Digital 2

Цифровой вход номер два!... ) Нумерация которых начинается с ноля. Получается третий от начала ) По поводу ошибки - скорее всего вы неправильно скопировали код с форума, надо через кнопку при наведении мышки на код "посмотреть скопировать код", а не из поста брать.

 

 

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

snickser пишет:

gulin176 пишет:

что значит D2?

Digital 2

Цифровой вход номер два!... ) Нумерация которых начинается с ноля. Получается третий от начала ) По поводу ошибки - скорее всего вы неправильно скопировали код с форума, надо через кнопку при наведении мышки на код "посмотреть скопировать код", а не из поста брать.

 

 

по кнопке появляющейся справа от кода копировал

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

Porosenok пишет:

код приёмника.

Я посылаю передатчиком такое

1A:2D:40:15:30:24:40:A3:34 (3 21 24.3 34.0 0)

А ваш код выдаёт это

PERIOD: 0  PACKET: 1D204510342043A43300 VALIDITY: FFFFFFFFFFFFFFFFFFFF TYPE: THGN132N
ID: 51 CHNL: 3 BAT: F TMP: 24.3C HUM: 34% CRC: OK  PROC. TIME: 619ms
 

 

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

snickser пишет:

Я посылаю передатчиком такое

1A:2D:40:15:30:24:40:A3:34 (3 21 24.3 34.0 0)

А ваш код выдаёт это

PERIOD: 0  PACKET: 1D204510342043A43300 VALIDITY: FFFFFFFFFFFFFFFFFFFF TYPE: THGN132N
ID: 51 CHNL: 3 BAT: F TMP: 24.3C HUM: 34% CRC: OK  PROC. TIME: 619ms

А в чём противоречие? В том, что я байты выдаю в том виде, в котором они приняты в описании протокола?

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

 

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

snickser пишет:

 

С вашим кодом что-то не так... ;)

Да вроде всё нормально. Сигнал шумный, в большинстве полученных посылок не сходится CRC. Но вот в строке 28, например, она сходится. Что-то не так?

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

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

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

gulin176 пишет:

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

Такое впечатление, что у вас не весь код скопирован. Либо компилятор настроен так, что он не видит функцию, если она в коде вызывается раньше, чем описана. Можно попробовать поставить setup() и loop() в конце скетча

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

#define THGN132 0x1D20      //Типы известных датчиков
#define THN132  0xEC40

#define MHZ 2               //Приёмник подключается к D2

#define FIND_PACKET   1     
#define ANALIZE_PACKETS 3

#define PER_LENGTH 976      // Период в мкс
#define THR_LENGTH 615     //Порог периода 0 или 1
#define LENGTH_TOLERANCE 20 //Допуск на период

#define READ_BITS 90        //Размер битовой посылки
#define READ_BITS2 180      //Двойной размер битовой посылки
#define PACKET_LENGTH 20    //Размер пакета данных
#define DEBUG_INFO 1        //Выводить ли диагностическую информацию

bool  reciever_ctrl = true; //Флаг контроля ресивера (выставляется при приходе импулься, сбрасывается в таймере)
bool  reciever_status = false; // Результат проверки состояния ресивера

//Массивы для хранения полученных данных:
float r_tmp[3];         //Температура
byte  r_hmdty[3];       //Влажность. Если = 101 - значит нет данных
bool  r_bat[3];         //Флаг батареи
bool  r_isreceived[3];  //Флаг о том, что по данному каналу приходил хоть один правильный пакет
word  r_type[3];        //Тип датчика
unsigned long rcv_time[3]; // времена прихода пакетов

byte _chnl;              

byte receive_status, packet_number;
byte start_pulse_cnt;

unsigned long pulse_length, work_time,  timer_marklong;  
unsigned long pulse_marker, right_pulse_marker, last_premarker;
unsigned long pre_marker[4]; // Для хранения временных меток преамбулы ()
unsigned long first_packet_end;

bool crc_c;             //Результат проверки CRC
word sens_type;         //Тип сенсора
bool pulse_type;        //Пустое

byte data_length, data_length2; //Длины пакетов
int data_val, data_val2;        // Качество пакетов

//Массивы данных для записи данных с канала и полученных битов
byte collect_data[READ_BITS2], collect_data2[READ_BITS2];
//А когда становится массивом полученных битов, то значения такие:
//                          0 - неизвестен
//                          >0 - единица
//                          <0 - ноль
byte decode_tacts[READ_BITS2]; //Массив тактов. значения
//                          0=ноль
//                          1=единица
//                          2=неизвестен
//                          3=переход+
//                          4=переход-

/////////    ПРЕРЫВАНИЕ   ///////////////////////////////////////////////////////////////////////////////////////////

volatile unsigned long pm;
volatile unsigned long pl, timer_mark;  

void int_0(void) {  
  if(digitalRead(MHZ)){
  //Начало импульса
    pl = 0;
    pm = micros();  
  }
  else{
    //Конец импульса
    //Вычисляется время окончания и длина
    pl = micros() - pm;  
    pm += pl;
  }
}  
//////////////// УСТАНОВКИ  ///////////////////////////////////////
void setup ()
{
  Serial.begin(57600);
   
  //Прерывание по сигналу от приёмника
  pinMode(MHZ,INPUT);   
  attachInterrupt(0, int_0, CHANGE);  
  
  receive_status = FIND_PACKET;
  start_pulse_cnt = 0;
  packet_number = 0;
  for (int i = 0; i < 3; i++){
    rcv_time[i] = 7000000;
    r_isreceived[i] = 0;
  }
  pinMode(13, OUTPUT);        //Будем мигать светодиодом
  digitalWrite(13, LOW);
}

//////////////// ГЛАВНЫЙ ЦИКЛ  ///////////////////////////////////////
void loop() 
{
  noInterrupts();
  pulse_length = pl;
  pl = 0;
  pulse_marker = pm;
  interrupts();
//////////////////////////////////////////////////////////////////////
//Получен некий импульс,//////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
  if (pulse_length != 0 && receive_status == FIND_PACKET){  
    reciever_ctrl = 1;
    //Режим поиска пакета в эфире
    if (start_pulse_cnt == 0){
    //Найдена первый "правильный" импульс - длинная единица!
      if (pulse_length < (PER_LENGTH) && pulse_length > (THR_LENGTH) ) {
        start_pulse_cnt = 1;
        pre_marker[start_pulse_cnt] = pulse_marker;
        pulse_length = 0;
      }
    }
    //Ищем следующие импульсы
    else{
    //Найден импуль правильной длины
      if (pulse_length <= (PER_LENGTH) && pulse_length >= (THR_LENGTH)) {
        //Если импульс в правильном месте, то добавляем счётчик найденых стартовых импульсов
        if(pulse_marker - pre_marker[start_pulse_cnt] > (PER_LENGTH*2-LENGTH_TOLERANCE) && pulse_marker - pre_marker[start_pulse_cnt] < (PER_LENGTH * 2 + LENGTH_TOLERANCE)){
          start_pulse_cnt++;
          pre_marker[start_pulse_cnt] = pulse_marker;
          pulse_length = 0;
        }
        ///...если  в неправильном месте то назначаем его первым
        else{
          start_pulse_cnt = 1;
          pre_marker[start_pulse_cnt] = pulse_marker;
          pulse_length = 0;
        }
      }
      else{
        //Если импульс неправильной длины, то стоит проверить, а не вышло ли время ожидания правильного импульса
        if(pulse_marker - pre_marker[start_pulse_cnt] < (PER_LENGTH * 2 + LENGTH_TOLERANCE)){
          //Время ещё не вышло, скорее всего это помеха. Пропускаем...
          pulse_length = 0;
        }
        else{
          //Время вышло, начинаем искать заново
            start_pulse_cnt = 0;
            pulse_length = 0;
          }
        }
      }
    }
    if(packet_number == 1 && (millis() - first_packet_end) > 200){ // Если найден первый пакет и вышло вермя ожидания второго
                                                               // Не ждём второго, а переходм в режим анализа
    receive_status = ANALIZE_PACKETS;
    }
//////////////////////////////////////////////////////////////////////
// Сбор данных////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

  //Если Найдены три длинных единицы и два длинных нуля. Возможно это начало посылки...
    if (start_pulse_cnt == 3 && receive_status == FIND_PACKET){
      work_time = millis();
      last_premarker = pre_marker[3];
      start_pulse_cnt = 0;
        if (packet_number == 0){
          collect(collect_data, &data_length);
          first_packet_end = millis();
          packet_number = 1;
        }
        else{
          collect(collect_data2, &data_length2);
          packet_number = 2;
          receive_status = ANALIZE_PACKETS;
        }
      }
      if  (receive_status == ANALIZE_PACKETS){     
        digitalWrite(13, HIGH);
  //////////////////////////////////////////////////////////////////////
  // Анализ данных////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////      
        bool halfshift;
  //Дамп собранных данных        
/*        if (DEBUG_INFO){
          for(int bt = 0; bt < 180; bt++){
            Serial.print(collect_data[bt], HEX);
            Serial.print(' ');
          }
          Serial.println(" ");

          for(int bt = 0; bt < 180; bt++){
            Serial.print(collect_data2[bt],HEX);
            Serial.print(' ');
          }
          Serial.println(" ");
        }
*/
        
        get_bits(collect_data);
        if (get_data(0, collect_data) > get_data(1, collect_data)){
          data_val = get_data(0, collect_data);
          halfshift = 0;
        }
        else {
          data_val = get_data(1, collect_data);
         halfshift = 0;
        }
        if (DEBUG_INFO){
          Serial.print("1)     ");
          for(int bt = 0; bt < READ_BITS; bt++){
            if (collect_data[bt] > 128 + 1) Serial.print('I');
            if (collect_data[bt] < 128 - 1) Serial.print('O');
            if (collect_data[bt] == 128 + 1) Serial.print('i');
            if (collect_data[bt] == 128 - 1) Serial.print('o');
            if (collect_data[bt] == 128) Serial.print('.');
          }
          Serial.print(" VAL:");
          Serial.print(data_val);
          //Serial.print(" SIZE:");
          //Serial.print(data_length);
          Serial.print(" SHIFT:");
          Serial.print(halfshift);
        }
        if (packet_number == 2){
          get_bits(collect_data2);
          if (get_data(0, collect_data2) > get_data(1, collect_data2)) {
            data_val2 = get_data(0, collect_data2);
            halfshift = 0;
          }
          else {
            data_val2 = get_data(1, collect_data2);
            halfshift = 1;
          }
          if (DEBUG_INFO){
          Serial.println(" ");  
          Serial.print("2)     ");
          for(int bt = 0; bt < READ_BITS; bt++){
            if (collect_data2[bt] > 128 + 1) Serial.print('I');
            if (collect_data2[bt] < 128 - 1) Serial.print('O');
            if (collect_data2[bt] == 128 + 1) Serial.print('i');
            if (collect_data2[bt] == 128 - 1) Serial.print('o');
            if (collect_data2[bt] == 128) Serial.print('.');
          }
          Serial.print(" VAL:");
          Serial.print(data_val2);
          //Serial.print(" SIZE:");
          //Serial.print(data_length2);
          Serial.print(" SHIFT:");
          Serial.print(halfshift);
        }
      }
      int correlation = correlate_data(collect_data, collect_data2);
        if (DEBUG_INFO){
          Serial.print(" COR: ");
          Serial.println(correlation);
        }
        byte* result_data, result_data_start, aux_data;
        if (packet_number == 1){
          result_data = collect_data;     
        }
        else{
          if (correlation > 0){
            result_data = collect_data2;
            assemble_data(collect_data2,collect_data, &correlation);
        }
        else{
          result_data = collect_data;
          correlation = -correlation;
          assemble_data(collect_data, collect_data2, &correlation);
        }
        //Вывод готовой посылки
      }
      if (DEBUG_INFO){
        Serial.print("RESULT ");
        byte* rdt = result_data;
        for(int bt = 0; bt < READ_BITS; bt++){
          if (*rdt > 128 + 1) Serial.print('I');
          if (*rdt < 128 - 1) Serial.print('O');
          if (*rdt == 128 + 1) Serial.print('i');
          if (*rdt == 128 - 1) Serial.print('o');
          if (*rdt == 128) Serial.print('.');
          rdt++;
        }
        Serial.println(" ");
      }
        //Обработка посылки
      Serial.print("PERIOD: ");
      Serial.print(millis()/40000);
      Serial.print(" ");
      byte packet[PACKET_LENGTH], valid_p[PACKET_LENGTH];
      if (get_info_data(result_data, packet, valid_p)){
        sens_type = get_sensor(packet); //Определяем тип пакета по типу датчика
        restore_data(packet, sens_type); // Восстанавливаем данные по типу датчика
        crc_c = check_CRC(packet, sens_type); // Проверяем CRC, если оно верно, то все сомнительные биты делаем уверенными
        
        if (crc_c) for (byte www = 0; www < PACKET_LENGTH; www++) valid_p[www] = 0x0f;
        Serial.print(" PACKET: ");
        for (int q = 0;q < PACKET_LENGTH; q++) Serial.print(packet[q], HEX);
        Serial.print(" VALIDITY: ");
          for (int q = 0; q < PACKET_LENGTH; q++) Serial.print(valid_p[q], HEX);
      }
      if (sens_type == THGN132 || sens_type == THN132){
        Serial.print(" TYPE: ");
        if (sens_type == THGN132) Serial.print("THGN132N ");
        if (sens_type == THN132) Serial.print("THN132N  ");
        Serial.print("ID: ");
        Serial.print(get_id(packet), HEX);
        Serial.print(" CHNL: ");
        _chnl=get_channel(packet)-1;
        Serial.print(_chnl+1);
        r_type[_chnl] = sens_type;
        if (crc_c) r_isreceived[_chnl] = 1;
        
        //......Если получен правильный пакет, сбрасываем таймер
        if(crc_c) rcv_time[_chnl] = millis();  //         
        
        Serial.print(" BAT: ");
        if(crc_c) r_bat[_chnl] = get_battery(packet);
        if (r_bat[_chnl]) Serial.print("F "); else Serial.print("e ");
       
        Serial.print("TMP: ");
        if(get_temperature_mask(valid_p)){
          if(crc_c) r_tmp[_chnl] = get_temperature(packet);
          Serial.print(r_tmp[_chnl], 1);
        }
        else {
          Serial.print("----");
        }
        Serial.print("C ");
        if (sens_type == THGN132) {
          Serial.print("HUM: ");
          if (get_humidity_mask(valid_p)) {
            if(crc_c) r_hmdty[_chnl] = get_humidity(packet);
            Serial.print(r_hmdty[_chnl], 1);
        }
        else{
          Serial.print("--");
          r_hmdty[_chnl] = 101;
        }
        Serial.print("%");
      }
      else Serial.print("        ");
      Serial.print(" CRC: ");
      if (crc_c) Serial.print("OK ");
      else Serial.print("-- ");
      
          
      Serial.print(" PROC. TIME: ");
      Serial.print(millis() - work_time);
      Serial.println("ms ");
    }
    else Serial.println(" WRONG  ");
    // Возвращаемся к исходному состоянию
    receive_status = FIND_PACKET;
    packet_number = 0;
    start_pulse_cnt = 0;
    sens_type = 0;
    _chnl = 0;
    digitalWrite(13, LOW);
  }

//////////////////////////////////////////////////////////////////////      
//Здесь записываются остальные  процедуры, например те, которые выполняются ежесекундно
//////////////////////////////////////////////////////////////////////      
  if ((millis() - timer_mark) > 1000) {
    {
      if (!reciever_status) Serial.println("RECEIVING...");
      reciever_status = 1;
    }
    reciever_ctrl = 0;
  }
//////////////////////////////////////////////////////////////////////      
//////////////////////////////////////////////////////////////////////      
//////////////////////////////////////////////////////////////////////      
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Извлекает из тактовой последовательности - битовую
//Параметры: cdptr - указатель на записанную тактовую последовательность
////////////////////////////////////////////////////////////////////////////////////////////////////
void get_bits(byte* cdptr){
  
//Сброс массивов
  byte* cdp=cdptr;
  for(int bt=0 ; bt<READ_BITS*2; bt++) decode_tacts[bt]=2;
      
        
  for(int bt=0 ; bt<READ_BITS*2; bt++){
        
    if ((*cdp&0xf0)>0x20 && (*cdp&0x0f)>0x04) decode_tacts[bt]=1;
    if ((*cdp&0xf0)<0x30 && (*cdp&0x0f)<0x05) decode_tacts[bt]=0;
    if ((*cdp&0xf0)<0x20 && (*cdp&0x0f)>0x04) decode_tacts[bt]=4;
    if ((*cdp&0xf0)>0x40 && (*cdp&0x0f)<0x02) decode_tacts[bt]=3;
    *cdp++;
  }
  return;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Извлекает из записи канала тактовую последовательность
//Параметры: cdptr - указатель на записанные данные
// btt - смещение в тактах. Смещение на такт при анализе может поммочь восстановить пакет, у которого разрушено начало
// Функция вовзращает качество или "годность" расшифровки - количесвто уверенно узнаных тактов.
// Сравнивая годность с btt=0 и btt=1 выбираем лучшую
////////////////////////////////////////////////////////////////////////////////////////////////////
int get_data(int btt, byte* cdptr){ //btt - смещение на такт при анализе может поммочь восстановить пакет, у которого разрушено начало
  
  byte* cdp=cdptr;
  for(int bt=0 ; bt<READ_BITS; bt++){
    *cdp=128;
    cdp++;
  }
  cdp=cdptr;
  *cdp=(128+2);
  cdp++;
  int packet_validity=0;
  for(int bt=1 ; bt<READ_BITS; bt++){
    if(decode_tacts[bt*2-btt]==0) *cdp-=1;
    if(decode_tacts[bt*2-btt]==1) *cdp+=1;
    if(decode_tacts[bt*2-2-btt]==1 && decode_tacts[bt*2-1-btt]==4) *cdp-=1;
    if(decode_tacts[bt*2-2-btt]==0 && decode_tacts[bt*2-1-btt]==3) *cdp+=1;
    if(decode_tacts[bt*2-2-btt]==0 && decode_tacts[bt*2-1-btt]==1) *cdp-=1;
    if(decode_tacts[bt*2-2-btt]==1 && decode_tacts[bt*2-1-btt]==0) *cdp+=1;

    if(decode_tacts[bt*2+2-btt]==1 && decode_tacts[bt*2+1-btt]==3) *cdp-=1;
    if(decode_tacts[bt*2+2-btt]==0 && decode_tacts[bt*2+1-btt]==4) *cdp+=1;
    if(decode_tacts[bt*2+2-btt]==0 && decode_tacts[bt*2+1-btt]==1) *cdp-=1;
    if(decode_tacts[bt*2+2-btt]==1 && decode_tacts[bt*2+1-btt]==0) *cdp+=1;

        //Подсчитываем кол-во достоверных бит в пакете
    if (*cdp>(128+1) )  packet_validity+=*cdp-128;
    if (*cdp<(128-1)) packet_validity+=128-*cdp;
    cdp++;
  }
  return packet_validity;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Прослушивание канала с частотой дискретизации 16384Гц
////////////////////////////////////////////////////////////////////////////////////////////////////
void collect(byte* cdptr, byte* dtl){
  
  // В функцию передаётся уазатель на область памяти, куда сливать данные.
  *dtl=0;
  bool cdp_prev_null;
  byte* cdp=cdptr;
  byte nulls_found=0;
  unsigned long tmp_marker=last_premarker+PER_LENGTH/32; //
  byte bt2=0;
  *cdp=0x88; //Первые два такта - единицы. Мы же поймали импульс!
  cdp++;
  //Ждём момента наступления первого считывания (конец последнего импулься зацепки + 1/16 такта)
  while (micros() <= tmp_marker);
  //Начинаем читать данные в память!
  for(int bt=1 ; bt<READ_BITS*2; bt++){// чИТАЕМ максимум ПО 90 БИТ (ПОСЫЛКА thgn - 96БИТ, THN - 76 бИТ + как минимум 3 бита 111, которые мы уже нашли)
    *cdp=0;
    for(byte ckl=0; ckl<8; ckl++){      // Читаем 8 раз за полутакт
      if (digitalRead(MHZ)) *cdp+=0x10; // Измерения запиываем в старший полубайт
      tmp_marker+=PER_LENGTH/16;
      while (micros() < tmp_marker);
    }
    last_premarker+=PER_LENGTH/2;
    tmp_marker=last_premarker+PER_LENGTH/32;
    
    for(byte ckl=0; ckl<8; ckl++){
      if (digitalRead(MHZ)) *cdp+=1;    // В следующий полутакт измерения запиываем в младший  полубайт. Это экономит память.
      tmp_marker+=PER_LENGTH/16;
      while (micros() < tmp_marker);
    }
    last_premarker+=PER_LENGTH/2;
    bt2++;
    //  Каждые 8 тактов добавлять 5мкс для выравнивания периода с 976мкс до 976.56мкс
    if (bt2==8){ 
      last_premarker+=5;
      bt2=0;
    }
    tmp_marker=last_premarker+PER_LENGTH/32;

    while (micros() < last_premarker);//Ждём прихода времени следующего полутакта
    if (*cdp==0 && cdp_prev_null==1) nulls_found++;                    
    //if (*cdp==0 && (*(cdp-1)==0)) nulls_found++;
    else nulls_found=0;
    
    if (nulls_found>1) return; //Если найдено более 7 нулевых тактов подряд, значит либо жёсткая помеха, убившая пакет
                                  //Либо конец посылки. Дальше читать нет смысла.

    cdp_prev_null= (*cdp==0) ? 1 : 0;
    cdp++;                              
    *dtl+=1;
  }
  return;
} 
////////////////////////////////////////////////////////////////////////////////////////////////////
//Определение смещения пакетов друг относительно друга
//В качестве параметров передаются указатели на массивы данных
// Возваращаяется смещение
// >0 - второй пакет начался раньше, <0 - Первый пакет начался раньше
////////////////////////////////////////////////////////////////////////////////////////////////////
int correlate_data(byte* ser1, byte* ser2){
  
  byte best_correl=0;
  int best_shift=0;
  byte best_correl_back=0;
  int best_shift_back=0;
  byte shift_score[READ_BITS];
  byte* s1;
  byte* s2;
  byte* s2t=ser2;
  //смещаем первый пакет относительно второго
  for( byte sht=0; sht<READ_BITS; sht++){
    s1=ser1;
    s2=s2t;
    shift_score[sht]=0;
    for(byte sp=0; sp<READ_BITS-sht; sp++){
      if ((*s1 >(128+1) && *s2 >(128+1))||(*s1 <(128-1) && *s2 <(128-1)) ) shift_score[sht]++;
      s2++;
      s1++;
    }
    s2t++;
  }

  for (int i=0; i<READ_BITS; i++){
    if (shift_score[i]>best_correl){
      best_correl=shift_score[i];
      best_shift=i;
    }
  }
 
//Теперь наоборот -втрой пакет относительно первого
  
  byte* s1t=ser1;
  for( byte sht=0; sht<READ_BITS; sht++){
    s2=ser2;
    s1=s1t;
    shift_score[sht]=0;
    for(byte sp=0; sp<READ_BITS-sht; sp++){
      if ((*s1 >(128+1) && *s2 >(128+1))||(*s1 <(128-1) && *s2 <(128-1)) ) shift_score[sht]++;
      s2++;
      s1++;
    }
    s1t++;
  }
// Ищем наилучшее совпадение для обоих вариантов 
  
  
  for (int i=0; i<READ_BITS; i++){
    if (shift_score[i]>best_correl_back){
      best_correl_back=shift_score[i];
      best_shift_back=i;
    }
  }
  //И возвращаем самое лучшее из двух
  if (best_correl_back > best_correl) return -best_shift_back;
  else return best_shift;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Сборка из двух пакетов
//В качестве параметров передаются указатели на массивы данных
// Причём первым должен идти результирующий пакет, т.е. тот который имеет более длинную преамбулу.
//shift - смещение втрого пакета относительного первого
////////////////////////////////////////////////////////////////////////////////////////////////////
void assemble_data(byte* s1, byte* s2, int* shift){
  
  for (int g=0; g<=*shift-1; g++) s1++;
  for (int i=0; i<(READ_BITS-*shift); i++){
      if(*s1 < (128+2) && *s1 > (128-2) && (*s2>(128+1) || *s2<(128-1))) {
      *s1=*s2;
    }
    s1++;
    s2++;
  }
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Создаёт кодовую посылку
//code - указатель на расшифрованную битовую последовательность
//result - указатель на кодовую посылку
//valid - указатель на карту достоверности кодовой посылки
////////////////////////////////////////////////////////////////////////////////////////////////////
byte get_info_data(byte* code, byte* result, byte* valid){
  
  byte* rd=result;
  byte* vd=valid;
  //Чистим массивы
  for (int l=0; l<PACKET_LENGTH; l++){
    *vd=0;
    *rd=0;
    vd++;
    rd++;
  }
  int csm;
  for (csm=0; csm<30;csm++){
    if (*code<128 && *(code+1)>128 && *(code+2)<128 && *(code+3)>128) break;//Найдена последовательность 0101 
    code++;
  }
  if (csm>22) return 0;// Стартовая последовательность в первых 20 битах не найдена, такой пакет этим методом не расшифруешь
  
  code+=4;//Переходим на начало считывания
  int ii=0;
  for (int i=0; i<READ_BITS-csm; i++) 
  {
    byte multipl;
    switch (ii){
      case 0: {multipl=0x01; break;}
      case 1: {multipl=0x02; break;}
      case 2: {multipl=0x04; break;}
      case 3: {multipl=0x08; break;}
    }
    if (*code==129 ) *result+=multipl;
    if (*code>129 ) {
      *result+=multipl;
      *valid+=multipl;
    }
    if (*code<127 ) *valid+=multipl;
    code++;
    ii++;
    if (ii==4) {
      ii=0;
      valid++;
      result++;
    }
  }
  return 1;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Возвращает значение температуры
//oregon_data - указатель на кодовую посылку
////////////////////////////////////////////////////////////////////////////////////////////////////
float get_temperature(byte* oregon_data){
  
  float tmprt;
  oregon_data+=8;
  //исправляем возможные ошибки:
  for (int g=0;g<4; g++)  if (*(oregon_data+g)>9) *(oregon_data+g)=*(oregon_data+g)-8;
  tmprt+=*(oregon_data)*0.1;
  tmprt+=*(oregon_data+1);
  tmprt+=*(oregon_data+2)*10;
  return (*(oregon_data+3)) ? -tmprt : tmprt;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Возвращает значение маски годности
//validity_data - указатель на карту достоверности кодовой посылки
////////////////////////////////////////////////////////////////////////////////////////////////////
byte get_temperature_mask(byte* validity_data){
  
    return (*(validity_data+8)==0x0f && *(validity_data+9)==0x0f && *(validity_data+10)==0x0f && *(validity_data+11)==0x0f) ? 1 : 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Возвращает тип сенсора
//oregon_data - указатель на кодовую посылку
////////////////////////////////////////////////////////////////////////////////////////////////////
word get_sensor(byte* oregon_data){
  
    return (word)(*(oregon_data))*0x1000 + (*(oregon_data+1))*0x0100 + (*(oregon_data+2))*0x10 + *(oregon_data+3);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Возвращает значение канала
//oregon_data - указатель на кодовую посылку
////////////////////////////////////////////////////////////////////////////////////////////////////
byte get_channel(byte* oregon_data){
  
  byte channel;  
  switch (*(oregon_data+4))  
  {  
  case 1:  
    channel = 1;  
    break;  
  case 2:  
    channel = 2;  
    break;  
  case 4:  
    channel = 3;  
    break;  
  }  
  return channel;  
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
byte get_battery(byte* oregon_data){

  return (*(oregon_data+7) & 0x4) ? 0 : 1;  
  
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Возвращает значение влажности
//oregon_data - указатель на кодовую посылку
////////////////////////////////////////////////////////////////////////////////////////////////////
byte get_humidity(byte* oregon_data){
  
  byte tmprt;
  oregon_data+=12;
  //исправляем возможные ошибки:
  for (int g=0;g<2; g++)  if (*(oregon_data+g)>9) *(oregon_data+g)=*(oregon_data+g)-8;
  tmprt=*(oregon_data);
  tmprt+=*(oregon_data+1)*10;
  return tmprt;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Возвращает значение маски годности влажности 4 бита, старший - знак, младший -  десятые доли градуса
//validity_data - указатель на карту достоверности кодовой посылки
////////////////////////////////////////////////////////////////////////////////////////////////////
byte get_humidity_mask(byte* validity_data){
  
 return (*(validity_data+13)==0x0f && *(validity_data+14)==0x0f) ? 1 : 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Возвращает id датчика
//oregon_data - указатель на кодовую посылку
////////////////////////////////////////////////////////////////////////////////////////////////////
byte get_id(byte* oregon_data){
  
  byte tmprt;
  oregon_data+=5;
  tmprt=*(oregon_data)*0x10;
  tmprt+=*(oregon_data+1);
  return tmprt;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
//Проверка CRC
//oregon_data - указатель на кодовую посылку
////////////////////////////////////////////////////////////////////////////////////////////////////
bool check_CRC(byte* oregon_data, word sensor_type){
  
  byte* pp=oregon_data;
  byte crc, resived_crc;
  crc=0;
  if (sensor_type==THGN132){
    for(int x=0; x<15; x++){
      crc+=*pp;
      pp++;  
    }
    resived_crc=(*(oregon_data+15))+(*(oregon_data+16))*0x10;
   return (resived_crc==crc)? 1 : 0;
  }

  if (sensor_type==THN132){
    for(int x=0; x<12; x++){
      crc+=*pp;
      pp++;  
    }
    resived_crc=(*(oregon_data+12))+(*(oregon_data+13))*0x10;
    return (resived_crc==crc)? 1 : 0;
  }
  return 0;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
//Востановление данных по типу датчика
////////////////////////////////////////////////////////////////////////////////////////////////////
void restore_data(byte* oregon_data, word sensor_type){
  
  byte* pp=oregon_data;
  if (sensor_type==THGN132){
    pp+=8;
    for(int x=0; x<6; x++){
      if(*pp>9 && x!=3) *pp-=8;
      pp++;  
    }
  }
  if (sensor_type==THN132){
    pp+=8;
    for(int x=0; x<3; x++){
      if(*pp>9) *pp-=8;
      pp++;  
    }
  }
  return;
}
скопировал ваш код, попытался скомпилировать. выдало ошибку. выделил весь код и поместил сюда. можно поправить код чтобы собралась прошивка. я слабоват в написании
snickser
Offline
Зарегистрирован: 02.07.2016

Porosenok пишет:

А в чём противоречие? В том, что я байты выдаю в том виде, в котором они приняты в описании протокола?

Ну как бы да, я предполагал что у вас код посылки в "обычном" виде, как у всех ;)

А у вас вместе 1A2D получается 1D20 какой-то... и потом тоже все перепутано...

 

 

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

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

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

Странно. Ваш скетч у меня компилируется.

Попробуйте вот так:

#define THGN132 0x1D20      //Типы известных датчиков
#define THN132  0xEC40

#define MHZ 2               //Приёмник подключается к D2

#define FIND_PACKET   1     
#define ANALIZE_PACKETS 3

#define PER_LENGTH 976      // Период в мкс
#define THR_LENGTH 615     //Порог периода 0 или 1
#define LENGTH_TOLERANCE 20 //Допуск на период

#define READ_BITS 90        //Размер битовой посылки
#define READ_BITS2 180      //Двойной размер битовой посылки
#define PACKET_LENGTH 20    //Размер пакета данных
#define DEBUG_INFO 1        //Выводить ли диагностическую информацию

bool  reciever_ctrl = true; //Флаг контроля ресивера (выставляется при приходе импулься, сбрасывается в таймере)
bool  reciever_status = false; // Результат проверки состояния ресивера

//Массивы для хранения полученных данных:
float r_tmp[3];         //Температура
byte  r_hmdty[3];       //Влажность. Если = 101 - значит нет данных
bool  r_bat[3];         //Флаг батареи
bool  r_isreceived[3];  //Флаг о том, что по данному каналу приходил хоть один правильный пакет
word  r_type[3];        //Тип датчика
unsigned long rcv_time[3]; // времена прихода пакетов

byte _chnl;              

byte receive_status, packet_number;
byte start_pulse_cnt;

unsigned long pulse_length, work_time,  timer_marklong;  
unsigned long pulse_marker, right_pulse_marker, last_premarker;
unsigned long pre_marker[4]; // Для хранения временных меток преамбулы ()
unsigned long first_packet_end;

bool crc_c;             //Результат проверки CRC
word sens_type;         //Тип сенсора
bool pulse_type;        //Пустое

byte data_length, data_length2; //Длины пакетов
int data_val, data_val2;        // Качество пакетов

//Массивы данных для записи данных с канала и полученных битов
byte collect_data[READ_BITS2], collect_data2[READ_BITS2];
//А когда становится массивом полученных битов, то значения такие:
//                          0 - неизвестен
//                          >0 - единица
//                          <0 - ноль
byte decode_tacts[READ_BITS2]; //Массив тактов. значения
//                          0=ноль
//                          1=единица
//                          2=неизвестен
//                          3=переход+
//                          4=переход-

/////////    ПРЕРЫВАНИЕ   ///////////////////////////////////////////////////////////////////////////////////////////

volatile unsigned long pm;
volatile unsigned long pl, timer_mark;  

void int_0(void) {  
  if(digitalRead(MHZ)){
  //Начало импульса
    pl = 0;
    pm = micros();  
  }
  else{
    //Конец импульса
    //Вычисляется время окончания и длина
    pl = micros() - pm;  
    pm += pl;
  }
}  

////////////////////////////////////////////////////////////////////////////////////////////////////
//Извлекает из тактовой последовательности - битовую
//Параметры: cdptr - указатель на записанную тактовую последовательность
////////////////////////////////////////////////////////////////////////////////////////////////////
void get_bits(byte* cdptr){
  
//Сброс массивов
  byte* cdp=cdptr;
  for(int bt=0 ; bt<READ_BITS*2; bt++) decode_tacts[bt]=2;
      
        
  for(int bt=0 ; bt<READ_BITS*2; bt++){
        
    if ((*cdp&0xf0)>0x20 && (*cdp&0x0f)>0x04) decode_tacts[bt]=1;
    if ((*cdp&0xf0)<0x30 && (*cdp&0x0f)<0x05) decode_tacts[bt]=0;
    if ((*cdp&0xf0)<0x20 && (*cdp&0x0f)>0x04) decode_tacts[bt]=4;
    if ((*cdp&0xf0)>0x40 && (*cdp&0x0f)<0x02) decode_tacts[bt]=3;
    *cdp++;
  }
  return;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Извлекает из записи канала тактовую последовательность
//Параметры: cdptr - указатель на записанные данные
// btt - смещение в тактах. Смещение на такт при анализе может поммочь восстановить пакет, у которого разрушено начало
// Функция вовзращает качество или "годность" расшифровки - количесвто уверенно узнаных тактов.
// Сравнивая годность с btt=0 и btt=1 выбираем лучшую
////////////////////////////////////////////////////////////////////////////////////////////////////
int get_data(int btt, byte* cdptr){ //btt - смещение на такт при анализе может поммочь восстановить пакет, у которого разрушено начало
  
  byte* cdp=cdptr;
  for(int bt=0 ; bt<READ_BITS; bt++){
    *cdp=128;
    cdp++;
  }
  cdp=cdptr;
  *cdp=(128+2);
  cdp++;
  int packet_validity=0;
  for(int bt=1 ; bt<READ_BITS; bt++){
    if(decode_tacts[bt*2-btt]==0) *cdp-=1;
    if(decode_tacts[bt*2-btt]==1) *cdp+=1;
    if(decode_tacts[bt*2-2-btt]==1 && decode_tacts[bt*2-1-btt]==4) *cdp-=1;
    if(decode_tacts[bt*2-2-btt]==0 && decode_tacts[bt*2-1-btt]==3) *cdp+=1;
    if(decode_tacts[bt*2-2-btt]==0 && decode_tacts[bt*2-1-btt]==1) *cdp-=1;
    if(decode_tacts[bt*2-2-btt]==1 && decode_tacts[bt*2-1-btt]==0) *cdp+=1;

    if(decode_tacts[bt*2+2-btt]==1 && decode_tacts[bt*2+1-btt]==3) *cdp-=1;
    if(decode_tacts[bt*2+2-btt]==0 && decode_tacts[bt*2+1-btt]==4) *cdp+=1;
    if(decode_tacts[bt*2+2-btt]==0 && decode_tacts[bt*2+1-btt]==1) *cdp-=1;
    if(decode_tacts[bt*2+2-btt]==1 && decode_tacts[bt*2+1-btt]==0) *cdp+=1;

        //Подсчитываем кол-во достоверных бит в пакете
    if (*cdp>(128+1) )  packet_validity+=*cdp-128;
    if (*cdp<(128-1)) packet_validity+=128-*cdp;
    cdp++;
  }
  return packet_validity;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Прослушивание канала с частотой дискретизации 16384Гц
////////////////////////////////////////////////////////////////////////////////////////////////////
void collect(byte* cdptr, byte* dtl){
  
  // В функцию передаётся уазатель на область памяти, куда сливать данные.
  *dtl=0;
  bool cdp_prev_null;
  byte* cdp=cdptr;
  byte nulls_found=0;
  unsigned long tmp_marker=last_premarker+PER_LENGTH/32; //
  byte bt2=0;
  *cdp=0x88; //Первые два такта - единицы. Мы же поймали импульс!
  cdp++;
  //Ждём момента наступления первого считывания (конец последнего импулься зацепки + 1/16 такта)
  while (micros() <= tmp_marker);
  //Начинаем читать данные в память!
  for(int bt=1 ; bt<READ_BITS*2; bt++){// чИТАЕМ максимум ПО 90 БИТ (ПОСЫЛКА thgn - 96БИТ, THN - 76 бИТ + как минимум 3 бита 111, которые мы уже нашли)
    *cdp=0;
    for(byte ckl=0; ckl<8; ckl++){      // Читаем 8 раз за полутакт
      if (digitalRead(MHZ)) *cdp+=0x10; // Измерения запиываем в старший полубайт
      tmp_marker+=PER_LENGTH/16;
      while (micros() < tmp_marker);
    }
    last_premarker+=PER_LENGTH/2;
    tmp_marker=last_premarker+PER_LENGTH/32;
    
    for(byte ckl=0; ckl<8; ckl++){
      if (digitalRead(MHZ)) *cdp+=1;    // В следующий полутакт измерения запиываем в младший  полубайт. Это экономит память.
      tmp_marker+=PER_LENGTH/16;
      while (micros() < tmp_marker);
    }
    last_premarker+=PER_LENGTH/2;
    bt2++;
    //  Каждые 8 тактов добавлять 5мкс для выравнивания периода с 976мкс до 976.56мкс
    if (bt2==8){ 
      last_premarker+=5;
      bt2=0;
    }
    tmp_marker=last_premarker+PER_LENGTH/32;

    while (micros() < last_premarker);//Ждём прихода времени следующего полутакта
    if (*cdp==0 && cdp_prev_null==1) nulls_found++;                    
    //if (*cdp==0 && (*(cdp-1)==0)) nulls_found++;
    else nulls_found=0;
    
    if (nulls_found>1) return; //Если найдено более 7 нулевых тактов подряд, значит либо жёсткая помеха, убившая пакет
                                  //Либо конец посылки. Дальше читать нет смысла.

    cdp_prev_null= (*cdp==0) ? 1 : 0;
    cdp++;                              
    *dtl+=1;
  }
  return;
} 
////////////////////////////////////////////////////////////////////////////////////////////////////
//Определение смещения пакетов друг относительно друга
//В качестве параметров передаются указатели на массивы данных
// Возваращаяется смещение
// >0 - второй пакет начался раньше, <0 - Первый пакет начался раньше
////////////////////////////////////////////////////////////////////////////////////////////////////
int correlate_data(byte* ser1, byte* ser2){
  
  byte best_correl=0;
  int best_shift=0;
  byte best_correl_back=0;
  int best_shift_back=0;
  byte shift_score[READ_BITS];
  byte* s1;
  byte* s2;
  byte* s2t=ser2;
  //смещаем первый пакет относительно второго
  for( byte sht=0; sht<READ_BITS; sht++){
    s1=ser1;
    s2=s2t;
    shift_score[sht]=0;
    for(byte sp=0; sp<READ_BITS-sht; sp++){
      if ((*s1 >(128+1) && *s2 >(128+1))||(*s1 <(128-1) && *s2 <(128-1)) ) shift_score[sht]++;
      s2++;
      s1++;
    }
    s2t++;
  }

  for (int i=0; i<READ_BITS; i++){
    if (shift_score[i]>best_correl){
      best_correl=shift_score[i];
      best_shift=i;
    }
  }
 
//Теперь наоборот -втрой пакет относительно первого
  
  byte* s1t=ser1;
  for( byte sht=0; sht<READ_BITS; sht++){
    s2=ser2;
    s1=s1t;
    shift_score[sht]=0;
    for(byte sp=0; sp<READ_BITS-sht; sp++){
      if ((*s1 >(128+1) && *s2 >(128+1))||(*s1 <(128-1) && *s2 <(128-1)) ) shift_score[sht]++;
      s2++;
      s1++;
    }
    s1t++;
  }
// Ищем наилучшее совпадение для обоих вариантов 
  
  
  for (int i=0; i<READ_BITS; i++){
    if (shift_score[i]>best_correl_back){
      best_correl_back=shift_score[i];
      best_shift_back=i;
    }
  }
  //И возвращаем самое лучшее из двух
  if (best_correl_back > best_correl) return -best_shift_back;
  else return best_shift;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Сборка из двух пакетов
//В качестве параметров передаются указатели на массивы данных
// Причём первым должен идти результирующий пакет, т.е. тот который имеет более длинную преамбулу.
//shift - смещение втрого пакета относительного первого
////////////////////////////////////////////////////////////////////////////////////////////////////
void assemble_data(byte* s1, byte* s2, int* shift){
  
  for (int g=0; g<=*shift-1; g++) s1++;
  for (int i=0; i<(READ_BITS-*shift); i++){
      if(*s1 < (128+2) && *s1 > (128-2) && (*s2>(128+1) || *s2<(128-1))) {
      *s1=*s2;
    }
    s1++;
    s2++;
  }
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Создаёт кодовую посылку
//code - указатель на расшифрованную битовую последовательность
//result - указатель на кодовую посылку
//valid - указатель на карту достоверности кодовой посылки
////////////////////////////////////////////////////////////////////////////////////////////////////
byte get_info_data(byte* code, byte* result, byte* valid){
  
  byte* rd=result;
  byte* vd=valid;
  //Чистим массивы
  for (int l=0; l<PACKET_LENGTH; l++){
    *vd=0;
    *rd=0;
    vd++;
    rd++;
  }
  int csm;
  for (csm=0; csm<30;csm++){
    if (*code<128 && *(code+1)>128 && *(code+2)<128 && *(code+3)>128) break;//Найдена последовательность 0101 
    code++;
  }
  if (csm>22) return 0;// Стартовая последовательность в первых 20 битах не найдена, такой пакет этим методом не расшифруешь
  
  code+=4;//Переходим на начало считывания
  int ii=0;
  for (int i=0; i<READ_BITS-csm; i++) 
  {
    byte multipl;
    switch (ii){
      case 0: {multipl=0x01; break;}
      case 1: {multipl=0x02; break;}
      case 2: {multipl=0x04; break;}
      case 3: {multipl=0x08; break;}
    }
    if (*code==129 ) *result+=multipl;
    if (*code>129 ) {
      *result+=multipl;
      *valid+=multipl;
    }
    if (*code<127 ) *valid+=multipl;
    code++;
    ii++;
    if (ii==4) {
      ii=0;
      valid++;
      result++;
    }
  }
  return 1;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Возвращает значение температуры
//oregon_data - указатель на кодовую посылку
////////////////////////////////////////////////////////////////////////////////////////////////////
float get_temperature(byte* oregon_data){
  
  float tmprt;
  oregon_data+=8;
  //исправляем возможные ошибки:
  for (int g=0;g<4; g++)  if (*(oregon_data+g)>9) *(oregon_data+g)=*(oregon_data+g)-8;
  tmprt+=*(oregon_data)*0.1;
  tmprt+=*(oregon_data+1);
  tmprt+=*(oregon_data+2)*10;
  return (*(oregon_data+3)) ? -tmprt : tmprt;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Возвращает значение маски годности
//validity_data - указатель на карту достоверности кодовой посылки
////////////////////////////////////////////////////////////////////////////////////////////////////
byte get_temperature_mask(byte* validity_data){
  
    return (*(validity_data+8)==0x0f && *(validity_data+9)==0x0f && *(validity_data+10)==0x0f && *(validity_data+11)==0x0f) ? 1 : 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Возвращает тип сенсора
//oregon_data - указатель на кодовую посылку
////////////////////////////////////////////////////////////////////////////////////////////////////
word get_sensor(byte* oregon_data){
  
    return (word)(*(oregon_data))*0x1000 + (*(oregon_data+1))*0x0100 + (*(oregon_data+2))*0x10 + *(oregon_data+3);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Возвращает значение канала
//oregon_data - указатель на кодовую посылку
////////////////////////////////////////////////////////////////////////////////////////////////////
byte get_channel(byte* oregon_data){
  
  byte channel;  
  switch (*(oregon_data+4))  
  {  
  case 1:  
    channel = 1;  
    break;  
  case 2:  
    channel = 2;  
    break;  
  case 4:  
    channel = 3;  
    break;  
  }  
  return channel;  
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
byte get_battery(byte* oregon_data){

  return (*(oregon_data+7) & 0x4) ? 0 : 1;  
  
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Возвращает значение влажности
//oregon_data - указатель на кодовую посылку
////////////////////////////////////////////////////////////////////////////////////////////////////
byte get_humidity(byte* oregon_data){
  
  byte tmprt;
  oregon_data+=12;
  //исправляем возможные ошибки:
  for (int g=0;g<2; g++)  if (*(oregon_data+g)>9) *(oregon_data+g)=*(oregon_data+g)-8;
  tmprt=*(oregon_data);
  tmprt+=*(oregon_data+1)*10;
  return tmprt;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Возвращает значение маски годности влажности 4 бита, старший - знак, младший -  десятые доли градуса
//validity_data - указатель на карту достоверности кодовой посылки
////////////////////////////////////////////////////////////////////////////////////////////////////
byte get_humidity_mask(byte* validity_data){
  
 return (*(validity_data+13)==0x0f && *(validity_data+14)==0x0f) ? 1 : 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Возвращает id датчика
//oregon_data - указатель на кодовую посылку
////////////////////////////////////////////////////////////////////////////////////////////////////
byte get_id(byte* oregon_data){
  
  byte tmprt;
  oregon_data+=5;
  tmprt=*(oregon_data)*0x10;
  tmprt+=*(oregon_data+1);
  return tmprt;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
//Проверка CRC
//oregon_data - указатель на кодовую посылку
////////////////////////////////////////////////////////////////////////////////////////////////////
bool check_CRC(byte* oregon_data, word sensor_type){
  
  byte* pp=oregon_data;
  byte crc, resived_crc;
  crc=0;
  if (sensor_type==THGN132){
    for(int x=0; x<15; x++){
      crc+=*pp;
      pp++;  
    }
    resived_crc=(*(oregon_data+15))+(*(oregon_data+16))*0x10;
   return (resived_crc==crc)? 1 : 0;
  }

  if (sensor_type==THN132){
    for(int x=0; x<12; x++){
      crc+=*pp;
      pp++;  
    }
    resived_crc=(*(oregon_data+12))+(*(oregon_data+13))*0x10;
    return (resived_crc==crc)? 1 : 0;
  }
  return 0;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
//Востановление данных по типу датчика
////////////////////////////////////////////////////////////////////////////////////////////////////
void restore_data(byte* oregon_data, word sensor_type){
  
  byte* pp=oregon_data;
  if (sensor_type==THGN132){
    pp+=8;
    for(int x=0; x<6; x++){
      if(*pp>9 && x!=3) *pp-=8;
      pp++;  
    }
  }
  if (sensor_type==THN132){
    pp+=8;
    for(int x=0; x<3; x++){
      if(*pp>9) *pp-=8;
      pp++;  
    }
  }
  return;
}
//////////////// УСТАНОВКИ  ///////////////////////////////////////
void setup ()
{
  Serial.begin(57600);
   
  //Прерывание по сигналу от приёмника
  pinMode(MHZ,INPUT);   
  attachInterrupt(0, int_0, CHANGE);  
  
  receive_status = FIND_PACKET;
  start_pulse_cnt = 0;
  packet_number = 0;
  for (int i = 0; i < 3; i++){
    rcv_time[i] = 7000000;
    r_isreceived[i] = 0;
  }
  pinMode(13, OUTPUT);        //Будем мигать светодиодом
  digitalWrite(13, LOW);
}

//////////////// ГЛАВНЫЙ ЦИКЛ  ///////////////////////////////////////
void loop() 
{
  noInterrupts();
  pulse_length = pl;
  pl = 0;
  pulse_marker = pm;
  interrupts();
//////////////////////////////////////////////////////////////////////
//Получен некий импульс,//////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
  if (pulse_length != 0 && receive_status == FIND_PACKET){  
    reciever_ctrl = 1;
    //Режим поиска пакета в эфире
    if (start_pulse_cnt == 0){
    //Найдена первый "правильный" импульс - длинная единица!
      if (pulse_length < (PER_LENGTH) && pulse_length > (THR_LENGTH) ) {
        start_pulse_cnt = 1;
        pre_marker[start_pulse_cnt] = pulse_marker;
        pulse_length = 0;
      }
    }
    //Ищем следующие импульсы
    else{
    //Найден импуль правильной длины
      if (pulse_length <= (PER_LENGTH) && pulse_length >= (THR_LENGTH)) {
        //Если импульс в правильном месте, то добавляем счётчик найденых стартовых импульсов
        if(pulse_marker - pre_marker[start_pulse_cnt] > (PER_LENGTH*2-LENGTH_TOLERANCE) && pulse_marker - pre_marker[start_pulse_cnt] < (PER_LENGTH * 2 + LENGTH_TOLERANCE)){
          start_pulse_cnt++;
          pre_marker[start_pulse_cnt] = pulse_marker;
          pulse_length = 0;
        }
        ///...если  в неправильном месте то назначаем его первым
        else{
          start_pulse_cnt = 1;
          pre_marker[start_pulse_cnt] = pulse_marker;
          pulse_length = 0;
        }
      }
      else{
        //Если импульс неправильной длины, то стоит проверить, а не вышло ли время ожидания правильного импульса
        if(pulse_marker - pre_marker[start_pulse_cnt] < (PER_LENGTH * 2 + LENGTH_TOLERANCE)){
          //Время ещё не вышло, скорее всего это помеха. Пропускаем...
          pulse_length = 0;
        }
        else{
          //Время вышло, начинаем искать заново
            start_pulse_cnt = 0;
            pulse_length = 0;
          }
        }
      }
    }
    if(packet_number == 1 && (millis() - first_packet_end) > 200){ // Если найден первый пакет и вышло вермя ожидания второго
                                                               // Не ждём второго, а переходм в режим анализа
    receive_status = ANALIZE_PACKETS;
    }
//////////////////////////////////////////////////////////////////////
// Сбор данных////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

  //Если Найдены три длинных единицы и два длинных нуля. Возможно это начало посылки...
    if (start_pulse_cnt == 3 && receive_status == FIND_PACKET){
      work_time = millis();
      last_premarker = pre_marker[3];
      start_pulse_cnt = 0;
        if (packet_number == 0){
          collect(collect_data, &data_length);
          first_packet_end = millis();
          packet_number = 1;
        }
        else{
          collect(collect_data2, &data_length2);
          packet_number = 2;
          receive_status = ANALIZE_PACKETS;
        }
      }
      if  (receive_status == ANALIZE_PACKETS){     
        digitalWrite(13, HIGH);
  //////////////////////////////////////////////////////////////////////
  // Анализ данных////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////      
        bool halfshift;
  //Дамп собранных данных        
/*        if (DEBUG_INFO){
          for(int bt = 0; bt < 180; bt++){
            Serial.print(collect_data[bt], HEX);
            Serial.print(' ');
          }
          Serial.println(" ");

          for(int bt = 0; bt < 180; bt++){
            Serial.print(collect_data2[bt],HEX);
            Serial.print(' ');
          }
          Serial.println(" ");
        }
*/
        
        get_bits(collect_data);
        if (get_data(0, collect_data) > get_data(1, collect_data)){
          data_val = get_data(0, collect_data);
          halfshift = 0;
        }
        else {
          data_val = get_data(1, collect_data);
         halfshift = 0;
        }
        if (DEBUG_INFO){
          Serial.print("1)     ");
          for(int bt = 0; bt < READ_BITS; bt++){
            if (collect_data[bt] > 128 + 1) Serial.print('I');
            if (collect_data[bt] < 128 - 1) Serial.print('O');
            if (collect_data[bt] == 128 + 1) Serial.print('i');
            if (collect_data[bt] == 128 - 1) Serial.print('o');
            if (collect_data[bt] == 128) Serial.print('.');
          }
          Serial.print(" VAL:");
          Serial.print(data_val);
          //Serial.print(" SIZE:");
          //Serial.print(data_length);
          Serial.print(" SHIFT:");
          Serial.print(halfshift);
        }
        if (packet_number == 2){
          get_bits(collect_data2);
          if (get_data(0, collect_data2) > get_data(1, collect_data2)) {
            data_val2 = get_data(0, collect_data2);
            halfshift = 0;
          }
          else {
            data_val2 = get_data(1, collect_data2);
            halfshift = 1;
          }
          if (DEBUG_INFO){
          Serial.println(" ");  
          Serial.print("2)     ");
          for(int bt = 0; bt < READ_BITS; bt++){
            if (collect_data2[bt] > 128 + 1) Serial.print('I');
            if (collect_data2[bt] < 128 - 1) Serial.print('O');
            if (collect_data2[bt] == 128 + 1) Serial.print('i');
            if (collect_data2[bt] == 128 - 1) Serial.print('o');
            if (collect_data2[bt] == 128) Serial.print('.');
          }
          Serial.print(" VAL:");
          Serial.print(data_val2);
          //Serial.print(" SIZE:");
          //Serial.print(data_length2);
          Serial.print(" SHIFT:");
          Serial.print(halfshift);
        }
      }
      int correlation = correlate_data(collect_data, collect_data2);
        if (DEBUG_INFO){
          Serial.print(" COR: ");
          Serial.println(correlation);
        }
        byte* result_data, result_data_start, aux_data;
        if (packet_number == 1){
          result_data = collect_data;     
        }
        else{
          if (correlation > 0){
            result_data = collect_data2;
            assemble_data(collect_data2,collect_data, &correlation);
        }
        else{
          result_data = collect_data;
          correlation = -correlation;
          assemble_data(collect_data, collect_data2, &correlation);
        }
        //Вывод готовой посылки
      }
      if (DEBUG_INFO){
        Serial.print("RESULT ");
        byte* rdt = result_data;
        for(int bt = 0; bt < READ_BITS; bt++){
          if (*rdt > 128 + 1) Serial.print('I');
          if (*rdt < 128 - 1) Serial.print('O');
          if (*rdt == 128 + 1) Serial.print('i');
          if (*rdt == 128 - 1) Serial.print('o');
          if (*rdt == 128) Serial.print('.');
          rdt++;
        }
        Serial.println(" ");
      }
        //Обработка посылки
      Serial.print("PERIOD: ");
      Serial.print(millis()/40000);
      Serial.print(" ");
      byte packet[PACKET_LENGTH], valid_p[PACKET_LENGTH];
      if (get_info_data(result_data, packet, valid_p)){
        sens_type = get_sensor(packet); //Определяем тип пакета по типу датчика
        restore_data(packet, sens_type); // Восстанавливаем данные по типу датчика
        crc_c = check_CRC(packet, sens_type); // Проверяем CRC, если оно верно, то все сомнительные биты делаем уверенными
        
        if (crc_c) for (byte www = 0; www < PACKET_LENGTH; www++) valid_p[www] = 0x0f;
        Serial.print(" PACKET: ");
        for (int q = 0;q < PACKET_LENGTH; q++) Serial.print(packet[q], HEX);
        Serial.print(" VALIDITY: ");
          for (int q = 0; q < PACKET_LENGTH; q++) Serial.print(valid_p[q], HEX);
      }
      if (sens_type == THGN132 || sens_type == THN132){
        Serial.print(" TYPE: ");
        if (sens_type == THGN132) Serial.print("THGN132N ");
        if (sens_type == THN132) Serial.print("THN132N  ");
        Serial.print("ID: ");
        Serial.print(get_id(packet), HEX);
        Serial.print(" CHNL: ");
        _chnl=get_channel(packet)-1;
        Serial.print(_chnl+1);
        r_type[_chnl] = sens_type;
        if (crc_c) r_isreceived[_chnl] = 1;
        
        //......Если получен правильный пакет, сбрасываем таймер
        if(crc_c) rcv_time[_chnl] = millis();  //         
        
        Serial.print(" BAT: ");
        if(crc_c) r_bat[_chnl] = get_battery(packet);
        if (r_bat[_chnl]) Serial.print("F "); else Serial.print("e ");
       
        Serial.print("TMP: ");
        if(get_temperature_mask(valid_p)){
          if(crc_c) r_tmp[_chnl] = get_temperature(packet);
          Serial.print(r_tmp[_chnl], 1);
        }
        else {
          Serial.print("----");
        }
        Serial.print("C ");
        if (sens_type == THGN132) {
          Serial.print("HUM: ");
          if (get_humidity_mask(valid_p)) {
            if(crc_c) r_hmdty[_chnl] = get_humidity(packet);
            Serial.print(r_hmdty[_chnl], 1);
        }
        else{
          Serial.print("--");
          r_hmdty[_chnl] = 101;
        }
        Serial.print("%");
      }
      else Serial.print("        ");
      Serial.print(" CRC: ");
      if (crc_c) Serial.print("OK ");
      else Serial.print("-- ");
      
          
      Serial.print(" PROC. TIME: ");
      Serial.print(millis() - work_time);
      Serial.println("ms ");
    }
    else Serial.println(" WRONG  ");
    // Возвращаемся к исходному состоянию
    receive_status = FIND_PACKET;
    packet_number = 0;
    start_pulse_cnt = 0;
    sens_type = 0;
    _chnl = 0;
    digitalWrite(13, LOW);
  }

//////////////////////////////////////////////////////////////////////      
//Здесь записываются остальные  процедуры, например те, которые выполняются ежесекундно
//////////////////////////////////////////////////////////////////////      
  if ((millis() - timer_mark) > 1000) {
    {
      if (!reciever_status) Serial.println("RECEIVING...");
      reciever_status = 1;
    }
    reciever_ctrl = 0;
  }
//////////////////////////////////////////////////////////////////////      
//////////////////////////////////////////////////////////////////////      
//////////////////////////////////////////////////////////////////////      
}

 

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

snickser пишет:

Ну как бы да, я предполагал что у вас код посылки в "обычном" виде, как у всех ;)

А у вас вместе 1A2D получается 1D20 какой-то... и потом тоже все перепутано...

Я руководствовался вот этим документом:

http://wmrx00.sourceforge.net/Arduino/OregonScientific-RF-Protocols.pdf

В нём в таблице известных датчиков THGN132 записан как 1D20h

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

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

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

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

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

В ряде случаев компилятор Си может плеваться, если в тексте функция описывается по тексту ниже места её первого вызова. Мы проблему решили переместив тело функции выше её вызова. Хотя грамотнее было бы использовать прототипы функций. Подробнее можно вот тут, например, почитать:

http://www.sbp-program.ru/c/sbp-function-c.htm#pr

RogerRU
RogerRU аватар
Offline
Зарегистрирован: 08.11.2016

gulin176 пишет:

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

Автор в предыдущем посте вам правильно ответил - нужно использовать прототипы. Но если вы не хотите морочиться просто перенисите функции setup() и loop() в самый конец кода.

Вот так: 

#define THGN132 0x1D20      //Типы известных датчиков
#define THN132  0xEC40

#define MHZ 2               //Приёмник подключается к D2

#define FIND_PACKET   1     
#define ANALIZE_PACKETS 3

#define PER_LENGTH 976      // Период в мкс
#define THR_LENGTH 615      //Порог периода 0 или 1
#define LENGTH_TOLERANCE 20 //Допуск на период

#define READ_BITS 90        //Размер битовой посылки
#define READ_BITS2 180      //Двойной размер битовой посылки
#define PACKET_LENGTH 20    //Размер пакета данных
#define DEBUG_INFO 1        //Выводить ли диагностическую информацию

bool  reciever_ctrl = true;    //Флаг контроля ресивера (выставляется при приходе импулься, сбрасывается в таймере)
bool  reciever_status = false; // Результат проверки состояния ресивера

							   //Массивы для хранения полученных данных:
float r_tmp[3];         //Температура
byte  r_hmdty[3];       //Влажность. Если = 101 - значит нет данных
bool  r_bat[3];         //Флаг батареи
bool  r_isreceived[3];  //Флаг о том, что по данному каналу приходил хоть один правильный пакет
word  r_type[3];        //Тип датчика
unsigned long rcv_time[3]; // времена прихода пакетов

byte _chnl;

byte receive_status, packet_number;
byte start_pulse_cnt;

unsigned long pulse_length, work_time, timer_marklong;
unsigned long pulse_marker, right_pulse_marker, last_premarker;
unsigned long pre_marker[4]; // Для хранения временных меток преамбулы ()
unsigned long first_packet_end;

bool crc_c;             //Результат проверки CRC
word sens_type;         //Тип сенсора
bool pulse_type;        //Пустое

byte data_length, data_length2; //Длины пакетов
int data_val, data_val2;        // Качество пакетов

								//Массивы данных для записи данных с канала и полученных битов
byte collect_data[READ_BITS2], collect_data2[READ_BITS2];
//А когда становится массивом полученных битов, то значения такие:
//                          0 - неизвестен
//                          >0 - единица
//                          <0 - ноль
byte decode_tacts[READ_BITS2]; //Массив тактов. значения
							   //                          0=ноль
							   //                          1=единица
							   //                          2=неизвестен
							   //                          3=переход+
							   //                          4=переход-

							   /////////    ПРЕРЫВАНИЕ   ///////////////////////////////////////////////////////////////////////////////////////////

volatile unsigned long pm;
volatile unsigned long pl, timer_mark;

void int_0(void) {
	if (digitalRead(MHZ)) {
		//Начало импульса
		pl = 0;
		pm = micros();
	}
	else {
		//Конец импульса
		//Вычисляется время окончания и длина
		pl = micros() - pm;
		pm += pl;
	}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Извлекает из тактовой последовательности - битовую
//Параметры: cdptr - указатель на записанную тактовую последовательность
////////////////////////////////////////////////////////////////////////////////////////////////////
void get_bits(byte* cdptr) {

	//Сброс массивов
	byte* cdp = cdptr;
	for (int bt = 0; bt<READ_BITS * 2; bt++) decode_tacts[bt] = 2;


	for (int bt = 0; bt<READ_BITS * 2; bt++) {

		if ((*cdp & 0xf0)>0x20 && (*cdp & 0x0f)>0x04) decode_tacts[bt] = 1;
		if ((*cdp & 0xf0)<0x30 && (*cdp & 0x0f)<0x05) decode_tacts[bt] = 0;
		if ((*cdp & 0xf0)<0x20 && (*cdp & 0x0f)>0x04) decode_tacts[bt] = 4;
		if ((*cdp & 0xf0)>0x40 && (*cdp & 0x0f)<0x02) decode_tacts[bt] = 3;
		*cdp++;
	}
	return;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Извлекает из записи канала тактовую последовательность
//Параметры: cdptr - указатель на записанные данные
// btt - смещение в тактах. Смещение на такт при анализе может поммочь восстановить пакет, у которого разрушено начало
// Функция вовзращает качество или "годность" расшифровки - количесвто уверенно узнаных тактов.
// Сравнивая годность с btt=0 и btt=1 выбираем лучшую
////////////////////////////////////////////////////////////////////////////////////////////////////
int get_data(int btt, byte* cdptr) { //btt - смещение на такт при анализе может поммочь восстановить пакет, у которого разрушено начало

	byte* cdp = cdptr;
	for (int bt = 0; bt<READ_BITS; bt++) {
		*cdp = 128;
		cdp++;
	}
	cdp = cdptr;
	*cdp = (128 + 2);
	cdp++;
	int packet_validity = 0;
	for (int bt = 1; bt<READ_BITS; bt++) {
		if (decode_tacts[bt * 2 - btt] == 0) *cdp -= 1;
		if (decode_tacts[bt * 2 - btt] == 1) *cdp += 1;
		if (decode_tacts[bt * 2 - 2 - btt] == 1 && decode_tacts[bt * 2 - 1 - btt] == 4) *cdp -= 1;
		if (decode_tacts[bt * 2 - 2 - btt] == 0 && decode_tacts[bt * 2 - 1 - btt] == 3) *cdp += 1;
		if (decode_tacts[bt * 2 - 2 - btt] == 0 && decode_tacts[bt * 2 - 1 - btt] == 1) *cdp -= 1;
		if (decode_tacts[bt * 2 - 2 - btt] == 1 && decode_tacts[bt * 2 - 1 - btt] == 0) *cdp += 1;

		if (decode_tacts[bt * 2 + 2 - btt] == 1 && decode_tacts[bt * 2 + 1 - btt] == 3) *cdp -= 1;
		if (decode_tacts[bt * 2 + 2 - btt] == 0 && decode_tacts[bt * 2 + 1 - btt] == 4) *cdp += 1;
		if (decode_tacts[bt * 2 + 2 - btt] == 0 && decode_tacts[bt * 2 + 1 - btt] == 1) *cdp -= 1;
		if (decode_tacts[bt * 2 + 2 - btt] == 1 && decode_tacts[bt * 2 + 1 - btt] == 0) *cdp += 1;

		//Подсчитываем кол-во достоверных бит в пакете
		if (*cdp>(128 + 1))  packet_validity += *cdp - 128;
		if (*cdp<(128 - 1)) packet_validity += 128 - *cdp;
		cdp++;
	}
	return packet_validity;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Прослушивание канала с частотой дискретизации 16384Гц
////////////////////////////////////////////////////////////////////////////////////////////////////
void collect(byte* cdptr, byte* dtl) {

	// В функцию передаётся уазатель на область памяти, куда сливать данные.
	*dtl = 0;
	bool cdp_prev_null;
	byte* cdp = cdptr;
	byte nulls_found = 0;
	unsigned long tmp_marker = last_premarker + PER_LENGTH / 32; //
	byte bt2 = 0;
	*cdp = 0x88; //Первые два такта - единицы. Мы же поймали импульс!
	cdp++;
	//Ждём момента наступления первого считывания (конец последнего импулься зацепки + 1/16 такта)
	while (micros() <= tmp_marker);
	//Начинаем читать данные в память!
	for (int bt = 1; bt<READ_BITS * 2; bt++) {// чИТАЕМ максимум ПО 90 БИТ (ПОСЫЛКА thgn - 96БИТ, THN - 76 бИТ + как минимум 3 бита 111, которые мы уже нашли)
		*cdp = 0;
		for (byte ckl = 0; ckl<8; ckl++) {      // Читаем 8 раз за полутакт
			if (digitalRead(MHZ)) *cdp += 0x10; // Измерения запиываем в старший полубайт
			tmp_marker += PER_LENGTH / 16;
			while (micros() < tmp_marker);
		}
		last_premarker += PER_LENGTH / 2;
		tmp_marker = last_premarker + PER_LENGTH / 32;

		for (byte ckl = 0; ckl<8; ckl++) {
			if (digitalRead(MHZ)) *cdp += 1;    // В следующий полутакт измерения запиываем в младший  полубайт. Это экономит память.
			tmp_marker += PER_LENGTH / 16;
			while (micros() < tmp_marker);
		}
		last_premarker += PER_LENGTH / 2;
		bt2++;
		//  Каждые 8 тактов добавлять 5мкс для выравнивания периода с 976мкс до 976.56мкс
		if (bt2 == 8) {
			last_premarker += 5;
			bt2 = 0;
		}
		tmp_marker = last_premarker + PER_LENGTH / 32;

		while (micros() < last_premarker);//Ждём прихода времени следующего полутакта
		if (*cdp == 0 && cdp_prev_null == 1) nulls_found++;
		//if (*cdp==0 && (*(cdp-1)==0)) nulls_found++;
		else nulls_found = 0;

		if (nulls_found>1) return; //Если найдено более 7 нулевых тактов подряд, значит либо жёсткая помеха, убившая пакет
								   //Либо конец посылки. Дальше читать нет смысла.

		cdp_prev_null = (*cdp == 0) ? 1 : 0;
		cdp++;
		*dtl += 1;
	}
	return;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Определение смещения пакетов друг относительно друга
//В качестве параметров передаются указатели на массивы данных
// Возваращаяется смещение
// >0 - второй пакет начался раньше, <0 - Первый пакет начался раньше
////////////////////////////////////////////////////////////////////////////////////////////////////
int correlate_data(byte* ser1, byte* ser2) {

	byte best_correl = 0;
	int best_shift = 0;
	byte best_correl_back = 0;
	int best_shift_back = 0;
	byte shift_score[READ_BITS];
	byte* s1;
	byte* s2;
	byte* s2t = ser2;
	//смещаем первый пакет относительно второго
	for (byte sht = 0; sht<READ_BITS; sht++) {
		s1 = ser1;
		s2 = s2t;
		shift_score[sht] = 0;
		for (byte sp = 0; sp<READ_BITS - sht; sp++) {
			if ((*s1 >(128 + 1) && *s2 >(128 + 1)) || (*s1 <(128 - 1) && *s2 <(128 - 1))) shift_score[sht]++;
			s2++;
			s1++;
		}
		s2t++;
	}

	for (int i = 0; i<READ_BITS; i++) {
		if (shift_score[i]>best_correl) {
			best_correl = shift_score[i];
			best_shift = i;
		}
	}

	//Теперь наоборот -втрой пакет относительно первого

	byte* s1t = ser1;
	for (byte sht = 0; sht<READ_BITS; sht++) {
		s2 = ser2;
		s1 = s1t;
		shift_score[sht] = 0;
		for (byte sp = 0; sp<READ_BITS - sht; sp++) {
			if ((*s1 >(128 + 1) && *s2 >(128 + 1)) || (*s1 <(128 - 1) && *s2 <(128 - 1))) shift_score[sht]++;
			s2++;
			s1++;
		}
		s1t++;
	}
	// Ищем наилучшее совпадение для обоих вариантов 


	for (int i = 0; i<READ_BITS; i++) {
		if (shift_score[i]>best_correl_back) {
			best_correl_back = shift_score[i];
			best_shift_back = i;
		}
	}
	//И возвращаем самое лучшее из двух
	if (best_correl_back > best_correl) return -best_shift_back;
	else return best_shift;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Сборка из двух пакетов
//В качестве параметров передаются указатели на массивы данных
// Причём первым должен идти результирующий пакет, т.е. тот который имеет более длинную преамбулу.
//shift - смещение втрого пакета относительного первого
////////////////////////////////////////////////////////////////////////////////////////////////////
void assemble_data(byte* s1, byte* s2, int* shift) {

	for (int g = 0; g <= *shift - 1; g++) s1++;
	for (int i = 0; i<(READ_BITS - *shift); i++) {
		if (*s1 < (128 + 2) && *s1 >(128 - 2) && (*s2>(128 + 1) || *s2<(128 - 1))) {
			*s1 = *s2;
		}
		s1++;
		s2++;
	}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Создаёт кодовую посылку
//code - указатель на расшифрованную битовую последовательность
//result - указатель на кодовую посылку
//valid - указатель на карту достоверности кодовой посылки
////////////////////////////////////////////////////////////////////////////////////////////////////
byte get_info_data(byte* code, byte* result, byte* valid) {

	byte* rd = result;
	byte* vd = valid;
	//Чистим массивы
	for (int l = 0; l<PACKET_LENGTH; l++) {
		*vd = 0;
		*rd = 0;
		vd++;
		rd++;
	}
	int csm;
	for (csm = 0; csm<30; csm++) {
		if (*code<128 && *(code + 1)>128 && *(code + 2)<128 && *(code + 3)>128) break;//Найдена последовательность 0101 
		code++;
	}
	if (csm>22) return 0;// Стартовая последовательность в первых 20 битах не найдена, такой пакет этим методом не расшифруешь

	code += 4;//Переходим на начало считывания
	int ii = 0;
	for (int i = 0; i<READ_BITS - csm; i++)
	{
		byte multipl;
		switch (ii) {
		case 0: {multipl = 0x01; break; }
		case 1: {multipl = 0x02; break; }
		case 2: {multipl = 0x04; break; }
		case 3: {multipl = 0x08; break; }
		}
		if (*code == 129) *result += multipl;
		if (*code>129) {
			*result += multipl;
			*valid += multipl;
		}
		if (*code<127) *valid += multipl;
		code++;
		ii++;
		if (ii == 4) {
			ii = 0;
			valid++;
			result++;
		}
	}
	return 1;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Возвращает значение температуры
//oregon_data - указатель на кодовую посылку
////////////////////////////////////////////////////////////////////////////////////////////////////
float get_temperature(byte* oregon_data) {

	float tmprt;
	oregon_data += 8;
	//исправляем возможные ошибки:
	for (int g = 0; g<4; g++)  if (*(oregon_data + g)>9) *(oregon_data + g) = *(oregon_data + g) - 8;
	tmprt += *(oregon_data)*0.1;
	tmprt += *(oregon_data + 1);
	tmprt += *(oregon_data + 2) * 10;
	return (*(oregon_data + 3)) ? -tmprt : tmprt;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Возвращает значение маски годности
//validity_data - указатель на карту достоверности кодовой посылки
////////////////////////////////////////////////////////////////////////////////////////////////////
byte get_temperature_mask(byte* validity_data) {

	return (*(validity_data + 8) == 0x0f && *(validity_data + 9) == 0x0f && *(validity_data + 10) == 0x0f && *(validity_data + 11) == 0x0f) ? 1 : 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Возвращает тип сенсора
//oregon_data - указатель на кодовую посылку
////////////////////////////////////////////////////////////////////////////////////////////////////
word get_sensor(byte* oregon_data) {

	return (word)(*(oregon_data)) * 0x1000 + (*(oregon_data + 1)) * 0x0100 + (*(oregon_data + 2)) * 0x10 + *(oregon_data + 3);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Возвращает значение канала
//oregon_data - указатель на кодовую посылку
////////////////////////////////////////////////////////////////////////////////////////////////////
byte get_channel(byte* oregon_data) {

	byte channel;
	switch (*(oregon_data + 4))
	{
	case 1:
		channel = 1;
		break;
	case 2:
		channel = 2;
		break;
	case 4:
		channel = 3;
		break;
	}
	return channel;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
byte get_battery(byte* oregon_data) {

	return (*(oregon_data + 7) & 0x4) ? 0 : 1;

}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Возвращает значение влажности
//oregon_data - указатель на кодовую посылку
////////////////////////////////////////////////////////////////////////////////////////////////////
byte get_humidity(byte* oregon_data) {

	byte tmprt;
	oregon_data += 12;
	//исправляем возможные ошибки:
	for (int g = 0; g<2; g++)  if (*(oregon_data + g)>9) *(oregon_data + g) = *(oregon_data + g) - 8;
	tmprt = *(oregon_data);
	tmprt += *(oregon_data + 1) * 10;
	return tmprt;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Возвращает значение маски годности влажности 4 бита, старший - знак, младший -  десятые доли градуса
//validity_data - указатель на карту достоверности кодовой посылки
////////////////////////////////////////////////////////////////////////////////////////////////////
byte get_humidity_mask(byte* validity_data) {

	return (*(validity_data + 13) == 0x0f && *(validity_data + 14) == 0x0f) ? 1 : 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//Возвращает id датчика
//oregon_data - указатель на кодовую посылку
////////////////////////////////////////////////////////////////////////////////////////////////////
byte get_id(byte* oregon_data) {

	byte tmprt;
	oregon_data += 5;
	tmprt = *(oregon_data) * 0x10;
	tmprt += *(oregon_data + 1);
	return tmprt;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
//Проверка CRC
//oregon_data - указатель на кодовую посылку
////////////////////////////////////////////////////////////////////////////////////////////////////
bool check_CRC(byte* oregon_data, word sensor_type) {

	byte* pp = oregon_data;
	byte crc, resived_crc;
	crc = 0;
	if (sensor_type == THGN132) {
		for (int x = 0; x<15; x++) {
			crc += *pp;
			pp++;
		}
		resived_crc = (*(oregon_data + 15)) + (*(oregon_data + 16)) * 0x10;
		return (resived_crc == crc) ? 1 : 0;
	}

	if (sensor_type == THN132) {
		for (int x = 0; x<12; x++) {
			crc += *pp;
			pp++;
		}
		resived_crc = (*(oregon_data + 12)) + (*(oregon_data + 13)) * 0x10;
		return (resived_crc == crc) ? 1 : 0;
	}
	return 0;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
//Востановление данных по типу датчика
////////////////////////////////////////////////////////////////////////////////////////////////////
void restore_data(byte* oregon_data, word sensor_type) {

	byte* pp = oregon_data;
	if (sensor_type == THGN132) {
		pp += 8;
		for (int x = 0; x<6; x++) {
			if (*pp>9 && x != 3) *pp -= 8;
			pp++;
		}
	}
	if (sensor_type == THN132) {
		pp += 8;
		for (int x = 0; x<3; x++) {
			if (*pp>9) *pp -= 8;
			pp++;
		}
	}
	return;
}
//////////////// УСТАНОВКИ  ///////////////////////////////////////
void setup()
{
	Serial.begin(57600);

	//Прерывание по сигналу от приёмника
	pinMode(MHZ, INPUT);
	attachInterrupt(0, int_0, CHANGE);

	receive_status = FIND_PACKET;
	start_pulse_cnt = 0;
	packet_number = 0;
	for (int i = 0; i < 3; i++) {
		rcv_time[i] = 7000000;
		r_isreceived[i] = 0;
	}
	pinMode(13, OUTPUT);        //Будем мигать светодиодом
	digitalWrite(13, LOW);
}

//////////////// ГЛАВНЫЙ ЦИКЛ  ///////////////////////////////////////
void loop()
{
	noInterrupts();
	pulse_length = pl;
	pl = 0;
	pulse_marker = pm;
	interrupts();
	//////////////////////////////////////////////////////////////////////
	//Получен некий импульс,//////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////////
	if (pulse_length != 0 && receive_status == FIND_PACKET) {
		reciever_ctrl = 1;
		//Режим поиска пакета в эфире
		if (start_pulse_cnt == 0) {
			//Найдена первый "правильный" импульс - длинная единица!
			if (pulse_length < (PER_LENGTH) && pulse_length >(THR_LENGTH)) {
				start_pulse_cnt = 1;
				pre_marker[start_pulse_cnt] = pulse_marker;
				pulse_length = 0;
			}
		}
		//Ищем следующие импульсы
		else {
			//Найден импуль правильной длины
			if (pulse_length <= (PER_LENGTH) && pulse_length >= (THR_LENGTH)) {
				//Если импульс в правильном месте, то добавляем счётчик найденых стартовых импульсов
				if (pulse_marker - pre_marker[start_pulse_cnt] > (PER_LENGTH * 2 - LENGTH_TOLERANCE) && pulse_marker - pre_marker[start_pulse_cnt] < (PER_LENGTH * 2 + LENGTH_TOLERANCE)) {
					start_pulse_cnt++;
					pre_marker[start_pulse_cnt] = pulse_marker;
					pulse_length = 0;
				}
				///...если  в неправильном месте то назначаем его первым
				else {
					start_pulse_cnt = 1;
					pre_marker[start_pulse_cnt] = pulse_marker;
					pulse_length = 0;
				}
			}
			else {
				//Если импульс неправильной длины, то стоит проверить, а не вышло ли время ожидания правильного импульса
				if (pulse_marker - pre_marker[start_pulse_cnt] < (PER_LENGTH * 2 + LENGTH_TOLERANCE)) {
					//Время ещё не вышло, скорее всего это помеха. Пропускаем...
					pulse_length = 0;
				}
				else {
					//Время вышло, начинаем искать заново
					start_pulse_cnt = 0;
					pulse_length = 0;
				}
			}
		}
	}
	if (packet_number == 1 && (millis() - first_packet_end) > 200) { // Если найден первый пакет и вышло вермя ожидания второго
																	 // Не ждём второго, а переходм в режим анализа
		receive_status = ANALIZE_PACKETS;
	}
	//////////////////////////////////////////////////////////////////////
	// Сбор данных////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////////

	//Если Найдены три длинных единицы и два длинных нуля. Возможно это начало посылки...
	if (start_pulse_cnt == 3 && receive_status == FIND_PACKET) {
		work_time = millis();
		last_premarker = pre_marker[3];
		start_pulse_cnt = 0;
		if (packet_number == 0) {
			collect(collect_data, &data_length);
			first_packet_end = millis();
			packet_number = 1;
		}
		else {
			collect(collect_data2, &data_length2);
			packet_number = 2;
			receive_status = ANALIZE_PACKETS;
		}
	}
	if (receive_status == ANALIZE_PACKETS) {
		digitalWrite(13, HIGH);
		//////////////////////////////////////////////////////////////////////
		// Анализ данных////////////////////////////////////////////////////////
		//////////////////////////////////////////////////////////////////////      
		bool halfshift;
		//Дамп собранных данных        
		/*        if (DEBUG_INFO){
		for(int bt = 0; bt < 180; bt++){
		Serial.print(collect_data[bt], HEX);
		Serial.print(' ');
		}
		Serial.println(" ");

		for(int bt = 0; bt < 180; bt++){
		Serial.print(collect_data2[bt],HEX);
		Serial.print(' ');
		}
		Serial.println(" ");
		}
		*/

		get_bits(collect_data);
		if (get_data(0, collect_data) > get_data(1, collect_data)) {
			data_val = get_data(0, collect_data);
			halfshift = 0;
		}
		else {
			data_val = get_data(1, collect_data);
			halfshift = 0;
		}
		if (DEBUG_INFO) {
			Serial.print("1)     ");
			for (int bt = 0; bt < READ_BITS; bt++) {
				if (collect_data[bt] > 128 + 1) Serial.print('I');
				if (collect_data[bt] < 128 - 1) Serial.print('O');
				if (collect_data[bt] == 128 + 1) Serial.print('i');
				if (collect_data[bt] == 128 - 1) Serial.print('o');
				if (collect_data[bt] == 128) Serial.print('.');
			}
			Serial.print(" VAL:");
			Serial.print(data_val);
			//Serial.print(" SIZE:");
			//Serial.print(data_length);
			Serial.print(" SHIFT:");
			Serial.print(halfshift);
		}
		if (packet_number == 2) {
			get_bits(collect_data2);
			if (get_data(0, collect_data2) > get_data(1, collect_data2)) {
				data_val2 = get_data(0, collect_data2);
				halfshift = 0;
			}
			else {
				data_val2 = get_data(1, collect_data2);
				halfshift = 1;
			}
			if (DEBUG_INFO) {
				Serial.println(" ");
				Serial.print("2)     ");
				for (int bt = 0; bt < READ_BITS; bt++) {
					if (collect_data2[bt] > 128 + 1) Serial.print('I');
					if (collect_data2[bt] < 128 - 1) Serial.print('O');
					if (collect_data2[bt] == 128 + 1) Serial.print('i');
					if (collect_data2[bt] == 128 - 1) Serial.print('o');
					if (collect_data2[bt] == 128) Serial.print('.');
				}
				Serial.print(" VAL:");
				Serial.print(data_val2);
				//Serial.print(" SIZE:");
				//Serial.print(data_length2);
				Serial.print(" SHIFT:");
				Serial.print(halfshift);
			}
		}
		int correlation = correlate_data(collect_data, collect_data2);
		if (DEBUG_INFO) {
			Serial.print(" COR: ");
			Serial.println(correlation);
		}
		byte* result_data, result_data_start, aux_data;
		if (packet_number == 1) {
			result_data = collect_data;
		}
		else {
			if (correlation > 0) {
				result_data = collect_data2;
				assemble_data(collect_data2, collect_data, &correlation);
			}
			else {
				result_data = collect_data;
				correlation = -correlation;
				assemble_data(collect_data, collect_data2, &correlation);
			}
			//Вывод готовой посылки
		}
		if (DEBUG_INFO) {
			Serial.print("RESULT ");
			byte* rdt = result_data;
			for (int bt = 0; bt < READ_BITS; bt++) {
				if (*rdt > 128 + 1) Serial.print('I');
				if (*rdt < 128 - 1) Serial.print('O');
				if (*rdt == 128 + 1) Serial.print('i');
				if (*rdt == 128 - 1) Serial.print('o');
				if (*rdt == 128) Serial.print('.');
				rdt++;
			}
			Serial.println(" ");
		}
		//Обработка посылки
		Serial.print("PERIOD: ");
		Serial.print(millis() / 40000);
		Serial.print(" ");
		byte packet[PACKET_LENGTH], valid_p[PACKET_LENGTH];
		if (get_info_data(result_data, packet, valid_p)) {
			sens_type = get_sensor(packet); //Определяем тип пакета по типу датчика
			restore_data(packet, sens_type); // Восстанавливаем данные по типу датчика
			crc_c = check_CRC(packet, sens_type); // Проверяем CRC, если оно верно, то все сомнительные биты делаем уверенными

			if (crc_c) for (byte www = 0; www < PACKET_LENGTH; www++) valid_p[www] = 0x0f;
			Serial.print(" PACKET: ");
			for (int q = 0; q < PACKET_LENGTH; q++) Serial.print(packet[q], HEX);
			Serial.print(" VALIDITY: ");
			for (int q = 0; q < PACKET_LENGTH; q++) Serial.print(valid_p[q], HEX);
		}
		if (sens_type == THGN132 || sens_type == THN132) {
			Serial.print(" TYPE: ");
			if (sens_type == THGN132) Serial.print("THGN132N ");
			if (sens_type == THN132) Serial.print("THN132N  ");
			Serial.print("ID: ");
			Serial.print(get_id(packet), HEX);
			Serial.print(" CHNL: ");
			_chnl = get_channel(packet) - 1;
			Serial.print(_chnl + 1);
			r_type[_chnl] = sens_type;
			if (crc_c) r_isreceived[_chnl] = 1;

			//......Если получен правильный пакет, сбрасываем таймер
			if (crc_c) rcv_time[_chnl] = millis();  //         

			Serial.print(" BAT: ");
			if (crc_c) r_bat[_chnl] = get_battery(packet);
			if (r_bat[_chnl]) Serial.print("F "); else Serial.print("e ");

			Serial.print("TMP: ");
			if (get_temperature_mask(valid_p)) {
				if (crc_c) r_tmp[_chnl] = get_temperature(packet);
				Serial.print(r_tmp[_chnl], 1);
			}
			else {
				Serial.print("----");
			}
			Serial.print("C ");
			if (sens_type == THGN132) {
				Serial.print("HUM: ");
				if (get_humidity_mask(valid_p)) {
					if (crc_c) r_hmdty[_chnl] = get_humidity(packet);
					Serial.print(r_hmdty[_chnl], 1);
				}
				else {
					Serial.print("--");
					r_hmdty[_chnl] = 101;
				}
				Serial.print("%");
			}
			else Serial.print("        ");
			Serial.print(" CRC: ");
			if (crc_c) Serial.print("OK ");
			else Serial.print("-- ");


			Serial.print(" PROC. TIME: ");
			Serial.print(millis() - work_time);
			Serial.println("ms ");
		}
		else Serial.println(" WRONG  ");
		// Возвращаемся к исходному состоянию
		receive_status = FIND_PACKET;
		packet_number = 0;
		start_pulse_cnt = 0;
		sens_type = 0;
		_chnl = 0;
		digitalWrite(13, LOW);
	}

	//////////////////////////////////////////////////////////////////////      
	//Здесь записываются остальные  процедуры, например те, которые выполняются ежесекундно
	//////////////////////////////////////////////////////////////////////      
	if ((millis() - timer_mark) > 1000) {
		{
			if (!reciever_status) Serial.println("RECEIVING...");
			reciever_status = 1;
		}
		reciever_ctrl = 0;
	}
	//////////////////////////////////////////////////////////////////////      
	//////////////////////////////////////////////////////////////////////      
	//////////////////////////////////////////////////////////////////////      
}

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

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

Porosenok пишет:

В нём в таблице известных датчиков THGN132 записан как 1D20h

Все мои Орегон сенсоры выдают 1A2D код, и расположение последующих байтов не совпадает с тем что описано в том документе, думаю он неточен. Почему бы вам просто не выводить то что пришло из эфира, и не делать перетасовку или подмену значений?...

 

 

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

спасибо большое датчик thgn132n видит показания сходятся с базавой станцией. однако я расстроился, что давление принимает основной блок а не датчик с улицы. это для меня ценность всего мониторинга теряется. есть ещё датчик thgn800  посмотрел по сайту тоже не принимает давление. ещё приёмник RF-5V с припаянной антенной не принимает с улицы. пришлось вылазить за окно, доставать датчик. в комнате уже берёт с любого места

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

snickser пишет:

Все мои Орегон сенсоры выдают 1A2D код, и расположение последующих байтов не совпадает с тем что описано в том документе, думаю он неточен. Почему бы вам просто не выводить то что пришло из эфира, и не делать перетасовку или подмену значений?...

Не вижу я в этом смысла. От перестановки полубайтов и добавления перед посылкой буковки "А" итоговые данные не изменятся. И ваш вариант и описанный в приведённом мной документе одинаково точны. Интерпретация разная. И никто не мешает вам переписать вывод в Серила в удобном для вас виде.

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

gulin176 пишет:

...однако я расстроился, что давление принимает основной блок а не датчик с улицы. это для меня ценность всего мониторинга теряется. есть ещё датчик thgn800  посмотрел по сайту тоже не принимает давление.

Ну, это вполне логично. Давление что в доме, что на улице одинаковое, если у вас не герметичное помещение, конечно. Расстраиваться не стоит. Датчик давления стоит сущие копейки.

gulin176 пишет:

ещё приёмник RF-5V с припаянной антенной не принимает с улицы. пришлось вылазить за окно, доставать датчик. в комнате уже берёт с любого места

 

Значит надо экспериметнтировать с антенной. Сделать её на сантиметр-два короче указанного, особенно если у вас она из толстого провода. Или припаять к земле ещё один такой провод в противоположном направлении. Получтся полуволновой вибратор, и можно выиграть до 1.5-2дБ. И антенна обязательно должна торчать перпендикулярно земле.

 

KVadik
KVadik аватар
Offline
Зарегистрирован: 15.06.2014

gulin176 пишет:

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

Дык, оно одинаковое, если вы не барокамере живете. Поэтому датчик давления в станциях только один и его логично разместить в более комфортных для электроники условиях.

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

ну так то да но это усложнение кострукции ещё надо датчик добавлять, интегрировать в код

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

провёл эксперимент. подстроечным винтом на катушке выкрутил на 1\4 оборота и стало принимать в любом месте квартиры куда смог дотянуться приёмником  RF-5V привязанным проводами к компьютеру. выкрутил ещё 1\4 оборота и сигнал полностью пропал. теперь записей в сериал типа wrong почти нет

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

По поводу антенны.Посчитал в NEC2 и вот что получилось. Если принять входное сопротивление приёмика около 40 Ом, то обычный четвертьволновой штырь, который все использют в вид пружинки или куска проволоки, более предпочтителен, чем полуволоновой вибратор, который даёт с учётом рассогласования на 1дБ меньше и более ширкую полосу пропускания. Так что я наверное неправ по поводу целесообразности припаивания второго штыря.

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

День добрый.

Подскажите пожалуйста.

Есть AtMega 2560.

Прошил ваш скетч.

Подключил приёмник к PWM 2 и GND.

А в Serial ничего не выводится.

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

Sprite пишет:

Подключил приёмник к PWM 2 и GND.

А +5В куда подключили?... )

 

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

На приемнике       На Ардуино

 1)   VCC         -           +5

2)                   -         GND

3)                   -         PWM 2

4)  GND          -         GND

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

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

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

Подскажите как?

Есть приёмник, есть передатчик, есть ОДНА ATMega 2560.

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

Sprite пишет:

На приемнике       На Ардуино

 1)   VCC         -           +5

2)                   -         GND

3)                   -         PWM 2

4)  GND          -         GND

Может надо так:

 1)   VCC         -           +5

2)    DATA        -         PWM 2

3)    DATA        -         PWM 2

4)  GND          -         GND

RogerRU
RogerRU аватар
Offline
Зарегистрирован: 08.11.2016

Porosenok пишет:

Sprite пишет:

На приемнике       На Ардуино

 1)   VCC         -           +5

2)                   -         GND

3)                   -         PWM 2

4)  GND          -         GND

Может надо так:

 1)   VCC         -           +5

2)    DATA        -         PWM 2

3)    DATA        -         PWM 2

4)  GND          -         GND

Там без разницы. Два средних вывода закорочены между собой