nrf51822蓝牙学习笔记四
目錄
- UUID
- UUID的原理
- 藍牙技術聯盟UUID
- 供應商特定UUID
- UUID的設置
- 串口透傳
- 初始化串口
- 服務的建立
- 雙向數據傳輸
- 藍牙遙控器的設計
- nrf51822內部flash操作
- flash事件派發
- flash初始化
- flash讀寫
- flash存儲接收內容
- 遠程修改參數
- 藍牙溫濕度采集
- DHT11
- 廣播包和數據包分析
- 廣播包
- 數據包
- LED讀寫數據包
- 讀
- 寫
- mac地址分析與設置
- BLE設備地址類型
- 公共設備地址
- 隨機設備地址
- 靜態設備地址
- 私密設備地址
- 不可解析私密地址
- 可解析私密地址
- 地址配置
- 藍牙信號rssi讀取
- 為什么是負值
- API
- 藍牙發射功率的設置
目前手里面有幾個項目用的是nrf51822這款藍牙芯片。由于我從未接觸過藍牙協議,所以在很多地方磕磕絆絆的,所以最近準備系統學習一下該芯片。并做一下筆記放在我的博客里面。系統學習資料來源于B站青峰電子。視頻名稱為 藍牙nrf51822視頻教程資料 編程開發 協議棧開發 青峰電子例程。
UUID
UUID的原理
UUID含義是通用唯一識別碼(Universally Unique Identifier),這是一個軟件建構的標準。UUID是指再一臺機器上生成的數字,它保證對再同一時空中的所有機器都是唯一的。通常平臺會提供生成的API。
在GATT層中,規范定義的所有屬性都有一個UUID值,UUID是全球唯一的128位的號碼,它用來識別不同的特性。
藍牙技術聯盟UUID
所有的藍牙技術聯盟定義UUID共用了一個基本的UUID。0x0000xxxx00001000800000805F9B34FB。為了進一步進化UUID,每一個藍牙技術聯盟的屬性有一個唯一的16位UUID,以代替基本UUID的xxxx部分。例如心率測量特性使用0x2A37。
供應商特定UUID
SoftDevice根據藍牙技術聯盟定義UUID類似的方式定義UUID:先增加一個特定的基本UUID,再定義一個16位的UUID,將16位UUID加載到基本的UUID中。這種采用為所有的定制屬性定義一個共用的基本UUID的方式使得應用變的更加簡單。
UUID的設置
uint32_t ble_nus_init(ble_nus_t * p_nus, const ble_nus_init_t * p_nus_init) {uint32_t err_code;ble_uuid_t ble_uuid;//基本UUID,xxxx使用00 00占位,數組下標與顯示方向相反ble_uuid128_t nus_base_uuid = NUS_BASE_UUID;if ((p_nus == NULL) || (p_nus_init == NULL)){return NRF_ERROR_NULL;}// Initialize the service structure.p_nus->conn_handle = BLE_CONN_HANDLE_INVALID;p_nus->data_handler = p_nus_init->data_handler;p_nus->is_notification_enabled = false;/**@snippet [Adding proprietary Service to S110 SoftDevice] */// Add a custom base UUID.//將16位UUID添加到128位基礎UUIDerr_code = sd_ble_uuid_vs_add(&nus_base_uuid, &p_nus->uuid_type);if (err_code != NRF_SUCCESS){return err_code;}ble_uuid.type = p_nus->uuid_type;ble_uuid.uuid = BLE_UUID_NUS_SERVICE;// Add the service.err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,&ble_uuid,&p_nus->service_handle);/**@snippet [Adding proprietary Service to S110 SoftDevice] */if (err_code != NRF_SUCCESS){return err_code;}// Add the RX Characteristic.err_code = rx_char_add(p_nus, p_nus_init);if (err_code != NRF_SUCCESS){return err_code;}// Add the TX Characteristic.err_code = tx_char_add(p_nus, p_nus_init);if (err_code != NRF_SUCCESS){return err_code;}return NRF_SUCCESS; }串口透傳
通過串口透傳數據傳輸給藍牙。
初始化串口
這個也太簡單了吧。隨便百度就OK。
服務的建立
服務ble_nus.c
雙向數據傳輸
tx,rx兩個子服務。
藍牙遙控器的設計
基于藍牙串口透傳,通過藍牙發起指令控制硬件,達到遙控器的目的。
nrf51822內部flash操作
flash事件派發
/**@brief Function for dispatching a system event to interested modules.** @details This function is called from the System event interrupt handler after a system* event has been received.** @param[in] sys_evt System stack event.*/ static void sys_evt_dispatch(uint32_t sys_evt) {pstorage_sys_event_handler(sys_evt);//需要有該函數,官方函數庫,直接調用即可ble_advertising_on_sys_evt(sys_evt); }// Register with the SoftDevice handler module for BLE events. err_code = softdevice_sys_evt_handler_set(sys_evt_dispatch);//ble_stack_init函數中,協議棧系統事件 APP_ERROR_CHECK(err_code);flash初始化
static pstorage_handle_t m_storage_handle; /**< Persistent storage handle for blocks requested by the module. */pstorage_module_param_t param; // Initialize persistent storage module. err_code = pstorage_init();//只能初始化一次,我曾經初始化兩次而出現問題//dm_init中有初始化 //All context with respect to a particular device is stored contiguously. param.block_size = ALL_CONTEXT_SIZE;//塊大小 param.block_count = DEVICE_MANAGER_MAX_BONDS;//塊數目 param.cb = dm_pstorage_cb_handler;//回調err_code = pstorage_register(¶m, &m_storage_handle);flash讀寫
pstorage_handle_t block_handle; err_code = pstorage_block_identifier_get(&m_storage_handle,0,&block_handle);//獲取ID,有注冊多次時需要用到,一次的話可以不調用 err_code = pstorage_clear(&block_handle, ALL_CONTEXT_SIZE);//擦除 err_code = pstorage_store(&block_handle,data,size,offset);//存儲 err_code = pstorage_load(data,&block_handle,size,offset);//讀取 pstorage_update(&block_handle,data,size,offset);//更新flash存儲接收內容
通過回調函數來進行存儲,例程函數名及注釋如下:
/**@brief Function for pstorage module callback.** @param[in] p_handle Identifies module and block for which callback is received.* @param[in] op_code Identifies the operation for which the event is notified.* @param[in] result Identifies the result of flash access operation.* NRF_SUCCESS implies, operation succeeded.* @param[in] p_data Identifies the application data pointer. In case of store operation, this* points to the resident source of application memory that application can now* free or reuse. In case of clear, this is NULL as no application pointer is* needed for this operation.* @param[in] data_len Length of data provided by the application for the operation.*/ static void dm_pstorage_cb_handler(pstorage_handle_t * p_handle,uint8_t op_code,uint32_t result,uint8_t * p_data,uint32_t data_len) {}源代碼太多,影響閱讀,所以不貼代碼,需要的話,自行閱讀。
存儲接收流程為手機發送數據->藍牙數據處理->寫入
此流程與例程功能并不相同。
藍牙回調函數中如下代碼:
pstorage_handle_t block_handle; pstorage_block_identifier_get(&m_storage_handle,0,&block_handle);//注冊一次可以不調用 pstorage_update(&block_handle,need_storage_data,len,offset);//更新數據遠程修改參數
流程:
藍牙發送參數->藍牙數據存儲參數->重啟初始化已經修改的參數
藍牙溫濕度采集
DHT11
單總線,很多開發板例程中都有它。也大多數使用的是模擬的IIC。
到這里了,不會還有人不會使用api去發送、接收藍牙數據吧?不會吧不會吧!
廣播包和數據包分析
使用Packet Sniffer工具進行抓包
抓包圖:
廣播包
顯示數據標記為11個部分。
- Packet Sniffer抓包序列數,依次計數
- 抓取包的延時
- 廣播包表示的是廣播信道,數據包表示的是數據信道。
數據鏈路層的兩種信道:
A:廣播信道,提供給還沒有建立連接的藍牙設備提供發射廣播、掃描、建立連接的信道。BLE有三個廣播信道,37,38,39.廣播設備分別在這三個信道各發送一次廣播信號。傳統藍牙信道有16-32個,而BLE只有三個。因此BLE廣播時間短。
B:數據信道:提供給已經建立藍牙連接的主從端提供可靠的數據通信信道。BLE規定有37個。為加強通訊的可靠性,避開干擾。BLE設備通過自適應跳頻的方式在37個信道上傳。 - 接入地址:0xBE89BED6。所有BLE設備的廣播幀都是使用的該地址,不分廠家
- PDU type是廣播類型(2 BYTE)。
- 以ADV開頭的幀表示為廣播幀。是由advertiser發出的。有四種類型:
①ADV_IND:通用的可以建立連接的廣播,nrf51822通常發此廣播
②ADV_DIRECT_IND:快速廣播。廣播最長發射事件為1.28S。
③ADV_NONCONN_IND:不能建立連接的廣播信號,ibeacon發此類廣播 - ADV_SCAN_IND為掃描幀,由scanner發出。
- ADV_SCAN_REQ:為掃描請求幀,由scanner發出。只在scanner想從advertiser獲取更多廣播數據時發出。相應的,當ADV_SCAN_REQ被發出以后,advertiser會以SCAN_RSP作為回應
- SCAN_RSP:ADV_SCAN_REQ回應。
- CONNECT_REQ為scanner向advertiser發出
- 以ADV開頭的幀表示為廣播幀。是由advertiser發出的。有四種類型:
- Txadd Rxadd用來表示發送該廣播幀的藍牙設備的藍牙地址類型。1表示random address,0表示為public address。
藍牙協議規定,任何一個藍牙設備必須擁有一個唯一的48bit的地址,用以標識身份。而且,在廣播的時候,必須要把藍牙地址廣播出去。藍牙地址有以下四種:
- public address:該地址是公司通過IEEE申請獲得的,稱為OUI。這個地址是固定地址,全球唯一,不可修改。用24bit表(LSB)示公司名,24bit(MSB)用來分配給不同的產品類型。
- random static address:是設備上電的時候隨機生成或者芯片廠家在生產芯片的時候,隨機燒錄的不重復的48bit的藍牙地址。nrf51822屬于后者。該地址存放在FICR中,用戶不可修改。最高位的后2bit必須位1。
- private Non-Resolvable address和Private Resolvable address不常用,mac地址設置與分析中介紹。
length表示PDU payload大小 - 藍牙設備地址
- PDU payload
0E 09 4C 65 64 42 75 74 74 6F 6E 44 65 6D 6F為1組。0E代表本字段長度 09為LOCAL NAME,也就是藍牙設備名稱。可查ASCII表。表示該設備名稱為LedButtonDemo.
03 19 34 12為1組,03為本字段長度:19為APPEARANCE(外觀,例如BLE_APPEARANCE_HID_MOUSE就會在手機或者PC中顯示有鼠標圖案),因為藍牙拉松數據是低位在前,所以3412其實為1234.0x1234轉成10進制為4660.APPEARANCE這個AD TYPE是新添加的TYPE,所以在CORE 4.0核心協議中找不到
02 01 05為1組,02為字段長度,01是FLAGS 06表示設備只支持BLE,不支持傳統藍牙。05為04+01,見后圖。 - CRC:校驗
- RSSI:信號強度
- FCS:反饋
信道分區圖:
廣播協議包:
藍牙廣播FLAG:
數據包
ble數據包
Access address為接入 地址,接入地址由主設備提供。地址隨機生成。但是遵從一定規律。不同于廣播接入地址固定,具體規定查看藍牙協議。
Direction連接方向。M為主機,S為從機
ACK status響應
Data Type數據類型
Data Header報頭。
? MESN:下一個預期序列號。SN:序列號。MD:更多數據,PDU-Length:PDU長度。沒有為0
- 00:保留
- 11:鏈路層控制報文:用于管理連接
- 10:高級報文開始:可用于一個完整報文
- 01高層報文延續
LED讀寫數據包
讀
寫
寫入01
mac地址分析與設置
BLE設備地址類型
一個BLE設備,可以使用兩種類型的地址(一個BLE設備可同時具備兩種地址):Public Device Address(公共設備地址)和Random Device Address(隨機設備地址)。而Random Device Address又分為Static Device Address(靜態設備地址)和Private Device Address(私密設備 地址)兩類。其中Private Device Address又可以分為Non-resolvable private Address(不可解析私密地址)和Resolvable private Address(可解析私密地址)。
公共設備地址
在通信系統中,設備地址是用來唯一識別一個物理設備的,如TCP/IP網絡中的MAC地址、傳統藍牙中的藍牙地址等。對設備地址而言,一個重要的特性就是唯一性。對經典藍牙(BR/EDR)來說,其設備地址是一個48bit的數字,稱作“48-bit universal LAN MAC addresses”。正常情況下,該地址需要向IEEE申請(就是購買)。IEEE保證地址的唯一性。這種地址分配方式,在BLE中保留下來,就是公共設備地址。由24-bit的company_id和24bit的company_assigned組成(已在本文中介紹)。
隨機設備地址
在BLE時代,公共設備地址不夠用了,原因如下:
1:需要購買,不小開銷
2:申請與管理是相當繁瑣、復雜。維護成本增大
3: 安全因素,BLE很大一部分應用場景是廣播通訊。意味只要設備地址,就可以獲取所有信息。不安全。
因此BLE協議新增該地址。設備地址不是固定分配,而是設備啟動后隨機生成
靜態設備地址
該地址是設備在上電隨機生成的地址,nrf51822官方例程默認使用靜態地址。
特征總結:
1:最高兩位必須為11
2:剩余最后46位是一個隨機數,不可全為0也不可全為1.
3:在一個上電周期內保持不變
4:下一次上電可以改變,但不是強制的。如果改變,上次保存的連接信息將會失效
應用場景總結:
1:46位隨機數,可解決唯一性問題。相同概率很小
2:地址隨機生成,可解決公共設備地址帶來的費用和維護問題
私密設備地址
此地址更近一步,通過定時更新、地址加密方法,提高藍牙地址的可靠性和安全性。根據地址是否解密,又分為兩類。
不可解析私密地址
該地址會定時更新,更新周期由GAP規定,稱作T_GAP,建議值是15分鐘。
特征總結:
1:最高兩位必須為00
2:剩余最后46位是一個隨機數,不可全為0也不可全為1.
3:以T_GAP為周期定時更新。
自己有可能都不知道變成什么地址了,沙雕一樣的方式,該地址類型不常用。
可解析私密地址
該地址比較有用,通過一個隨機數和IRK密碼生成,因此只可能被擁有相同IRK的設備掃描到,可以防止被位置設備掃描和跟蹤。
格式如下:
特征:
A:由兩部分組成,高位是隨機數部分,最高兩個bit為10,用于表示地址類型。低位時隨機數和IRK經過hash運算得到的hash值。運算公式為hash=ah(IRK,prand)
B:當對端BLE設備掃描到該類型藍牙地址后,會使用保存在本機的IRK,和該地址中的prand,進行同樣的hash運算,并將運算結果和地址中的hash字段進行比較,相同的時候才進行后續操作。該過程稱為解析。
C:以T_GAP為周期,定時更新,哪怕在廣播、掃描、已連接過程中也可能改變。
D:不能單獨使用,因此使用該類型的地址的話,設備需要同時具備公共設備地址或者靜態設備地址中的一種。
地址配置
此時可以看廣播包數據分析的第六部分和第七部分 ,如果是隨機地址可通過查看地址最高兩位來判斷地址類型。
函數api:
SVCALL(SD_BLE_GAP_ADDRESS_SET, uint32_t, sd_ble_gap_address_set(uint8_t addr_cycle_mode, const ble_gap_addr_t *p_addr)); //addr_cycle_mode : //①:BLE_GAP_ADDR_CYCLE_MODE_AUTO:該模式下,設置為可解析私密地址或者不可解析私密地址。協議棧內部會自動周期性根據結構體p_addr中的addr_type元素生成地址 //②:BLE_GAP_ADDR_CYCLE_MODE_NONE:該模式下,可以使用public地址和static random類型,addr中存放的最高兩位必須為11,不然會被認為無效且自動替換。替換為藍牙mac地址。和沒有使用該函數一樣。默認狀態:
官方demo是沒有主動調用過該函數,都默認使用靜態設備地址。是芯片出廠就設置的。
這兩個視頻應該是放反了
藍牙信號rssi讀取
rssi接收的信號強度指示。用于判斷連接質量。以及是否增大廣播發送強度。
為什么是負值
無線信號多為mW級別,對他進行了極化,轉換為dbm而已。
公式:Rssi=10 * log§
將P帶入即可。
API
/**@brief Start reporting the received signal strength to the application. ** A new event is reported whenever the RSSI value changes, until @ref sd_ble_gap_rssi_stop is called.** @param[in] conn_handle Connection handle.* @param[in] threshold_dbm Minimum change in dBm before triggering the @ref BLE_GAP_EVT_RSSI_CHANGED event. Events are disabled if threshold_dbm equals @ref BLE_GAP_RSSI_THRESHOLD_INVALID.* @param[in] skip_count Number of RSSI samples with a change of threshold_dbm or more before sending a new @ref BLE_GAP_EVT_RSSI_CHANGED event.** @retval ::NRF_SUCCESS Successfully activated RSSI reporting.* @retval ::NRF_ERROR_INVALID_STATE Disconnection in progress. Invalid state to perform operation.* @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied.*/ SVCALL(SD_BLE_GAP_RSSI_START, uint32_t, sd_ble_gap_rssi_start(uint16_t conn_handle, uint8_t threshold_dbm, uint8_t skip_count)); //開始測量信號強度/**@brief Get the received signal strength for the last connection event.** @param[in] conn_handle Connection handle.* @param[out] p_rssi Pointer to the location where the RSSI measurement shall be stored.** @ref sd_ble_gap_rssi_start must be called to start reporting RSSI before using this function. @ref NRF_ERROR_NOT_FOUND* will be returned until RSSI was sampled for the first time after calling @ref sd_ble_gap_rssi_start.** @retval ::NRF_SUCCESS Successfully read the RSSI.* @retval ::NRF_ERROR_NOT_FOUND No sample is available.* @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.* @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied.* @retval ::NRF_ERROR_INVALID_STATE RSSI reporting is not ongoing, or disconnection in progress.*/ SVCALL(SD_BLE_GAP_RSSI_GET, uint32_t, sd_ble_gap_rssi_get(uint16_t conn_handle, int8_t *p_rssi)); //獲取信號強度藍牙發射功率的設置
nrf51822可以設置9個發送等級分別是-40,-30,-20,-16,-12,-8,-4,0,4dBm。如果沒有設置,則默認為0dbm。
1,廣播初始化:設置廣播的tx_power_level,用于初始化廣播的發送功率。
#define TX_POWER_LEVEL 0 static void advertising_init(void){int8_t tx_power_level=TX_POWER_LEVEL;advdata.p_tx_power_level = &tx_power_level;ble_advertisingOinit(&advdata,&scanrsp,&options,on_adv_evt,NULL); }2,GAP初始化:通過sd_ble_gap_tx_power_set設置。該函數可動態修改發送功率。
errcode = sd_ble_gap_tx_power_set(TX_POWER_LEVEL);本文章首發于本人個人網站
總結
以上是生活随笔為你收集整理的nrf51822蓝牙学习笔记四的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 推荐一些经典书籍,100多本(转)
- 下一篇: 清华大学(软件学院)-中国核能电力股份有