استخدام ميزان الحرارة اللاسلكي Buro H999 الخارجي مع الأجهزة المنزلية

الجميع في حالة جيدة في محطة الطقس Buro H146G مع ميزان الحرارة اللاسلكي الخارجي H999. ولكن فقط لرؤية القراءات على شاشتها LCD الباهتة تتطلب إضاءة جيدة. وسيكون من الأفضل بالنسبة لي إذا تم عرض إخراج درجة الحرارة والرطوبة خارج النافذة على مؤشرات ساطعة بما فيه الكفاية (على سبيل المثال ، الجمع بين عرض درجة الحرارة والرطوبة مع عقارب الساعة في مؤشرات تصريف الغاز IN-12). ليس من الصعب إنشاء مثل هذه الطائرة ، لكن عليك معرفة بروتوكول التبادل باستخدام مقياس حرارة لاسلكي. كانت هناك بالفعل مقالات حول استخدام مقياس حرارة محطة الطقس اللاسلكية للحصول على درجة الحرارة والرطوبة على الهواء. لكن بالنسبة لمحطات Buro ، لم يتم بعد وصف بروتوكول التبادل. لذلك ، نحن بحاجة إلى إصلاحه: ربما شخص ما يمكن أن يكون في متناول اليدين.

على الإنترنت ، لم أجد وصفًا للبروتوكول لتبادل محطات BURO. وهذا يعني أنه يجب عليك فتح بروتوكول تبادل هذا المستشعر اللاسلكي.

يشبه ميزان الحرارة الخارجي الخاص بي هذا:



من خلال توصيل مستقبل صيني بقوة 433.92 ميغاهيرتز بمستقبل الذبذبات والضغط على زر TEST على مقياس الحرارة ، كان من الواضح بوضوح كيف كانت نبضات الإرسال تعمل. حسنًا ، بما أن التردد قليل ، فقد تم توصيل إخراج المستقبل بإدخال بطاقة الصوت عبر مقسم مقاوم. بعد معالجة ملف الصوت المسجل ، قام المقارن بإظهار الصورة التالية:



كما هو الحال مع محطات الطقس الأخرى ، يتم التعديل عن طريق تغيير دورة العمل. يبدأ الإرسال من كتلة الساعة ، ثم هناك إشارة ساعة أخرى ، ثم هناك بيانات ، وبعدها تذهب إشارة الساعة النهائية. ظاهرتان بعد إشارة الساعة ، على ما يبدو ، هما معرف بداية البيانات - على أي حال ، لم ألاحظ تغيرها أبدًا. يتم تكرار البيانات مع بداية ونهاية الساعة ست مرات. ويتم تبادل البيانات من قبل يقضم.

من أجل فك التشفير ، قررت أن أبدأ في استلام الساعة الأولى واثنين من الأصفار ، وأنهي الساعة الأخيرة.

لفك تشفير هذه الإشارة ، يكفي حساب المدة بين قطرات الإشارة.

لهذا ، كتبت برنامج اختبار بسيط لوحدة التحكم Atmega8:

برنامج Atmega8
//---------------------------------------------------------------------------------------------------- // //---------------------------------------------------------------------------------------------------- #include <avr/io.h> #include <util/delay.h> #include <string.h> #include <stdlib.h> #include <stdbool.h> #include <stdio.h> #include <avr/interrupt.h> #include <avr/pgmspace.h> #include <string.h> #include <stdbool.h> #include <stdint.h> //---------------------------------------------------------------------------------------------------- //  //---------------------------------------------------------------------------------------------------- #define F_CPU 8000000UL //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //   UART, / #define UART_SPEED 9600UL //---------------------------------------------------------------------------------------------------- // //---------------------------------------------------------------------------------------------------- //  enum BLOCK_TYPE { BLOCK_TYPE_UNKNOW,//  BLOCK_TYPE_DIVIDER,// BLOCK_TYPE_SYNCHRO,// BLOCK_TYPE_ONE,// BLOCK_TYPE_ZERO// }; //  enum MODE { MODE_WAIT_SYNCHRO,//  MODE_WAIT_ZERO_FIRST,//   MODE_WAIT_ZERO_SECOND,//   MODE_RECEIVE_DATA//  }; //---------------------------------------------------------------------------------------------------- //  //---------------------------------------------------------------------------------------------------- static const uint16_t MAX_TIMER_INTERVAL_VALUE=0xFFFF;//    static volatile bool TimerOverflow=false;//    static uint8_t Buffer[20];//   static uint8_t BitSize=0;//   static uint8_t Byte=0;//  //---------------------------------------------------------------------------------------------------- //  //---------------------------------------------------------------------------------------------------- void InitAVR(void);//  void UART_Write(unsigned char byte);//   COM- void SendText(const char *text);//   COM- void RF_Init(void);// void RF_SetTimerOverflow(void);//    void RF_ResetTimerOverflow(void);//    bool RF_IsTimerOverflow(void);//,     uint16_t RF_GetTimerValue(void);//   void RF_ResetTimerValue(void);//   BLOCK_TYPE RF_GetBlockType(uint32_t counter,bool value);//   void RF_AddBit(bool state);//   void RF_ResetData(void);//    void RF_AnalizeCounter(uint32_t counter,bool value,MODE &mode);//  //---------------------------------------------------------------------------------------------------- //   //---------------------------------------------------------------------------------------------------- int main(void) { InitAVR(); _delay_ms(200); SendText("Thermo unit\r\n"); _delay_ms(200); sei(); while(1); cli(); } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //  //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //---------------------------------------------------------------------------------------------------- //  //---------------------------------------------------------------------------------------------------- void InitAVR(void) { //  DDRB=0; DDRD=0; DDRC=0; //   PORTB=0; PORTD=0; PORTC=0; //    UART UCSRB=(1<<RXEN)|(1<<TXEN)|(0<<RXCIE); //RXCIE=1    ( I=1   SREG) :      UART  //TXCIE=1    ( I=1   SREG) :      UART  //UDRIE=1    ( I=1   SREG) :      UART  //RXEN=1 :  ,  D0   UART. //TXEN=1 :  ,  D1   UART. //CHR9=1 :       11  (9   + -  + -). //RXB8- - //TXB8- - //      unsigned long speed=F_CPU/(16UL); speed=(speed/UART_SPEED)-1UL; UBRRH=(speed>>8)&0xff; UBRRL=speed&0xFF; RF_Init(); } //---------------------------------------------------------------------------------------------------- //   COM- //---------------------------------------------------------------------------------------------------- void UART_Write(unsigned char byte) { while(!(UCSRA&(1<<UDRE))); UDR=byte; } //---------------------------------------------------------------------------------------------------- //   COM- //---------------------------------------------------------------------------------------------------- void SendText(const char *text) { while((*text)) { UART_Write(*text); text++; } } //---------------------------------------------------------------------------------------------------- // //---------------------------------------------------------------------------------------------------- void RF_Init(void) { //   ACSR=(0<<ACD)|(1<<ACBG)|(0<<ACO)|(0<<ACI)|(1<<ACIE)|(0<<ACIC)|(0<<ACIS1)|(0<<ACIS0); //ACD -   (0 - !) //ACBG -       ' //ACO -   ( ) //ACI -     //ACIE -     //ACIC -       T1 //ACIS1,ACID0 -      //  T1   31250  TCCR1A=(0<<WGM11)|(0<<WGM10)|(0<<COM1A1)|(0<<COM1A0)|(0<<COM1B1)|(0<<COM1B0); //COM1A1-COM1A0 -   OC1A //COM1B1-COM1B0 -   OC1B //WGM11-WGM10 -    TCCR1B=(0<<WGM13)|(0<<WGM12)|(1<<CS12)|(0<<CS11)|(0<<CS10)|(0<<ICES1)|(0<<ICNC1); //WGM13-WGM12 -    //CS12-CS10 -    (      256 (  31250 )) //ICNC1 -       //ICES1 -      TCNT1=0;//   TIMSK|=(1<<TOIE1);//    ( T1 ) } //---------------------------------------------------------------------------------------------------- //    //---------------------------------------------------------------------------------------------------- void RF_SetTimerOverflow(void) { cli(); TimerOverflow=true; sei(); } //---------------------------------------------------------------------------------------------------- //    //---------------------------------------------------------------------------------------------------- void RF_ResetTimerOverflow(void) { cli(); TimerOverflow=false; sei(); } //---------------------------------------------------------------------------------------------------- //,     //---------------------------------------------------------------------------------------------------- bool RF_IsTimerOverflow(void) { cli(); bool ret=TimerOverflow; sei(); return(ret); } //---------------------------------------------------------------------------------------------------- //   //---------------------------------------------------------------------------------------------------- uint16_t RF_GetTimerValue(void) { cli(); uint16_t ret=TCNT1; sei(); return(ret); } //---------------------------------------------------------------------------------------------------- //   //---------------------------------------------------------------------------------------------------- void RF_ResetTimerValue(void) { cli(); TCNT1=0; sei(); RF_ResetTimerOverflow(); } //---------------------------------------------------------------------------------------------------- //   //---------------------------------------------------------------------------------------------------- BLOCK_TYPE RF_GetBlockType(uint32_t counter,bool value) { static const uint32_t DIVIDER_MIN=(31250UL*12)/44100UL; static const uint32_t DIVIDER_MAX=(31250UL*25)/44100UL; static const uint32_t ZERO_MIN=(31250UL*80)/44100UL; static const uint32_t ZERO_MAX=(31250UL*100)/44100UL; static const uint32_t ONE_MIN=(31250UL*160)/44100UL; static const uint32_t ONE_MAX=(31250UL*200)/44100UL; static const uint32_t SYNCHRO_MIN=(31250UL*320)/44100UL; static const uint32_t SYNCHRO_MAX=(31250UL*400)/44100UL; if (counter>DIVIDER_MIN && counter<DIVIDER_MAX) return(BLOCK_TYPE_DIVIDER);// if (counter>ZERO_MIN && counter<ZERO_MAX) return(BLOCK_TYPE_ZERO);// if (counter>ONE_MIN && counter<ONE_MAX) return(BLOCK_TYPE_ONE);// if (counter>SYNCHRO_MIN && counter<SYNCHRO_MAX) return(BLOCK_TYPE_SYNCHRO);// return(BLOCK_TYPE_UNKNOW);//  } //---------------------------------------------------------------------------------------------------- //   //---------------------------------------------------------------------------------------------------- void RF_AddBit(bool state) { if ((BitSize>>2)>=19) return;//  Byte<<=1; if (state==true) Byte|=1; BitSize++; if ((BitSize&0x03)==0) { Buffer[(BitSize>>2)-1]=Byte; Byte=0; } } //---------------------------------------------------------------------------------------------------- //    //---------------------------------------------------------------------------------------------------- void RF_ResetData(void) { BitSize=0; Byte=0; } //---------------------------------------------------------------------------------------------------- //  //---------------------------------------------------------------------------------------------------- void RF_AnalizeCounter(uint32_t counter,bool value,MODE &mode) { //   BLOCK_TYPE type=RF_GetBlockType(counter,value); if (type==BLOCK_TYPE_UNKNOW) { mode=MODE_WAIT_SYNCHRO; RF_ResetData(); return; } if (type==BLOCK_TYPE_DIVIDER) return;//    //      if (mode==MODE_WAIT_SYNCHRO)//  { if (type==BLOCK_TYPE_SYNCHRO) { mode=MODE_WAIT_ZERO_FIRST; return; } mode=MODE_WAIT_SYNCHRO; RF_ResetData(); return; } if (mode==MODE_WAIT_ZERO_FIRST || mode==MODE_WAIT_ZERO_SECOND)//   { if (type==BLOCK_TYPE_SYNCHRO && mode==MODE_WAIT_ZERO_FIRST) return;//  if (type==BLOCK_TYPE_ZERO && mode==MODE_WAIT_ZERO_FIRST) { mode=MODE_WAIT_ZERO_SECOND; return; } if (type==BLOCK_TYPE_ZERO && mode==MODE_WAIT_ZERO_SECOND) { mode=MODE_RECEIVE_DATA; return; } mode=MODE_WAIT_SYNCHRO; RF_ResetData(); return; } //  if (type==BLOCK_TYPE_SYNCHRO)//  { uint8_t size=(BitSize>>2); char str[30]; if (size!=10) { mode=MODE_WAIT_SYNCHRO; RF_ResetData(); return; } //  for(uint8_t n=0;n<size;n++) { uint8_t b=Buffer[n]; uint8_t mask=(1<<3); for(uint8_t m=0;m<4;m++,mask>>=1) { if (b&mask) SendText("1"); else SendText("0"); } SendText(" "); } uint8_t channel=Buffer[2]&0x03; uint8_t key=(Buffer[8]>>3)&0x01; uint8_t h=(Buffer[7]<<4)|(Buffer[6]);// int16_t temp=(Buffer[5]<<8)|(Buffer[4]<<4)|(Buffer[3]);// int16_t k=18; int16_t t=(10*(temp-1220))/k; sprintf(str,"%i",key); SendText("Key:"); SendText(str); sprintf(str,"%i",channel+1); SendText(" Ch:"); SendText(str); sprintf(str,"%i",h); SendText(" H:"); SendText(str); SendText("%, T:"); if (t<0) { t=-t; sprintf(str,"-%i.%i",(int)(t/10),(int)(t%10)); } else { sprintf(str,"%i.%i",(int)(t/10),(int)(t%10)); } SendText(str); SendText(" C\r\n"); mode=MODE_WAIT_SYNCHRO; RF_ResetData(); return; } //  if (type==BLOCK_TYPE_ONE) { RF_AddBit(true); return; } if (type==BLOCK_TYPE_ZERO) { RF_AddBit(false); return; } mode=MODE_WAIT_SYNCHRO; RF_ResetData(); } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //   //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //---------------------------------------------------------------------------------------------------- //    T1 (16-  )   //---------------------------------------------------------------------------------------------------- ISR(TIMER1_OVF_vect) { RF_SetTimerOverflow(); } //---------------------------------------------------------------------------------------------------- //     //---------------------------------------------------------------------------------------------------- ISR(ANA_COMP_vect) { ACSR&=0xFF^(1<<ACIE);//  ACSR|=(1<<ACI);//    static MODE mode=MODE_WAIT_SYNCHRO; //   uint16_t length=RF_GetTimerValue(); if (RF_IsTimerOverflow()==true) length=MAX_TIMER_INTERVAL_VALUE;// ,    RF_ResetTimerValue(); //   bool value=true; if (ACSR&(1<<ACO)) value=false; RF_AnalizeCounter(length,value,mode); ACSR|=(1<<ACIE);//  } 


