Pulse Decoding


Closed Thread
Results 1 to 13 of 13

Thread: Pulse Decoding

  1. #1
    Join Date
    May 2008
    Posts
    46

    Default Pulse Decoding

    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?i...8235605zw2.png
    Stop: http://img47.imageshack.us/my.php?im...8235856ae3.png
    Down: http://img47.imageshack.us/my.php?im...8000034iy4.png

    So um... anyone know how I might go about reading these signals with a PIC/picbasic?
    Last edited by Freman; - 29th May 2008 at 15:07. Reason: More information

  2. #2
    Join Date
    Dec 2005
    Posts
    1,073


    Did you find this post helpful? Yes | No

    Default

    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.

  3. #3
    Join Date
    May 2008
    Posts
    46


    Did you find this post helpful? Yes | No

    Default

    I don't honestly know what type of receiver.

    This is the transmitter chip: http://pdf1.alldatasheet.com/datashe...TC/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

  4. #4
    Join Date
    Dec 2005
    Posts
    1,073


    Did you find this post helpful? Yes | No

    Default

    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.

  5. #5
    Join Date
    Jul 2003
    Posts
    2,405


    Did you find this post helpful? Yes | No

    Default

    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.
    Code:
    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}
    Attached Images Attached Images  
    Regards,

    -Bruce
    tech at rentron.com
    http://www.rentron.com

  6. #6
    Join Date
    May 2008
    Posts
    46


    Did you find this post helpful? Yes | No

    Default

    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.
    Last edited by Freman; - 31st May 2008 at 18:20. Reason: More info

  7. #7
    Join Date
    May 2008
    Posts
    46


    Did you find this post helpful? Yes | No

    Default

    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?i...8222006dl4.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

    Code:
    ' 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
    Last edited by Freman; - 1st June 2008 at 14:04.

  8. #8
    Join Date
    Dec 2005
    Posts
    1,073


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by Freman View Post
    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.

  9. #9
    Join Date
    May 2008
    Posts
    46


    Did you find this post helpful? Yes | No

    Default

    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
    Last edited by Freman; - 2nd June 2008 at 03:07.

  10. #10
    Join Date
    May 2008
    Posts
    46


    Did you find this post helpful? Yes | No

    Default

    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.

    Code:
    ' 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

  11. #11
    skimask's Avatar
    skimask Guest


    Did you find this post helpful? Yes | No

    Default

    Increase your pulsin_max until it kicks out a false positive, then back up a bit.

  12. #12
    Join Date
    Dec 2005
    Posts
    1,073


    Did you find this post helpful? Yes | No

    Default

    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...to see what I mean.

  13. #13
    Join Date
    May 2008
    Posts
    46


    Did you find this post helpful? Yes | No

    Default

    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
    Last edited by Freman; - 2nd June 2008 at 23:47.

Similar Threads

  1. Pulse Capture and byte building
    By boroko in forum mel PIC BASIC Pro
    Replies: 2
    Last Post: - 21st July 2009, 01:59
  2. Single digit 7 Seg LED clock - PIC16F88
    By thirsty in forum Code Examples
    Replies: 4
    Last Post: - 17th July 2009, 08:42
  3. Replies: 3
    Last Post: - 13th September 2008, 17:40
  4. Decoding an incoming infrared signal: need advice
    By xnihilo in forum mel PIC BASIC Pro
    Replies: 10
    Last Post: - 9th May 2008, 16:28
  5. Pulse Frequency Multiplication
    By jamie_s in forum mel PIC BASIC Pro
    Replies: 2
    Last Post: - 21st August 2005, 10:39

Members who have read this thread : 1

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts