Go Down

Topic: weather station, manchester encoding, capture (Read 2815 times) previous topic - next topic

kayno

Hi All

I have an inexpensive wireless weather station, and i wish to use an arduino to capture the data that is transmitted.

Using an RF receiver I was able to feed the transmitted data into my soundcard, and using audacity I can see that it looks like it is manchester encoded (http://en.wikipedia.org/wiki/Manchester_encoding):


(http://twitpic.com/wmblf/full)

I have captured many packets using my soundcard, and after some analysis I have worked out which bits contain the weather station id, wind direction, etc.

Now the bit where I am stuck - getting the data from the RF receiver to the arduino. I have hooked it up to pin 8, and used code such as http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1195830186/3 (using ISR(TIMER1_OVF_vect) and ISR(TIMER1_CAPT_vect).

I think I am on the right track, but I was wondering if there were some examples of this kind of capture and decoding out there that would help me out?

any help would be greatly appreciated!

kayno

Udo Klein

Would you post your code and maybe some hints on the timing requirements? That is: how high would the required sample rate be?

Cheers, Udo
Check out my experiments http://blog.blinkenlight.net

kayno

no worries Udo. i havent written any code myself, just working with several examples i have found. i guess i am stuck at the point where I am unsure exactly how to read this bitstream and decode it. here are some of the things i have tried:

I started with some code for a la crosse weather station (http://github.com/practicalarduino/WeatherStationReceiver). the main part of the input capture looks like:

Code: [Select]
#define INPUT_CAPTURE_IS_RISING_EDGE()    ((TCCR1B & _BV(ICES1)) != 0)
#define INPUT_CAPTURE_IS_FALLING_EDGE()   ((TCCR1B & _BV(ICES1)) == 0)
#define SET_INPUT_CAPTURE_RISING_EDGE()   (TCCR1B |=  _BV(ICES1))
#define SET_INPUT_CAPTURE_FALLING_EDGE()  (TCCR1B &= ~_BV(ICES1))


ISR( TIMER1_CAPT_vect )
{
 // Immediately grab the current capture time
 uiICP_CapturedTime = ICR1;

 //----------------------------------------------------------------------------
 //immediately grab the current capture polarity and reverse it to catch all the subsequent high and low periods coming in
 //If the initial period filter passes below, this will be inspected to become bICP_EventPolarity
 if( INPUT_CAPTURE_IS_RISING_EDGE() )
 {
   SET_INPUT_CAPTURE_FALLING_EDGE();      //previous period was low and just transitioned high
   bICP_CapturedPeriodWasHigh = false;    //uiICP_CapturedPeriod about to be stored will be a low period      
 } else {
   SET_INPUT_CAPTURE_RISING_EDGE();       //previous period was high and transitioned low
   bICP_CapturedPeriodWasHigh = true;     //uiICP_CapturedPeriod about to be stored will be a high period      
 }

 //----------------------------------------------------------------------------
 //calculate the current period just measured, to accompany the polarity now stored
 uiICP_CapturedPeriod = (uiICP_CapturedTime - uiICP_PreviousCapturedTime);

 //----------------------------------------------------------------------------
 // RF Pulse filtering, width test and polarity are analysed now, call the
 // interpreter(s) to analyse them
 RF_Interpreter_WS2355();

 //----------------------------------------------------------------------------
 //save the current capture data as previous so it can be used for period calculation again next time around
 uiICP_PreviousCapturedTime           = uiICP_CapturedTime;
 uiICP_PreviousCapturedPeriod         = uiICP_CapturedPeriod;
 bICP_PreviousCapturedPeriodWasHigh   = bICP_CapturedPeriodWasHigh;
}

void RF_Interpreter_WS2355()
{

   //Check if this is a valid zero(long high) or one(short high) bit, or low period in between
   if( bICP_CapturedPeriodWasHigh )
   {
     //got a high period, could be a valid bit
     if( (uiICP_CapturedPeriod >= WSR_SHORT_PERIOD_MIN) && (uiICP_CapturedPeriod <= WSR_SHORT_PERIOD_MAX) )
     {
       //short high, valid one bit
       bValidBit = WSR_BIT_ONE;
     } else if( (uiICP_CapturedPeriod >= WSR_LONG_PERIOD_MIN) && (uiICP_CapturedPeriod <= WSR_LONG_PERIOD_MAX) ) {
       //long high, valid zero bit
       bValidBit = WSR_BIT_ZERO;
     } else {
       //invalid high period, in the dead zone between short and long bit period lengths
       WSR_RESET();
     }
   }
}


but i think this particular weather station is not using manchester encoding, unless I do not correctly understand the terms "long high" and "short high"

I have also used the code in http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1195830186/0#0, which tells me:

Code: [Select]
Got 1090 pulses: min=493, max=1006 (0 timer overflows)

so re: timing - i think the short width pulse is ~500us, and the long width pulse is ~1000us. i dont think this translates directly to 1s and 0s, as they depend on where the high is within each 1000us. to better describe this:


http://alyer.frihost.net/thn128decoding.htm

(note this is not the same time of weather station as i have either, but represents manchester encoding)

essentially what i *think* i need to do is sync up with the incoming stream which starts with a long series of short width pulses, and then, keeping in mind where the clock is at, see where the pulse starts - if its at the beginning of the start of the clock period, or mid way through the clock period.

i hope this makes sense - im a little lost!

kayno

here is another screenshot of the data:

http://twitpic.com/wu7yg/full

the white gap is where i cut out the repeating short pulses to make the images less wide.

essentially there is a long series of short pulses, before the data starts.

can this be used to sync up with the stream? does anyone know of a existing library to decode this?

Udo Klein

Just to be sure that I understand you issue properly. If I understood you right the issue is not that you can not capture the data. The issue is that you can not decode it? That is: you are already able to capture and distinguish short and long pulses?

Did I get this right?
Check out my experiments http://blog.blinkenlight.net

kayno

correct Udo, i can capture the data on the arduino, using pin 8. the interrupt fires when the data comes in, its just how to decode it into the actual 1s and 0s.

kayno

#6
Jan 06, 2010, 10:47 am Last Edit: Jan 06, 2010, 10:48 am by kayno Reason: 1
my current thought process is that (based on http://twitpic.com/wu7yg/full) is that I need to look for a series of the short (horizontal) width pulses, until it changes to a long width (horizontal) pulse (a series of 1 bits followed by a 0 bit) which signifies that the data is coming up.

then to read the data, i know that if the next pulse width is short, the it is the same as the previous bit (0), else if its long, its the opposite bit (1). if i continue in this fashion - short pulse means same as previous pulse, long pulse means the opposite bit - i should have decoded the stream.

does that make sense?? i hope my use of the terms "long" and "short" pulses is correct!

Udo Klein

#7
Jan 06, 2010, 05:15 pm Last Edit: Jan 06, 2010, 05:17 pm by udoklein Reason: 1
So if I got it right you can log a sequence of "long" and "short" pulses and now need to decode them. Have you already dumped such a sequence and tried if you can decode it manually? I am asking if you already know the code you want to decode? Or do you still need to reverse engineer the code?

How do you know that it is Manchester Code / which Manchestercode it is?

http://www.virtium.com/docs/pdf/codes.pdf

Describes two different kinds of Manchester Codes.

Do you know the chip used inside the weather station?

Cheers, Udo
Check out my experiments http://blog.blinkenlight.net

kayno

Sorry Udo - i'm getting you confused i think!

I am yet to successfully capture the sequence of long and short pulses using the arduino and convert them into 1s and 0s. I have played around with this code (adapted from http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1195830186/0#0) in an attempt to do this:

Code: [Select]
#define icpPin 8        // ICP input pin on arduino

volatile unsigned int Value;     // this stores the current ICR1 value
int current_bit = 1;


/* ICR interrupt vector */
ISR(TIMER1_CAPT_vect){
  Value = ICR1;                    // save the input capture value
       if(Value < 750) {
         Serial.print(current_bit);
       } else {
         if(current_bit == 1) {
           current_bit = 0;
         } else {
           current_bit = 1;
         }

         Serial.print(current_bit);
       }

}

void setup() {
 Serial.begin(19200);

 pinMode(icpPin, INPUT);                // ICP pin (digital pin 8 on arduino) as input

 TCCR1A = 0 ;                    // this register set to 0!
 TCCR1B =_BV(CS11);              // NORMAL MODE!!, prescaller 8, rising edge ICP1 - this works
 TCCR1B |= _BV(ICES1);           // enable input capture

 TIMSK1 =  _BV(ICIE1);                         // enable input capture interrupt for timer 1
 TIMSK1 |= _BV(TOIE1);                         // enable overflow interrupt to detect missing input pulses
 Serial.print("Finished setup\r\n");
}


I believe it is manchester code because when i captured the raw signal from the RF receiver with my soundcard and analysed it, i assumed it was manchester just by how it looked, and when i decoded it to ones and zeros, i could see the weather station's station id (which is used to sync the weather transmitter to its display base station) at the start of the packet, and i also captured packets for differing wind directions (set anemometer to north, capture packet, set  anemometer  to south, capture packet, etc) with my soundcard, and i have determined which parts of the packet changed to represent the wind direction.

the type of manchester code, according to the PDF you posted, is "2.2.3 Manchester"

so what i need to do, is work out the arduino code that will capture the input, work out whether it is high/low transition and the length of the pulse, so i can determine if its a one or zero.

as i mentioned earlier, i think i can determine the 1 or 0 as follows:  the series of initial short pulses are 1s, then there is one long pulse which is a 0. from then on, if the pulse width is short, the it is the same as the previous bit (0), else if its long, it's the opposite bit (1). if i continue in this fashion - short pulse means same as previous pulse, long pulse means the opposite bit - i should have decoded the stream to 1s and 0s. from there, i can process it to determine weather station id, and the wind, rain value and temp.

the code above is trying to achieve what i just described.

the 'chips' on the weather transmitter are just black blobs (of silicon?). i have googled some of the codes on the PCB, but get no results. the weather station is this one: http://www.home-weather-stations-guide.com/thermor-weather-station.html

i believe this can be done, somehow! its quite frustrating at the moment - i have captured the packets using my soundcard, decoded them manually on paper and worked out what they mean and how they translate to the weather. i just need to get the arduino to do this!

Udo Klein

Sorry for answering that late but I was somewhat busy. Your code below has two issues which might be causing you troubles:

1) I do not see where you reset ICR1. If you do not reset it, it should most often have a value >750

2) You use Serial.print inside an ISR. This is usually not a good idea because Serial.print may take some time and during that time no other interrupts can be handled.

My suggestions would be

1) reset ICR1 after reading it
2) collect the data to be sent into a string, once a whole dataset is captured use some flag to indicate that it can be sent, send it outside the ISR.

Attention: ensure that you will never overwrite the allocated memory for the string. Either implement a ring buffer or implement some overflow check.

Cheers, Udo
Check out my experiments http://blog.blinkenlight.net

Udo Klein

Oops, you have to reset timer 1, not ICR1 ...
Check out my experiments http://blog.blinkenlight.net

Mario_H

Kayno,

I was wondering if you made any progress on the subject.
I also want to do a project involving receiving sensor data but I'm stuck at receiving and displaying the raw data packets.

Cheers,

Mario

kayno

Hi Mario

I was able to decode the manchester signal, see http://kayno.net/2010/01/18/arduino-based-thermorbios-weather-station-receiver-sketch/

Cheers
Kayne

Mario_H

Hi Kayne,

Thanks for the link.
I'll have a look to see if it can get me going.

Cheers,

Mario


Go Up