PDA

View Full Version : Pulse Decoding



Freman
- 29th May 2008, 14:04
G'day there.

I've still trying to replace a pic on a board. I've got a whole new approach that I'm working on.

I want to decode the pulses received from the RF receiver.

I don't have a CRO or anything useful like that, but can anyone give me any idea how I might have the pic read these pulses and store details about them in eeprom?

Or perhaps how I can read and compare these pulses to a list of knowns? (I have the specs on the transmitter, but not the receiver)

EDIT -

Ok, I've hacked myself up a cheap scope (sound card + voltage divider :))

UP: http://img443.imageshack.us/my.php?image=05292008235605zw2.png
Stop: http://img47.imageshack.us/my.php?image=05292008235856ae3.png
Down: http://img47.imageshack.us/my.php?image=05302008000034iy4.png

So um... anyone know how I might go about reading these signals with a PIC/picbasic? :)

dhouston
- 29th May 2008, 15:38
Is that all there is to the code? Frequently there is a wide pulse/space pair that acts as a Start of Frame marker.

What type of transmitter? receiver? ASK vs. FSK and whether or not there is a carrier detect signal makes a huge difference in how you detect the start of a transmission.

The codes themselves are quite simple, containing 24 data bits (the last pulse is an End of Frame marker). Each bit has a fixed period (~0.67mS) and the width of the pulse determines 1 vs. 0. I would assign 1 to the wider pulses and just use PulsIn to capture them.

Freman
- 29th May 2008, 15:53
I don't honestly know what type of receiver.

This is the transmitter chip: http://pdf1.alldatasheet.com/datasheet-pdf/view/205521/PTC/PT2264.html
it's running at around 12v and has a 1.5 mOhm resistor on it's osc.

This is what I've worked out with the scope program - Give or take

600u whole bit.

1: 450 high, 150 low
0: 150 high, 450 low

UP: 11110001001101011100000
Stop: 11110001001101001100000
Down: 11110001001101100000011

dhouston
- 29th May 2008, 16:47
That's not the transmitter. It's just the encoder chip.

Bruce Reynolds has posted code for decoding these signals. I don't recall whether it was this specific encoder or a Holtek encoder which works the same way.

There is no Start of Frame so you have to detect the long silence which occurs between codes and capture/decode the 2nd or later copy. A search here will turn up Bruce's code. Or, he's likely to jump in and point you to it.

Bruce
- 30th May 2008, 14:36
I posted a simple example for decoding a Holtek 8-bit encoder here;
http://www.picbasic.co.uk/forum/showthread.php?t=6581

The Holtek 640 encoder is similar to the one you have with 2 pulses per bit, but the Holtek
packets are 10-bit address with 8-bit data. It should at least give you a good base to start
from.

Here's a simple chopped-down version example of decoding a Holtek HT12E.


DEFINE OSC 20 ' 20MHz xtal

DEFINE PULSIN_MAX 3000 ' Set MAX wait for pulses to speed-up response time
PBIT VAR BYTE[12]' Pulse-in values after NCD
NUMS VAR WORD ' RAW pulsin value
ADDRESS VAR BYTE ' address
DBYTE VAR BYTE ' data byte
X VAR BYTE ' GP loop counter
Y VAR BYTE ' GP variable
DIN VAR PORTB.0 ' Data input direct from HT12E encoder IC

TRISB.0=1

GET_ADD:
ADDRESS=0 : DBYTE=0 : NUMS=0

GET_P:
PULSIN DIN,1,NUMS
IF NUMS < 100 THEN GET_P '
' if sync pulse is less than 200uS restart.
FOR X = 0 TO 11 ' read 12 pulses
PULSIN DIN,1,NUMS '
PBIT[X] = NCD NUMS ' convert high-bit-set
NEXT X ' loop until done

