![]() |
Forum Index : Microcontroller and PC projects : How to learn RF remote codes?
![]() ![]() ![]() ![]() |
|||||
Author | Message | ||||
Grogster![]() Admin Group ![]() Joined: 31/12/2012 Location: New ZealandPosts: 9586 |
Yes, from what I could see, the very first data packet was corrupted. But the subsequent ones were not. I'm glad it makes sense to you! ![]() Smoke makes things work. When the smoke gets out, it stops! |
||||
disco4now![]() Guru ![]() Joined: 18/12/2014 Location: AustraliaPosts: 1000 |
Hi Jim, Thanks for this clever idea/tip. I have used it to decode a remote temperature/humidity sensor from Bangood . It was in the too hard basket but this gave me inspiration and I have cracked the decoding of it. I will start another thread about it so as not to hijack Grogster's thread any further. thanks Gerry Latest F4 Latest H7 FotS |
||||
TassyJim![]() Guru ![]() Joined: 07/08/2011 Location: AustraliaPosts: 6266 |
Grogster, Can you try this code generator and see if it matches your devices. It runs on a MX170 with the Tx pin on pin 16 but can be any. OPTION DEFAULT NONE DIM INTEGER xmitpin = 16 ' the pin connected to the 433mhz module data pin DIM FLOAT lengths(68) DIM FLOAT noise(255) DIM STRING testkey DIM INTEGER testVal DIM INTEGER n FOR n = 0 TO 255 noise(n) = RND()*500+20 ' fill noise array NEXT n PIN(xmitpin)=0 ' set the data pin low SETPIN xmitpin, DOUT ' set it as an output '*************** Main Loop *************** DO testkey = INKEY$ IF testkey <>"" THEN testval = VAL(testkey) PRINT testval sendit(testval) END IF LOOP END ' *********** END *************************** SUB sendit(code AS INTEGER) LOCAL FLOAT pulselength=295 ' us for the short pulse length Long is 3 times this LOCAL INTEGER repeat=3 'number of times to repeat the transmission LOCAL STRING senddata$ 'string containg the binary data IF code >= 0 AND code <10 THEN SELECT CASE code CASE 0 senddata$ = "011101010001110000000010" CASE 1 senddata$ = "011101010001110000000010" CASE 2 senddata$ = "011101010001110000000010" CASE 3 senddata$ = "011101010001110000000010" CASE 4 senddata$ = "011101010001110000000010" CASE 5 senddata$ = "011101010001110000000010" CASE 6 senddata$ = "011101010001110000000010" CASE 7 senddata$ = "011101010001110000000010" CASE 8 senddata$ = "011101010001110000000010" CASE 9 senddata$ = "N011101010001110000000010" END SELECT ' pulsecount = len(senddata$)*2 SEND433MHZ(pulselength,repeat,xmitpin,senddata$) ENDIF END SUB SUB SEND433MHZ(pulselength AS FLOAT,repeat AS INTEGER ,thexmitpin AS INTEGER,senddata$ AS STRING) LOCAL INTEGER long,short LOCAL INTEGER j,i,n short=pulselength long=pulselength*3 IF LEFT$(senddata$,1) = "N" THEN n = 1 senddata$ = MID$(senddata$,2) 'print "Noise" ENDIF lengths(0)=short lengths(1)=short*31 'sync pulse FOR i=1 TO LEN(senddata$) IF MID$(senddata$,i,1) = "1" THEN 'One lengths(i*2)=long lengths(i*2+1)=short ELSE 'Zero lengths(i*2)=short lengths(i*2+1)=long END IF NEXT i ' Call the CFunction IF n = 1 THEN bitbanger(thexmitpin,254,noise()) FOR j=0 TO repeat-1 bitbanger(thexmitpin,LEN(senddata$)*2+2,lengths()) NEXT j END SUB CSUB bitbanger INTEGER,INTEGER,FLOAT 'pin number, number of bits, floating point array of bit lengths in usec 00000000 27BDFFC0 AFBF003C AFBE0038 AFB70034 AFB60030 AFB5002C AFB30024 AFB20020 AFB1001C AFB00018 AFB40028 3C109D00 8E030000 00808821 8E020080 8C640000 00A09021 00002821 00C0B021 0040F809 8E140064 00409821 8E02009C 3C0449F4 0040F809 24842400 00402821 0280F809 02602021 0040B821 8E240000 8E020024 24050007 0040F809 241E0001 AFA20010 8E020028 0040F809 8E240000 8E520000 8E030040 005EF004 0060F809 00122080 AFA20014 12400013 0040A821 0000A021 00008821 3C139D00 0014A080 02D41821 8C640000 8E620058 8E70007C 0040F809 02E02821 26310001 0200F809 00402021 02B4A021 0232182B AE820000 1460FFF2 0220A021 8FA30014 3C040008 8C620000 2442FFFD AC620000 3C03BF88 AC641064 3C03BF88 00001021 AC601068 40824800 8FA50014 8FA30010 2652FFFF AC7E0000 8CA40000 00442021 40024800 0044182B 1460FFFD 00000000 1640FFF6 24A50004 8FBF003C 3C020008 3C03BF88 AC621064 3C03BF88 8FBE0038 8FB70034 8FB60030 8FB5002C 8FB40028 8FB30024 8FB20020 8FB1001C 8FB00018 AC621068 03E00008 27BD0040 END CSUB enter 0 to 9 to select the code you want to send. All codes are the same in this demo except No 9 which has an "N" as the first digit. This cause a burst of random noise to be sent before the data. The pulse length is set at 295uS which might need tweaking. Long pulses are 3 times the short ones. Thanks to PeterM and disco4now for the code I based it on. If it looks OK, I will start playing with receiving the data. Jim VK7JH MMedit |
||||
Grogster![]() Admin Group ![]() Joined: 31/12/2012 Location: New ZealandPosts: 9586 |
Hi Jim. ![]() Thanks very much for your efforts! ![]() Do you want me to capture the output of your code from the 170, into the logic analyser and compare with the actual transmitter? I think that is what you want me to do, yes? EDIT: I can't feed it into the TX and then receive on the receiver, as the Tx units are sealed watches, and unless you want me to hack one of those to bypass the 1527, and inject the data to the TX side of the device and then receive THAT across the link.... I can put up a photo of the internals of the watch TX if you like, but it is just a small PCB with the TX AND encoder all on one, along with the button and batteries. Smoke makes things work. When the smoke gets out, it stops! |
||||
TassyJim![]() Guru ![]() Joined: 07/08/2011 Location: AustraliaPosts: 6266 |
Just feed the output directly into your logic analyser and compare. I am looking for a way of testing various receive decoding methods without having the transmitter or receiver. Jim VK7JH MMedit |
||||
Grogster![]() Admin Group ![]() Joined: 31/12/2012 Location: New ZealandPosts: 9586 |
Hi there. ![]() @ TassyJim - Here is the data you requested. I have run tests 1 and 9. If you need more tests, please let me know. ![]() 2018-03-17_163102_TassyJim_01tests_1_and_9.zip Smoke makes things work. When the smoke gets out, it stops! |
||||
TassyJim![]() Guru ![]() Joined: 07/08/2011 Location: AustraliaPosts: 6266 |
That looks good enough to play with. Jim VK7JH MMedit |
||||
Grogster![]() Admin Group ![]() Joined: 31/12/2012 Location: New ZealandPosts: 9586 |
Awesome. ![]() Do you want me to do any of the other tests? (2-8) Smoke makes things work. When the smoke gets out, it stops! |
||||
TassyJim![]() Guru ![]() Joined: 07/08/2011 Location: AustraliaPosts: 6266 |
When I 'sent' this "011101010001110000000010" I received and decoded this "001110101000111000000001000111010100011100000000100011101010001110000000010" Which is the sent code repeated 3 times. The extra zeros are the sync pulses. The sender is a 170 and the receiver is an explore64. The receiving code is basically the one I posted earlier in the discussion. I need to sort out the sync pulse timing and try some other, faster methods of decoding to get it running on an 170 although I assume you have a few spare explore64s available. By using the simulator instead of the real thing, I can push the speeds up to see how close we are to failure. Jim VK7JH MMedit |
||||
Grogster![]() Admin Group ![]() Joined: 31/12/2012 Location: New ZealandPosts: 9586 |
Marvellous, thanks for your efforts. ![]() Yes, I have E64's here if I need to use one for testing anything you need. Smoke makes things work. When the smoke gets out, it stops! |
||||
TassyJim![]() Guru ![]() Joined: 07/08/2011 Location: AustraliaPosts: 6266 |
DIM INTEGER tick, tock, period, pulsetime = 50, synctime = pulsetime * 10 DIM code$ DIM pulses(500) ' store all timing intervals for later processing DIM inSync ' used to signal when sync pulse has been received DIM pulsecount DIM firstRun, syncs DIM validAlarms$(20) CONST ticker = 49 ' connect PWM output (pin 48) to here CONST rxPin = 46 ' pin that the receiver output connects to validAlarms$(1) = "011101010001110000000010" validAlarms$(2) = "011101010001110000100010" validAlarms$(3) = "011101010001110001100010" validAlarms$(4) = "011101010001110000000001" validAlarms$(5) = "011101010101110000000010" validAlarms$(6) = "011101011101110110100010" validAlarms$(7) = "011101011001110001100010" validAlarms$(8) = "011101011001110000000010" validAlarms$(9) = "011101011111110000000010" validAlarms$(10) = "011101000001110000100010" validAlarms$(11) = "011101100001110001100010" validAlarms$(12) = "011101010001110001000001" validAlarms$(13) = "010101010001110000000010" validAlarms$(14) = "011001010001110000100010" validAlarms$(15) = "011011010001110001100010" validAlarms$(16) = "011101010001110100000001" validAlarms$(17) = "011101010001111100000010" validAlarms$(18) = "011101010001101000100010" validAlarms$(19) = "011101010001000001100010" validAlarms$(20) = "011101010000110000000001" PWM 1, 100000, 50 ' this is out high resolution timer whch gets connected to ticker pin SETPIN ticker, CIN SETPIN rxPin, INTB, blip ' triggers on a high or low transition tock = PIN(ticker) SETTICK 3000, checkit DO ' IF INKEY$<>"" THEN ' decode ' ENDIF LOOP END SUB blip tick = PIN(ticker) IF inSync = 0 THEN IF (tick - tock) > synctime AND PIN(rxPin) = 1 THEN' long enough to have been sync pulse inSync = 1 pulsecount = 0 pulses(pulsecount) = tick - tock ENDIF ELSE pulsecount = pulsecount + 1 pulses(pulsecount) = tick - tock IF pulsecount > 400 THEN inSync = 0 pulsecount = 0 'print "overflow" ENDIF ENDIF tock = tick END SUB SUB checkit LOCAL n, t t = TIMER decode FOR n = 1 TO 20 IF validAlarms$(n)<>"" THEN IF INSTR(code$,"s"+validAlarms$(n))>0 THEN ' we have lift off!! PRINT "!!!! ",n, " needs help!" ENDIF ENDIF NEXT n PRINT "Checkit time ",TIMER - t END SUB SUB decode LOCAL n, pulsetimes code$ = "" ' check every second timing PRINT pulses(0) 'DEBUG pulsetimes = 0 'DEBUG FOR n = 1 TO 400 STEP 2 pulsetimes = pulsetimes + pulses(n)+pulses(n+1) 'DEBUG PRINT pulses(n), pulses(n+1), pulsetimes 'DEBUG IF pulses(n) > synctime OR pulses(n+1) > synctime THEN ' a sync pulse code$ = code$ + "s" ELSEIF (pulses(n) + pulses(n+1)) = 0 THEN ' all done EXIT FOR ELSEIF pulses(n+1) = 0 AND pulses(n) < pulsetime THEN ' final transition code$ = code$ + "0" ELSEIF pulses(n) > pulses(n+1) THEN code$ = code$ + "1" ELSE code$ = code$ + "0" ENDIF NEXT n PRINT code$ 'DEBUG inSync = 0 syncs = 0 pulsecount = 0 FOR n = 1 TO 400 pulses(n) = 0 NEXT n END SUB How it works. The PWM 1 output is connected to a counting pin with a frequency of 100kHz. That gives us a tick counter of 10uS On the explorer64, PWM is on pin 48 which is conveniently next to count pin 49 I used pin 46 for the radio receiver input but any would do. The interrupt routine attempts to wait for a sync pulse then fills the pulses()array with the time intervals. It is limited to 400 ticks so we don't overflow our string when it comes to decoding. After 400 ticks, it loops from the start. There is a SETTICK timer which periodically checks the pulses() array and looks for patterns it recognises. It is set to 3 seconds for testing but should be as often as possible once the debug printing is removed. I would try 500mS to start with. There is a timer to keep track of time taken to decode to enable setting the best decode interval. The decode SUB scans the array and looks for sync pulses. It also compares two adjacent time intervals and decides if we have a "1" or "0" The results are stored in a string. The string is then scanned for each of the "residents codes" and if found, raises an alarm. If the receiver doesn't have a squelch, the code will spend a lot of time in the interrupt SUB. The main thing to check is the different times saved for 'short' and 'long' pulses 89 44 23301 72 44 23417 75 44 23536 44 58 23638 44 73 23755 43 75 23873 90 43 24006 73 44 24123 44 60 24227 45 71 24343 45 72 24460 89 44 24593 44 0 24637 0 0 24637 s011101010001110000100010s011101010001110000100010s01110101000111000010001ss011101010001110001100010s0111010100011100011 00010s011101010001110001100010 !!!! 2 needs help! !!!! 3 needs help! If the times are too close together, we have reached to limits of the micromite. In the above example I sent two codes quickly and both were found in the one string. You need to fill the array with some valid codes. 2018-03-18_152629_panicalarm.zip I have attached this file for the exp64 and an updated sending file for the MX170 with the device codes set to match sender and receiver. code 9 still send code 1 with noise at the start. Clear as mud? Jim VK7JH MMedit |
||||
Grogster![]() Admin Group ![]() Joined: 31/12/2012 Location: New ZealandPosts: 9586 |
AWESOME! ![]() Thank you VERY much for your efforts. I will load this into an E64 tomorrow. I wish I could tonight, but I don't have time. ![]() With the array storing the remote addresses, that will work beautifully. If I wanted to LEARN a new remote code into the system, is there much involved in that kind of idea? I know this is not part of your demo code, and I may well be able to work it out from the sample code you have supplied...... Smoke makes things work. When the smoke gets out, it stops! |
||||
TassyJim![]() Guru ![]() Joined: 07/08/2011 Location: AustraliaPosts: 6266 |
To learn a new code, run it with PRINT code$ active. That will give you a line similar to the example output. Copy the data between two 's' markers and paste it into the array section of the program. If you have a good decode, there will be three the same in the string. In practice, checking the string every 500mS or more often is required to prevent overwriting good data with noise. This means you are likely to get half a code in most strings but with three being sent, there should always be at least one good one. It could be automated without too much effort but lets see how well it works in real life first. Jim VK7JH MMedit |
||||
vegipete![]() Guru ![]() Joined: 29/01/2013 Location: CanadaPosts: 1127 |
To add to the confusion, looking at Grogster's screen shot, and later link to the wider screen image, the valid data starts just before about the 30ms mark. The long low pulse is the inter-packet delay. My original decoding firmware always missed the first packet because the noise was being interpreted as valid pulses that weren't cleaned up until a long low appeared. Before changing to a better receiver, my software plan was to pay more attention to pulse lengths. Pulses representing zero and one bits have fairly specific lengths, although this jitters a bit because there is no synchronization between transmitter and receiving software. My plan was to reset the incoming pulse count any time the pulse was shorter than the shortest valid pulse or longer than the longest one. How much shorter or longer? Well, I never got around to actually trying different values because of the change in hardware. This firmware was to be running in C or assembly on the target microcontroller. I have no idea if interpreted MMBasic is fast enough to catch these subtle variations in pulse length. Using hardware with a radio signal strength indicator really simplified things. Visit Vegipete's *Mite Library for cool programs. |
||||
Grogster![]() Admin Group ![]() Joined: 31/12/2012 Location: New ZealandPosts: 9586 |
Finally had a chance to play with this. Sorry for the delay. ![]() ![]() ![]() First image is just me running the code, 2nd image is with me putting the transmitter code into slot #20, which then does respond. So, this is the first actual test with the actual transmitter and not just with a simulator, but they seem to agree. ![]() Anything else you would like me to try? Smoke makes things work. When the smoke gets out, it stops! |
||||
Azure![]() Guru ![]() Joined: 09/11/2017 Location: AustraliaPosts: 446 |
If it's not too long can you post the current code being used. My only suggestion is it needs a valid sync detected before it attempts to decode. That way it wont try to decode the noise. |
||||
Grogster![]() Admin Group ![]() Joined: 31/12/2012 Location: New ZealandPosts: 9586 |
Go back to the end of page 6. ![]() It's a direct copy of the code Jim posted for me to try. Smoke makes things work. When the smoke gets out, it stops! |
||||
TassyJim![]() Guru ![]() Joined: 07/08/2011 Location: AustraliaPosts: 6266 |
That is very promising. It shows that my timing was close to the real thing. The next big thing is to get access to the WAKEB pin on the IC and use it as an interrupt to configure the main data interrupt. I would set the data interrupt ON when you have RF and OFF when it stops. That should prevent any overwriting. Jim VK7JH MMedit |
||||
Grogster![]() Admin Group ![]() Joined: 31/12/2012 Location: New ZealandPosts: 9586 |
Cool, I will try that next. I should configure the interrupt pin(from WAKEB) to fire the BLIP sub, yes? Smoke makes things work. When the smoke gets out, it stops! |
||||
TassyJim![]() Guru ![]() Joined: 07/08/2011 Location: AustraliaPosts: 6266 |
THis is how I would try: SUB arm IF PIN(wakeb) = 0 THEN ' we have data arriving SETPIN rxPin, INTB, blip ELSE SETPIN rxPin, OFF ' data has finished ENDIF END SUB rem out the original "SETPIN rxPin, INTB, blip" The interrupt to blip is only active when there is likely data arriving. It is not called at all when there is no RF. Jim VK7JH MMedit |
||||
![]() ![]() ![]() ![]() |
![]() |
![]() |
The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |