痞酷網_PIGOO

 找回密碼
 立即註冊
!!! [系統偵測到廣告阻擋軟體] !!!

如果您覺得痞酷網對您有些許幫助,或者您認同痞酷網的理想,

那麼希望您將痞酷網設定為白名單.

並請在上論壇的時候,動動您的手指,用行動支持我們.

謝謝!
查看: 10901|回復: 14

[實做與討論] PLRF1166 RF 無線led 遙控器

[複製鏈接]
發表於 2019-3-12 14:21:16 | 顯示全部樓層 |閱讀模式
本文章最後由 jojoling 於 2019-3-12 02:28 PM 編輯

傳說有個痞友手上有很多家用 led 無線遙控器。讓我們就來好好研究一下這顆 RC (remote control)吧~
順便練習一下寫篇文章,好久沒發文了。

遙控器長這個樣子:
相片 2019-3-12 上午4 21 53.jpg


其實我不會拆,是痞友說從正面試試,按鍵面拉開後,底下是鎖住個。
相片 2019-3-9 下午4 19 01.jpg


底下電路長這樣,我們可以發現上面是433Mhz 的基本發射電路,433Mhz晶體震盪加上NPN 950 構成一個發射器。
相片 2019-3-9 下午4 21 17.jpg


手上有一台簡易的2Ghz的載波頻率檢測器,拿來試試,發現數值跳來跳去,可能是程式問題或是假像頻率信號太大了吧~
此台被我分解過,長的很難看。
相片 2019-3-9 下午4 28 34.jpg


我們從RF信號的前端可拉出原始傳送資料。我們只需從晶震/npn前端電阻拉出及可。
相片 2019-3-9 下午6 13 23.jpg
參考電路圖,google 一下 "433mhz schematic"
https://electronics.stackexchang ... transmitter-circuit


這時,我們需要拿出示波器來,好好的仔細觀察傳送信號可能像那種專用接收ic用的。
我們會發現傳送信號是由2個不同50% duty cycle的頻率組成。
仔細調整示波器,可發現信號最前面都為 48個細的週期(比較高頻)。
相片 2019-3-9 下午6 23 54.jpg


緊接著為4個大周期的信號(比較低頻)。
相片 2019-3-9 下午6 54 34.jpg


此為細週期,先初步用我的示波器計算一下半週 T約為 275uS 。
相片 2019-3-9 下午6 35 29.jpg


此為寬週期,示波器初步觀看為 595uS,不過此可能設定解析度偏大而有誤差。
相片 2019-3-9 下午6 39 41.jpg


在不同的按鍵對映的編碼,在分析過程會發現有時會在負半週期時有錯誤的編碼。
猜測可能是mcu程式沒處理好的bug。
相片 2019-3-9 下午6 28 44.jpg


拿出我"愛買"的433Mhz接收模組,此模組為SYN470+1257解碼器,我是獨立從syn470拉出"解調"信號。
相片 2019-3-9 下午11 42 06.jpg


並接上我的邏輯分析儀:
相片 2019-3-10 上午12 54 58.jpg


原始發射未調變前之信號:
2019-03-12_040319.png


細週期 275us ,約為 1.8Khz
2019-03-12_040232.png


寬週期 552 us, 約為 900hz
2019-03-12_040346.png


2個調變信號,中間間隔約為25ms
2019-03-12_044632.png


上為發射信號解析,下為接收器解調。
我們會發現有點shift,此為合理的。
另外我會發現在接收器解析的信號在正負半波週期會有點改變,可能是接收器特性吧。
2019-03-10_004226.png


此處也發現有些負半週週期調變應該有點錯誤。
2019-03-12_040543.png


數據分析記錄1:
此數據會發現每個傳輸信號是由110個大小周期信號混合。
例如:ON鍵: 48小 4大 1小 1大 3小 3大 1小 1大 7小 1大.........共 110個
相片 2019-3-12 上午4 55 11.jpg


接收器實作在 arduino 上,使用 D2 當中斷檢測信號。
相片 2019-3-11 下午6 16 23.jpg


我是用網路上現成的rc-switch來修改的,我之後再描述這套庫的限制。
https://github.com/sui77/rc-switch
此為第1個test例子
2019-03-12_044330.png


此為第2個test例子
2019-03-12_044143.png

