Манчестерское кодирование, реализация

wasq
Offline
Зарегистрирован: 26.05.2018

Манчестерский код реализация

Удобный способ передачи данных. Требуется один информационный провод (+ общий). Может передаваться без постоянной составляющей ( по эфиру, трансформаторная связь, переполюсовка проводов). Синхро информация присутствует в каждом бите, в результате не критичен к стабильности скорости приема/передачи. Привожу реализацию тестовой программы ан AVR. Программа написана на МикроПаскале, учебный язык понятный всем. Передача и прием работают на одной плате ARDUINO UNO R3. Передача ведется на пином PD7, прием пином PD3 ( INT1), как бы две программы работают на одном кристалле, якобы двух задачность, так было проще отлаживать алгоритм — чем на двух платах ARDUINO. Надо ставить перемычку между пином PD7 и PD3. Скорость приема/передачи не высока = 520,3 бит/сек, легко повышается в 10 раз не переписывая ничего ( смена 3 констант ), при изменении настроек таймера еще в 5 раз ( уже до 25 000 бит/сек), а при написании обработчика таймера на ассемблере, можно повысить еще в 3 раза. Но мне надо было отладить алгоритм и на скорости 500 быт/сек, чисто технически мне было так проще. Самая сложная часть это прием, синхронизация и дешефрирование выполнено полностью на прерываниях таймера и INT, что позволяет работать и основной программе и не подвисать контроллер. Передатчик частично выполнен на прерываниях, при желании его также можно перевести в этот режим, а основная программа сможет заниматься чем то еще.

Алгоритм построен на знании с какой скоростью ведется прием/передача, не согласованность скоростей может достигать +-12,5%, что вполне устраивает при применении AVR без кварцевого резонатора, используя внутренний генератор. Можно алгоритм усложнить и приемнику рассчитывать скорость передачи бит и от этого плясать, но это в личных устройствах практически не требуеться, т. к. автор передачи и приема один и тот же товарищ.

Прием ведется по алгоритму, рассмотрим.

Каждый фронт ( любой полярности ) запускает время ожидания 0.75 периода передачи, попавший в этот промежуток времени следующий фронт пропускается, после окончания периода ожидания считывается значение на входе приемника и запоминается. Как видно на картинке зацеп синхронизации произойдет в любом случае, максимум с пропуском первых 2-3 бит. Причем прием и дешифрация могут получиться и в инверсном виде, зависит от того, как пришло от передатчика. Для разрешения данной коллизии я с начало передаю байт B11010111, где переходы из 1 в 0 и наоборот гарантируют захват синхронизации приемником, затем передаю синхро байт 0x55. При приеме этот принятый байт сравнивается с кодом 0x55 и 0xAA. Если он равен 0x55, то прием последующих байтов ведется без изменений, если он равен 0xAA, то значит прием инверсный и все последующие байты данных надо инвертировать.

Код программы

program send;

{ передатчик и приемник манчесстрекого кода
  с использованием прерываний по таймеру 2 d приемника.
  Прием и передача осуществляються  на одном процессоре и одной плате. 
  Передача основной процесс, прием в режиме прерываний по тацймеру 2
  и внешнему прерыванию INT1
  Как бы работают две не зависимые программы, одна передает 
  манчестерский код на пин PD7,
  вторая программа принимает код и расшифровывает его на пине PD3-INT1- 
  Плата исподзуеться ARDUINO UNO R3 CPU Atmega 328P 16 мГц. 
  Надо для работы программы закоротить пин PD7  пином PD3, т.е. соеденить
  выход передачика со входом приемника }

Var a,b,i:byte;
    tikpriem:byte;   // Счетчик тиков приемника   прерываний таймера 2
    tikpered:byte;   // Счетчик тиков передатчика прерываний таймера 2
    bsh:byte;        // Счетчик битов в байте
    bpriem:byte;     // байт приема битиков с линии
    flag1440:byte;   // флаг ожидания в приемнике т.к. подождали 
                     //30 тиков считали бит и готовы к след старту
    flagstop:byte;       // Если =0 - приема НЕТ !! т.е в прерываниях
                        // делать ничего не надо
    tmout:word;         // Подсчет времени приема, еслти он более 
                        //2,2 сек = ошибка надо выйти это = 46 000 тиков
    flagsinxro:byte;    // Флаг синхронизации, считывает входной байт 
                        //синхро  0xAA или 0x55 и идет процесс записи буфера
    bindex:byte;          // идекс записи в приемный буфер
    
    ssend:array [0..31] of byte; // Буфер для передачи

    stran:array [0..31] of byte; // Буфер приема
    // Для Отладки
    su:string[10];               // для отладки и вывода на экран
    bfs:array[0..511] of byte;
    ch:char;                     // Отладка
    bbb,qqq,qqf:byte;            // Отладка
    b00:word;
    b11:word;
    www,tikprw,tikperw:word;     // Отладка
    
// Преобразования байта с строку-массив БИТОВУЮ ДВОИЧНУЮ + 0
Procedure ByteTobin(b:byte; var ss:string[10]);
Var   pr, i, y, r: Byte;
  Begin
  ss:='00000000';
  pr:=b; y:=%10000000;
  for i:=0 To 7 Do
    Begin
     r:= pr AND y;
     if r=0 Then ss[i]:='0'  Else ss[i]:='1';
     y:= y SHR 1;
    End;
  End;

// Вывод в порт UART LN = типа - Serial.println
Procedure uartLN;
    Begin
      UART1_Write(0xD);  UART1_Write(0xA);
    End;

// Ожидание нажатия клавиши, и вывода отладочной информации
Procedure timeout(ss:char; bp:byte);
 Var hh:char;
     bst:string[10];
  Begin
     ByteToBin(bp,bst);
     UART1_Write(ss);  UART1_Write(' '); UART1_Write_Text(bst);
     uartLN;
     While (UART1_Data_Ready() <> 1) Do;
     hh := UART1_Read();
  End;

// Манчестер - передача подготовленнного буфера на пин PD7
// Передаеться начиная с младшего бита в байте к старшему
Procedure  Sendbuf;
Var b,i,a,q:byte;
   Begin
     For  q:=0 to 31 Do   // Пройдемся по всему буферу
     Begin
       a:=ssend[q];
       For i:=0 to 7 Do   // Проход по байту
         Begin
           b:= 1 shl i;  // какой бит передаем, 
                         //сначало младщий - затем старший
           If (a AND b)=0 Then //  Передача нулевого бита 
                               //делаем '1' 960 us затем '0' и 960 us
              Begin
                PORTD:= PORTD OR %10000000;
                tikpered:=0;
                while (tikpered<20) Do;
                PORTD:= PORTD  AND %01111111;
                tikpered:=0;
                while (tikpered<20) Do;
              End
                Else  //  Передача еденичного бита
                      // делаем '0' 960 us затем '1' и 960 us
                  Begin
                     PORTD:= PORTD AND %01111111;
                     tikpered:=0;
                     while (tikpered<20) Do;
                     PORTD:=PORTD OR %10000000;
                     tikpered:=0;
                     while (tikpered<20) Do;
                  End;
         End;
     End;
   End;


// Для приема будем использовать таймер2 и int1 - вывод PORTD.3
// Сначало обработка прерывания по int1 по любому переходу !!
// Любой переход уровня на INT1 запускаеть счет 1,5 периодов
// Это определяет флаг flagg1440
Procedure INT1_pr; iv IVT_ADDR_INT1 ;
Label goend;
Var bt:byte;
 Begin
   if (flagstop=0)  then goto goend;      // Если прием не включен = выйди
   if (flag1440>0)  then goto goend;      //  Если была включена задержка
                                          // на 1440 мкС = выйди
   flag1440:=0xFF;        //  Запустили задержку на 1440 мкС
   tikpriem:=0;           // Обнулили тик приемника  для подсчета задержки
 goend:
 End;

{  Таймер 2 !! прерывания 
  Примерно макс время обработки 8-9 мкС, что вроде допустимо,
  но вносит очень большую ошибку в передачу по программной 
  задержкае 30*19= 300 мкС на0,96 мС, т.е. надо передачу также
  по таймерному счетчику на прерываниях сделать, 
  Все передавать на 500 бод, т.е. период 1,920 мС. 
  Передача  из двух половинок по 0,96 мС, приемная задержка 0,75 периода
  = 1,440 мС. Прерывание от таймера по 48 мкС. реально не 50 мкС, 
  а при 16 мГц = (1/125000)*6 = 48 мкС и не 1 мС, а  = 960 мкс = 0,96 мС
  период = 1,920 мС, задержака 30 тиков 1,5 периода передачи  =  1,440 мС
  Все константы и счетчики пересмотрены на это регламент
  }

