インターネットでは、BUROステーションを交換するためのプロトコルの説明は見つかりませんでした。 これは、このワイヤレスセンサーの交換のプロトコルを開く必要があることを意味します。
私の外部温度計は次のようになります。

中国の超回生433.92 MHzレシーバーをオシロスコープに接続し、温度計のTESTボタンを押すと、送信パルスがどのように流れているかがはっきりと見えました。 さて、周波数が小さいため、レシーバーの出力は抵抗分割器を介してサウンドカードの入力に接続されていました。 録音されたサウンドファイルを処理した後、コンパレータは次の図を確認しました。

他の気象ステーションと同様に、変調はデューティサイクルを変更することによって実行されます。 送信はクロックブロックから始まり、別のクロック信号があり、次にデータがあり、その後に最終クロック信号が送られます。 クロック信号の後の2つのゼロは、明らかに、データの先頭の識別子です。いずれにしても、私はそれらの変化に気付いたことはありません。 開始および終了クロックを持つデータは6回複製されます。 データ交換はニブルによって実行されます。
デコードのために、最初のクロックと2つのゼロで受信を開始し、最後のクロックで終了することにしました。
このような信号をデコードするには、信号がドロップする間隔を計算するだけで十分です。
このために、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ボー。
デコード後、次のデータストリームを取得します(2つの先行ゼロを捨てます)。
//ボタンなし、チャンネル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)は何らかの理由で、気象観測所では通常とは異なる形式に設定されています。 私が見つけたさまざまな気象観測所の交換プロトコルの説明から判断すると、10分の1度の温度と、温度計の下限のシフトが予想されます。 だから 実験により、この気象観測所の温度コードは(T-1220)/ 18として摂氏温度に変換されることが示されました。 これらのマジックナンバーは、この交換プロトコルを思いついた中国人だけにどのように知られていますか。
wolowizardがコメントで示唆したように、ステーションは華氏の10分の1単位で温度を転送するため、摂氏の意味のある換算は0.1 *(T-320)* 5 / 9-500 = 0.1 *(T-1220)/1.8になります。
ビットKは、TESTボタンを押すことに対応します。
残りのフィールドの割り当ては確立できませんでしたが、温度計の華氏/摂氏スイッチの値が交換プロトコルに入らないことが判明しました。 おそらく、最後のニブル(または最後から2番目のニブル)もCRCですが、アルゴリズムの計算に成功していません(計算にニブルの行と列が関与している疑いがあります)。 誰もがこの謎を解決できる場合は、計算アルゴリズムを教えてください。
頭を悩ませたいが、そのような体温計を持っていない人のために、受け入れられたデータの表を提供します。
テーブル
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