數據分析記錄2:
此為利用 arduino 解出的碼。右側為此按盤的掃描接線,此pcb上面有一堆的 TP 點。
如果不愛原來的碼,可直接拆除原 mcu 並浮接自己的mcu(ex:attiny)並跳接那些 TP 點及可擁有自定款。
相片 2019-3-12 上午4 56 04.jpg

目前發現在每一個按鍵有可能跳出不同的碼,以 key on 來說明。
key-on: 00000000-0000F474-0594E304-0200
1.在不同次的按鍵觸發時,F474 可變成 F476,放開再按可再變成 F474。
  猜測可能是故意做的,可同時控制2組。
2.按住後持續按住一陣子後,F474可變成F475,F476可變F477。
  猜測可能是讓接收器進入加速調整(如led背光強度調整)


此為數據2裏,可發現一個檢查碼驗證 674(hex)
相片 2019-3-12 上午4 56 55.jpg


結論:
其實我是還沒找到這顆是用那顆解碼器,只好手動寫個解碼程式。


arduino sample code:
RC_PLRF1166_TEST.zip (7.77 KB, 下載次數: 2)
RC_PLRF1166_TEST2.zip (7.13 KB, 下載次數: 5)

評分

21

查看全部評分

 樓主| 發表於 2019-3-12 14:56:05 | 顯示全部樓層
本文章最後由 jojoling 於 2019-3-12 03:54 PM 編輯

數據說明:
* 此為arduino 所抓取的一個完整傳輸信號,單位為 uSec
* 第1個  26820 指調變信號前的 low 信號 ,如果接連2個信號發射時,中間都有一個約25ms的無調變信號。
* 接下來每一行描述10個波形,表示正半週負半週共 20組。
* 最後一行少了最後一個負半週,因為這個負半週後會緊接 25ms的 low 信號,所以不會被檢測到。
* 前面 48個ticks 共 48*2 個約在275us 上下,我們會發現一開始的正半週為 336,第2個為 220 ,有可能是檢測ic 在warm up 過程,但它會其保持 約在 1.8Khz 的週期。
  1.     26820
  2.     336 220 336 216 336 216 332 228 324 224 328 232 316 236 316 240 308 248 308 244
  3.     304 252 304 244 308 252 296 260 296 252 296 268 284 264 296 260 288 264 284 268
  4.     284 272 284 272 284 264 284 272 280 276 280 272 280 276 276 272 280 276 276 280
  5.     276 272 284 272 280 272 280 272 284 272 284 268 284 272 280 276 276 276 276 276
  6.     280 272 280 276 280 276 276 280 276 276 272 284 272 276 280 272 556 556 548 556
  7.     552 556 548 280 276 560 548 552 272 280 276 276 276 284 548 556 548 560 552 552
  8.     276 276 556 556 548 556 272 284 272 284 272 276 276 280 272 284 272 280 544 564
  9.     268 284 544 564 544 560 268 288 268 284 548 560 268 288 540 568 264 288 268 284
  10.     544 560 544 568 540 568 264 284 264 292 264 284 548 564 544 560 268 292 260 288
  11.     268 288 264 288 268 284 540 576 260 292 264 280 268 288 268 288 264 288 264 288
  12.     264 292 264 284 540 572 264 284 268 284 272 288 264 288 268 288 264 284 268
複製代碼