Procedure Timer2_pr; iv IVT_ADDR_TIMER2_OVF;
Label goend;
Var bt:byte;
  Begin
    // Снова зарядим таймер  6 тиков по 8 мкС = 48 мкС
    TCNT2:=250;
    tikpered:=tikpered+1;         // Тик передатчика
    tmout:=tmout+1;               // Тик тайм аута
    //  Простые ограничителои как ошибок так и не работы
    if (flagstop=0)  then goto goend;    // Если прием не включен = выйди
    if (tmout>46000) then
          Begin
             tmout:=0xC000;  //   Чтобы сам не  перешел через переполнение к нулю.
             goto goend;    //  Счетчик прерываний, если более 2,2 сек
                            // = тайм аут = ошибка по времени
          End;                               // 2 200 000 / 48 мкС =
    // Если flag1440 <>0 - режим паузы 1440 мкС, ждем ее окончания, это tikpriem>30
    // Нарастим счетчик, 30 тиков = 1440 мкС = 1,5 от 960 =взятие бита данных и запись его
     if (flag1440>0) then
       Begin
        tikpriem:=tikpriem+1;
        If tikpriem>30 Then
         Begin
           flag1440:=0;               // Пришло время считать занчения бита
           bt:=PIND AND %00001000;    // Выделили бит на входе порта приема PD3
           bpriem:=bpriem shr 1;      // занесем его в байт, предварительно сдвинув его
           if bt<>0 then bpriem:=bpriem OR %10000000;  
          // Если bt=0 то уже при сдвиге в старший бит заноситься 0
          // Через 8 сдвигов первый приянтый будет младшив в байте
           bsh:=bsh + 1;              // Счетчик битов в байте
           if (flagsinxro=0)    then  // Если еще Синхронизации нет, ожидаем ее и проверяем
               Begin
                  if bpriem=0xAA  Then flagsinxro:=0xAA;  // Есть синхронизация инверстная
                  if bpriem=0x55  Then flagsinxro:=0x55;  // Есть синхронизация прямая
                  bsh:=0;            // начинаем прием информационных битов
                  bindex:=0;
               End
                 Else                // Есть синхронизация наполняем буфер
                   Begin
                      if (bsh=8) Then   // Байт сформирован
                          Begin
                             if flagsinxro=0x55 Then
                                 stran[bindex]:=bpriem
                                    Else  stran[bindex]:=NOT bpriem;
                             if (bindex<29) Then bindex:=bindex+1;
                             bsh:=0;
                          End;
                   End;
         End;
       End;
   goend:
   End;
   
