2017年8月15日 星期二

*0*nRF24L01+*0* Arduino 二點四GHz 訊號掃描器

網頁最後修改時間:2017/08/15 

藍牙、WiFi、ZieBee、手機、麥克風,甚至是微波爐  ... 等裝置 ( NI 國家儀器:2.4 GHz 的廚房裡有太多廚師想大展身手 ),都會使用到 2.4GHz 頻率。簡單 DIY 個 2.4 GHz 訊號掃描器,能夠在掃描器掃描的範圍內,看到選定頻率頻道訊號強弱的分布,藉此來得知哪些頻率頻道正在被使用 ? 或是還有哪些頻率頻道可以被使用 ?

為了測試掃描器是否能正常動作,藉由切換無線路由器的無線頻道可以很方便的檢驗,並且更換使用外接天線的無線模組進行接收靈敏度的測試。雖然它不是一個非常高檔的 2.4G 訊號掃描器,但是為了之後要查詢還有哪些 2.4GHz ISM 頻段可以做為通訊來說,夠用了 !
掃描器無線模組使用 nRF24L01+ 負責掃描(接收)不同頻率的訊號,因為 LCD 只有 16 的字元寬度,所以根據下表可得知 WiFi 頻道由中心頻率 2.412 GHz 開始,每間隔 5 MHz 為一個頻道;由於頻率 (範圍 2.400 GHz ~ 2.525 GHz,1 MHz 間隔,共 126 個頻率) 可自己設定,所以可大概產生一個產生 WiFi 頻道的公式:

channel[i] = 12 + i * 5;    // i = 0 ... 15
2.4 GHz Wi-Fi channels (802.11b,g WLAN).svg
Michael Gauthier, Wireless Networking in the Developing World - I created this work based on Image:2.4_GHz_Wi-Fi_channels_(802.11b,g_WLAN).png, 創用CC 姓名標示-相同方式分享 3.0, 連結

nRF24L01+ 通電之後,由微控制器 (這裡指的是 Arduino Nano) 先進行基本初始化後進入到 Standy 模式。將上面設定好的通道頻率依順序設定入 nRF24L01+ 後,進入 RX 模式準備接收訊號。接收時間到之後切換回 standy 模式,這時若之前有接收到該頻率且訊號強度大於 -64 dBm 以上的話,nRF24L01+ 的暫存器 0x09 的最低位元 RPD 會被設定為 1;讀取這個值並記錄下來。