解碼程式,此解碼程式是直接修改 rc-switch裏的,發現無法套用原來的,就直接簡單修改了它。

  1. bool RECEIVE_ATTR RCSwitch::receiveProtocol(unsigned int changeCount) {

  2.     uint32_t code = 0;
  3.     uint32_t received_code[4];

  4.     /* For protocols that start low, the sync period looks like
  5.      *               _________
  6.      * _____________|         |XXXXXXXXXXXX|
  7.      *
  8.      * |--1st dur--|-2nd dur-|-Start data-|
  9.      *
  10.      * The 3rd saved duration starts the data.
  11.      *
  12.      * For protocols that start high, the sync period looks like
  13.      *
  14.      *  ______________
  15.      * |              |____________|XXXXXXXXXXXXX|
  16.      *
  17.      * |-filtered out-|--1st dur--|--Start data--|
  18.      *
  19.      * The 2nd saved duration starts the data
  20.      */
  21.     unsigned int firstDataTiming = 1;//(pro.invertedSignal) ? (2) : (1);

  22.     // must have 220 data record.
  23.     if(changeCount != 220) return false;

  24.     for (unsigned int i = firstDataTiming; i < changeCount - 1; i += 2) {

  25.         if (diff(RCSwitch::timings[i], 275) < 75 &&
  26.             diff(RCSwitch::timings[i + 1], 275) < 350) {
  27.             // zero
  28.         } else if (diff(RCSwitch::timings[i], 550) < 25 &&
  29.                    diff(RCSwitch::timings[i + 1], 550) < 350) {
  30.             // one
  31.             code |= 1;
  32.         } else {
  33.             // Failed
  34.             return false;
  35.         }

  36.         if( (i+1)%64 == 0 && i !=1) {
  37.           received_code[(i+1)/64-1] = code;
  38.           code = 0;
  39.         }
  40.         code <<= 1;
  41.     }
  42.     code <<= 18;
  43.     received_code[3] = code;

  44.     //if (changeCount > 7) {    // ignore very short transmissions: no device sends them, so this must be noise
  45.         if(!RCSwitch::release) {
  46.           RCSwitch::nReceivedValue[0] = received_code[0];
  47.           RCSwitch::nReceivedValue[1] = received_code[1];
  48.           RCSwitch::nReceivedValue[2] = received_code[2];
  49.           RCSwitch::nReceivedValue[3] = received_code[3];
  50.           RCSwitch::nReceivedBitlength = (changeCount) / 2;
  51.         }
  52.         if( received_code[0] == 0 &&
  53.             (received_code[1] & 0xFFFFF000 ) == 0x0000F000 &&
  54.             received_code[2] == 0x594e304 ) {
  55.             uint16_t v1 = received_code[1] & 0xFFC;
  56.             uint16_t v2 = received_code[3] >> 16;
  57.             uint8_t key;
  58.             v1 ^= v2;
  59.             v1 &= 0xFFF;
  60.             if(v1 == 0x674) {
  61.               switch(v2) {
  62.                 case 0x200: key = KEY_ON; break;
  63.                 case 0x220: key = KEY_OFF; break;
  64.                 case 0x620: key = KEY_PAIR; break;
  65.                 case 0x400: key = KEY_UP; break;
  66.                 case 0x420: key = KEY_DOWN; break;
  67.                 case 0x000: key = KEY_1; break;
  68.                 case 0x040: key = KEY_2; break;
  69.                 case 0x020: key = KEY_3; break;
  70.                 case 0x700: key = KEY_4; break;
  71.                 case 0x740: key = KEY_5; break;
  72.                 case 0x720: key = KEY_6; break;
  73.                 case 0x300: key = KEY_7; break;
  74.                 case 0x340: key = KEY_8; break;
  75.                 case 0x320: key = KEY_9; break;
  76.                 default: break;
  77.               }
  78.               insert_key (key);
  79.             }
  80.         }
  81.         return true;
  82.     //}
  83.     //return false;
  84. }
複製代碼


* 細週期 275us,容許誤差 75us ,因為我們之前有發現剛接收到的信號,正負半週的誤差會比較大。
  1. diff(RCSwitch::timings[i], 275) < 75
複製代碼


* 寬週期 575us,容許誤差 25us
  1. diff(RCSwitch::timings[i], 550) < 25
複製代碼


*下述因為我們前面有提到在負半週會有不正確的週期長度,所以我們上面在負半週檢查的2行,容許誤差改為 350us,或不檢查它也行。
  1. diff(RCSwitch::timings[i + 1], 275) < 350
  2. diff(RCSwitch::timings[i + 1], 550) < 350
複製代碼



DOUBLE_BUFF 是我另外定義的,原因為檢測信號太快,如果你需要保持檢測到的數據,需另外保存,不然會被下一個碼覆蓋。
這裏會發現,rc-switch檢測需要連續發送最少2個碼才會進入檢測,所以需要按比較久點。
如需要商用更改的話,需再加入一個timer去定時檢測觸發。

  1. void RECEIVE_ATTR RCSwitch::handleInterrupt() {

  2.   static unsigned int changeCount = 0;
  3.   static unsigned long lastTime = 0;
  4.   static unsigned int repeatCount = 0;

  5.   const long time = micros();
  6.   const unsigned int duration = time - lastTime;

  7.   if (duration > RCSwitch::nSeparationLimit) {
  8.     // A long stretch without signal level change occurred. This could
  9.     // be the gap between two transmission.
  10.     if (diff(duration, RCSwitch::timings[0]) < 200) {
  11.       // This long signal is close in length to the long signal which
  12.       // started the previously recorded timings; this suggests that
  13.       // it may indeed by a a gap between two transmissions (we assume
  14.       // here that a sender will send the signal multiple times,
  15.       // with roughly the same gap between them).
  16.       repeatCount++;
  17.       if (repeatCount == 2) {
  18.         if (receiveProtocol(changeCount)) {
  19. #ifdef DOUBLE_BUFF
  20.           memcpy(timings_x,RCSwitch::timings,RCSWITCH_MAX_CHANGES*sizeof(unsigned int));
  21. #endif
  22.         }
  23.         repeatCount = 0;
  24.       }
  25.     }
  26.     changeCount = 0;
  27.   }

  28.   // detect overflow
  29.   if (changeCount >= RCSWITCH_MAX_CHANGES) {
  30.     changeCount = 0;
  31.     repeatCount = 0;
  32.   }

  33.   RCSwitch::timings[changeCount++] = duration;
  34.   lastTime = time;
  35. }
