• AVR Freaks

AnsweredHot!Guidance on 433MHz PIC16F Receiver Project

Page: 123 > Showing page 1 of 3
Author
btommo
Starting Member
  • Total Posts : 89
  • Reward points : 0
  • Joined: 2017/07/07 02:59:33
  • Location: 0
  • Status: offline
2019/07/09 03:07:39 (permalink)
0

Guidance on 433MHz PIC16F Receiver Project

Hi All,
 
I'm trying to add an RF remote control capability to a circuit which acts as a self learning receiver (after button press on an input, state changes to programming state, wait for input on uart, save data to eeprom location), the remotes would be purchased elsewhere.
 
The trouble I'm having is deciphering the data seen on a 433MHz receiver module, attached is the Realterm results I received from 1 remote lock/unlock at 1200 baud rate and also without any button pressed, I have also attached the result seen on a oscilloscope for which I can provide more data for if helpful.
 
the period of each pulse seems to be approximately 1.5ms with the short high pule being high 400uS and low 1100uS and long high pulse being high 1100uS and low 400uS.
 
S = high 400uS
      low 1100uS  26.67% duty cycle
H = high 1100uS
       low 400uS   73.33% duty cycle
 
Remote 1 unlock: SSSLLLLL LLLLLLLS LSSSSSSL S 
Remote 1 lock:    SSSLLLLL LLLLLLLS LSSSSSLS S 
Remote 2 unlock: LLSSLLLL LLLLSLSS LLSSSSSL S
Remote 2 lock:     LLSSLLLL LLLLSLSS LLSSSSLS S
 
Any suggestions based on the experience anyone has on the subject of RF communication at 433MHz would be extremely helpful.
 
I'm planning on using a PIC16F1823 for this project.
 
Thanks in advance.

Attached Image(s)

#1
pcbbc
Super Member
  • Total Posts : 1101
  • Reward points : 0
  • Joined: 2014/03/27 07:04:41
  • Location: 0
  • Status: offline
Re: Guidance on 433MHz PIC16F Receiver Project 2019/07/09 03:43:41 (permalink)
0
Not quite sure why you are having a problem?  You seem to have done most of the hard work.
 
Your short and long pulses would appear to be binary 1 and 0 encoded in pulse width modulation.
Lets assume a long high pulse is a 1 and a short high pulse is a 0.  We do not know for sure unless we see the protocol spec, but really it does not matter how we represent them internally.
 
Looks like you have 25 bits of data.
Perhaps first 22 bits (maybe less) are the individual address of the remote:
SSSLLLLL LLLLLLLS LSSSSS = 00011111 11111110 100000
LLSSLLLL LLLLSLSS LLSSSS = 11001111 11110100 110000
Next 2 bits (maybe more) are the key code/function:
SL = 01 (unlock)
LS = 10 (lock)
Final bit possibly parity on previous 24 bits (all codes have 14 "L" bits = even parity)
 
Edit:
Ah - I think I see what you are asking.  You are asking how to get from the serial data received from the module to the transmitted waveforms you show on the scope?
Which RF receiver module are you using?  Is it designed for receiving from this specific key type?
Or is it just a generic 433MHz serial receiver?  For example ALPHA-RX433S?
I think most of these will have their own manufacturer specific OTA protocol, compatible with their associated transmitter.
In that case most likely the data you are seeing is just garbage.
post edited by pcbbc - 2019/07/09 03:54:06
#2
btommo
Starting Member
  • Total Posts : 89
  • Reward points : 0
  • Joined: 2017/07/07 02:59:33
  • Location: 0
  • Status: offline
Re: Guidance on 433MHz PIC16F Receiver Project 2019/07/09 04:37:13 (permalink)
0
Hi Pcbbc,
 
Thank you for your reply. The problem I was having was that the serial window didn't seem to correspond with the signal seen on the scope even though the scope used the same receiver module.
 
