2014年6月18日 星期三

[ Wireless-RF] 使用樹莓派模擬 HT12E 遙控器編碼晶片的編碼格式

網頁中所使用的零件可至露天賣場訂購:

樹莓派控制 RF 發射模組使用 HT12E 編碼模擬

網路上有許多關於使用無線發射接收模組遙控家用電源開關的例子,但都只侷限在對於市面上各種遙控器的控制,若是能夠直接瞭解其編碼原則以及傳輸格式的話,那不管是哪一種型式的無線電源控制器都能夠一通百通,玩弄於股掌之間。

本篇文章主要的用意,是要與大家分享如何使用樹莓派來模擬 HT12E 晶片的編碼,並藉由無線發射模組遙控遠端 HT12D 所連接的四顆 LED;若將 LED 換成繼電器,就可以用來無線控制電源的開關,而且可控制到 256 組的無線接收端,每一組控制端可再接四個繼電器,換算起來一組無線發射模組可控制 1,024 顆繼電器。

要知道怎麼做,就請繼續往下看吧!!

賣場無線套件就是為了要寫這篇使用樹莓派模擬 HT12E 編碼的文章所整理出來的。而要寫這篇文章就要先了解編碼、解碼晶片的線路和控制方式,最後再說明 HT12E 編碼原則與格式,以循序漸進的方式做介紹,才能達到這組套件所要表達的東西,讓購買的使用者能夠活用以及將解碼的方式與程式用到其他的微控制器上,因為觀念與做法都是一樣的!

網路上關於使用無線模組控制家用電源的例子很多,據我所知且本篇文章所參考的有:
  • 發表在 TheMagPi Issue 8 雜誌hoagieshouse 的 Safe Automated Main Socket
  • STATUS Remote Control Power Sockets, from TheMagPi issue 8

    作者先在 PC 端安裝 Audacity 音訊處理軟體,將其做為擷取無線接收模組訊號的截取工具,然後使用 PC 音效卡的 Line In 孔拉線插到麵包板再串聯 1M 電阻,最後再與無線接收模組連接
    The code capturing system, from: www.hoagieshouse.com

    裝設好截取線路之後,開啟 Audacity 並按下遙控器上面的按鈕,就會在螢幕上看到上上下下的波形,再根據這些波形解碼出 "0" 和 "1" 的編碼原則
    Audacity 所接收到的訊號波形, from: www.hoagieshouse.com

    但這只是專為無線開關其中的一種所做,對於其他類型的就需要再做一次波形的截取以及解碼動作,才能知道正確的編碼,雖然費工但是其中擷取方法確是可以學起來。

    很可惜的是,我的 NB 沒有 Line In 孔可以用,所以在擷取編碼比對時,是使用另一個工具來確認 HT12E 的編碼,工具不同但是使用方法都是一樣的,下面會介紹到。
  • VirtualWire library for Arduino

  • 這函式庫就是撰寫樹莓派 bcm2835 的作者很早之前寫的,最新版 ( ver. 1.14 )  VirtualWire 可上 www.open.com.au 下載。

    VirtualWire 針對市面上的無線電源開關幾乎包含在內,PJRC 寫了一個使用 RF 315 MHz 無線發射接收模組的教學網頁 "VirtualWire Library, for very cheap wireless communication",雖然使用的無線模組不同,但是線路接法都是一樣的,主要是要看 VirtualWire 函式庫使用的方法與 Arduino 的程式範例。

    若對 Arduino 函式庫的安裝不熟的話,請參考官網 "Installing Additional Arduino Libraries" 的詳細說明。

  • rc-switch - Arduino library to operate low cost 315 MHz / 433 MHz remote control devices

  • 這個 Arduino 函式庫對於各種可以直接使用的搖控器、操作範例和接線說明的相當清楚,若手邊已經有無線電源開關,建議就使用這個函式庫配合 Arduino會方便許多。

    各種支援的開關與設定方式,請參考 "What kind of switch"

    若要直接在樹莓派使用的話,可以上 github 下載  rcswitch-pi 原始檔後,在樹莓派下進行程式編譯 ( make ) 就可以了,要使用的話請自己試試!

    對於手邊有無線電源開關組的人來說,使用上面所說的函式庫來做控制會方便許多!

接下來,分為幾個步驟將 HT12E 的編碼原則與格式找出來,再寫成程式做測試,首先要做的就是要知道 HT12E 的編碼原則與格式。


HT12E 編碼原則與格式:

開啟 HT12E 資料手冊的第六頁,在上方可以看到 HT12E 的編碼傳送時序圖。當將 HT12E 的 TE 接地時,晶片會從 DOUT 發出次編碼字元組的編碼訊號,直到 TE 浮接或是變為高準位,再傳送次編碼字元組結束;編碼字元組是 HT12E 自行定義的編碼原則,與 1 byte = 8-bit 不一樣。

再翻到資料手冊的第七頁,就會有關於編碼字元組的圖示以及說明,因為使用的晶片是 HT12E,對於圖形上方的文字敘述不用理會 ( for HT12A )。要注意的是,圖形所表達的就是每一個字元組裡面所包含的編碼資料是什麼 ?

編碼位元組由四個部分組成,每一個部分解釋如下:
  • pilot period ( 12-bit )

  • 這 12-bit 都是 0 ( 低電位 ),在傳輸編碼位址與編碼資料前可以提高信號穩定性,是編碼字元組傳輸的前導字元;雖然它不適用於特殊格式的編碼只是單純的傳送 0 ( 低準位 ),但每個 bit 也是以三個為一組,共需要傳送 36 個低準位訊號的長度。

  • 1/3 bit sync. period

  • 1/3 bit 的 1 ( 高位元 )。這後面會說到 1/3 bit 的同步訊號是多長;這與後面的編碼位址與資料的格式有關係

  • address code period

  • 編碼位址輸入;八個編碼位址字元,但不是單純的 0 或 1 編碼,是特殊格式

  • data code period

  • 編碼資料輸入;四個編碼資料位元,但不是單純的 0 或 1,是特殊格式

編碼字元組的格式如下圖所示
由上面描述之後已經清楚知道,當給 TE 一個低準位的脈衝訊號時,DOUT 會傳送四次的編碼字元組的訊號出去,除了 pilot1/3 bit sync. 這兩部分是單純的 01 訊號之外,剩下來的 address codedata code 都必須使用下面的編碼格式來表現 0 ( Zero )1 ( One ) 的訊號,而且都是由最低位元開始送出編碼

 One:001

Zero:011