複製代碼



發表於 2019-3-12 15:56:56 來自手機 | 顯示全部樓層
這費工,請問終極目標
 樓主| 發表於 2019-3-12 16:04:44 | 顯示全部樓層
xiaolaba 發表於 2019-3-12 03:56 PM
這費工,請問終極目標

還好啦,花了2個晚上而以~
終極目標嘛,這個遙控器大家可以拿來 diy 啊~
發表於 2019-3-12 17:11:51 | 顯示全部樓層
" 負半週會有不正確的週期長度,所以我們上面在負半週檢查的2行,容許誤差改為 350us,或不檢查它也行。"

過去的經驗  最大來源自電池電力  影響正確的週期長度
電池用沒多久就有不正確的週期長度,誤差抓太小  電池被迫常換而不實用
於是偷懶   (長周+短周)把它均分當分界劈了 , 不是長那就是短囉!!  
   

評分

1

查看全部評分

發表於 2019-3-12 18:14:33 來自手機 | 顯示全部樓層
jojoling 發表於 2019-3-12 04:04 PM
還好啦,花了2個晚上而以~
終極目標嘛,這個遙控器大家可以拿來 diy 啊~

那看來要進j大完成一個應用實例才行,這種玩具難度不小
 樓主| 發表於 2019-3-12 21:38:48 | 顯示全部樓層
SIMON1016 發表於 2019-3-12 05:11 PM
" 負半週會有不正確的週期長度,所以我們上面在負半週檢查的2行,容許誤差改為 350us,或不檢查它也行。"

...

那個負半週應該是軟體錯誤造成的。
目前我手上的這些,mcu出來的頻率都與第1隻有點偏差~
我個人猜測是mcu內部的 RC 振盪有點偏移掉了,需再調整一些些看看。
發表於 2019-3-12 23:11:24 | 顯示全部樓層
1#   關於 [數據分析記錄2:  ...檢查碼驗證 674(hex) ]

這個有點變化 數據分析記錄2: 的照片裡 ,
ON   F474  0594e304  0200   檢查碼驗證  0x474  + 0x200 = 0x 674
OFF  F454    ...........   0220   檢查碼驗證  0x454  + 0x220 = 0x 674
....
10% F674    ...........   0000   檢查碼驗證  0x674  + 0x000 = 0x 674
20% F634    ...........   0040   檢查碼驗證  0x634  + 0x040 = 0x 674
30% F654    ...........   0020   檢查碼驗證  0x654  + 0x020 = 0x 674

....以上OK ;  以下就變了 874  ??? ....

40% F174    ...........   0700   檢查碼驗證  0x174  + 0x700 = 0x 874
50% F134    ...........   0740   檢查碼驗證  0x134  + 0x700 = 0x 874
60% F154    ...........   0700   檢查碼驗證  0x154  + 0x700 = 0x 874
70% F574    ...........   0300   檢查碼驗證  0x574  + 0x300 = 0x 874
80% F534    ...........   0340   檢查碼驗證  0x534  + 0x340 = 0x 874
90% F554    ...........   0320   檢查碼驗證  0x554  + 0x320 = 0x 874


 樓主| 發表於 2019-3-12 23:36:26 | 顯示全部樓層
SIMON1016 發表於 2019-3-12 11:11 PM
1#   關於 [數據分析記錄2:  ...檢查碼驗證 674(hex) ]

這個有點變化 數據分析記錄2: 的照片裡 ,

報告 Simon哥~~
做為檢查校驗,除了 CRC 之外,最簡單的就是 XOR 了,這個不是加,是 XOR~