I'm using a cheap RF-5V module admittedly it's not the module found on the receiver paired with the remote that it originally came with which is RXB12 and has a SYN470R (can't find much detail on this). I'm ordering some of these as well.
 
Another issue I had was how to sort through the garbage for the data I need on UART (remote commands) and how to go about saving data on a remote to eeprom (I've used eeprom read/write functions for small data but not large).
post edited by btommo - 2019/07/09 04:58:54
#3
pcbbc
Super Member
  • Total Posts : 1101
  • Reward points : 0
  • Joined: 2014/03/27 07:04:41
  • Location: 0
  • Status: offline
Re: Guidance on 433MHz PIC16F Receiver Project 2019/07/09 05:44:28 (permalink)
+1 (1)
So the scope trace on the right is the output from the serial module (from remote 2 by the looks of things) and then you are feeding this same data into a UART and displaying the results in Realterm?
 
Are you sure the module you are using even outputs UART serial data?  It looks to me like it just outputs the raw demodulated 433MHz bit stream.  UART data is not PWM encoded.  The data steam you captured on the scope is PWM.  I would expect to see regular start stop bits and longer, irregular on//off periods for a UART bitstream.
 
I would be connecting the signal to one of the PIC capture compare modules, not the UART.  Then time the lengths of the pulses to decode the data.
 
Is it just this one remote key type protocol you will be learning?  If so then you do not need to store "large amounts" of data to EEPROM.  3 bytes will be sufficient per remote key (22 bit address).  Then recreate the 400us/1100us PWM signal on playback.
#4
btommo
Starting Member
  • Total Posts : 89
  • Reward points : 0
  • Joined: 2017/07/07 02:59:33
  • Location: 0
  • Status: offline
Re: Guidance on 433MHz PIC16F Receiver Project 2019/07/09 06:22:54 (permalink)
0
The trace is data out of the RF-5V module from remote 2 as an example of what is seen on scope not the serial module, what is seen on the terminal is from connecting the RF-5V module to a TTL to serial module.
 
Looking at it closely it looks like it could just be raw data as the main device on the module is a LM358 op amp, where as the RF receiver on the original unit has a circuit based around the SYN470R, which is a "single chip AFK/OOK(On Off Keyed) RF receiver IC" which is probably where I am going wrong, I've ordered a few of the receivers used on the original paired receiver to examine.
 
You were right I was mostly getting garbage 
 
I'll look into capture compare modules as an option as it's not something I've used before but may be easy to represent a high/low based on the length of time the input is high for and change into 1's and 0's to compare against a known sequence, along the right lines?
 
It would just be these remotes I would be working with for now.
post edited by btommo - 2019/07/09 06:26:10
#5
pcbbc
Super Member
  • Total Posts : 1101
  • Reward points : 0
  • Joined: 2014/03/27 07:04:41
  • Location: 0
  • Status: offline
Re: Guidance on 433MHz PIC16F Receiver Project 2019/07/09 06:36:40 (permalink)
0
btommoI'll look into capture compare modules as an option as it's not something I've used before but may be easy to represent a high/low based on the length of time the input is high for and change into 1's and 0's to compare against a known sequence, along the right lines?

Exactly.
 
Yes, the very basic 433MHz transmitter/receivers are protocol agnostic.  They just transmit a raw bitstream using OOK (On Off Keying).  That could be a UART compatible serial bit stream if you wanted, the problem is your chosen keys aren't sending a UART compatible bit stream.  Actually, it would be a quite odd design if they did.  Normally you chose some self-clocking protocol for OTA communications - PWM, PPM or Manchester Encoding are common choices.
#6
ric
Super Member
  • Total Posts : 22715
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: offline
Re: Guidance on 433MHz PIC16F Receiver Project 2019/07/09 18:21:54 (permalink)
0
Also note, OOK protocols normally send some dummy data at the start just to let AGC circuits in the receiver to settle down.
 
 

I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#7
btommo
Starting Member
  • Total Posts : 89
  • Reward points : 0
  • Joined: 2017/07/07 02:59:33
  • Location: 0
  • Status: offline
Re: Guidance on 433MHz PIC16F Receiver Project 2019/07/10 00:51:37 (permalink)
0
pcbbc - I only appear to have 1 eccp module on the PIC16F1823 which would only accomplish measuring the period of the signal, would I need a device with two, one set to rising edge (reset TMR?), one set to falling edge(high time) with both pins connected to the data pin of the receiver module? or is there a possible way around this?
 
ric- The first part of the data seems to be individual to the transmitting remote, I'm going to spend some time examining a larger sample of remotes, 2 samples does seem a bit low to see how big a difference there is in the data sent by the remotes.
#8
pcbbc
Super Member
  • Total Posts : 1101
  • Reward points : 0
  • Joined: 2014/03/27 07:04:41
  • Location: 0
  • Status: offline
Re: Guidance on 433MHz PIC16F Receiver Project 2019/07/10 03:41:52 (permalink)
+2 (2)
Just one input, and initially set for rising edge.
When you get a capture, record the value of CCPR1H:CCPR1L and toggle to falling edge mode.
Now at the next capture subtract first value from current CCPR1H:CCPR1L to get the high time and toggle back to rising edge.  This value will tell you if it was a ONE (1100us) or a ZERO (400us).
At the next capture, subtract first value from current CCPR1H:CCPR1L to get the total period.  This should be 1500us, but if it's not you've got some kind error receiving.
Once you have 25 valid bits all received without a timing error you have a valid key press.
You may find your remote sends each key press multiple times.  You will probably want to wait until you have received 2 successive key presses to provide some error correction/noise immunity.
 
You can either do the above an interrupt routine, or polling.  Polling is probably slightly easier to get your head around - but does tie up the PIC meaning it's difficult to do anything else at the same time.
 
What ric is referring to is called clock run in.  It doesn't look like your remotes are using any, as you'd expect all transmissions to start with a similar pattern (e.g. 8 x 1 bits) and your two keys start with two distinctly different patterns.  They probably rely on the re-transmission of the key presses instead.  If the receiver doesn't get the first transmission, the AGC will have adjusted for the subsequent re-transmissions.
#9
btommo
Starting Member
  • Total Posts : 89
  • Reward points : 0
  • Joined: 2017/07/07 02:59:33
  • Location: 0
  • Status: offline
Re: Guidance on 433MHz PIC16F Receiver Project 2019/07/10 04:00:11 (permalink)
0
Ah OK so have the micro check the mode whether it's rising edge or falling, save time (CCPR1H:CCPR1L) in rising edge variable or failing edge variable dependent on current mode. Shouldn't I reset the TMR after one period (set a flag after first rising edge, calculate period at second rising edge, reset flag and TMR) so I don't have a problem if it overflows?
 
I think the receiver that came with the remote needs to see two key presses consecutively as it doesn't seem to activate on one set of data, attached is set of data from 3 more remotes with pulse width time taken from scope.
 
I'll try it in interrupt as I have a bit of experience with them and would ensure the data won't be missed.
 
edit:
 
Please see below code for the ISR, is it along the right lines?
void ECCP_CaptureISR(void)
{
    //CCP_PERIOD_REG_T module;

    if(CCP1CONbits.CCP1M == 0b0101) //rising edge
    {
        if(periodF == 0)
        {
            periodF = 1; //set period flag to calculate period on next rising edge
            riseT = (CCPR1H << 8) + CCPR1L; //store time at rising edge
        }
        else
        {
            periodF = 0;
            periodT = ((CCPR1H << 8) + CCPR1L) - riseT;//calculate period from
            TMR1L = 0; //new time and previous riseT
            TMR1H = 0;
            riseT = (TMR1H << 8) + TMR1L; //store time at rising edge
        }
        // Clear the ECCP interrupt flag
        PIR1bits.CCP1IF = 0;
        CCP1CONbits.CCP1M = 0b0100; //switch to falling edge mode
        return;
    }
    if(CCP1CONbits.CCP1M == 0b0100) //falling edge
    {
        fallT = (CCPR1H << 8) + CCPR1L;
        pulseT = fallT - riseT;
        PIR1bits.CCP1IF = 0;
        return;
    }
    
    /*// Copy captured value.
    module.ccprl = CCPR1L;
    module.ccprh = CCPR1H;
    
    // Return 16bit captured value
    ECCP_CallBack(module.ccpr_16Bit);
    
    // Clear the ECCP interrupt flag
    PIR1bits.CCP1IF = 0;*/
}

 
originally it was generated by MCC so commented out unused code, would it be good to use a variable in the ISR to be used in main for the S/L such as pulse = 0 if short detected, pulse = 1 if long detected else pulse = 2 then shift/store bit in main if 0/1 is seen?
post edited by btommo - 2019/07/10 05:03:57

Attached Image(s)

#10
pcbbc
Super Member
  • Total Posts : 1101
  • Reward points : 0
  • Joined: 2014/03/27 07:04:41
  • Location: 0
  • Status: offline
Re: Guidance on 433MHz PIC16F Receiver Project 2019/07/10 06:05:13 (permalink)
+1 (1)
btommoShouldn't I reset the TMR after one period (set a flag after first rising edge, calculate period at second rising edge, reset flag and TMR) so I don't have a problem if it overflows?

You can reset the timer if you want, but you will introduce measurement inaccuracies because it is hard/impossible to guarantee the interrupt latency.
 
If you just let the timer free-run and you won't have a problem with overflow, as unsigned integer arithmetic will cope with the wrap around automatically:
First Edge: 0xFFD1
Second Edge: 0x0016
0x0016 - 0xFFD1 = 0x0045
Which you will see is the correct answer (so long as the timer hasn't overflowed more than once).
 
The theoretical problem would be with intervals > 0xFFFF ticks.  But as that represents 65ms (at 1MHz) you'd be very unlikely to get a series of pulses which, modulo 65ms, were an exact timing fit for your protocol.  And as 1MHz gives 1us accuracy, and that is overkill for measuring 400us vs 1100us, you can actually run the clock slower than that.
 
But if you want you can detect the timer roll over interrupt and extend the timer to 24 bits, or whatever level of precision you require.
 
Your code looks good. Here's what I came up with though.  I assumed 1MHz clock for simplicity.
uint16_t rising_time;
uint8_t remote_bit;
uint32_t remote_code;

void __interrupt() ISR(void)
{
    if (PIR1bits.CCP1IF)
    {
        uint16_t current_time = CCPR1;
        PIR1bits.CCP1IF = 0; //Clear interrupt
        
        uint16_t elapsed_time = current_time - rising_time;
        if (CCP1CONbits.CCP1M0)
        {
            //It was a rising edge...            
            CCP1CONbits.CCP1M0 = 0; //Prepare for next falling edge
            
            if (elapsed_time < 1400 || elapsed_time > 1600)
            {
                //It's an invalid period
                remote_bit = 0;
                remote_code = 0;
            }
 
            rising_time = current_time; //Record rising edge time
        }
        else
        {
            //It was a falling edge...
            CCP1CONbits.CCP1M0 = 1; //Prepare for next rising edge
            
            if (elapsed_time >= 300 && elapsed_time <= 500)
            {
                //It was a valid "0" pulse width...
                remote_code <<= 1;
                remote_bit++;
            }
            else if (elapsed_time >= 1000 && elapsed_time <= 1200)
            {
                //It was a valid "1" pulse width...
                remote_code <<= 1;
                remote_code |= 1;
                remote_bit++;                
            }
            else
            {
                //It's an invalid pulse width
                remote_bit = 0;
                remote_code = 0;
            }
            
            //Check if we have received all bits yet
            if (remote_bit == 25)
            {
                //Valid code received into remote_code
                //Do something with it!
            }                       
        }
    }
}

Take your pick.  I don't guarantee my code is 100% correct, but it's a starting point.
Note that checking/clearing/setting single bits on PIC is a single instruction.  So that's why I check and toggle the CCP1M0 bit rather than reading/writing the whole of CCP1M.
 
Edit: My rising/faling edge logic was round the wrong way.  I fixed it.
post edited by pcbbc - 2019/07/10 06:13:34
#11
btommo
Starting Member
  • Total Posts : 89
  • Reward points : 0
  • Joined: 2017/07/07 02:59:33
  • Location: 0
  • Status: offline
Re: Guidance on 433MHz PIC16F Receiver Project 2019/07/10 07:45:17 (permalink)
0
Thanks pcbbc, your way does seem more efficient, I do have a couple of queries about the code;
I understood the valid pulse width portion within the rising edge mode code but got confused when you shifted remote code by one to the left before toggling bit 1, shouldn't this be done before as below else it would see that it has a valid '0' before the 1 is added?
else if(elapsed_time >= 1000 && elapsed_time <= 1300)
        {
            //valid "1" pulse width
            remote_code |= 1;
            remote_code <<= 1;
            remote_bit++;
        }

 
Also there is an if statement in the falling edge portion of the code;
 
if(elapsed_time < 1400 || elapsed_time > 1600)
       {
           //it's invalid period
           remote_bit = 0;
           remote_code = 0;
       }

but elapsed time is;
uint16_t elapsed_time = current_time - rise_time;

For which rise time updates in the rising edge detection mode routine so wouldn't the time elapsed seen in the falling edge be the pulse width and not the period and the time elapsed be the period in the rising edge detection mode?
 
My apologies if I have misunderstood. 
 
edit: didn't see you changed it sorry!!
post edited by btommo - 2019/07/10 07:46:22
#12
pcbbc
Super Member
  • Total Posts : 1101
  • Reward points : 0
  • Joined: 2014/03/27 07:04:41
  • Location: 0
  • Status: offline
Re: Guidance on 433MHz PIC16F Receiver Project 2019/07/10 08:16:47 (permalink)
+1 (1)
else if(elapsed_time >= 1000 && elapsed_time <= 1300)
        {
            //valid "1" pulse width
            remote_code |= 1;
            remote_code <<= 1;
            remote_bit++;
        }

You can't set the 1 bit until you have an empty place to "put it".  So shift first (to make a space) and then set the low order bit.
If you do it your way you always have an unused (zero) bit as the low order bit and everything is shifted left one place.
It does not matter that there is temporarily a zero bit shifted in, as we immediately set it to 1 in the next line.  And because we are in an ISR nothing is going to "see" that this operation was non-atomic.
 
 
Also there is an if statement in the falling edge portion of the code;
if(elapsed_time < 1400 || elapsed_time > 1600)
       {
           //it's invalid period
           remote_bit = 0;
           remote_code = 0;
       }

but elapsed time is;
uint16_t elapsed_time = current_time - rise_time;

Yes - Sorry...
I corrected my post a few minutes after I posted.  I realised had my falling/rising logic around the wrong way....
edit: didn't see you changed it sorry!!

...which is presumably why you edited and wrote this!
#13
pcbbc
Super Member
  • Total Posts : 1101
  • Reward points : 0
  • Joined: 2014/03/27 07:04:41
  • Location: 0
  • Status: offline
Re: Guidance on 433MHz PIC16F Receiver Project 2019/07/10 08:25:10 (permalink)
0
I had some thoughts about rollover of T1...
uint16_t rising_time;
uint8_t t1_rollovers = 0;
uint8_t remote_bit;
uint32_t remote_code;

void __interrupt() ISR(void)
{
    //Timer 1 overflow
    if (PIR1bits.TMR1IF)
    {
        if (t1_rollovers < 0xFF) t1_rollovers++;
        PIR1bits.TMR1IF = 0;
    }
    
    if (PIR1bits.CCP1IF)
    {
        uint16_t current_time = CCPR1;
        PIR1bits.CCP1IF = 0; //Clear interrupt
        
        uint16_t elapsed_time = current_time - rising_time;
        
        //Has T1 rolled over such that elapsed_time is invalid?
        if (t1_rollovers >= 2 || (t1_rollovers == 1 && current_time >= rising_time))
        {            
            elapsed_time = 0xFFFF; //Interval exceeded maximum
        }
                
        if (CCP1CONbits.CCP1M0)
        {
            //It was a rising edge...            
            CCP1CONbits.CCP1M0 = 0; //Prepare for next falling edge
            
            if (elapsed_time < 1400 || elapsed_time > 1600)
            {
                //It's an invalid period
                remote_bit = 0;
                remote_code = 0;
            }
            
            rising_time = current_time; //Record rising edge time
            t1_rollovers = 0; //Reset timer 1 overflow counter
        }
        else
        {
            //It was a falling edge...
            CCP1CONbits.CCP1M0 = 1; //Prepare for next rising edge

            if (elapsed_time >= 300 && elapsed_time <= 500)
            {
                //It was a valid "0" pulse width...
                remote_code <<= 1;
                remote_bit++;
            }
            else if (elapsed_time >= 1000 && elapsed_time <= 1200)
            {
                //It was a valid "1" pulse width...
                remote_code <<= 1;
                remote_code |= 1;
                remote_bit++;                
            }
            else
            {
                //It's an invalid pulse width
                remote_bit = 0;
                remote_code = 0;
            }
            
            //Check if we have received all bits yet
            if (remote_bit == 25)
            {
                //Valid code received into remote_code
                //Do something with it!
            }
        }
    }
}

 
#14
btommo
Starting Member
  • Total Posts : 89
  • Reward points : 0
  • Joined: 2017/07/07 02:59:33
  • Location: 0
  • Status: offline
Re: Guidance on 433MHz PIC16F Receiver Project 2019/07/11 01:39:40 (permalink)
0
Thanks pcbbc I've added to the code, please see below for my ECCP interrupt routine as it stands, I'm comparing the received against remote 1 for now and LEDs for lock/unlock as well as unknown and a counter to check for a repeating keypress, I'm planning on using a state machine in main for future after checking valid and comparing keypress in interrupt also a state in main that would tell the interrupt that it's in programming mode to store new remote key;
void ECCP_CaptureISR(void)
{
    //CCP_PERIOD_REG_T module;
    uint16_t current_time = CCPR1;
    PIR1bits.CCP1IF = 0;
    
    uint16_t elapsed_time = current_time - riseT;
    
    //has T1 rolled over such that elapsed time is invalid?
    if(t1_rollovers >= 2 || (t1_rollovers == 1 && current_time >= riseT))
    {
        elapsed_time = 0xFFFF; //interval exceed maximum
    }
    
    if(CCP1CONbits.CCP1M0) //rising edge
    {
        CCP1CONbits.CCP1M0 = 0; //switch to falling edge mode
        if(elapsed_time < 1400 || elapsed_time > 1600)
       {
           //it's invalid period
           remote_bit = 0;
           remote_code = 0;
       }
        riseT = current_time; //record rising edge time
        t1_rollovers = 0; //reset timer 1 overflow counter
    }
    else //falling edge
    {
       CCP1CONbits.CCP1M0 |= 1;
       
       if(elapsed_time >= 300 && elapsed_time <= 500)
        {
            //valid "0" pulse width
            remote_code <<= 1;
            remote_bit++;
        }
        else if(elapsed_time >= 1000 && elapsed_time <= 1300)
        {
            //valid "1" pulse width
            remote_code <<= 1;
            remote_code |= 1;
            remote_bit++;
        }
        else
        {
            //invalid pulse width
            remote_bit = 0;
            remote_code = 0;
        }
        if(remote_bit == 25)
        {
            key_count++;
            if(key_count < 2)
            {
                remote_codeS = remote_code; //store first keypress
            }
            if(key_count >= 2) //check second keypress
            {
                if(remote_code != remote_codeS) //not the same
                {
                    key_count = 0;
                }
                if(remote_code == remote_codeS) // same key code seen twice
                { //check against known remote
                    if(remote_code == remote1)
                    {
                        unlock_SetHigh();
                        lock_SetLow();
                        unknown_SetLow();
                    }
                    if(remote_code == remote1 + 2)
                    {
                        lock_SetHigh();
                        unlock_SetLow();
                        unknown_SetLow();
                    }
                    if(remote_code != (remote1 || remote1 + 2))
                    {
                        unknown_SetHigh();
                    }
                    key_count = 0;
                }
            }
            remote_bit = 0; //check next keypress
            //valid remote code
            //compare with known programmmed remote
            //lock/unlock (LED for development)
        }
    }

I'm planning on testing what I've got at the moment later on today when some DIP package PICs arrive.
 
I do have a question, how would I go about splitting then storing the bytes in eeprom? don't really need the LSB as it seems to be a consistently '0' for which I can just shift the read left by one to add a '0' on the end. I've only really stored 1 byte values before.
post edited by btommo - 2019/07/11 01:49:25
#15
pcbbc
Super Member
  • Total Posts : 1101
  • Reward points : 0
  • Joined: 2014/03/27 07:04:41
  • Location: 0
  • Status: offline
Re: Guidance on 433MHz PIC16F Receiver Project 2019/07/11 03:11:45 (permalink)
+1 (1)
btommoI do have a question, how would I go about splitting then storing the bytes in eeprom? don't really need the LSB as it seems to be a consistently '0' for which I can just shift the read left by one to add a '0' on the end. I've only really stored 1 byte values before.

Several options...
 
1. Write a function that takes a pointer to a byte array and a length, and then iterates over the array writing to EEPROM a byte at a time (you'll also need a similar routine for reading).
 
Then you can either:
i. Cast the address of your data (uint32_t in this case) to a byte pointer, and pass in the length:
write_eeprom_bytes(EEPROM_ADR, (uint8_t*)&remote_code, sizeof(remote_code));

Do this individually for all the variables you have to save to EEPROM.
ii. If you have more than 1 or 2 values to save, define a structure with all your EEPROM data in it, and create a union type with a byte array.  Then you have access to the data as either bytes or as whole variables:
typedef struct {
    uint32_t remote_code;
    uint8_t some_other_setting;    
    //etc
} EEPROM_STRUCT;

union {
    uint8_t bytes[sizeof(EEPROM_STRUCT)];
    EEPROM_STRUCT values;
} nvdata;
 
nvdata.values.remote_code = 1234;
write_eeprom_bytes(EEPROM_ADR, nvdata.bytes, sizeof(nvdata.bytes));

 
2. The 16F parts have the __eeprom qualifier which allows you to specify any global variable as being stored in the EEPROM.  The compiler then automatically generates the code to read and write for you.
__eeprom uint32_t remote_code;

I'd advise against access of these variables from the ISR though!  There is obviously quite an overhead in accessing the EEPROM over normal RAM.
 
Personally I use the struct/union approach for my projects.  It means I know exactly where and how the data is laid out in the EEPROM.  I can also easily checksum the data when reading and writing to make sure configuration hasn't been corrupted.
 
I wouldn't be so quick to assume that last bit is always going to be zero.  Yes, it may be a hardcoded zero stop bit.  But also all of the codes you have captured so far (in a sample size of 5) have an even number of L bits.  That last S bit could just as easily be an even parity bit.
 
Also I see that lots of these generic remote fobs advertise 1,000,000 codes and come in 2 and 4 button varieties. If we take 20 bits for the unique code (2^20 = 1,048,576) and then use 4 bits (one per button) that gives 24 bits.
 
From what you have captured, we might guess the 4 button variety buttons are encoded:
0001
0010
0100
1000
That may appear wasteful, but I guess the idea is for error correction.  If you get a code with more than one bit set in the "buttons" positions you know it is an error.  And if there is one thing you want to avoid at all costs is an error in the button data.
#16
pcbbc
Super Member
  • Total Posts : 1101
  • Reward points : 0
  • Joined: 2014/03/27 07:04:41
  • Location: 0
  • Status: offline
Re: Guidance on 433MHz PIC16F Receiver Project 2019/07/11 03:19:42 (permalink)
+2 (2)
And what are you trying to do here...
if(remote_code == remote1 + 2)
//Why "+2"?
 
//This code almost certainly isn't doing what you think it is...
if(remote_code != (remote1 || remote1 + 2))
//I think you probably intended...
if(remote_code != remote1 && remote_code != remote1 + 2)
//Although I still don't know what the "+2" is about

 
Edit, ah!
+2 because you have captured the unlock key (ending xx010 = 2), and are trying to test for the lock key (ending xx100 = 4).  4-2 = 2.
 
   //Test just the ID part of the received remote1 code is equal
    if (((remote_code ^ remote1) & 0xFFFFFFF8) == 0)
    {
        //Correct Remote ID
        uint8_t key = (uint8_t)remote1 & 0x7;
        if (key == 0b010)
        {
            //Unlock key
            unlock_SetHigh();
            lock_SetLow();
            unknown_SetLow();
        }
        else if (key == 0b100)
        {
            //Lock key
            lock_SetHigh();
            unlock_SetLow();
            unknown_SetLow();
        }
        else
        {
            //Unknown Key
            unknown_SetHigh();
        }
    }
    else
    {
        //Incorrect Remote ID
        unknown_SetHigh();        
    }

Also you want to think about how to reset key_count if you get 2 valid single transmissions of a key, but which are too far apart (separate presses).  I don't think your current code will reject those unless there is another remote (or different key) which transmits in between.
post edited by pcbbc - 2019/07/11 03:40:34
#17
btommo
Starting Member
  • Total Posts : 89
  • Reward points : 0
  • Joined: 2017/07/07 02:59:33
  • Location: 0
  • Status: offline
Re: Guidance on 433MHz PIC16F Receiver Project 2019/07/11 03:57:11 (permalink)
0
remote1 + 2 is equal to the lock for since 0b010 (2) is unlock and 0b100 (4) is lock since the bits swap thought +2 was OK instead of having a seperate value, the lock and unlock LEDs activate in hardware at the correct key press for two sets of correct data. The unknown LED seems to be constantly on but I guess that's due to the '||' operand, just changed to '&&' which corrected this.
 
I'll look into and spend some time digesting the information you've given and get back to you later on, I think i'll have to save multiple remote codes (as spares) possibly read and stored into an array/look up table on start up?
 
I thought about the reset the key_count after a debounce period, TMR2 interrupt to reset key_count if overflowed (reset and turn on when key count = 1 and off when key count = 2) 
 
I can't seem to find the function "write_eeprom_bytes()" and isn't in the xc8 manual :/. 
 
  
post edited by btommo - 2019/07/11 04:48:45
#18
pcbbc
Super Member
  • Total Posts : 1101
  • Reward points : 0
  • Joined: 2014/03/27 07:04:41
  • Location: 0
  • Status: offline
Re: Guidance on 433MHz PIC16F Receiver Project 2019/07/11 04:48:13 (permalink)
0
btommoThe unknown LED seems to be constantly on but I guess that's due to the '||' operand, just changed to '&&' which corrected this.

Hopefully you changed...
if(remote_code != (remote1 || remote1 + 2))

..to..
if(remote_code != remote1 && remote_code != remote1 + 2)

..and not to...
if(remote_code != (remote1 && remote1 + 2))

If not you need to understand why the first and third examples are nonsense.
 
I thought about the reset the key_count after a debounce period, TMR2 interrupt to reset key_count if overflowed (reset and turn on when key count = 1 and off when key count = 2)

Don't know what the delay is between transmissions when you hold a button down, but almost certainly you can use T1 rollovers for this without having to use another timer.
 
I can't seem to find the function "write_eeprom_bytes()" and isn't in the xc8 manual

As far as I know, no such routine exists.  Sorry.
I said you'll need to write your own routine which makes multiple calls to the single byte read/write functions.
Of if you are using a version of the compiler where those have been removed, write your own byte read/write replacements also.
#19
btommo
Starting Member
  • Total Posts : 89
  • Reward points : 0
  • Joined: 2017/07/07 02:59:33
  • Location: 0
  • Status: offline
Re: Guidance on 433MHz PIC16F Receiver Project 2019/07/11 05:06:19 (permalink)
0
I did change it to the second example, the first one not correct because it will always be on as remote1 is not remote1 +2 and vice versa and the third one is completely wrong as it would be a different value it is comparing against.
 
putting the reset in the t1 rollover code sorted the debounce;

//has T1 rolled over such that elapsed time is invalid?
if(t1_rollovers >= 2 || (t1_rollovers == 1 && current_time >= riseT))
{
elapsed_time = 0xFFFF; //interval exceed maximum
key_count = 0;
}

 
I'll start creating the eeprom function using the MCC generated memory functions for which there is a write/read byte function.
#20
Page: 123 > Showing page 1 of 3
Jump to:
© 2019 APG vNext Commercial Version 4.5