重複上面的流程數次,紀錄訊號被檢測到的次數,就可以得到各通道在一個完成循環的訊號強度,最後將這些訊號強度轉換到整合型 LCD 上做顯示就得到下面影片中的結果。
*********************************************************************************
[備註]
無線路由器無線頻道:Channel 10 (2.457 GHz [頻率範圍:2.446 GHz ~ 2.468 GHz),涵蓋到 Channel 9 (2.452 GHz) 和 Channel 11 (2.462 GHz),所以 channel 9 / 10 / 11  訊號會較強;相對於其他頻道的微小訊號,不用去管!除非有其他 2.4GHz 裝置在旁邊且訊號很強,不然結果會類似 !
*********************************************************************************
現在,我們就可以開始動手作!

參考接線圖:
2.4GHz 訊號掃描器參考接線圖
/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* 材料:
大概就以上列出的材料就可以做出來,不過要注意的是:圖面上需要的部分表示兩種列出的無線模組都可以用,接線選擇一種就可以 (接線圖沒有特別將轉接板畫出來,但建議使用,避免電壓問題贈成的通訊失敗);另外,上面的整合型 LCD 程式碼與其他 LCD 不一定相容,若使用不一樣的液晶螢幕,顯示部分的程式要自己做修改 (這部分下面會再另外說明);參考電路圖接好線之後,網頁的測試線路如下所示
實際接線完成示意圖
函式庫下載:
我們使用的函式庫對於 nRF24L01+ 支援很好,經過幾個版本的更新之後更臻完善,而且以此為基礎支援 Network layout 和 Mesh Network ... 等,推薦大家下載此一支援 nRF24L01 和 nRF24L01+ 的函式庫來用

推薦函式庫下載

/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* 整合型 LCD 的長條圖顯示函式庫:
這裡使用到整合型 LCD 自訂字元的功能,相關的函式庫與程式碼都在{ 單晶片 + Arduino + 樹莓派 } 整合型 LCD ( @ I2C 模式 ) 的漂亮數字顯示 ( 自訂字型或圖案 ) 部落格網頁裡,裡面有說明也有範例;另外有 {5V} 整合型 LCD 雲端資料夾 ( { 5V } 整合型 1602 LCD 螢幕 / codes / Arduino / 整合型 LCD 長條圖標頭檔 (for nRF24l01+ scanner) / iiclcdbar.h )可直接下載使用。

長條圖顯示函式庫與大型數字顯示函式庫基本上相同,改變的如下所述:
  • 移除 void displayNumeric() 函式宣告與程式碼
  • 移除 const unsigned char Numerics[][] 陣列
  • 移除 const int nix[] const int pix[] 兩個陣列
  • -------------------------------------------------------------------
  • 修改 const unsigned char CGRAM_block[] 陣列如下
  • 加入 void displayBarOnLCD() 函式如下
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const unsigned char CGRAM_block[]={
    0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F, // 0,
    0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0X1F, // 1,
    0X00,0X00,0X00,0X00,0X00,0X1F,0X1F,0X1F, // 2,
    0X00,0X00,0X00,0X00,0X1F,0X1F,0X1F,0X1F, // 3,
    0X00,0X00,0X00,0X1F,0X1F,0X1F,0X1F,0X1F, // 4,
    0X00,0X00,0X1F,0X1F,0X1F,0X1F,0X1F,0X1F, // 5,
    0X00,0X1F,0X1F,0X1F,0X1F,0X1F,0X1F,0X1F, // 6,
    0X1F,0X1F,0X1F,0X1F,0X1F,0X1F,0X1F,0X1F, // 7,
};

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
void displayBarOnLCD( unsigned char pos, unsigned char lev ) {
    if( lev > 7 ) {
        displayCGRAM( lev - 8, 1, pos );
        displayCGRAM( 7, 2, pos );
    }
    else {
        displayCharOnLCD( 1, pos, " ", 1 );
        displayCGRAM( lev, 2, pos );
    }

}

程式碼:
2.4GHz 訊號掃描器是參考函式庫裡面的範例程式,不過我們進行了一些小修改,先將它載進來吧 !

打開 Arduino IDE,選擇 "File/Examples/RF24/scanner"  載入程式碼,載入完成後先另存新檔,並且複製 iiclcdbar.h 這個檔案到目錄中

/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* 標頭檔:
在原有程式的標頭檔,新增兩個標頭檔宣告,如下所示

1
2
3
4
5
6
#include <Wire.h>           // <---- 加入此標頭檔
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
#include "printf.h"
#include "iiclcdbar.h"      // <---- 加入此標頭檔

/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* 全局宣告區:
setup() 函式往上至 #include "iiclcdbar.h 之間所有的程式碼刪掉,插入下面程式碼
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
/** nRF24L01+ */
#define     CEPIN       7
#define     CSNPIN      8
const uint8_t num_channels = 16;         // for 1602 LCD
//----------------------------------------------------
// 設定 channel ( CH = 0 ~ 125, 2.4Ghz ~ 2.525Ghz)
uint8_t channel[num_channels];         // 在程式中指定,可依固定間隔跳頻
// uint8_t carrierCount[num_channels] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; 
uint8_t carrierCount[num_channels];     // 載波檢測到的次數
//----------------------------------------------------
RF24    rf24( CEPIN, CSNPIN );

在這裡重新定義連接 nRF24L01+ <CE> <CSN> 的接腳;掃描的頻率頻道修改為 16 (原本的 128 也是錯的!最多只有 126 個頻率頻道可使用)

/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* 新增一個函示:
loop() 函式的後面,插入下面的程式碼新增一個函式
1
2
3
4
5
6
bool checki2cdevice( uint8_t i2caddr ) {
    // 呼叫此函示之前, Wire 必須先初始化
    Wire.beginTransmission( i2caddr );
    if( Wire.endTransmission() == 0 ) return true;
    return false;
}

藉由這個函式,可偵測 I2C 裝置是否有接好或是是否有接上,只需要相關裝置的 I2C 位址。

/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* 變更 radio 為 rf24:
我將原本的 RF24 radio() 宣告改為 RF24 rf24(),所以在做進一步修改之前,先將整個程式使用到 radio 的全部變更為 rf24

/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* setup():
移除掉 // Print out header, high then low digit 開始至 setup() 函式最後面這幾行程式碼,未修改前的 setup() 函式程式碼如下所示。基本上,這幾行程式碼是之後修改的主架構,只是加入了我們新增的程式碼。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
void setup(void)
{
    //
    // Print preamble
    //

    Serial.begin(57600);
    printf_begin();
    printf("\n\rRF24/examples/scanner/\n\r");

    //
    // Setup and configure rf radio
    //

    rf24.begin();
    rf24.setAutoAck(false);

    // Get into standby mode
    rf24.startListening();
    rf24.stopListening();

}

有兩個部分需要新增,首先是整合型 LCD 初始化相關程式碼。複製下面程式碼插入到  printf() 下面 ( setup(), line10 下面找一處)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
    /** 整合型 LCD (IIC 模式) */
    Wire.begin();
    // 檢查整合型 LCD 是否接上與接好 ?
    if( !checki2cdevice( IIC_ADDR_LCD1 ) )   {
        Serial.println( "LCD not found!" );
        while(1) delay(1);
    }
    // 初始化
    initLCD();
    delay(100);
    clearLCD();
    delay(100);
    // 自訂字元寫入
    writeCGRAM( &CGRAM_block[0],  3, 1 );
    writeCGRAM( &CGRAM_block[24], 3, 4 );
    writeCGRAM( &CGRAM_block[48], 2, 7 );
    displayCharOnLCD( 1, 1, "**IIC LCD ready*", 16 );
    delay( 500 );

接著,在 rf24.begin() 的下一行,插入下面的程式碼
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
    //檢查 RF24 是否接上與接好 ?
    if( !rf24.isChipConnected() ) {
        Serial.println( "nRF24L01/+ not found!" );
        while(1) delay(1);
    }
    //----- RF 掃描頻道設定 -----
    for( int i = 0; i < num_channels; i++ )
        channel[i] = 12 + i * 5;             // 2.412, 2.417, 2.422, ...
    displayCharOnLCD( 2, 1, "RF channel ready", 16 );
    //---------------------------

如此,插入這兩部份的程式碼之後,在每一個連接的週邊模組初始化之前都會先檢查連接的正確性或是否有接上 ? 若是程式開始一段時間之後沒有動作,就可以打開 Serial Monitor 看看輸出的情況,由此來判斷哪裡出錯了!另外,程式在一開始的時候也會在 LCD 上輸出,每完成一個週邊初始化就會輸出一行文字,只要其中一行沒輸出 ... ready 那麼也可以判斷出哪裡出了問題!

setup() 完成程式碼修改之後,下面進行 loop() 函式的修改!

/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* loop():
loop() 函式在進行修改前基本的樣子如下所示。特別注意 line 4 ~ 6,原本有的那一行要刪掉;while( rep_counter--) {} 後面接的 //Print out... 什麼的,全部刪除掉
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//
// Loop
//



void loop(void)
{
    // Clear measurement values
    memset(values,0,sizeof(values));

    // Scan all channels num_reps times
    int rep_counter = num_reps;
    while (rep_counter--)
    {
        int i = num_channels;
        while (i--)
        {
            // Select this channel
            rf24.setChannel(i);

            // Listen for a little
            rf24.startListening();
            delayMicroseconds(128);
            rf24.stopListening();

            // Did we get a carrier?
            if ( rf24.testCarrier() )
                ++values[i];
        }
    }

}

上面就是處理掃描的基本程式架構,等一下會變更幾個變數名稱以及新增整合型 LCD 顯示和 Serial 輸出的部分。

首先,改變一下 loop() 基本架構變數宣告與編排,修改之後如下
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void loop(void)
{

    uint8_t sweeps = 200;
    uint8_t maxCount = 0;
    uint8_t i = 0, j = 0;

    // Clear measurement values
    memset(carrierCount, 0, sizeof(carrierCount));

    // Scan all channels num_reps times
    while (sweeps--) 
    {
        for( i = 0; i < num_channels; i++ ) 
        {
            // Select this channel
            rf24.setChannel(i);

            // Listen for a little
            rf24.startListening();
            delayMicroseconds(128);
            rf24.stopListening();

            // Did we get a carrier?
            if ( rf24.testCarrier() )
                ++carrierCount[i];
        }
    }
}

最後要插入下面的程式碼到 loop() 函式裡的最後面,將掃描之後的結果輸出到 Serial 和整合型 LCD 上 (不要對下面程式碼有所疑慮,只要編譯通過就表示可以用)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
    for( j = 0; j < num_channels; j++ )
        if( maxCount < carrierCount[j]) maxCount = carrierCount[j];

    /** 顯示各頻道的載波值 */
    for( i = 0; i < num_channels; i++ ) {
        uint8_t level = map( carrierCount[i] , 0, maxCount, 0, 15 );        
        displayBarOnLCD( i + 1, level );        
        printf_P( PSTR("%02d "), level );
    }
    printf_P( PSTR( "| %02d\n" ), maxCount );

完成上面的步驟之後,程式碼基本就完成修改可進行編譯與上傳,實際動作結果就如網頁前面的影片。

能夠成功上傳程式之後,接著讓我們來做一些小測試,看看效果如何 ?

測試:
我們測試的重點有兩個:第一個,是測試整個電路與程式是否能正常運作;第二個,則是在第一個測試 OK 之後,更換使用外接天線的的無線模組進行測試,看看兩者之間究竟有何不同 ?

/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* 頻道頻率測試:
因為要測試,所以頻率不能亂選擇,畢竟現在不是用在傳送與接收數據上,由於無線網路大多家中都有,而且設定也很方便,所以就選擇無線網路頻段來做測試 (這部份的一些訊息可上 WIKIPEDIA, WLAN 信道列表查看)
WLAN 頻道頻率列表
看一下上表可以知道,Channel 1 - 12 每個頻道頻率間隔 5MHz,每個頻道的中心頻率就是我們所設定掃描的頻率,但這有範圍!所以只要有涵蓋到這個中心頻率的 WLAN 頻道,在進行訊號掃描時就會接收到訊號。

如下所示,手動選擇無線頻道為  4
WLAN 使用的無線頻道 (Channel 4)
打開掃描器的電源後,可以看到其中 Channel 3, 45 反映大於其他通道,由於測試環境附近沒什麼 2.4GHz 裝置在動作,所以輸出畫面中的結果是可接受的
板載天線無線模組,WLAN Channel  = 4, 掃描過程中其中的一次結果畫面
接著,切換無線頻道為自動頻道 (這是之前預設的設定),自動選擇的無線頻道是 10
WLAN 使用的無線頻道 (Channel 10)
可以在液晶螢幕中看到,無線頻道由 4 改到 10 的時候,畫面中的長條圖由 4 移動到 10 的情況 (當然在照片是看不出來,實際操作會看到)
板載天線無線模組,WLAN Channel  = 10, 掃描過程中其中的一次結果
最後一項測試!

/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* PA+LNA 外接天線模組:
緊接著上面的測試,將無線模組換成 PA+LNA 外接天線式的無線模組 (程式與硬體接腳都是相容的),兩者使用相同的 nRF24L01+ 晶片,在這邊只是順便做測試,測試一下它接收的能力 (當然它的發射功率也是相當不錯的 ! ),而且從下圖也可以看到接收能力比板載天線的無線模組好多了。
PA+LNA 外接天線無線模組,WLAN Channel  = 10, 掃描過程中其中的一次結果
所以若是在實驗階段並不進行實地測試的時候,節省起見可以使用板載無線模組進行測試,當需要實地測試與增大傳輸距離時,就可以換成這種外接天線式的無線模組來用;由於接腳是相同的 (需要注意安裝空間),更換很方便 !

結論:
這是個簡易且實用的二點四GHz 訊號掃描器,做為 nRF24L01+ 無線模組在部落格網頁的起頭,我覺得不錯 ! 即便手邊沒有整合型 LCD,也可以換成其他的液晶螢幕來用,來顯示更多的頻道頻率。

接下來,就要進入到 nRF24L01+ 傳送與接收的部分了,不過還不會太深入!要先來加強板載天線的無線模組傳送與接收的能力,要利用這些改裝的無線模組來做穿牆的測試,為了更後面的多節點無線溫濕度環境監控作準備,所以有興趣的就繼續看下去吧 !

<< 部落格相關網頁 >>

沒有留言:

張貼留言