**講解基於資料報裡配套的sdk5.1版本中的串列埠demo。高版本的sdk基本都是差不多的。
**在路徑***xx\keil\arm\device\nordic\nrf51822\board\pca10001\s110\experimental中
int main(void)
}static void leds_init(void)
設定的pin_config暫存器使能兩個引腳的作為輸出功能。用來當做指示燈指示廣播和鏈結的狀態。
static void timers_init(void)
初始化軟體定時器模組,該定時器模組並不是使用timer0-2來實現定時功能。而是使用51822中的rtc1 來軟體模擬出定時器模組。rtc1使用32.768k時鐘經過分頻後是時鐘來作為時鐘源。所以該函式內部實現就是設定rtc1相關的暫存器和做一些初始化。其原理和timer 定時/計數器模組類似。具體細節參考晶元資料手冊。
false:不使用排程,排程模組沒有細看。貌似51822關於排程的都是傳false不使用排程。51822的協議棧實現是基於非同步事件驅動的。
static void buttons_init(void)
這裡的按鍵設定比較簡單,主要通過pin_cnf暫存器來設定乙個io口來作為來作為sensing mechanism機制的引腳。這裡是設定了wakeup_button_pin這個引腳來作為這個功能,設定成低電平時觸發這個機制。而這個機制類似乙個wakeup機制,當其被觸發時會產生乙個detect signal而這個訊號會將cpu從system off模式中喚醒。
static void uart_init(void)
初始化uart設定輸入輸出引腳,是否關閉流控。一般使用官方例子的時候都要先將流控關掉,hwfc為false。然後開啟uart的接收中斷,開啟uart模組的中斷功能,以及設定優先順序。波特率在******_uart_config中設定,該函式設定完引腳後使能uart開啟uart的接收和傳送功能。
static void ble_stack_init(void)
//設定lfclk(32.768k)的時鐘源(協議棧需要使用),這裡設定為外部晶振。false為不使用排程。softdevice_ble_evt_handler_set(
設定必要的裝置的gap引數。
static void gap_params_init(void)
static void services_init(void)
(1)
ble_nus_init該函式中實現新增服務以及新增特徵值
uint32_t ble_nus_init(ble_nus_t * p_nus, constble_nus_init_t * p_nus_init) ;
if ((p_nus == null) || (p_nus_init == null))
// 初始化連線控制代碼,因為現在並未與手機連線所以先賦值無效。
//賦值資料處理函式,就是上面剛提到的列印收到的手機資料
//設定notify是否使能的標誌量,該標誌量在手機連上板子並且使能了具//有notfify的特徵值時(這裡是rx特徵值後面會講到),該標誌會被設// 置。這個標誌量僅僅只是乙個類似flag的作用,甚至可能並未被
// 用到。
p_nus->conn_handle = ble_conn_handle_invalid;
p_nus->data_handler = p_nus_init->data_handler;
p_nus->is_notification_enabled = false;
// 因為是自己定義的uuid,所以需要呼叫該函式來賦值p_nus->uuid_type
//該函式會將這個nus_base_uuid放到協議棧內部的表中
err_code =
sd_ble_uuid_vs_add(&nus_base_uuid, &p_nus->uuid_type);
if (err_code != nrf_success)
//設定服務uuid以及uuid_type(就是上面呼叫的函式或得的)
ble_uuid.type = p_nus->uuid_type;
ble_uuid.uuid = ble_uuid_nus_service;
// 到這裡就新增服務到協議棧內部表中了
err_code =
sd_ble_gatts_service_add(ble_gatts_srvc_type_primary,
&ble_uuid,
&p_nus->service_handle);
if (err_code != nrf_success)
// 乙個服務通常有幾個特徵值
//這裡在上面註冊的服務中新增了兩個特徵值。
err_code = rx_char_add(p_nus, p_nus_init);
if (err_code != nrf_success)
// add tx characteristic.
err_code = tx_char_add(p_nus, p_nus_init);
if (err_code != nrf_success)
return nrf_success; }
本篇教程主要說明協議棧的整體框架和。關於服務的建立和特徵值的新增。這裡不做細將,主要因為特徵值的新增涉及到很多的概念和引數設定。後面分單獨發一篇教程針對如何建立自己的服務並新增特徵值。
廣播引數的初始化
static void advertising_init(void)
};
//這裡設定廣播的名字為全名,設定標誌,就是上面提到的。
memset(&a***ata, 0, sizeof(a***ata));
a***ata.name_type = ble_a***ata_full_name;
a***ata.flags.size = sizeof(flags);
a***ata.flags.p_data = &flags;
//這裡設定的是掃瞄響應資料。該資料在裝置收到掃瞄請求的時候才會發出去。
//有時候需要廣播的資料可能太多,廣播包中放不下,那麼就可以放在掃瞄響應
//資料中,這樣對端裝置便可以通過掃瞄請求來或得剩下的資料。
memset(&scanrsp, 0, sizeof(scanrsp));
scanrsp.uuids_complete.uuid_cnt = sizeof(adv_uuids) / sizeof(adv_uuids[0]);
scanrsp.uuids_complete.p_uuids =adv_uuids;
err_code = ble_a***ata_set(&a***ata, &scanrsp);
}
設定連線引數
static void conn_params_init(void)
安全引數的初始化。主要設定
mitm: 是否需要中間人保護。
io_caps:本裝置的i/o能力。比如有顯示屏,有鍵盤。
:當使能了mitm 並且兩端裝置乙個有鍵盤,乙個有顯示屏時,配對過程中就會顯示乙個配對碼,對端裝置通過鍵盤再輸入。
如果沒有mitm保護配對過程中的資訊是很容易被監聽到的。但是如果有了mitm因為這個配對碼資訊是一端顯示一端輸入,並不會通過鏈路傳輸。
因為除了兩端裝置不會有第三個裝置知道。因此後續的鏈路加密就很難被破解。
oob:與mitm類似,只是配對碼不是通過鍵盤輸入而是通過兩端裝置別的通訊通道傳輸,比如nfc,當然前提是該通訊鏈路是安全的。不如也沒必要繞個彎而不直接用ble來傳輸了。
後面就是設定加密秘鑰的最大和最小值。加密秘鑰的大小在7-16位元組之間
配對的過程相對比較複雜,這裡不做理論解釋。後期需要的話會單獨做一片配對的詳細教程,群檔案中有我上傳了乙個作為從機的配對歷程也是基於uart,當主機在使能有第乙個特徵值的notify時便會觸發配對,配對碼是通過串列埠列印的。使用的隨機產生的。當然也可以設定為靜態的。
void sec_params_init(void)
static void advertising_start(void)
BLE NRF51822教程 RSSI獲取
當手機和裝置連線上後,裝置端可以通過獲取rssi來 在一定程度上判斷手機離裝置的相對距離的遠近。獲取函式很簡單直接呼叫sd ble gap rssi get介面函式就行了,傳入連線控制代碼和buff就能獲取到 最近一次連線事件中的 接收訊號強度。呼叫該函式之前需要先呼叫sd ble gap rssi...
BLE NRF51822教程8 動態廣播
本講接收如何實現動態廣播。教程基於 9.0 sdk中的 uart例子。實現動態廣播的方法是 廣播 停止廣播 修改引數 重啟廣播 所以我們通過乙個定時器來週期性的 關閉廣播然後再修改廣播資料之後再開啟廣播。sdk 9.0中的廣播搞了好幾個模式,做的有點麻煩,所以我對他做了比較大的改動。首先 在main...
BLE NRF51822教程8 動態廣播
ble nrf51822教程8 動態廣播 2015 12 29 17 38 35 分類 嵌入式 本講接收如何實現動態廣播。教程基於 9.0 sdk中的 uart例子。實現動態廣播的方法是 廣播 停止廣播 修改引數 重啟廣播 所以我們通過乙個定時器來週期性的 關閉廣播然後再修改廣播資料之後再開啟廣播。...