' Get address
ADDRESS=$FF ' start with all 1's and find each 0
FOR X = 0 TO 7 ' PBIT bytes 0 to 7 = address
IF PBIT[X] >7 THEN ADDRESS.0[X] = 0 ' If NCD val > 7 it's a 0
NEXT X

' Get data
Y=0
DBYTE=$0F ' start with all 1's and find each 0
FOR X = 8 TO 11 ' PBIT bytes 8 to 11 = encoder 4-bit data
IF PBIT[X] >7 THEN DBYTE.0[Y]=0' DBYTE bits 0 to 3 are our data-bits
Y=Y+1
NEXT X

' show results
HSEROUT ["ADD = ",IBIN8 ADDRESS," : ",IDEC ADDRESS,13,10]
HSEROUT ["DAT = ",IBIN4 DBYTE," : ",IDEC DBYTE,13,10]
GOTO GET_ADD

END
The .JPG file attached shows a logic analyzer capture of the HT12E output.

Serial terminal result;
ADD = %10111011 : #187
DAT = %1011 : #11

This matches the address & data I had set on the HT12E encoder when the program ran.
You can change the address & data, press /TE, and watch the results on-screen.

Note: This code example is a chopped version with only a single-pass. In most
applications you will want to do 2 or 3 passes, then verify multiple address/data packets
before you change a decoders outputs. Otherwise it's prone to errors.

This version is suceptible to noise. That's why it was tested with a direct connection from
encoder to PIC input. This remains stable. The data output of an RF receiver however, is a
diferent story. You'll se a TON of noise pulses there.

The tricky part is working in the multi-pass & verify routines. That part I can't share...;o}

Freman
- 31st May 2008, 17:58
Thanks for the information Bruce.

My input signal appears to be high and fairly noisy with pulses low - I really need a real scope :(

If I read the code you provided correctly, it shouldn't reach GOTO GET_ADD without receiving a full pulse (or at least a full initial pulse)

Mine's running all the way through without thinking about it, even with a resistor to gnd and no actual signal.

I don't have a uart hooked up to this board at the moment so I'm just storing the values in eeprom - they're all showing up as 0's

- Edit

Oh dear, spoze if it wasn't 3 am and I'd had some coffee I would have done some thinking :)

1) 4 mhz clock (getting 20 mhz crystals tomorrow, ran out)
2) This is probably a one off - so at the very least I can look for 4 high pulses at the start, if not look specifically for more components of the bitstream

I'll go to bed now and resume banging head on desk tomorrow.

Freman
- 1st June 2008, 13:45
Ok, so further testing - this time using Audacity to record the waveforms as it gives me more freedom to scroll back and forth - has resulted in the following 3 waveforms: http://img527.imageshack.us/my.php?image=06012008222006dl4.png

I'm going to opt to completely ignore the first transmission sequence as the start of it is a little messed up and target the second transmission sequence (I pushed the button as fast as I could, I always got 2 or more sequences).

So the following code is what I've got (haven't run it yet).

Does it look right?

I was playing around with it before as '1's instead of '0's in pulsin but it was picking up the block of 0's not the block of 1's. (If that makes any sense)

I've decided to chop the data comming up as
ADDRESS-DATA-S
1111000100110101-11000000-0
1111000100110101-00110000-0
1111000100110101-00000011-0

Following the encoder's specs this is actually
110F01FF1000S
110F01FF0100S
110F01FF0001S
F = Floating
S = Sync

Further reading of the specs - there'll be 4 sequences. Seeing as the first of the sequence is trashed, I just need to record and compare the other 3



' Configure the FUSE options for the compiler
@ device pic16F628A, hs_osc, wdt_off, pwrt_on, lvp_off, protect_off, bod_on, cpd_off, pwrt_off, mclr_off

' Running a 4Mhz clock
DEFINE OSC 20
DEFINE PULSIN_MAX 3000

