在自制设备上使用外部Buro H999无线温度计

配备外部无线温度计H999的Buro H146G气象站的每个人都很擅长。 但是,仅是要在褪色的LCD上查看读数,就需要良好的照明。 如果在窗外输出的温度和湿度显示在足够明亮的指示器上(例如,将温度和湿度显示与IN-12气体排放指示器上的时钟相结合),则对我来说会更好。 制作这种工艺品并不难,但是您需要了解与无线温度计进行交换的协议。 已经关于使用无线气象站温度计来获取空中温度和湿度的文章。 但是对于Buro站,尚未描述交换协议。 因此,我们需要对其进行修复:也许有人可以派上用场。

在Internet上,我没有找到有关交换BURO站的协议的描述。 这意味着您必须打开此无线传感器的交换协议。

我的外部温度计看起来像这样:



通过将中国的超再生式433.92 MHz接收器连接到示波器并按下温度计上的“测试”按钮,就可以清楚地看到传输脉冲的运行方式。 好吧,由于那里的频率很小,所以接收器的输出通过电阻分压器连接到声卡的输入。 处理记录的声音文件后,比较器将显示以下图片:



与其他气象站一样,通过更改占空比来进行调制。 传输从时钟块开始,然后是另一个时钟信号,然后是数据,之后是最后一个时钟信号。 时钟信号之后的两个零显然是数据开头的标识符-无论如何,我从未注意到它们的变化。 具有开始时钟和结束时钟的数据重复六次。 数据交换是通过半字节进行的。

对于解码,我决定在第一个时钟和两个零开始接收,并在最后一个时钟结束。

为了解码这样的信号,足够计算信号下降之间的持续时间。

为此,我为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。 这些魔术数字如何仅知道提出此交换协议的中国人。

正如评论员所建议的那样,气象站以十分之一华氏度的温度传递温度,因此,以摄氏度为单位的有意义的转换为0.1 *(T-320)* 5 / 9-500 = 0.1 *(T-1220)/1.8。

位K对应于按下TEST按钮。

无法确定其余字段的分配,但是事实证明,温度计上的华氏/摄氏温度开关的值未纳入交换协议中。 大概最后一个半字节(或者可能是倒数第二个半字节)也是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 

Source: https://habr.com/ru/post/zh-CN432704/


All Articles