begin

     flagstop:=0;     // НЕТ приема, прерывания могут быть, но обрабатыаться они не будут
   { Порт D  Пин 7 - вывод данных Манчестерского кода
     0 -> 1 передача '1'
     1 -> 0 передача '0'    }
     DDRD := DDRD OR %11100000;    // пины 5,6,7 на вывод = пины 6 и 5 были мне нужны для отладжки
     PORTD:= PORTD AND %00011111;  // Во все пины вывода запишем = 0

     // Подготовка буфера к передачи, это тест для отладки, поэтому все в ручную и наглядно
     ssend:='===111111YUIIOPASD1234567890====';  // 0..31
     ssend[0]:=%11101011;   // для запуска синхронизации
     ssend[1]:=0x55;   // синхро байт
     ssend[2]:=25;     // После него записано 25 байт иноформации  с контрольной суммой = 24 шт. + КС
     ssend[28]:=0;     // Сюда запишем контрольную сумму
     For i:=3 to 27 Do ssend[28]:=ssend[28]+ssend[i]; // КС сумма

     //  Разрешим прерывание и прерывания от INT1 по любому смену уровн и ТАЙМЕРА2
     DDRD := DDRD AND %11100111;        //  вывод PIND.3 на ввод  и PD4 (для отладки был нужен )
     PORTD := PORTD OR %00011000;       //  и подтянем их резистором к +5V

    // Теперь настроим таймер 2 и организуем от него прерывания - для - 328P = UNO R3
     TCCR2B := 0;    // СТОП таймер.
     TCCR2A := 0;    // Нормальный режим биты 0 и 1
     TCNT2  := 250;  // 250 на 16 мГц дает частоту прерываний 48 мкС
                     // коэфф счета = 256-0,000048/(1/125000)= 250
     TCCR2B := %00000101; // Предделитель на 128. Общее деление (16 000 000) / 128 = 125 000 раз в секунд
     TIFR2  := 1;    // сброс флага прерывания       --  (1<<TOV2);
     TIMSK2 := 1;    // Прерывание от переполнения   --  (1<<TOIE2);

     // Настройка INT1 - у порта PD2 !!!   ИМЕННО для 328
     //  Для других кристалов - искать аналоги в даташите.
     EICRA := %00000100; // причина прерыванмя - любое изменение уровня на входе INT1 вызывет прерывание
     EIMSK := %00000010; // разрешение для int1
     asm sei end; // разрешение прерывания - глобальное
    //  Все прерывание разрешены все, установлено от INT1 по любому переходу, есть обработчик
    Uart1_Init(9600);      // Инит канал связи с ПК
    // Передаем буфер
    // Передача с младшего бита к старшему, от младшего байта к старшему
    While ( 1>0 ) Do      // т.е. циклись бесконечно
      Begin
        // Ждем передачи любого симбола с ПК для старта
        timeout('S', tikpriem);
       // Начальные установки передачи и приема
        stran:='WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW';    // Типа обнуление приемного буфера
        flag1440:=0;       // Флаг начало запуска периода 1,5 передачи бита
        bindex:=0;         // Индекс буфера приема = Обязательно
        flagsinxro:=0;     // Сброс флага синхронизации, ждем  кода синхр  0xAA или 0x55
        tmout:=0;          // Счетчик до 2 сек, чтоб не повиснуть на приеме при ошибке или отсутсвии передачи
        // Поехали
        flagstop:=0xFF;    // Разрешаем работу приемнику = СТАРТ ЕМУ
        SendBuf;           // Запустим передачу буфера ssend
        Delay_ms(10);      // Отладочная задержка
        flagstop:=0;       // стоп приемник;
        // Вывод результата и отладочной информации
        WordToStr(tmout,su);   Uart1_Write_Text(su);  // Вывод количества тиков таймера на прием всего буфера
        uartLN;  // На новую строку
        // Выведем принятый буфер
        For bbb:=0 To 30 Do Begin Uart1_Write(stran[bbb]); End;
        uartLN;   // На новую строку
        // подсчитаем КС принятого буффера и сравним с переданным
        b00:=0;
        For bbb:=1 To 25 Do b00:=b00+stran[bbb];
        Uart1_Write_Text('Длина Инфо = '); ByteToStr(stran[0],su);          Uart1_Write_Text(su);
        Uart1_Write_Text(' | КС передана = '); ByteToStr(ssend[28],su);     Uart1_Write_Text(su);
        Uart1_Write_Text(' | КС подсчитана приема = '); ByteToStr(b00,su);  Uart1_Write_Text(su);
        uartLN;   // На новую строку
        timeout('I',flagsinxro);   // Вывод полученного байта сихронизации

      End;
end.

 

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Наш человек!

   if (flagstop=0)  then goto goend;      // Если прием не включен = выйди
   if (flag1440>0)  then goto goend;      //  Если была включена задержка
...
    if (flagstop=0)  then goto goend;    // Если прием не включен = выйди
...
             goto goend;    //  Счетчик прерываний, если более 2,2 сек

Мужчина!