所以總結來說,HT12E 的編碼字元組的發射順序就是:36 個低準位訊號 ( pilot period+ 1 個 高準位訊號 ( 1/3 bit sync. period+ 24 個特殊編碼格式的位址訊號 ( address code period+ 12 個特殊編碼格式的資料訊號,總共發出 63 個高低準位訊號表示表碼字元組,而這個過程在 TE 接收到低準位脈衝訊號時重複發送次。

知道編碼字元組的編碼原則與格式之後,由於編碼發送是使用 bit-banging 的方式,每一個 bit 之間的時間掌控就變得很重要,但我們要如何知道時間長短呢 ?

還記得在 "RF433MHZ 無線發射接收模組搭配 HT12( D / E ) 遙控器編碼解碼晶片" 裏,HT12E 所使用的 Rocs 電阻值嗎 ? 在資料手冊的第十一頁 "振盪器頻率 vs 供應電壓" 右邊找到 1.0M Ohm,沿著線移動到與下方 VDD 等於 5V 的交點再往左看,這個數值 ( fosc ) 就是 HT12E 所使用的振盪頻率,接近 3kHz,換算為週期為 0.333 ms ( 0.000333 sec );這個數值是接近值,因為電阻值會根據環境溫度及本身的誤差而變動,以此週期為基礎往上或往下做調整,就能找到適當的週期時間。
Oscillator frequency vs supply voltage


程式架構:

在樹莓派裡控制 GPIO 的 C 語言函式庫是 bcm2835,若之前沒有安裝過,可至賣場部落格 "Raspberry Pi - BCM2835 C 語言函式庫" 觀看,裡面有下載及安裝的說明。

HT12E 編碼訊號的模擬,是使用樹莓派的 GPIO #18 做為編碼資料傳送接腳;宣告兩個全局變數 E_ADDRESSE_DATA 做為儲存使用者的編碼位址與資料;常數 SYNC_PERIOD 用來設定 1/3 bit 的時間長度 ( HT12E 的 bit "0" 或 "1" 是由三個數位訊號組成 );全局陣列變數 sCode[12] 用來將編碼位址與資料解成單一 bit 存到陣列去,將 sCode[12] 做為 SendEncode(int *Code) 的引數,SendEncode 會負責傳送 12 次編碼字元組由 GPIO #18 出去,"0" 和 "1" 編碼的傳送則是由函式 Send0Send1 負責,當中使用到的週期時間設定則是由結構變數 sleeptime 和 remaintime 負責再由時間函數 nanosleep 執行。

#include <stdio.h>
#include <time.h>
#include <bcm2835.h>

// 接腳定義
#define BITBANG         18

// 變數設定
int E_ADDRESS, E_DATA;

const long int SYNC_PERIOD = 193000;

int sCode[12]; // 儲存編碼器位址與資料

struct timespec sleeptime;
struct timespec remaintime;

void SendEncode(int *Code);
void Send0();
void Send1();

在主程式 ( main() ) 的部分,先做 bcm2835 函式庫的初始化,再初始化 bit-banging 接腳與狀態;然後進入到無窮迴圈的選單列表,裡面有編碼位址、編碼資料、傳送和離開程式,這裡面較重要的是傳送的處理。

選擇 "Transmit.." 後,由 E_ADDRESS 的低位元開始比對,並將 0 或 1 存入到 sCode 陣列的 0 - 7 之中;然後同樣的由 E_DATA 的低位元開始比對,比對後的結過存入到 sCode 陣列的 8 - 11 之中;最後將資料給 SendEncode 函式,準備發送

int main(int argc, char** argv)
{
 int sel = 0;
 
    // bcm2835 函式庫初始化
    if(!bcm2835_init())
        return 1;
    
    // IO 初始化與初始狀態設定
    bcm2835_gpio_fsel(BITBANG, BCM2835_GPIO_FSEL_OUTP);
    bcm2835_gpio_write(BITBANG, LOW);
    
    /*- 編碼測試 -*/
    while(1)
    {
     // 列出選單
     printf("\n");
     printf("<1> Encoder address setting\n");
     printf("<2> Encoder data settigng\n");
     printf("<3> Transmit... \n");
     printf("<4> Exit the program !!\n");
     printf("your select: ");
     scanf("%d", &sel);
     fflush(stdin);
     
  if(sel == 1) // Encoder address setting
  {
   // 位址設定
      printf("Please input encoder address [0-255] (%d, %d): ", E_ADDRESS, E_DATA);
      scanf("%d", &E_ADDRESS);
      fflush(stdin);
      if((E_ADDRESS < 0) || (E_ADDRESS > 255))
      {
          printf("\nWrong encoder address setting, temporary set E_ADDRESS = 255\n");
          E_ADDRESS = 255;
      }
      
  }
  else if(sel == 2) // Encoder data setting
  {
      // 資料設定
      printf("Please input encoder data [0-15] (%d, %d): ", E_ADDRESS, E_DATA);
      scanf("%d", &E_DATA);
      fflush(stdin);
      if((E_DATA < 0) || (E_DATA > 15))
      {
          printf("\nWrong encoder DATA setting, temporary set E_DATA = 0\n");
          E_DATA = 0;
      }
  }
  else if(sel == 3) // transmit
  {
   printf("\nTransmit: Encoder-address = %d, data = %d\n", E_ADDRESS, E_DATA);
   
   // 編碼器位址
      // 0-7
      int nCodePos = 0;
      for(int nCodeA = 0; nCodeA < 8; nCodeA++)
      {
          sCode[nCodePos++] = (((E_ADDRESS) & (1 << nCodeA)) > 0);
      }
  
      // 編碼器資料
      // 7-12
      for(int nCodeD = 0; nCodeD < 4; nCodeD++)
      {
          sCode[nCodePos++] = (((E_DATA) & (1 << nCodeD)) > 0);
      }
  
      // 開始傳送
      SendEncode(sCode); 
  }
  else if(sel == 4) // Exit the program
  {
      // 關閉 bcm2835 函式庫
      if (!bcm2835_close())
      {
          printf("Failed to close the library, deallocating any allocated memory and closing /dev/mem\n");
          printf("\nPress any key to exit...");
                  while(getchar() > 0){}          
          return 4;
      }
   return 0;
  }
  else 
  {
   printf("\nYou select the wrong number, try again !!\n");
      break;
  }     
    }
   
    return 0;   
}

雖然 HT12E 本身會重複發出編碼字元組四次,但是別忘了!當 TE 恢復成高準位時它會再重複傳送四次,總共次的編碼字元組 ( 在後面測試與驗證時,會有波形證明 ),在程式裡重複重傳送的次數設定為 12 次;只要能正確接收次數可以再做修改。

SencEncode 分為四個部分傳送編碼資料:
  • pilot period:這是一個 12 "bit" 低準位的長度,時間是 36 週期的時間 ( 別忘了 HT12E 的 1 "bit" 等於三個數位訊號長度也就是三個周期長度 );設為 9450000 us

  • 1/3 bit sync. period:這是一個 1/3 "bit" 的高準位訊號也就是一個週期的長度;設為 193000 us

  • address code period and data code period:發送存放在 sCode 裡的 12 個數字。若為 1 ,使用 Send1 函數傳送 001 三個數位訊號,每一個數位訊號長度 SYNC_PERIOD = 193000;若為 0 ,使用 Send0 函數傳送 011 三個數位訊號,每一個數位訊號長度 SYNC_PERIOD = 193000
void SendEncode(int *Code)
{   
    for(int sendno = 0; sendno < 12; sendno++) // 編碼重覆傳送次數
    {                
        /*- pilot  period (12 bits) -*/
        sleeptime.tv_sec = 0;        
        sleeptime.tv_nsec = 9450000;
        bcm2835_gpio_write(BITBANG, LOW);
        nanosleep(&sleeptime, &remaintime);       
        
        /*- 1/3 bit sync. period -*/   
        sleeptime.tv_sec = 0;        
        sleeptime.tv_nsec = SYNC_PERIOD;
        bcm2835_gpio_write(BITBANG, HIGH);
        nanosleep(&sleeptime, &remaintime);
        bcm2835_gpio_write(BITBANG, LOW);
        
        /*- address code period and data code period -*/
        for(int i = 0; i < 12; i++)
        {
            if(Code[i] == 1) // Code 只存放數字 0 或 1
            {
                // "One" bit waveform
                //           _   _   _  
                // fosc     | |_| |_| |_
                //                   ___
                // "One"    ________|   |
                Send1();
            }
            else if(Code[i] == 0)
            {
                // "Zero" bit waveform
                //           _   _   _  
                // fosc     | |_| |_| |_
                //               _______
                // "Zero"   ____|       |
                Send0();
            }
            else
            {
                printf("Get wrong encoding !!!");
                bcm2835_gpio_write(BITBANG, LOW);
            }
        }
    }
    bcm2835_gpio_write(BITBANG, LOW);
}

下面是 Send0 與 Send1 兩個函數的程式碼

void Send0()
{
    // "Zero" bit waveform
    //           _   _   _  
    // fosc     | |_| |_| |_
    //               _______
    // "Zero"   ____|       |
    // 011
    bcm2835_gpio_write(BITBANG, LOW);
    nanosleep(&sleeptime, &remaintime);                
    bcm2835_gpio_write(BITBANG, HIGH);
    nanosleep(&sleeptime, &remaintime);
    nanosleep(&sleeptime, &remaintime);
    bcm2835_gpio_write(BITBANG, LOW);
}

void Send1()
{
    // "One" bit waveform
    //           _   _   _  
    // fosc     | |_| |_| |_
    //                   ___
    // "One"    ________|   |
    bcm2835_gpio_write(BITBANG, LOW);
    nanosleep(&sleeptime, &remaintime);
    nanosleep(&sleeptime, &remaintime);
    bcm2835_gpio_write(BITBANG, HIGH);
    nanosleep(&sleeptime, &remaintime);
    bcm2835_gpio_write(BITBANG, LOW);
}


原始程式碼以及執行檔下載,請依下面指令輸入:

pi@raspberrypi ~ $ cd codes
pi@raspberrypi ~/codes $ mkdir RPi_sim_HT12E
pi@raspberrypi ~/codes $ cd RPi_sim_HT12E
pi@raspberrypi ~/codes/ERPi_sim_HT12E $ wget -O - http://goo.gl/QJMgD | tar xvf -

編譯方式:

sudo gcc rpi_rf_ht12e_sim.c -l rt -l bcm2835 -std=gnu99 -o rpi_rf_ht12e_sim


測試與驗證:

如下圖將 RF 無線模組裝到樹莓派上去
  • RPi ( P1, 5V0, pin-2 )    --[ 紅 ]-->  RF ( VCC )

  • RPi ( P1, GND, pin-9 )    --[ 綠 ]-->  RF ( GND )

  • RPi ( P1, pin-12 )  --[ 藍 ]-->  RF ( DATA )
RF 發射模組與樹莓派的接線
使用有線網路是避免干擾;接到 5V0 是盡可能的增加傳輸距離。如果不是在這條件下的話,傳輸距離有可能會大幅減少,那就必須焊接天線增加傳輸的距離與效果。

測試成功後,再將無線發射模組的電源換成 3V3,一樣可遙控接收端,不過可看看兩者之間傳輸距離有何不同 ?

接收端可以使用賣場部落格 "RF433MHZ 無線發射接收模組搭配 HT12( D / E ) 遙控器編碼解碼晶片" 網頁中所接的麵包板線路做測試
無線發射模組麵包板線路

設定接收端的編碼位址為 0111 1111 ( 127 ),然後輸入下面指令進行程式測試

pi@raspberrypi ~/codes/ERPi_sim_HT12E $ sudo ./rpi_rf_ht12e_sim

<1> Encoder address setting
<2> Encoder data settigng
<3> Transmit...
<4> Exit the program !!
your select: 1
Please input encoder address [0-255] (0, 0): 127

<1> Encoder address setting
<2> Encoder data settigng
<3> Transmit...
<4> Exit the program !!
your select: 2
Please input encoder data [0-15] (127, 0): 7

<1> Encoder address setting
<2> Encoder data settigng
<3> Transmit...
<4> Exit the program !!
your select: 3

Transmit: Encoder-address = 127, data = 7

<1> Encoder address setting
<2> Encoder data settigng
<3> Transmit...
<4> Exit the program !!
pi@raspberrypi ~/codes/ERPi_sim_HT12E $

成功傳送編碼資料之後,您就會看到接收端的紅色 LED 亮滅,最上面三顆 LED 亮起。額外加了二通道光隔離繼電器於最下面兩顆 LED 處,只有當低態作動時,繼電器才會作動。
模擬 HT12E 訊號,控制 HT12D 接收端 LED 與 繼電器

接下來,我們來比較一下 HT12E 實際編碼以及模擬 HT12E 編碼後兩者的波形。如果手邊有示波器或是任何可擷取數位訊號的裝置可以使用,可自己動手試試!

HT12E 實際編碼波形:

按一下無線發射線路的發射按鈕 ( 不需按住 ),擷取完成後就會看到 8 組凸起的波形;這就是每次 TE 被低準位脈衝訊號觸發時,所發出的八次編碼字元組訊號
HT12E 觸發時所發出的編碼訊號次數

由下圖,確認 pilot period 與 1/3 bit sync. period 的時間;寬度 ( width:9.456 ms) 表示 pilot 的時間,週期 ( Period:9.731 ) 減掉寬度等於 0.275 ms 可表示 1/3 bit 的時間;9.456 / 0.275 等於 34.38,可強詞奪理的說就是 36 個週期時間。

上面這些值會因為電路元件以及量測儀器的誤差,或多或少的變動!沒法說準確到百分之百,但卻是能提供設計上的一個思考的方向。
pilot period

接著再看看 "0" 所發出的低準位與高準位的周期時間。低準位的兩倍週期時間 (0.269 x 2 = 0.538 ms ) 大約等於一個高準位的週期時間 ( 0.818 - 0.269 = 0.549 ms )
bit "0", 011

繼續看看 "1" 所發出的低準位與高準位的周期時間。高準位的兩倍週期時間 ( 0.814 - 0.539 = 0.275 ms, 0.275 x 2 = 0.55 ms) 大約等於一個低準位的週期時間 ( 0.539 ms )
bit "1", 001


HT12E 實際編碼波形:

看過實際的波形之後,接著來看看使用樹莓派模擬 HT12E 的波形。還記得程式中的設定值嗎  ( SYNC_PERIOD = 193,000 us,period period = 9,450,000 us )?在程式中,所設定的數值會因為作業系統以及程式碼編寫方式的因素會有所延遲,只要這些設定值能夠接近實際值並且在晶片所容許的誤差範圍之內,都可以達到所期望的結果。

現在就讓我們來截取數莓派所模擬的 HT12E 編碼訊號!

下圖是我手邊最簡單的數位訊號截取工具,白線接地 ( GND )、棕線接 GPIO #18,再使用 Saleae logic 軟體擷取訊號
擷取樹莓派模擬的 HT12E 編碼訊號

同樣的,也是四張圖片,分別秀出編碼字元組發送次數、pilot period 的時間、bit "0" 和 bit "1" 的週期時間。

每一次編碼字元組的發送,程式設定為 12 次,可以事情情況增檢減,但除非必要,軟體都應該在硬體確認無誤或是無法再作改善時才修改
樹莓派模擬HT12E 觸發時所發出的編碼訊號次數

由下圖,pilot period 與 1/3 bit sync. period 的時間;寬度 ( width:9.546 ms) 表示 pilot 的時間,週期 ( Period:9.824 ) 減掉寬度等於 0.278 ms 可表示 1/3 bit 的時間;9.546 / 0.278 = 34.34
樹莓派模擬 HT12E, pilot period

模擬後 "0" 所發出的低準位與高準位的周期時間。低準位的兩倍週期時間 (0.273 x 2 = 0.546 ms ) 大約等於一個高準位的週期時間 ( 0.813 - 0.273 = 0.54 ms )
樹莓派模擬 HT12E, bit "0", 011

模擬 "1" 所發出的低準位與高準位的周期時間。高準位的兩倍週期時間 ( 0.811 - 0.540 = 0.271 ms, 0.271 x 2 = 0.542 ms) 大約等於一個低準位的週期時間 ( 0.540 ms )
樹莓派模擬 HT12E, bit "1", 001

我們將模擬後數值與實際值做比較,可以知道程式裡所設定的數值非常接近實際值,且之間的誤差值在 HT12E 所允許的容許範圍內
HT12E 程式設定值 模擬後數值
width: 9.456 ms
9,450,000 ( us )
width: 9.546 ms
period: 9.731 ms period: 9.824 ms
width: 0.269 ms
193,000 ( us )
width: 0.273 ms
period: 0.818 ms period: 0.813 ms
width: 0.539 ms
193,000 ( us )
width: 0.540 ms
period: 0.814 ms period: 0.811 ms


配合賣場套件硬體線路與本文說明,總結如下:
  • 接收端電壓一定要夠 ( 5V ),電壓不足一定會影響接收的能力

  • 若編碼正常,但運行多次之後接收端會失去控制,要重新開關接收端才會恢復正常,那就是接收端的電壓不夠造成,確認可正常執行後再做其他電壓測試

  • SYNC_PERIOD:1/3 bit 同步訊號長度
  • 測試過的範圍值在 1930000 到 200000 都是可正常運作的,其他範圍值可自行嘗試

  • sleep.tv_nsec 脈波訊號長度值 (3個為一組)
  • 測試過的範圍值在 9450000 到 9500000 都是可正常運作的,其他範圍值可自行嘗試

樹莓派接收無線訊號:

使用樹莓派接收資料,同樣也可使用 bit-banging 的方式,不過我沒特別去研究過,有興趣的可以 Google 一下。我所使用的方法與 "RF433 MHZ 搭配微控制器的使用方法" 相同,程式碼也類似,若想使用樹派接收一些編碼的話,可以使用這個方法試試!

我們需要 wiringPi 函式庫並修改兩份文件才能使用樹莓派的 UART,如果您已經有安裝 wiringPi 函式庫,下面安裝指令就可以略過

pi@raspberrypi ~ $ cd; sudo apt-get install git-core
## 取得更新過的程式碼
pi@raspberrypi ~ $ git clone git://git.drogon.net/wiringPi
pi@raspberrypi ~ $ cd wiringPi pi@raspberrypi ~/wiringPi $ git pull origin ... # 如果是最新版了,就會出現 Already up-to-date ... ## 編譯及安裝 wiringPi,使用 build script pi@raspberrypi ~/wiringPi $ ./build ...

接著修改文件,修改之前將兩份文件先備份
pi@raspberrypi ~ $ sudo cp /boot/cmdline.txt /boot/cmdline.txt.orig
pi@raspberrypi ~ $ sudo cp /etc/inittab /etc/inittab.orig

打開 cmdline.txt 文件 ( sudo nano /boot/cmdline.txt ),原始檔案為
dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait

將裡面與 ttyAMA0 相關的參數全部刪掉
console=ttyAMA0,115200 kgdboc=ttyAMA0,115200

完成的 cmdline.txt 檔案內容如下,記得存檔後再離開 nano
dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait

再打開 inittab 文件 ( sudo nano /ect/inittab ) 搜尋 ( Ctrl + w ) ttyAMA0,再移動至此行的最前方加上 "#" 將其做為註解取消掉 ( 如下最後一行 ),存檔之後再離開。
已經修改好的 /etc/inittab

重新開機之後,設定就會生效,就可以開始使用樹莓派的 UART 了。

發射端可以使用不同的微控制器 ( 可至網頁 "RF433 MHZ 搭配微控制器的使用方法" 下載原始程式碼和編譯後檔案 ),使用 ATtiny2313 做為無線發射編碼控制器,持續重複發射編碼訊號 0xAA --> 0x44 --> 0x11 --> 0x55 --> 0xAA --> 0x44 --> 0x22 --> 0x66
ATtiny2313 發射線路 ( 使用 3V 電池 或 5V 電源 皆可)

樹莓派與無線接收模組之間的接線,如下圖。要特別注意到無線接收模組的電源是接到 3V3 而不是 5V0,接錯電源接收資料會不正常
樹莓派與無線接收模組的接線

連結好發射與接收的線路之後,在樹莓派下輸入下面指令,下載執行檔與原始檔
pi@raspberrypi ~ $ cd codes
pi@raspberrypi ~/codes $ mkdir RPi_RFreceive_UART
pi@raspberrypi ~/codes/RPi_RFreceive_UART $ cd RPi_RFreceive_UART
pi@raspberrypi ~/codes/RPi_RFreceive_UART $ wget -O - http://goo.gl/PRV0N | tar xvf -
--2013-03-01 13:40:14--  http://goo.gl/PRV0N
正在查找主機 goo.gl (goo.gl)... 173.194.72.138, 173.194.72.139, 173.194.72.100, ...
正在連接 goo.gl (goo.gl)|173.194.72.138|:80... 連上了。
已送出 HTTP 要求,正在等候回應... 301 Moved Permanently
位置:  <<...此行內容刪除...>> [跟隨至新的 URL]
--2013-03-01 13:40:14-- <<...此行內容刪除...>>

正在查找主機 dl.dropbox.com (dl.dropbox.com)... 54.235.190.162, 107.21.118.1, 107.21.226.115, ...
正在連接 dl.dropbox.com (dl.dropbox.com)|54.235.190.162|:80... 連上了。
已送出 HTTP 要求,正在等候回應... 200 OK
長度: 13824 (14K) [application/x-tar]
Saving to: `STDOUT'

 0% [                                                       ] 0           --.-K/s              rpi_serial_receive
rpi_serial_receive.c
100%[======================================================>] 13,824      60.8K/s   in 0.2s

2013-03-01 13:40:15 (60.8 KB/s) - written to stdout [13824/13824]

pi@raspberrypi ~/codes/RPi_RFreceive_UART $ ls -l
總計 12
-rwxr-xr-x 1 pi pi 8035  2月 28 16:33 rpi_serial_receive
-rwxr-xr-x 1 pi pi 3395  2月 28 16:33 rpi_serial_receive.c


直接輸入 :$ sudo ./rpi_serial_receive 執行無線接收的程式。下表是樹莓派與微控制器間不同供應電壓操作時的情形

ATtiny2313 AT89S51 樹莓派 結果
3V0 -- 3V3 RPi 接收不正常,無法收到微控制器正確的編碼
5V0 5V0 3v3 RPi 正確接收微控制器編碼
3V3 or 5V0 5V0 5V0 RPi 會接收到雜訊訊號,無法正常接收編碼


這只是簡單的使用 UART 做為接收無線訊號的例子,要深入使用必須還要解決接收資料的穩定性及判斷資料正確性的方法,讓各位去發揮吧!


<<相關資料與使用說明連結>>

4 則留言:

  1. 請問一下RF433 樹莓派程式中的SYNC_PERIOD、sleep.tv_nsec 是怎麼測出來的呢?

    我大概了解 sleep.tv_nsec = 9,450,000 ( us )
    width: 9.456 ms ~ width: 9.546 ms

    SYNC_PERIOD = 193,000 ( us ) 這個我就不了解了
    width: 0.269 ms ~ width: 0.273 ms
    還有
    width: 0.539 ms ~ width: 0.540 ms
    193,000 這個直是怎麼出來的呢?

    回覆刪除
    回覆
    1. 由波形圖得出的。
      要知道波形代表的意思,必須先知道 HT12E/D 的編解碼原則,然後對照波形找出規則。由於使用 bit-banging 的方式,因此不會執行 delay 100 us 就會真的延遲 100 us,所以必須重複取得波形,並驗證與實際可動作的硬體電路發射與接收的波形是否一致,然後以嘗試法的方式設定這些間隔時間。

      刪除
  2. 使用 Saleae logic 軟體擷取訊號,是直接插在樹梅派上面執行?

    是如何執行,然後看到擷取到的訊號呢?

    Saleae logic的usb端直接接到樹梅派的電源?
    然後 白線接地 ( GND )、棕線接 GPIO #18
    這樣就能在樹梅派上面看到訊號?
    有操作的方法能提供的嗎?

    那是不是需要兩台樹梅派呢?
    一台傳送rf433,一台Saleae logic擷取?

    請你幫我回答這些問題~謝謝

    回覆刪除
  3. 用示波器也可以!
    Saleae logic 需要搭配它能通訊的硬體才能做使用,使用說明跟賣家或是上網找一下就有,跟電表使用的方式一樣。

    回覆刪除