يتم توصيل الإخراج المتلقي إلى دبوس 13 (AIN1). يتصل Atmega عبر max232 بمنفذ COM للكمبيوتر (أو بمحول USB-COM). سرعة المنفذ 9600 باود.

بعد فك التشفير ، نحصل على دفق البيانات التالي (أرمي الأصفار البادئة):

// بدون زر ، القناة 1
1100 1100 0000 1110 1000 0110 1100 0001 0000 1001 الرطوبة: 28٪ درجة الحرارة: 25.4
// لا زر ، القناة 2
1100 1100 0001 1110 1000 0110 1101 0001 0000 0110 الرطوبة: 29٪ درجة الحرارة: 25.4

مجموع الحزمة يشبه هذا:



I0-I7 - معرف مقياس الحرارة. في كل مرة يتم تشغيل ميزان الحرارة ، يتغير المعرف.

C0-C1 - قناة (هناك 3 ممكن المجموع). يتم ترقيم القنوات من الصفر.

H0-H7 - الرطوبة. تتم قراءة الرطوبة كنسبة مئوية ، لكن درجة الحرارة (T0-T11) تم تعيينها لسبب ما في تنسيق غير عادي لمحطات الطقس. استنادا إلى أوصاف بروتوكولات التبادل لمحطات الطقس المختلفة التي وجدتها ، يتوقع المرء درجة حرارة في أعشار الدرجة مع حدوث تحول في الحد الأدنى لمقياس الحرارة. لذا لا. أوضحت التجارب أن كود درجة الحرارة لمحطة الطقس هذه يترجم إلى درجة مئوية مثل (T-1220) / 18. كيف تعرف هذه الأرقام السحرية فقط الصينيين الذين توصلوا إلى بروتوكول التبادل هذا.

