IoT大殺器nRF52832
nRF52832 SoC芯片主要參數:
* ARM Cortex-M4,32-bit
* 最大主頻64 MHz
* 內部閃存512kB
* SRAM達到64kB
* 支持Bluetooth 5和NFC
* 支持多種開發環境
相比之下Arduino Uno的ATmega328芯片的主頻才16MHz,Flash 32kB,SRAM 2kB,不帶任何無線功能。對比強烈。
Nordic的官方組件評測可以看:
一款基於Cortex-M4的BLE SoC——Nordic nRF52開發套件評測搜狐科技搜狐網
Arduino也推出了Primo這個板子:
Arduino使用Nordic nRF52832 SoC的Arduino Primo基板-通信/網絡-與非網
RedBear BLE Nano Kit v2
入手的是RedBear推出的超小型開發板。小巧全能就是王道!
這個板子雖然是某香港/深圳公司做的,中文世界的介紹幾乎沒有,RedBear的人看到此文不介意給本人支付廣告費(@HᴗP@)。
nRF52832的特性之外,還有:
* Arduino IDE,Mbed,JavaScript,Nordic nRF52 SDK,Python,Apache Mynewt,FreeRTOS等開發環境
* 板載LED D13
* UART,SPI,I2C
* 最大11個端口,也足夠用了
* VDD除了3.3V,還支持1.8V的輸出
* 可以在1.8V-3.6V工作
* 大小隻有大概2釐米見方
* 支持Over-The-Air,也就是不連電腦直接通過BLE寫程序
還有官方Kit,多了USB讀寫器DAPLink
開發板介紹:
Kickstarter page
nRF5x/nRF52832 at master · redbear/nRF5x · GitHub
RedBear (注意:官網是找不到Nano2介紹頁面的=͟͟͞͞(HㅍP),只有
基於nRF51832的一代Nano的介紹,兩代非常不同 )
官方還有擴展板
RedBear BLE Nano Kit v2開箱
可以看到其實BLE Nano的板子只比USB插口大了一點點,大概就是正常人的拇指那麼大吧。下面作對比的是ESP32。
插電前必須注意插入讀寫器的方向,白色的小熊logo是朝外的。
插電後就可以進行BLE測試,本來已經預先安裝了心率服務:nRF5x/Getting_Started_Guide.md at master · redbear/nRF5x · GitHub
windows系統可能需要先安裝mbed的驅動:https://developer.mbed.org/handbook/Windows-serial-configuration
Arduino IDE追加庫
按照官方介紹操作:nRF5x/Arduino_Board_Package_Installation_Guide.md at master · redbear/nRF5x · GitHub
- 先在設置那裏添加鏈接:https://redbear.github.io/arduino/package_redbear_nRF5x_index.json
- 然後在Boards Manager裏面搜索RedBear nRF52832
安裝完了之後就可以看到IDE裏面出現了BLE_Nano2的板子,注意不要搞混一代Nano和二代了,兩者不通用。
這時候可以進行Arduino標準的LED測試,記得端口換成D13就行。
BLE Simple Chat測試
先安裝官方的APP:BLEController
Arduino IDE裏面打開File>Examples>BLE_Examples>SimpleChat並上傳
官方APP裏面找到設備並連接,
在手機裏面輸入文字,Serial Monitor裏面就有反應。
反過來Serial Monitor裏面輸入文字,手機就有輸出。
實現簡單的文字傳輸功能。
並非Arduino風格的BLE語法
好了,用是可以使用,看一下具體代碼的話就會發現,BLE部分的語法並不是一般arduino裏面常用的那種,而是類似mbed的語法,這個說明又是一個大坑了。
另外可以用Nordic SDK,自由度更高,開發HID等高級功能逃不過,當然這個坑更大更深。
/*
* Copyright (c) 2016 RedBear
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <nRF5x_BLE_API.h>
#define DEVICE_NAME "BLE_Peripheral" // 被搜索的時候看到的名字
#define TXRX_BUF_LEN 20 // 這個是BLE每次傳輸緩衝的最大字節數,最大20
BLE ble;
Timeout timeout;
static uint8_t rx_buf[TXRX_BUF_LEN]; // 這個是BLE每次傳輸緩衝的最大字節數,最大20
static uint8_t rx_buf_num;
static uint8_t rx_state=0;
// 需要自己定義16進制的uuid
// The uuid of service and characteristics
static const uint8_t service1_uuid[] = {0x71, 0x3D, 0, 0, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
static const uint8_t service1_tx_uuid[] = {0x71, 0x3D, 0, 3, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
static const uint8_t service1_rx_uuid[] = {0x71, 0x3D, 0, 2, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
static const uint8_t uart_base_uuid_rev[] = {0x1E, 0x94, 0x8D, 0xF1, 0x48, 0x31, 0x94, 0xBA, 0x75, 0x4C, 0x3E, 0x50, 0, 0, 0x3D, 0x71};
uint8_t tx_value[TXRX_BUF_LEN] = {0,};
uint8_t rx_value[TXRX_BUF_LEN] = {0,};
// Initialize value of chars
GattCharacteristic characteristic1(service1_tx_uuid, tx_value, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE ); // 定義特徵的讀寫權限等
GattCharacteristic characteristic2(service1_rx_uuid, rx_value, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
GattCharacteristic *uartChars[] = {&characteristic1, &characteristic2};
GattService uartService(service1_uuid, uartChars, sizeof(uartChars) / sizeof(GattCharacteristic *));
// BLE斷開後的操作
void disconnectionCallBack(const Gap::DisconnectionCallbackParams_t *params) {
Serial.println("Disconnected!");
Serial.println("Restarting the advertising process");
ble.startAdvertising(); // 開始advertising
}
// central設備有write請求時候的操作
void gattServerWriteCallBack(const GattWriteCallbackParams *Handler) {
uint8_t buf[TXRX_BUF_LEN];
uint8_t index;
uint16_t bytesRead = TXRX_BUF_LEN;
Serial.println("onDataWritten : ");
if (Handler->handle == characteristic1.getValueAttribute().getHandle()) {
// 讀出特徵的數據
ble.readCharacteristicValue(characteristic1.getValueAttribute().getHandle(), buf, &bytesRead);
Serial.print("bytesRead: ");
Serial.println(bytesRead, HEX);
for(index=0; index<bytesRead; index++) {
Serial.write(buf[index]);
}
Serial.println("");
}
}
void m_uart_rx_handle() { //update characteristic data
ble.updateCharacteristicValue(characteristic2.getValueAttribute().getHandle(), rx_buf, rx_buf_num);
memset(rx_buf, 0x00,20);
rx_state = 0;
}
void uart_handle(uint32_t id, SerialIrq event) { /* Serial rx IRQ */
if(event == RxIrq) {
if(rx_state == 0) {
rx_state = 1;
timeout.attach_us(m_uart_rx_handle, 100000);
rx_buf_num=0;
}
while(Serial.available()) {
if(rx_buf_num < 20) {
rx_buf[rx_buf_num] = Serial.read();
rx_buf_num++;
}
else {
Serial.read();
}
}
}
}
void setup() {
// put your setup code here, to run once
Serial.begin(9600);
Serial.attach(uart_handle);
ble.init();
ble.onDisconnection(disconnectionCallBack);
ble.onDataWritten(gattServerWriteCallBack);
// setup adv_data and srp_data
ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
ble.accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME,
(const uint8_t *)"TXRX", sizeof("TXRX") - 1);
ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
(const uint8_t *)uart_base_uuid_rev, sizeof(uart_base_uuid_rev));
// set adv_type
ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
// add service
ble.addService(uartService);
// set device name
ble.setDeviceName((const uint8_t *)"Simple Chat");
// set tx power,valid values are -40, -20, -16, -12, -8, -4, 0, 4
ble.setTxPower(4);
// set adv_interval, 100ms in multiples of 0.625ms.
ble.setAdvertisingInterval(160);
// set adv_timeout, in seconds
ble.setAdvertisingTimeout(0);
// start advertising
ble.startAdvertising();
Serial.println("Advertising Start!");
}
void loop() {
ble.waitForEvent();
}
諸多參考
BLE Nanoを試してみました - surga Lab
RedBearLab BLE Nano の設定方法とOTA | Home Made Garbage
BLE Car01
blenanov2をarduinoideを使ってプログラミングする方法
【Arduino】BLE NanoでスマートフォンとBLE通信する - おもちゃラボ
ArduinoRedBearLab BLE Nanoを使ってみる : 工作と競馬
BLE NanoではじめてのBLE通信!クラゲのIoTテクノロジー
BLE Nano2ではじめてのBLE通信!クラゲのIoTテクノロジー
BLEnanoで必要なときだけLCDに情報を表示する方法 : 試行錯誤な日々
有事別忘了騷擾官方論壇:BLE Nano 2 (nRF52832) - Discussion Forums