發表於 2019-3-12 23:48:39 | 顯示全部樓層
jojoling 發表於 2019-3-12 11:36 PM
報告 Simon哥~~
做為檢查校驗,除了 CRC 之外,最簡單的就是 XOR 了,這個不是加,是 XOR~

剛剛看懂了 來不及改了...
XOR.gif

評分

1

查看全部評分

 樓主| 發表於 2019-3-19 01:54:07 | 顯示全部樓層
把手上的資料更新一下。

* 我手上共有7個這個控制器,在測試第2組後就發現一些狀況,如Simon哥提到的每個 RC 裏的頻率飄移都不一樣(此處因為使用mcu,所以應該mcu 內部的 rc 振盪飄移),所以重新修正了一下, range拉的不小,應該可以通用了。
  1.         if(RCSwitch::timings[i] > 150 && RCSwitch::timings[i] < 350 &&
  2.            RCSwitch::timings[i+1] > 150 && RCSwitch::timings[i+1] < 650) {
  3.             // zero
  4.         } else if (RCSwitch::timings[i] > 400 && RCSwitch::timings[i] < 650 &&
  5.                    RCSwitch::timings[i+1] > 150 && RCSwitch::timings[i+1] < 650) {

  6.             // one
  7.             code |= 1;
  8.         } else {
  9.             // Failed
  10.             if(RCSwitch::release)
  11.               return false;
  12.         }
複製代碼


* 每個控制器應該都是獨立的 id ,底下為我手上的內部編碼。
ON: 00000000-0000F474-0594E304-0200
ON: 00000000-0000F474-05900B04-06E8
ON: 00000000-0000F474-05544304-0260
ON: 00000000-0000F474-0150B304-0290
ON: 00000000-0000F474-0595C304-0320
ON: 00000000-0000F474-0394D304-0430

所以修正識別按鍵碼為 F474 這一列。且也不花時間在研究解碼公式了,如需要學習功能,直接整個碼都學習起來及可。

* 新版程式可具有學習功能或一般萬用型。
  //mySwitch.learnRemoteControl(0); demo 程式這行點開來,就會在第一次按鍵時學習,目前程式建設內可學習最多2隻。

  1. void RCSwitch::setRemoteControlId(int select, uint32_t id) {
  2.   RCSwitch::Id[select] = id;
  3. }

  4. uint32_t RCSwitch::getRemoteControlId(int select) {
  5.   return RCSwitch::Id[select];
  6. }

  7. void RCSwitch::learnRemoteControl(int select) {
  8.   RCSwitch::learn = (uint8_t)select+1;
  9. }
複製代碼


* 在一開始查不同控制器freq的問題,結果不一下改一改就變成會解碼收到的任何信號,其實那些數字就是各種不同遙控器的編碼了。
底下影片裏有很多搖控器,包含我樓下大樓車庫的控制器(345Mhz)與315Mhz都可以解碼。影片有一個控制器按了沒反應,其實只是我12v電池不夠裝。
影片是使用433Mhz ,只是那些搖控器都存在其它的頻率存在,或是這個接收器沒濾掉其它的帶寬 這裏就不解釋了。


arduino 程式碼:
RC_PLRF1166_TEST_20190319.zip (8.3 KB, 下載次數: 2)

評分

3

查看全部評分

發表於 2019-3-19 16:27:41 | 顯示全部樓層
拿去蠻牛旁邊摳程式碼~~~
發表於 2019-4-2 18:39:43 | 顯示全部樓層
jojoling 發表於 2019-3-12 02:56 PM
數據說明:
* 此為arduino 所抓取的一個完整傳輸信號,單位為 uSec
* 第1個  26820 指調變信號前的 low 信 ...


KS012.jpg
KS011.jpg
 樓主| 發表於 2019-4-2 22:54:55 | 顯示全部樓層


報告大盤~
我找不到這些解碼ic的資訊,可能是自定版吧。
發表於 2019-4-2 23:48:32 | 顯示全部樓層
晶隼科技股份有限公司
可能倒了或者轉型不賣這種
您需要登錄後才可以回帖 登錄 | 立即註冊

本版積分規則

關閉

站長小叮嚀上一條 /1 下一條

禁閉室|手機版|連繫我們|痞酷網電子技術論壇

GMT+8, 2024-11-18 02:39 AM , Processed in 0.277504 second(s), 21 queries , Gzip On.

Powered by Discuz! X3.4 Licensed

© 2001-2023 Discuz! Team.