' Setup the USART
DEFINE HSER_RCSTA 90h ' Receive register to receiver enabled
DEFINE HSER_TXSTA 20h ' Transmit register to transmitter enabled
DEFINE HSER_BAUD 9600 ' Set baud rate

CMCON = 7
ALL_DIGITAL

RFIN VAR PORTB.7

INPUT RFIN

PBITS VAR BYTE[17] ' The bits we've read
RAW VAR BYTE ' The raw pulsin value
ADDRESS VAR WORD ' Storage for the address
DBYTE VAR BYTE ' Storage for the data
X VAR BYTE
Y VAR BYTE


GET_ADD:
ADDRESS = 0 : RAW = 0 : DBYTE = 0

GET_PULSE:
' Count 4 long pulses.
FOR x = 0 TO 3
PULSIN RFIN, 0, RAW
if RAW < 220 OR RAW > 230 THEN GET_PULSE
NEXT X

' Count 3 short pulse.
FOR X = 0 to 2
PULSIN RFIN, 0, RAW
IF RAW < 70 OR RAW > 80 THEN GET_PULSE
NEXT X

' Read 9 address bits and 8 data bits
FOR X = 0 TO 16
PULSIN RFIN, 0, RAW
PBITS[x] = NCD RAW
NEXT X

' Read a sync bit
PULSIN RFIN, 0, RAW
IF RAW < 70 OR RAW > 80 THEN GET_PULSE


ADDRESS = 511 ' Maxmimum known ID
FOR X = 0 to 8
IF PBITS[x] > 7 THEN ADDRESS.0[X] = 0
NEXT X

DBYTE = 255 ' Maximum known data value
Y=0
FOR X = 9 TO 16
IF PBITS[X] > 7 THEN DBYTE.0[Y] = 0
Y = Y + 1
NEXT X


IF ADDRESS > 0 THEN
WRITE 1, ADDRESS.LowByte
WRITE 2, ADDRESS.HighByte
Write 3, DBYTE
HSEROUT ["ADD = ",IBIN9 ADDRESS," : ",IDEC ADDRESS,13,10]
HSEROUT ["DAT = ",IBIN8 DBYTE," : ",IDEC DBYTE,13,10]
ENDIF
GOTO GET_ADD
END

dhouston
- 1st June 2008, 14:47
I'm going to opt to completely ignore the first transmission sequence as the start of it is a little messed up and target the second transmission sequence (I pushed the button as fast as I could, I always got 2 or more sequences).You will always need 2 or more copies of the code as the first (and sometimes the second, third and...) will always be messed up. This is because the receiver's AGC/ATC circuitry has not yet adapted to the signal strength. How many are messed up depends on the strength of the signal. This is why I never recommend using 10101010 type sequences as a start of frame marker. In this case, Bruce uses the long silence that follows each copy of the code as a start of frame marker for the next. All you can do is test each bit and abort if the pulse or space width exceeds a maximum. I define MAX PULSE for this.

I was playing around with it before as '1's instead of '0's in pulsin but it was picking up the block of 0's not the block of 1's. (If that makes any sense)With this particular protocol, the bit period is constant and the pulses and spaces are complementary (i.e wide pulse & narrow space and vice versa) so it really doesn't matter whether you use 1 or 0 with PulsIn.

Freman
- 1st June 2008, 20:47
Yes I've slept on it, so I'll be aiming for the long low pulse as my 'start of sequence' then working on the bits. It annoys me that I have to go to work for 8 hours before I can test this :)

Edit

Ok, so the long pulse is 4.6 ms long - so I should increase DEFINE PULSIN_MAX 3000 to say DEFINE PULSIN_MAX 5000 yes?

Or is that calculated the same was as the actual pulsein is calculated...

ie: DURATION / CLOCKSPEED

In which case... 3000 is just perfect

Freman
- 2nd June 2008, 14:17
Well here we go, and it even works - well there's no false positives, but some times it doesn't activate, but better then it was.



' Configure the FUSE options for the compiler
@ device pic16F628A, hs_osc, wdt_off, pwrt_on, lvp_off, protect_off, bod_on, cpd_off, pwrt_off, mclr_off

' Running a 4Mhz clock
DEFINE OSC 20
DEFINE PULSIN_MAX 3000

CMCON = 7
ALL_DIGITAL

' Setup the USART
DEFINE HSER_RCSTA 90h ' Receive register to receiver enabled
DEFINE HSER_TXSTA 20h ' Transmit register to transmitter enabled
DEFINE HSER_BAUD 9600 ' Set baud rate

RFIN VAR PORTB.7

INPUT RFIN

PBITS VAR BYTE[24] ' The bits we've read
RAW VAR WORD ' The raw pulsin value
ADDRESS VAR WORD ' Storage for the address
DBYTE VAR BYTE ' Storage for the data
LOOPDBYTE VAR BYTE
LOOPADDRESS VAR WORD
X VAR BYTE
Y VAR BYTE

GET_ADD:
ADDRESS = 0 : RAW = 0 : DBYTE = 0

GET_PULSE:
' Look for one huge low pulse
PULSIN RFIN, 0, RAW
' 2350 is about mean average
IF RAW < 2330 OR RAW > 2370 THEN GET_PULSE

' Read 16 address bits and 8 data bits
FOR X = 0 TO 23
PULSIN RFIN, 0, RAW
PBITS[x] = NCD RAW
NEXT X

ADDRESS = 65535 ' Maxmimum known ID
FOR X = 0 to 15
IF PBITS[x] > 7 THEN ADDRESS.0[X] = 0
NEXT X

DBYTE = 255 ' Maximum known data value
Y=0
FOR X = 16 TO 23
IF PBITS[X] > 7 THEN DBYTE.0[Y] = 0
Y = Y + 1
NEXT X

' If we've done a loop...
IF ADDRESS == LOOPADDRESS AND DBYTE == LOOPDBYTE THEN
SELECT CASE DBYTE
CASE 3
GOSUB subUp
CASE 12
GOSUB subStop
CASE 192
GOSUB subDown
END SELECT
LOOPDBYTE = 0
LOOPADDRESS = 0
ELSE
' Start a loop
LOOPDBYTE = DBYTE
LOOPADDRESS = ADDRESS
ENDIF

GOTO GET_ADD
END

subUp:
HSEROUT ["UP",10,13]
RETURN

subStop:
HSEROUT ["STOP", 10, 13]
RETURN

subDown:
HSEROUT ["DOWN",10,13]
RETURN


Any suggestible improvements? (btw, thanks for all the help so far

skimask
- 2nd June 2008, 16:02
Increase your pulsin_max until it kicks out a false positive, then back up a bit.

dhouston
- 2nd June 2008, 16:30
When looking for a long-0 pulse, DEFINE MAX PULSE really doesn't do anything. It's only useful when looking for a long 1-pulse.

I suggest testing each bit as received and aborting if it is shorter than the shortest normal 0-pulse. With a weak signal, noise pulses will appear during the silences (i.e.. 0-pulses), shortening the measured PulsIn value but they will just be superimposed on a 1-pulse. In some cases there may be insufficient time to do this test but I think it will work here. Take a look at...http://davehouston.org/rf-noise.htmto see what I mean.

Freman
- 2nd June 2008, 21:31
I'll add that check tonight dhouston.

I went with 0 instead of 1 because it gave me a much tighter average long pulse.
Almost all the long pulses were comming in qt 2355 exactly, I only added a little bit of deviation after adding the loop code.

To be honest I didn't do the math behind the short pulses, only the super massive long pulse so I will sit down and do the math to make it more accurate.

Now that the 'easy' stuff is done tho... I have to work on replicating their method for reading the input buttons as described here: http://picbasic.co.uk/forum/showthread.php?p=56697 :)