Щас структурасты с мисрастами набигут, начнут корованы грабить :(

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Паскаль, да еще с goto, это не просто передастия, а некро-зоо-передастия! 0_0 Ин май хамбл, пАнимашь опиньён.

Short Circuit
Short Circuit аватар
Offline
Зарегистрирован: 17.05.2015
wasq
Offline
Зарегистрирован: 26.05.2018

Спасибо, ранее не видел, посмотрел. Очень много кода и функций и таймер используеться для измерения импульса, а сам процесс приема или передачи все равно подвештвает  МК, моя цель была меньше кода, всего две процедуры на передачу 10-12 команд на прием 20-25 команд и причем все работает в фоновом процессе, основная программа может заниматься еще чем пожелает, а здесь буфер пусть передаеться или принимаеться и не мешает работе основной  программе.

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

 

miks69
Offline
Зарегистрирован: 16.02.2020

Столкнулся с похожей задачей, а именно необходимостью принять и разобрать сигнал от имеющегося термо-радиодатчика, передаваемый, как выяснилось, в манчестер-коде. До этого для приема данных с термодатчика я некоторое время использовал готовое решение от Nodo RFLink Gateway - http://www.rflink.nl/blog2/easyha, представляющее из себя закрытую прошивку для Меги, т.е. для передачи полученной информации необходимо использовать дополнительный контроллер. При этом, как показала практика, прием сигнала очень не стабильный, прошивка периодически зависает. По качеству приема я сначала грешил на приемник (китайское дешевое дерьмо), а вот с зависаниями пришлось бороться программно, отправляя на Мегу ресет всякий раз, когда прошивка перестает отвечать на запрос. Когда мне все это порядком надоело я начал сам разбираться в этом зоопарке протоколов передачи данных от радиодатчиков. Безуспешно перепробовал многочисленные найденные неработающие поделки, включая целый набор клонов якобы исходного кода упомянутого проекта. Изучая код таких доморощенных поделок в попытках запустить их в работу, я пришел к выводу, что все это, как говорится, не то. Как верно заметил автор данной темы: "Очень много кода и функций и для измерения импульса используется таймер, а сам процесс приема или передачи все равно подвешивает МК". Отсюда и неустойчивый прием, и зависания, и все остальные пляски с бубном.

По этой причине для своих экспериментов я выбрал библиотеку RCSwitch - https://github.com/sui77/rc-switch, в которой измерение импульсов и прием сигнала ведется по аппаратным прерываниям, что, на мой взгляд, гораздо надежнее и, главное, оставляет контроллеру время на выполнение основной программы. Да и код написан куда более профессионально и понятно.

В исходном варианте библиотека уверенно принимает и обрабатывает данные типовых радиодатчиков, работающих по принципу ШИМ-модуляции. Кроме того, судя по дате последних изменений, библиотека по прежнему поддерживается автором. Кстати говоря, я с легкостью добавил к ней описание протокола найденного у себя в эфире соседского термо-радиодатчика, также использующего ШИМ, но с другим соотношением длительности импульсов.

Но вернемся к манчестер-кодированию, которое, как известно, использует метод наложения передаваемых данных на импульсы синхронизации. Такой подход, как уже было описано выше, вынуждает нас синхронизировать прием и считывать данные, дождавшись очередного синхроимпульса. И здесь нас опять выручают аппаратные прерывания, поскольку длительность синхроимпульсов может варьироваться в диапазоне +/- 12%. В итоге, доработка процедуры обработки прерывания указанной библиотеки для устойчивого приема сигнала в манчестер-коде вылилась у меня в пару десятков строк кода и несколько дней отладки (без осциллографа, т.е. что называется методом тыка). Расшифровка полученных данных много времени не заняла, поскольку информации на эту тему в сети достаточно, да и исходные коды опробованных ранее библиотек оказались очень даже кстати. Результат меня порадовал, теперь все работает стабильно и принимает все передачи от радиодатчиков без исключения даже с дешевым китайским приемником. А главное, что я теперь могу использовать такой код как часть основной прошивки контроллера, выполняющей также и другие задачи.

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

AleksBAM
Offline
Зарегистрирован: 13.09.2014

miks69, можете поделиться своим кодом. Хочу собрать приемник , для получения данных от беспроводного датчика китайской метеостанции. И передачи на народный мониторинг (narodmon.ru). Сигнал прочитал с помощью осциллографа. 

miks69
Offline
Зарегистрирован: 16.02.2020

И что за сигнал? Манчестер? Можете выложить скриншот?

AleksBAM
Offline
Зарегистрирован: 13.09.2014

Импульс длительностью около 510мкс. Стартовая пауза около 7500мкс. Короткая пауза около 2100мкс. Пауза между пачками импульсов около 4200мкс.

Данные в пакете повторяются 5 раз.  В пакете 42 бита.

xx0010010001000000101001011010000010001011001

Следующий пакет данных отправляется через 50 секунд.

В пакете отсылается (ID,Ch, T, H, Bat, crc).

miks69
Offline
Зарегистрирован: 16.02.2020

Это не похоже на манчестер-код, да и на обычный ШИМ тоже не похоже...

На девайсе есть хоть какие-нибудь обозначения?

 

AleksBAM
Offline
Зарегистрирован: 13.09.2014

аналог метеостанции DYKIE

Расшифровку брал здесь. Показания совпали. Не разобрался с контрольной суммой. 

http://orobote.ru/получение-показаний-датчиков-метеос/

http://orobote.ru/дальнейшее-исследование-формата-пер/

 

inspiritus
Offline
Зарегистрирован: 17.12.2012

А чем не устраивает ЭТО?

наверняка еще чтонить аппаратное найдется

miks69
Offline
Зарегистрирован: 16.02.2020

AleksBAM пишет:

аналог метеостанции DYKIE

Расшифровку брал здесь. Показания совпали. Не разобрался с контрольной суммой. 

http://orobote.ru/получение-показаний-датчиков-метеос/

http://orobote.ru/дальнейшее-исследование-формата-пер/

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

Эту библиотеку пробовали - https://github.com/mchr3k/arduino-libs-manchester ?

AleksBAM
Offline
Зарегистрирован: 13.09.2014

Inspiritus, ссылка не открывается.

AleksBAM
Offline
Зарегистрирован: 13.09.2014

Этот сигнал читал на входе передатчика радиомодуля.
Форму сигнала получаемую на приемнике не читал так как нет функции записи сигнала осциллографам.

miks69
Offline
Зарегистрирован: 16.02.2020

Беру свои слова обратно, это не манчестер-код. Это обычный ШИМ, который та же библиотека RCSwitch принимает на ура. Единственное что от вас требуется, это корректно указать соотношения длительностей импульсов. По вашему описанию очень похоже на протокол BL999, прием которого подробно описан здесь - https://soltau.ru/index.php/arduino/item/526-chtenie-dannykh-datchika-po.... Я сам принимал этот код с соседского датчика с помощью указанной библиотеки, в которой добавил такое описание протокола { 400, {  1, 22 }, {  1,  5 }, {  1, 10 }, false }     // protocol 8 BL999 thermo/hydro sensor

miks69
Offline
Зарегистрирован: 16.02.2020

Расшифровка протокола в процедуре RCSwitch::receiveProtocol

		if (p == 8) {				// for protocol 8 (BL999)
		
			// checkSum = sum of nibbles
			byte sum = 0;
			unsigned long data1 = data;
			for (int i=0; i<8; i++) {
				sum += bitReverse(data1 & 0xF, 4);
				data1 >>= 4;
			}
			sum &= 0xF;
			sum = bitReverse(sum, 4);
			//RCSwitch::nCheckSum = checkSum;
			//RCSwitch::nCheckSumMatch = (sum == checkSum);
			
			if (sum == checkSum) {
			
				RCSwitch::nDeviceID = data >> 24;					// device ID
				RCSwitch::nChannelID = (data >> 26) & 0x3;			// channel ID
				RCSwitch::nBattery = ((data >> 23) & 0x1)^1;		// battery status
				//RCSwitch::unknown = (data >> 20) & 0x3;			// unknown
				
				//Temperature is stored in T4,T5,T6 nibbles, lowest nibble - first
				//since we already reversed bits order in these nibbles
				//all we have to do is to reverse nibbles order
				
				//temperature = (((int)bl999_data[5] << 8) | ((int)bl999_data[4] << 4) | (int)bl999_data[3]);

				int temperature = (RCSwitch::nReceivedValue >> 8) & 0xFFF;
				temperature = bitReverse(temperature,12);
							   
				//if ((bl999_data[5] & 1) == 1) {
				if ((temperature & 0x100) == 1) {
					
					//negative number, use two's compliment conversion
					temperature = ~temperature + 1;

					//clear higher bits and convert to negative
					temperature = -1 * (temperature & 0xFFF);
				}

				RCSwitch::nTemperature = temperature/10.0;
				
				//Humidity is stored in nibbles T7,T8
				//since bits in these nibbles are already in reversed order
				//we just have to get number by reversing nibbles orderßßß
				
				//int humidity = ((int)bl999_data[7] << 4) | (int)bl999_data[6];
				byte humidity = (RCSwitch::nReceivedValue) & 0xFF;

				//negative number, use two's compliment conversion
				humidity = ~humidity + 1;

				//humidity is stored as 100 - humidity
				RCSwitch::nHumidity = 100 - (byte)humidity;
			
			}
			
		}

Процедура bitReverse

unsigned int bitReverse(unsigned int number, byte lengh) {
  unsigned int result = 0;
  for(byte i = 0; i < lengh; i++) {
    result <<= 1;
    result |= number & 1;
    number >>= 1;
  }
  return result;
}

Получение температуры и влажности

float RCSwitch::getTemperature() {
    return RCSwitch::nTemperature;
}

byte RCSwitch::getHumidity() {
	return RCSwitch::nHumidity;
}

 

AleksBAM
Offline
Зарегистрирован: 13.09.2014

miks69. Помоги, я не понял, что исправить в библиотеке. И куда вписывать расшифровку протокола.

У меня только базовые знания.

miks69
Offline
Зарегистрирован: 16.02.2020

Создал ветку на Github - https://github.com/miksumin/rc-switch

Пример для вашего случая в папке ReceiveDemo_BL999

Качайте и пробуйте, должно работать.