كما اقترح wolowizard في التعليقات ، تقوم المحطة بنقل درجة الحرارة في أعشار درجة فهرنهايت ، وبالتالي فإن الترجمة الهادفة بالدرجات المئوية ستكون 0.1 * (T-320) * 5 / 9-500 = 0.1 * (T-1220) /1.8.

بت K يتوافق مع الضغط على زر اختبار.

تعذر تحديد تعيين الحقول المتبقية ، لكن اتضح أن قيمة مفتاح فهرنهايت / مئوية على مقياس الحرارة لا تدخل في بروتوكول التبادل. يُفترض أن آخر nibble (أو ربما جزء من ما قبل الأخير) هو أيضًا CRC ، لكنني لم أتمكن من حساب الخوارزمية بعد (هناك شك في أن الصفوف والأعمدة nibble متورطة في الحساب). إذا كان بإمكان أي شخص حل هذا اللغز ، فيرجى إخبارنا بخوارزمية الحساب.
بالنسبة لأولئك الذين يريدون رف أدمغتهم ، ولكن ليس لديهم مقياس حرارة كهذا ، أعطي جدولًا للبيانات المقبولة.

الجدول
 1001 0110 0101 1011 1000 0110 1000 0010 0001 1111 Key:0 Ch:2 H:40%, T:25.2 C 1001 1001 0000 1101 1010 0100 0101 0101 0000 0110 Key:0 Ch:1 H:85%, T:-1.2 C 1001 0110 0101 1100 1000 0110 1010 0010 0001 0100 Key:0 Ch:2 H:42%, T:25.3 C 1001 0110 1001 0110 0111 0110 1101 0001 0010 1111 Key:0 Ch:2 H:29%, T:24.1 C 1001 0110 1001 0000 0111 0110 1101 0001 0010 1000 Key:0 Ch:2 H:29%, T:23.7 C 1001 0110 1001 0010 0101 0110 1110 0001 0010 1111 Key:0 Ch:2 H:30%, T:22.1 C 1001 0110 1001 1001 0011 0110 1110 0001 0010 1100 Key:0 Ch:2 H:30%, T:20.7 C 1001 0110 1001 1111 0001 0110 1111 0001 0010 1010 Key:0 Ch:2 H:31%, T:19.2 C 1001 0110 0101 1001 0000 0110 0001 0010 0010 1000 Key:0 Ch:2 H:33%, T:18.0 C 1001 0110 0101 0010 1111 0101 0010 0010 0010 0111 Key:0 Ch:2 H:34%, T:16.7 C 1001 0110 0101 0100 1110 0101 0010 0010 0010 0010 Key:0 Ch:2 H:34%, T:16.0 C 1001 0110 0101 0100 1101 0101 0011 0010 0010 0001 Key:0 Ch:2 H:35%, T:15.1 C 1001 0110 0101 1100 1100 0101 0100 0010 0010 1110 Key:0 Ch:2 H:36%, T:14.6 C 1001 0110 0101 1111 1011 0101 0101 0010 0010 1111 Key:0 Ch:2 H:37%, T:13.9 C 1001 0110 0101 0011 1011 0101 0101 0010 0010 0001 Key:0 Ch:2 H:37%, T:13.2 C 1001 0110 0101 1001 1010 0101 0110 0010 0010 0101 Key:0 Ch:2 H:38%, T:12.7 C 1001 0110 0101 0100 1010 0101 0111 0010 0010 1000 Key:0 Ch:2 H:39%, T:12.4 C 1001 0110 0101 1011 1001 0101 0111 0010 0010 1010 Key:0 Ch:2 H:39%, T:11.9 C 1001 0110 0101 0011 1001 0101 1000 0010 0010 1001 Key:0 Ch:2 H:40%, T:11.5 C 1001 0110 0101 1011 1000 0101 1000 0010 0010 1110 Key:0 Ch:2 H:40%, T:11.0 C 1001 0110 0101 0111 1000 0101 1001 0010 0010 0101 Key:0 Ch:2 H:41%, T:10.8 C 1001 0110 0101 1111 0111 0101 1001 0010 0010 1101 Key:0 Ch:2 H:41%, T:10.3 C 1001 0110 0101 0111 0111 0101 1010 0010 0010 0111 Key:0 Ch:2 H:42%, T:9.9 C 1001 0110 0101 0001 0111 0101 1011 0010 0010 0101 Key:0 Ch:2 H:43%, T:9.6 C 1001 0110 0101 1011 0110 0101 1100 0010 0010 0110 Key:0 Ch:2 H:44%, T:9.2 C 1001 0110 0101 1000 0110 0101 1100 0010 0010 1100 Key:0 Ch:2 H:44%, T:9.1 C 1001 0110 0101 0011 0110 0101 1101 0010 0010 0110 Key:0 Ch:2 H:45%, T:8.8 C 1001 0110 0101 1001 0101 0101 1110 0010 0010 0110 Key:0 Ch:2 H:46%, T:8.2 C 1001 0110 0101 0101 0101 0101 1111 0010 0010 1101 Key:0 Ch:2 H:47%, T:8.0 C 1001 0110 0101 0010 0101 0101 1111 0010 0010 1100 Key:0 Ch:2 H:47%, T:7.8 C 1001 0110 0101 1110 0100 0101 1111 0010 0010 0000 Key:0 Ch:2 H:47%, T:7.6 C 1001 0110 0101 1100 0100 0101 1111 0010 0010 1100 Key:0 Ch:2 H:47%, T:7.5 C 

Source: https://habr.com/ru/post/ar432704/


All Articles